Spade
Mini Shell
PK$d�[<���
bootstrap.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
include __DIR__ . '/Loader.php';
return \Gantry5\Loader::get();
PK$d�[���.classes/Gantry/Admin/Controller/Html/About.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Admin\ThemeList;
use Gantry\Component\Admin\HtmlController;
class About extends HtmlController
{
public function index()
{
// TODO: Find better way:
$this->params['info'] = (new
ThemeList)->getTheme($this->container['theme.name']);
return
$this->render('@gantry-admin/pages/about/about.html.twig',
$this->params);
}
}
PK$d�[$�_EYY.classes/Gantry/Admin/Controller/Html/Cache.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Response\JsonResponse;
use Gantry\Component\Filesystem\Folder;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Cache extends HtmlController
{
public function index()
{
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
Folder::delete($locator('gantry-cache://theme'), false);
Folder::delete($locator('gantry-cache://admin'), false);
// Make sure that PHP has the latest data of the files.
clearstatcache();
return new JsonResponse(['html' => 'Cache was
successfully cleared', 'title' => 'Cache
Cleared']);
}
}
PK$d�[��x� Cclasses/Gantry/Admin/Controller/Html/Configurations/Assignments.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html\Configurations;
use Gantry\Component\Admin\HtmlController;
use Gantry\Framework\Assignments as AssignmentsObject;
use RocketTheme\Toolbox\Event\Event;
class Assignments extends HtmlController
{
public function index()
{
$outline = $this->params['outline'];
if ($this->hasAssignments($outline)) {
$assignments = new AssignmentsObject($outline);
$this->params['assignments'] =
$assignments->get();
$this->params['options'] =
$assignments->assignmentOptions();
$this->params['assignment'] =
$assignments->getAssignment();
}
return
$this->render('@gantry-admin/pages/configurations/assignments/assignments.html.twig',
$this->params);
}
public function store()
{
// Authorization.
if (!$this->authorize('outline.assign')) {
$this->forbidden();
}
$outline = $this->params['outline'];
if (!$this->hasAssignments($outline)) {
$this->undefined();
}
if (!$this->request->post->get('_end')) {
throw new \OverflowException("Incomplete data received.
Please increase the value of 'max_input_vars' variable (in
php.ini or .htaccess)", 400);
}
// Save assignments.
$assignments = new AssignmentsObject($outline);
$assignments->save($this->request->post->getArray('assignments'));
// Fire save event.
$event = new Event;
$event->gantry = $this->container;
$event->theme = $this->container['theme'];
$event->controller = $this;
$event->assignments = $assignments;
$this->container->fireEvent('admin.assignments.save',
$event);
return '';
}
protected function hasAssignments($outline)
{
// Default outline and system outlines cannot have assignments.
return $outline !== 'default' && $outline[0] !==
'_';
}
}
PK$d�[�}mFmF>classes/Gantry/Admin/Controller/Html/Configurations/Layout.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html\Configurations;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Config\BlueprintSchema;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Layout\Layout as LayoutObject;
use Gantry\Component\Response\JsonResponse;
use Gantry\Framework\Outlines;
use RocketTheme\Toolbox\Event\Event;
class Layout extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/create' => 'create',
'/create/*' => 'create',
'/*' => 'undefined',
'/switch' => 'listSwitches',
'/switch/*' => 'switchLayout',
'/preset' => 'undefined',
'/preset/*' => 'preset'
],
'POST' => [
'/' => 'save',
'/*' => 'undefined',
'/*/*' => 'particle',
'/switch' => 'undefined',
'/switch/*' =>
'switchLayout',
'/preset' => 'undefined',
'/preset/*' => 'preset',
'/particles' => 'undefined',
'/particles/*' => 'undefined',
'/particles/*/validate' => 'validate'
],
'PUT' => [
'/*' => 'replace'
],
'PATCH' => [
'/*' => 'update'
],
'DELETE' => [
'/*' => 'destroy'
]
];
public function create($id = null)
{
if (!$id) {
// TODO: we might want to display list of options here
throw new \RuntimeException('Not Implemented', 404);
}
$layout = $this->getLayout("presets/{$id}");
if (!$layout) {
throw new \RuntimeException('Preset not found', 404);
}
$this->params['page_id'] = $id;
$this->params['layout'] =
$layout->prepareWidths()->toArray();
return
$this->render('@gantry-admin/pages/configurations/layouts/create.html.twig',
$this->params);
}
public function index()
{
$outline = $this->params['outline'];
$layout = $this->getLayout($outline);
if (!$layout) {
throw new \RuntimeException('Layout not found', 404);
}
$groups = [
'Positions' => ['position' => [],
'spacer' => [], 'system' => []],
'Particles' => ['particle' => []]
];
$particles = [
'position' => [],
'spacer' => [],
'system' => [],
'particle' => []
];
$particles = array_replace($particles, $this->getParticles());
foreach ($particles as &$group) {
asort($group);
}
unset($group);
foreach ($groups as $section => $children) {
foreach ($children as $key => $child) {
$groups[$section][$key] = $particles[$key];
}
}
$this->params['page_id'] = $outline;
$this->params['layout'] =
$layout->prepareWidths()->toArray();
$this->params['preset'] = $layout->preset;
$this->params['preset_title'] =
ucwords(trim(str_replace('_', ' ',
$layout->preset['name'])));
$this->params['id'] =
ucwords(str_replace('_', ' ', ltrim($outline,
'_')));
$this->params['particles'] = $groups;
$this->params['switcher_url'] =
str_replace('.', '/',
"configurations.{$outline}.layout.switch");
return
$this->render('@gantry-admin/pages/configurations/layouts/edit.html.twig',
$this->params);
}
public function save()
{
$layout = $this->request->post->get('layout');
$layout = json_decode($layout);
if (!isset($layout)) {
throw new \RuntimeException('Error while saving layout:
Structure missing', 400);
}
$outline = $this->params['outline'];
$preset =
$this->request->post->getJsonArray('preset');
// Create layout from the data.
$layout = new LayoutObject($outline, $layout, $preset);
$layout->init(false, false);
/** @var Outlines $outlines */
$outlines = $this->container['outlines'];
// Update layouts from all inheriting outlines.
$elements = $layout->sections() + $layout->particles(false);
foreach ($outlines->getInheritingOutlines($outline) as
$inheritedId => $inheritedName) {
LayoutObject::instance($inheritedId)->updateInheritance($outline,
$outline, $elements)->save()->saveIndex();
}
// Save layout and its index.
$layout->save()->saveIndex();
// Fire save event.
$event = new Event;
$event->gantry = $this->container;
$event->theme = $this->container['theme'];
$event->controller = $this;
$event->layout = $layout;
$this->container->fireEvent('admin.layout.save',
$event);
}
public function particle($type, $id)
{
if ($type === 'atom') { return ''; }
$outline = $this->params['outline'];
$layout = $this->getLayout($outline);
if (!$layout) {
throw new \RuntimeException('Layout not found', 404);
}
$item = $layout->find($id);
$item->type = $this->request->post['type'] ?:
$type;
$item->subtype = $this->request->post['subtype']
?: $type;
$item->title = $this->request->post['title']
?: ucfirst($type);
$parent = $this->request->post['parent'] ?:
$layout->getParentId($id);
if (!isset($item->attributes)) {
$item->attributes = new \stdClass;
}
if (!isset($item->inherit)) {
$item->inherit = new \stdClass;
}
$block =
$this->request->post->getArray('block');
if (!empty($block)) {
$item->block = (object) $block;
}
$attributes =
$this->request->post->getArray('options');
$inherit =
$this->request->post->getArray('inherit');
$particle = !$layout->isLayoutType($type);
if (!$particle) {
$name = $type;
$section = ($type === 'section');
$hasBlock = $section && !empty($block);
$prefix = "particles.{$type}";
$defaults = [];
$attributes += (array) $item->attributes;
$blueprints =
BlueprintForm::instance("layout/{$type}.yaml",
'gantry-admin://blueprints');
} else {
$name = $item->subtype;
$hasBlock = true;
$prefix = "particles.{$name}";
$defaults = (array)
$this->container['config']->get($prefix);
$blueprints =
$this->container['particles']->getBlueprintForm($name);
$blueprints->set('form/fields/_inherit',
['type' => 'gantry.inherit']);
}
if ($hasBlock) {
$blockBlueprints =
BlueprintForm::instance('layout/block.yaml',
'gantry-admin://blueprints');
} else {
$blockBlueprints = null;
}
$file =
"gantry-admin://blueprints/layout/inheritance/{$type}.yaml";
if (file_exists($file)) {
$inheritType = $particle ? 'particle' :
'section';
/** @var Outlines $outlines */
$outlines = $this->container['outlines'];
if ($outline !== 'default') {
if ($particle) {
$list =
$outlines->getOutlinesWithParticle($item->subtype, false);
} else {
$list =
$outlines->getOutlinesWithSection($item->id, false);
}
unset($list[$outline]);
} else {
$list = [];
}
if (!empty($inherit['outline']) || (!($inheriting =
$outlines->getInheritingOutlines($outline, [$id, $parent])) &&
$list)) {
$inheritable = true;
$inheritance = BlueprintForm::instance($file,
'gantry-admin://blueprints');
$inheritance->set('form/fields/outline/filter',
array_keys($list));
if (!$hasBlock) {
$inheritance->undef('form/fields/include/options/block');
}
if ($particle) {
$inheritance->set('form/fields/particle/particle', $name);
}
} elseif (!empty($inheriting)) {
// Already inherited by other outlines.
$inheritance =
BlueprintForm::instance('layout/inheritance/messages/inherited.yaml',
'gantry-admin://blueprints');
$inheritance->set(
'form/fields/_note/content',
sprintf($inheritance->get('form/fields/_note/content'),
$inheritType, ' <ul><li>' . implode('</li>
<li>', $inheriting) . '</li></ul>')
);
} elseif ($outline === 'default') {
// Base outline.
$inheritance =
BlueprintForm::instance('layout/inheritance/messages/default.yaml',
'gantry-admin://blueprints');
} else {
// Nothing to inherit from.
$inheritance =
BlueprintForm::instance('layout/inheritance/messages/empty.yaml',
'gantry-admin://blueprints');
}
}
$item->attributes = (object) $attributes;
$item->inherit = (object) $inherit;
$this->params['id'] = $name;
$this->params += [
'extra' => $blockBlueprints,
'inherit' =>
!empty($inherit['outline']) ? $inherit['outline'] :
null,
'inheritance' => isset($inheritance) ?
$inheritance : null,
'inheritable' => !empty($inheritable),
'item' => $item,
'data' => ['particles' =>
[$name => $item->attributes]],
'defaults' => ['particles' =>
[$name => $defaults]],
'prefix' => "particles.{$name}.",
'particle' => $blueprints,
'parent' => 'settings',
'route' =>
"configurations.{$outline}.settings",
'action' => str_replace('.',
'/', 'configurations.' . $outline .
'.layout.' . $prefix . '.validate'),
'skip' => ['enabled'],
'editable' => $particle,
'overrideable' => $particle,
];
if ($particle) {
$result =
$this->render('@gantry-admin/pages/configurations/layouts/particle.html.twig',
$this->params);
} else {
$typeLayout = $type === 'container' ?
'container' : 'section';
$result =
$this->render('@gantry-admin/pages/configurations/layouts/' .
$typeLayout . '.html.twig', $this->params);
}
return $result;
}
public function listSwitches()
{
$this->params['presets'] = LayoutObject::presets();
$result =
$this->render('@gantry-admin/layouts/switcher.html.twig',
$this->params);
return new JsonResponse(['html' => $result]);
}
public function switchLayout($id)
{
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
$outline = $this->params['outline'];
$layout = $this->getLayout($id);
if (!$layout->toArray()) {
// Layout hasn't been defined, return default layout
instead.
$layout = $this->getLayout('default');
}
$input =
$this->request->post->getJson('layout');
$deleted = isset($input) ?
$layout->clearSections()->copySections($input): [];
if ($outline === 'default') {
$layout->inheritNothing();
} elseif (!$input &&
$this->request->post['inherit'] === '1') {
$layout->inheritAll();
}
$message = $deleted
?
$this->render('@gantry-admin/ajax/particles-loss.html.twig',
['particles' => $deleted])
: null;
return new JsonResponse([
'title' => ucwords(trim(str_replace('_',
' ', $layout->preset['name']))),
'preset' => json_encode($layout->preset),
'data' =>
$layout->prepareWidths()->toJson(),
'deleted' => $deleted,
'message' => $message
]);
}
public function preset($id)
{
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
$preset = LayoutObject::preset($id);
if (!$preset) {
throw new \RuntimeException('Preset not found', 404);
}
$layout = new LayoutObject($id, $preset);
$input =
$this->request->post->getJson('layout');
$deleted = isset($input) ?
$layout->clearSections()->copySections($input): [];
$message = $deleted
?
$this->render('@gantry-admin/ajax/particles-loss.html.twig',
['particles' => $deleted])
: null;
return new JsonResponse([
'title' => ucwords(trim(str_replace('_',
' ', $id))),
'preset' => json_encode($layout->preset),
'data' =>
$layout->prepareWidths()->toJson(),
'deleted' => $deleted,
'message' => $message
]);
}
public function validate($particle)
{
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
// Load particle blueprints and default settings.
$validator = new BlueprintSchema;
$name = $particle;
if (in_array($particle, ['wrapper', 'section',
'container', 'grid', 'offcanvas'], true)) {
$type = $particle;
$particle = null;
$file =
CompiledYamlFile::instance("gantry-admin://blueprints/layout/{$type}.yaml");
$validator->embed('options',
(array)$file->content());
$file->free();
} else {
$type = in_array($particle, ['spacer',
'system', 'position'], true) ? $particle :
'particle';
$validator->embed('options',
$this->container['particles']->get($particle));
}
// Create configuration from the defaults.
$data = new Config(
[
'type' => $type,
],
function () use ($validator) {
return $validator;
}
);
// Join POST data.
$data->join('options',
$this->request->post->getArray("particles." . $name));
if ($particle) {
$data->set('options.enabled', (int)
$data->get('options.enabled', 1));
}
if ($particle) {
if ($type !== $particle) {
$data->set('subtype', $particle);
}
$data->join('title',
$this->request->post['title'] ?: ucfirst($particle));
}
$block =
$this->request->post->getArray('block');
if ($block) {
// TODO: remove empty items in some other way:
foreach ($block as $key => $param) {
if ($param === '') {
unset($block[$key]);
continue;
}
if ($key === 'size') {
$param = round($param, 4);
if ($param < 5) {
$param = 5;
} elseif ($param > 100) {
$param = 100;
}
$block[$key] = $param;
}
}
$data->join('block', $block);
}
$inherit =
$this->request->post->getArray('inherit');
$clone = !empty($inherit['mode']) &&
$inherit['mode'] === 'clone';
$inherit['include'] =
!empty($inherit['include']) ? explode(',',
$inherit['include']) : [];
if (!$clone && !empty($inherit['outline'])
&& count($inherit['include'])) {
// Clean up inherit and add it to the data.
if (!$block) {
$inherit['include'] =
array_values(array_diff($inherit['include'],
['block']));
}
unset($inherit['mode']);
$data->join('inherit', $inherit);
}
// Optionally send children of the object.
if (in_array('children', $inherit['include'],
true)) {
$layout = LayoutObject::instance($inherit['outline']
?: $this->params['outline']);
if ($clone) {
$item = $layout->find($inherit['section']);
} else {
$item =
$layout->inheritAll()->find($inherit['section']);
}
$data->join('children', !empty($item->children)
? $item->children : []);
}
// TODO: validate
return new JsonResponse(['data' =>
$data->toArray()]);
}
/**
* @param string $name
* @return LayoutObject
*/
protected function getLayout($name)
{
return LayoutObject::instance($name);
}
protected function getParticles($onlyEnabled = false)
{
/** @var Config $config */
$config = $this->container['config'];
$particles = $this->container['particles']->all();
$list = [];
foreach ($particles as $name => $particle) {
$type = isset($particle['type']) ?
$particle['type'] : 'particle';
$particleName = isset($particle['name']) ?
$particle['name'] : $name;
$particleIcon = isset($particle['icon']) ?
$particle['icon'] : null;
if (!$onlyEnabled ||
$config->get("particles.{$name}.enabled", true)) {
$list[$type][$name] = ['name' =>
$particleName, 'icon' => $particleIcon];
}
}
return $list;
}
}
PK$d�['��L-L-<classes/Gantry/Admin/Controller/Html/Configurations/Page.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html\Configurations;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Config\BlueprintSchema;
use Gantry\Component\Config\Config;
use Gantry\Component\Layout\Layout;
use Gantry\Component\Response\JsonResponse;
use Gantry\Framework\Atoms;
use Gantry\Framework\Services\ConfigServiceProvider;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Page extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index'
],
'POST' => [
'/' => 'save',
'/*' => 'save',
'/*/**' => 'formfield',
'/atoms' => 'undefined',
'/atoms/*' => 'atom',
'/atoms/*/validate' => 'atomValidate'
],
'PUT' => [
'/' => 'save'
],
'PATCH' => [
'/' => 'save'
],
'DELETE' => [
'/' => 'forbidden'
]
];
public function index()
{
$outline = $this->params['outline'];
if ($outline == 'default') {
$this->params['overrideable'] = false;
$data = $this->container['config'];
} else {
$this->params['overrideable'] = true;
$this->params['defaults'] = $defaults =
$this->container['defaults'];
$data = ConfigServiceProvider::load($this->container,
$outline, false, false);
}
$deprecated = $this->getDeprecatedAtoms();
if ($deprecated) {
$data->set('page.head.atoms', $deprecated);
}
if (isset($defaults)) {
$currentAtoms = $data->get('page.head.atoms');
if (!$currentAtoms) {
// Make atoms to appear to be inherited in they are loaded
from defaults.
$defaultAtoms = (array)
$defaults->get('page.head.atoms');
$atoms = (new
Atoms($defaultAtoms))->inheritAll('default')->toArray();
$defaults->set('page.head.atoms', $atoms);
}
}
$this->params += [
'data' => $data,
'page' =>
$this->container['page']->group(),
'route' => "configurations.{$outline}",
'page_id' => $outline,
'atoms' => $this->getAtoms(),
'atoms_deprecated' => $deprecated
];
return
$this->render('@gantry-admin/pages/configurations/page/page.html.twig',
$this->params);
}
public function save($id = null)
{
$data = $id ? [$id => $this->request->post->getArray()]
: $this->request->post->getArray('page');
foreach ($data as $name => $values) {
$this->saveItem($name, $values);
}
// Fire save event.
$event = new Event;
$event->gantry = $this->container;
$event->theme = $this->container['theme'];
$event->controller = $this;
$event->data = $data;
$this->container->fireEvent('admin.page.save',
$event);
return $id ? $this->display($id) : $this->index();
}
public function formfield($id)
{
$path = func_get_args();
$end = end($path);
if ($end === '') {
array_pop($path);
}
if (end($path) == 'validate') {
return call_user_func_array([$this, 'validate'],
$path);
}
// Load blueprints.
$blueprints =
$this->container['page']->getBlueprintForm($id);
list($fields, $path, $value) =
$blueprints->resolve(array_slice($path, 1), '/');
if (!$fields) {
throw new \RuntimeException('Page Not Found', 404);
}
$data =
$this->request->post->getJsonArray('data');
$offset = "page.{$id}." . implode('.', $path);
if ($value !== null) {
$parent = $fields;
$fields = ['fields' =>
$fields['fields']];
$offset .= '.' . $value;
$data = $data ?:
$this->container['config']->get($offset);
$data = ['data' => $data];
$scope = 'data.';
} else {
$data = $data ?:
$this->container['config']->get($offset);
$scope = 'data';
}
$fields['is_current'] = true;
array_pop($path);
$outline = $this->params['outline'];
$configuration = "configurations/{$outline}";
$this->params = [
'configuration' => $configuration,
'blueprints' => $fields,
'data' => $data,
'prefix' => '',
'scope' => $scope,
'parent' => $path
? "$configuration/settings/particles/{$id}/"
. implode('/', $path)
: "$configuration/settings/particles/{$id}",
'route' =>
"configurations.{$outline}.{$offset}",
] + $this->params;
if (isset($parent['key'])) {
$this->params['key'] = $parent['key'];
}
if (isset($parent['value'])) {
$this->params['title'] =
$parent['value'];
}
return
$this->render('@gantry-admin/pages/configurations/settings/field.html.twig',
$this->params);
}
public function validate($particle)
{
$path = implode('.', array_slice(func_get_args(), 1,
-1));
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
// Load particle blueprints.
$validator =
$this->container['particles']->get($particle);
// Create configuration from the defaults.
$data = new Config(
[],
function () use ($validator) {
return $validator;
}
);
$data->join($path,
$this->request->post->getArray('data'));
// TODO: validate
return new JsonResponse(['data' =>
$data->get($path)]);
}
public function atom($name)
{
$outline = $this->params['outline'];
$atoms = Atoms::instance($outline);
$data = $this->request->post['data'];
if ($data) {
$data = json_decode($data, true);
} else {
$data = $this->request->post->getArray();
}
// Create atom and get its blueprint.
$item = $atoms->createAtom($name, $data);
$blueprint = $item->blueprint();
// Load inheritance blueprint.
$inheritance = $atoms->getInheritanceBlueprint($name,
$item->id);
$inheritable = $inheritance &&
$inheritance->get('form/fields/outline/filter', []);
$this->params += [
'inherit' =>
!empty($inherit['outline']) ? $inherit['outline'] :
null,
'inheritance' => $inheritance,
'inheritable' => $inheritable,
'item' => $item,
'data' => ['particles' =>
[$name => $item->attributes]],
'blueprints' => $blueprint,
'parent' => 'settings',
'prefix' => "particles.{$name}.",
'route' =>
"configurations.default.settings",
'action' =>
"configurations/{$outline}/page/atoms/{$name}/validate",
'skip' => ['enabled']
];
return new JsonResponse(['html' =>
$this->render('@gantry-admin/modals/atom.html.twig',
$this->params)]);
}
/**
* Validate data for the atom.
*
* @param string $name
* @return JsonResponse
*/
public function atomValidate($name)
{
// Load particle blueprints and default settings.
$validator = new BlueprintSchema;
$validator->embed('options',
$this->container['particles']->get($name));
$blueprints =
$this->container['particles']->getBlueprintForm($name);
// Create configuration from the defaults.
$data = new Config([],
function () use ($validator) {
return $validator;
}
);
$data->set('id',
$this->request->post['id']);
$data->set('type', $name);
$data->set('title',
$this->request->post['title'] ?:
$blueprints->get('name'));
$data->set('attributes',
$this->request->post->getArray("particles.{$name}"));
$data->def('attributes.enabled', 1);
$block =
$this->request->post->getArray('block');
foreach ($block as $key => $param) {
if ($param === '') {
unset($block[$key]);
}
}
$inherit =
$this->request->post->getArray('inherit');
$clone = !empty($inherit['mode']) &&
$inherit['mode'] === 'clone';
$inherit['include'] =
!empty($inherit['include']) ? explode(',',
$inherit['include']) : [];
if (!$clone && !empty($inherit['outline'])
&& count($inherit['include'])) {
unset($inherit['mode']);
$data->join('inherit', $inherit);
}
// TODO: validate
// Fill parameters to be passed to the template file.
$this->params['item'] = (object) $data->toArray();
return new JsonResponse(['item' =>
$data->toArray()]);
}
protected function saveItem($id, $data)
{
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
// Save layout into custom directory for the current theme.
$outline = $this->params['outline'];
// Move atoms out of layout.
if ($id === 'head') {
$layout = Layout::instance($outline);
if (is_array($layout->atoms())) {
$layout->save(false);
}
if (isset($data['atoms'])) {
$atoms = new Atoms($data['atoms']);
$data['atoms'] =
$atoms->update()->toArray();
}
}
$save_dir =
$locator->findResource("gantry-config://{$outline}/page",
true, true);
$filename = "{$save_dir}/{$id}.yaml";
$file = YamlFile::instance($filename);
if (!is_array($data)) {
if ($file->exists()) {
$file->delete();
}
} else {
$blueprints =
$this->container['page']->getBlueprintForm($id);
$config = new Config($data, function () use ($blueprints) {
return $blueprints; });
$file->save($config->toArray());
}
$file->free();
}
protected function getDeprecatedAtoms()
{
$id = $this->params['outline'];
$layout = Layout::instance($id);
return $layout->atoms();
}
protected function getAtoms($onlyEnabled = false)
{
$config = $this->container['config'];
$atoms = $this->container['particles']->all();
$list = [];
foreach ($atoms as $name => $atom) {
$type = isset($atom['type']) ?
$atom['type'] : 'atom';
$atomName = isset($atom['name']) ?
$atom['name'] : $name;
if (!$onlyEnabled ||
$config->get("particles.{$name}.enabled", true)) {
$list[$type][$name] = $atomName;
}
}
return $list['atom'];
}
}
PK$d�[�Qޙ""@classes/Gantry/Admin/Controller/Html/Configurations/Settings.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html\Configurations;
use Gantry\Admin\Particles;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Config\Config;
use Gantry\Component\Response\JsonResponse;
use Gantry\Framework\Services\ConfigServiceProvider;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Settings extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/particles' => 'undefined',
'/particles/*' => 'display',
'/particles/*/**' => 'formfield',
],
'POST' => [
'/' => 'save',
'/particles' => 'forbidden',
'/particles/*' => 'save',
'/particles/*/**' => 'formfield'
],
'PUT' => [
'/' => 'save',
'/particles' => 'forbidden',
'/particles/*' => 'save'
],
'PATCH' => [
'/' => 'save',
'/particles' => 'forbidden',
'/particles/*' => 'save'
],
'DELETE' => [
'/' => 'forbidden',
'/particles' => 'forbidden',
'/particles/*' => 'reset'
]
];
public function index()
{
$outline = $this->params['outline'];
if ($outline === 'default') {
$this->params['overrideable'] = false;
$data = $this->container['config'];
} else {
$this->params['overrideable'] = true;
$this->params['defaults'] =
$this->container['defaults'];
$data = ConfigServiceProvider::load($this->container,
$outline, false, false);
}
/** @var Particles $particles */
$particles = $this->container['particles'];
$this->params += [
'data' => $data,
'particles' =>
$particles->group(['atom']),
'route' =>
"configurations.{$outline}.settings",
'page_id' => $outline
];
return
$this->render('@gantry-admin/pages/configurations/settings/settings.html.twig',
$this->params);
}
public function display($id)
{
$outline = $this->params['outline'];
/** @var Particles $particles */
$particles = $this->container['particles'];
$blueprints = $particles->getBlueprintForm($id);
$prefix = 'particles.' . $id;
if($outline === 'default') {
$this->params['overrideable'] = false;
$data = $this->container['config'];
} else {
$this->params['overrideable'] = true;
$this->params['defaults'] =
$this->container['defaults']->get($prefix);
$data = ConfigServiceProvider::load($this->container,
$outline, false, false);
}
$this->params += [
'scope' => 'particle.',
'particle' => $blueprints,
'data' => ['particle' =>
$data->get($prefix)],
'id' => $id,
'parent' =>
"configurations/{$outline}/settings",
'route' =>
"configurations.{$outline}.settings.{$prefix}",
'skip' => ['enabled']
];
return
$this->render('@gantry-admin/pages/configurations/settings/item.html.twig',
$this->params);
}
public function formfield($id)
{
$path = func_get_args();
$end = end($path);
if ($end === '') {
array_pop($path);
}
if (end($path) === 'validate') {
return call_user_func_array([$this, 'validate'],
$path);
}
/** @var Particles $particles */
$particles = $this->container['particles'];
// Load blueprints.
$blueprints = $particles->getBlueprintForm($id);
list($fields, $path, $value) =
$blueprints->resolve(array_slice($path, 1), '/');
if (!$fields) {
throw new \RuntimeException('Page Not Found', 404);
}
$data =
$this->request->post->getJsonArray('data');
/** @var Config $config */
$config = $this->container['config'];
$offset = "particles.{$id}." . implode('.',
$path);
if ($value !== null) {
$parent = $fields;
$fields = ['fields' =>
$fields['fields']];
$offset .= '.' . $value;
$data = $data ?: $config->get($offset);
$data = ['data' => $data];
$scope = 'data.';
} else {
$data = $data ?: $config->get($offset);
$scope = 'data';
}
$fields['is_current'] = true;
array_pop($path);
$outline = $this->params['outline'];
$configuration = "configurations/{$outline}";
$this->params = [
'configuration' => $configuration,
'blueprints' => $fields,
'data' => $data,
'scope' => $scope,
'parent' => $path
?
"{$configuration}/settings/particles/{$id}/" .
implode('/', $path)
:
"{$configuration}/settings/particles/{$id}",
'route' =>
"configurations.{$outline}.settings.{$offset}",
] + $this->params;
if (isset($parent['key'])) {
$this->params['key'] = $parent['key'];
}
if (isset($parent['value'])) {
$this->params['title'] =
$parent['value'];
}
return
$this->render('@gantry-admin/pages/configurations/settings/field.html.twig',
$this->params);
}
public function validate($particle)
{
$path = implode('.', array_slice(func_get_args(), 1,
-1));
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
/** @var Particles $particles */
$particles = $this->container['particles'];
// Load particle blueprints.
$validator = $particles->get($particle);
// Create configuration from the defaults.
$data = new Config(
[],
function () use ($validator) {
return $validator;
}
);
$data->join($path,
$this->request->post->getArray('data'));
// TODO: validate
return new JsonResponse(['data' =>
$data->get($path)]);
}
public function save($id = null)
{
if (!$this->request->post->get('_end')) {
throw new \OverflowException("Incomplete data received.
Please increase the value of 'max_input_vars' variable (in
php.ini or .htaccess)", 400);
}
$data = $id ? [$id =>
$this->request->post->getArray('particle')] :
$this->request->post->getArray('particles');
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
// Save layout into custom directory for the current theme.
$outline = $this->params['outline'];
$save_dir =
$locator->findResource("gantry-config://{$outline}/particles",
true, true);
foreach ($data as $name => $values) {
$this->saveItem($name, $values, $save_dir);
}
@rmdir($save_dir);
// Fire save event.
$event = new Event;
$event->gantry = $this->container;
$event->theme = $this->container['theme'];
$event->controller = $this;
$event->data = $data;
$this->container->fireEvent('admin.settings.save',
$event);
return $id ? $this->display($id) : $this->index();
}
protected function saveItem($id, $data, $save_dir)
{
$filename = "{$save_dir}/{$id}.yaml";
$file = YamlFile::instance($filename);
if (!is_array($data)) {
if ($file->exists()) {
$file->delete();
}
} else {
/** @var Particles $particles */
$particles = $this->container['particles'];
$blueprints = $particles->getBlueprintForm($id);
$config = new Config($data, function() use ($blueprints) {
return $blueprints; });
$file->save($config->toArray());
}
$file->free();
}
public function reset($id)
{
$this->params += [
'data' => [],
];
return $this->display($id);
}
}
PK%d�[�[T�
>classes/Gantry/Admin/Controller/Html/Configurations/Styles.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html\Configurations;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Config\Config;
use Gantry\Component\Response\JsonResponse;
use Gantry\Framework\Services\ConfigServiceProvider;
use Gantry\Framework\Theme;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Styles extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/blocks' => 'undefined',
'/blocks/*' => 'display',
'/blocks/*/**' => 'formfield'
],
'POST' => [
'/' => 'save',
'/blocks' => 'forbidden',
'/blocks/*' => 'save',
'/compile' => 'compile'
],
'PUT' => [
'/' => 'save',
'/blocks' => 'forbidden',
'/blocks/*' => 'save'
],
'PATCH' => [
'/' => 'save',
'/blocks' => 'forbidden',
'/blocks/*' => 'save'
],
'DELETE' => [
'/' => 'forbidden',
'/blocks' => 'forbidden',
'/blocks/*' => 'reset'
]
];
public function index()
{
$outline = $this->params['outline'];
if($outline == 'default') {
$this->params['overrideable'] = false;
$this->params['data'] =
$this->container['config'];
} else {
$this->params['overrideable'] = true;
$this->params['defaults'] =
$this->container['defaults'];
$this->params['data'] =
ConfigServiceProvider::load($this->container, $outline, false, false);
}
$this->params['blocks'] =
$this->container['styles']->group();
$this->params['route'] =
"configurations.{$outline}.styles";
return
$this->render('@gantry-admin/pages/configurations/styles/styles.html.twig',
$this->params);
}
public function display($id)
{
$outline = $this->params['outline'];
$blueprints =
$this->container['styles']->getBlueprintForm($id);
$prefix = 'styles.' . $id;
if($outline == 'default') {
$this->params['overrideable'] = false;
$this->params['data'] =
$this->container['config']->get($prefix);
} else {
$this->params['overrideable'] = true;
$this->params['defaults'] =
$this->container['defaults']->get($prefix);
$this->params['data'] =
ConfigServiceProvider::load($this->container, $outline, false,
false)->get($prefix);
}
$this->params += [
'block' => $blueprints,
'id' => $id,
'parent' =>
"configurations/{$outline}/styles",
'route' =>
"configurations.{$outline}.styles.{$prefix}",
'skip' => ['enabled']
];
return
$this->render('@gantry-admin/pages/configurations/styles/item.html.twig',
$this->params);
}
public function formfield($id)
{
$path = func_get_args();
$outline = $this->params['outline'];
// Load blueprints.
$blueprints =
$this->container['styles']->getBlueprintForm($id);
list($fields, $path, $value) =
$blueprints->resolve(array_slice($path, 1), '/');
if (!$fields) {
throw new \RuntimeException('Page Not Found', 404);
}
$fields['is_current'] = true;
// Get the prefix.
$prefix = "styles.{$id}." . implode('.',
$path);
if ($value !== null) {
$parent = $fields;
$fields = ['fields' =>
$fields['fields']];
$prefix .= '.' . $value;
}
array_pop($path);
if($outline == 'default') {
$this->params['overrideable'] = false;
$this->params['data'] =
$this->container['config']->get($prefix);
} else {
$this->params['overrideable'] = true;
$this->params['defaults'] =
$this->container['defaults']->get($prefix);
$this->params['data'] =
ConfigServiceProvider::load($this->container, $outline, false,
false)->get($prefix);
}
$this->params = [
'blueprints' => $fields,
'parent' => $path
?
"configurations/{$outline}/styles/blocks/{$id}/" .
implode('/', $path)
:
"configurations/{$outline}/styles/blocks/{$id}",
'route' => 'styles.' . $prefix
] + $this->params;
if (isset($parent['key'])) {
$this->params['key'] = $parent['key'];
}
return
$this->render('@gantry-admin/pages/configurations/styles/field.html.twig',
$this->params);
}
public function reset($id)
{
$this->params += [
'data' => [],
];
return $this->display($id);
}
public function compile()
{
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
$warnings = $this->compileSettings();
if ($warnings) {
$this->params += ['warnings' => $warnings];
return new JsonResponse(
[
'html' =>
$this->render('@gantry-admin/layouts/css-warnings.html.twig',
$this->params),
'warning' => true,
'title' => 'CSS Compiled With
Warnings',
]
);
} else {
return new JsonResponse(['html' => 'The CSS
was successfully compiled', 'title' => 'CSS
Compiled']);
}
}
public function save($id = null)
{
/** @var Config $config */
$config = $this->container['config'];
if ($id) {
$data = (array) $config->get('styles');
$data[$id] = $this->request->post->getArray();
} else {
$data =
$this->request->post->getArray('styles');
}
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
// Save layout into custom directory for the current theme.
$outline = $this->params['outline'];
$save_dir =
$locator->findResource("gantry-config://{$outline}", true,
true);
$filename = "{$save_dir}/styles.yaml";
$file = YamlFile::instance($filename);
$file->save($data);
$file->free();
// Fire save event.
$event = new Event;
$event->gantry = $this->container;
$event->theme = $this->container['theme'];
$event->controller = $this;
$event->data = $data;
$this->container->fireEvent('admin.styles.save',
$event);
// Compile CSS.
$warnings = $this->compileSettings();
if (empty($this->params['ajax'])) {
// FIXME: HTML request: Output compiler warnings!!
return $id ? $this->display($id) : $this->index();
}
if ($warnings) {
$this->params += ['warnings' => $warnings];
return new JsonResponse(
[
'html' =>
$this->render('@gantry-admin/layouts/css-warnings.html.twig',
$this->params),
'warning' => true,
'title' => 'CSS Compiled With
Warnings',
]
);
} else {
return new JsonResponse(['html' => 'The CSS
was successfully compiled', 'title' => 'CSS
Compiled']);
}
}
/**
* @returns array
*/
protected function compileSettings()
{
/** @var Theme $theme */
$theme = $this->container['theme'];
$outline = $this->params['outline'];
return $theme->updateCss($outline !== 'default' ?
[$outline => ucfirst($outline)] : null);
}
}
PK%d�[���7VV7classes/Gantry/Admin/Controller/Html/Configurations.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Response\HtmlResponse;
use Gantry\Component\Response\JsonResponse;
use Gantry\Component\Response\RedirectResponse;
use Gantry\Component\Response\Response;
use Gantry\Component\Layout\Layout as LayoutObject;
use Gantry\Framework\Outlines as OutlinesObject;
class Configurations extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/*' => 'forward',
'/*/delete' =>
'confirmDeletion',
'/*/**' => 'forward',
],
'POST' => [
'/' => 'undefined',
'/*' => 'undefined',
'/create' => 'createForm',
'/create/new' => 'create',
'/*/rename' => 'rename',
'/*/duplicate' => 'duplicateForm',
'/*/duplicate/new' => 'duplicate',
'/*/delete' => 'undefined',
'/*/delete/confirm' => 'delete',
'/*/**' => 'forward',
],
'PUT' => [
'/' => 'undefined',
'/**' => 'forward'
],
'PATCH' => [
'/' => 'undefined',
'/**' => 'forward'
]
];
public function index()
{
return
$this->render('@gantry-admin/pages/configurations/configurations.html.twig',
$this->params);
}
public function createForm()
{
if (!$this->authorize('outline.create')) {
$this->forbidden();
}
$params = [
'presets' => LayoutObject::presets(),
'outlines' =>
$this->container['outlines']
];
$response = ['html' =>
$this->render('@gantry-admin/ajax/outline-new.html.twig',
$params)];
return new JsonResponse($response);
}
public function create()
{
// Check if we want to duplicate outline instead.
if ($this->request->post['from'] ===
'outline') {
return
$this->duplicate($this->request->post['outline']);
}
if (!$this->authorize('outline.create')) {
$this->forbidden();
}
/** @var OutlinesObject $outlines */
$outlines = $this->container['outlines'];
$title = $this->request->post['title'];
$preset = $this->request->post['preset'];
$id = $outlines->create(null, $title, $preset);
$html =
$this->render('@gantry-admin/layouts/outline.html.twig',
['name' => $id, 'title' => $outlines[$id]]);
return new JsonResponse(['html' => 'Outline
created.', 'id' => "outline-{$id}",
'outline' => $html]);
}
public function rename($outline)
{
if (!$this->authorize('outline.rename')) {
$this->forbidden();
}
/** @var OutlinesObject $outlines */
$outlines = $this->container['outlines'];
$title = $this->request->post['title'];
$id = $outlines->rename($outline, $title);
$html =
$this->render('@gantry-admin/layouts/outline.html.twig',
['name' => $id, 'title' => $outlines[$id]]);
return new JsonResponse(['html' => 'Outline
renamed.', 'id' => "outline-{$outline}",
'outline' => $html]);
}
public function duplicateForm($outline)
{
if (!$this->authorize('outline.create')) {
$this->forbidden();
}
$params = [
'outlines' =>
$this->container['outlines'],
'outline' => $outline,
'duplicate' => true
];
$response = ['html' =>
$this->render('@gantry-admin/ajax/outline-new.html.twig',
$params)];
return new JsonResponse($response);
}
public function duplicate($outline)
{
if (!$this->authorize('outline.create')) {
$this->forbidden();
}
/** @var OutlinesObject $outlines */
$outlines = $this->container['outlines'];
$title = $this->request->post['title'];
$inherit =
in_array($this->request->post['inherit'], ['1',
'true']);
$id = $outlines->duplicate($outline, $title, $inherit);
$html =
$this->render('@gantry-admin/layouts/outline.html.twig',
['name' => $id, 'title' => $outlines[$id]]);
return new JsonResponse(['html' => 'Outline
duplicated.', 'id' => $id, 'outline' =>
$html]);
}
public function delete($outline)
{
if (!$this->authorize('outline.delete')) {
$this->forbidden();
}
/** @var OutlinesObject $outlines */
$outlines = $this->container['outlines'];
$list = $outlines->user();
if (!isset($list[$outline])) {
$this->forbidden();
}
$outlines->delete($outline);
return new JsonResponse(['html' => 'Outline
deleted.', 'outline' => $outline]);
}
/**
* @return JsonResponse
*/
public function confirmDeletion($id)
{
/** @var OutlinesObject $outlines */
$outlines = $this->container['outlines'];
$params = [
'id' => $id,
'page_type' => 'OUTLINE',
'outline' => $outlines->title($id),
'inherited' =>
$outlines->getInheritingOutlines($id)
];
$html =
$this->render('@gantry-admin/pages/configurations/confirm-deletion.html.twig',
$params);
return new JsonResponse(['html' => $html]);
}
/**
* @return HtmlResponse|RedirectResponse|JsonResponse
*/
public function forward()
{
$path = func_get_args();
$outline = array_shift($path);
$page = array_shift($path);
$method = $this->params['method'];
if ((!isset($outline) || !isset($page)) &&
$this->params['format'] !== 'json') {
// Redirect path to the styles page of the selected outline.
return new
RedirectResponse($this->container->route('configurations',
is_string($outline) ? $outline : 'default', 'styles'));
}
$outlines = $this->container['outlines'];
if (!isset($outlines[$outline])) {
throw new \RuntimeException('Outline not found.',
404);
}
$this->container['outline'] = $outline;
$this->container['configuration'] = $outline;
$resource = $this->params['location'] . '/'.
$page;
$this->params['outline'] = $outline;
$this->params['configuration'] = $outline;
$this->params['location'] = $resource;
$this->params['configuration_page'] = $page;
$this->params['navbar'] =
!empty($this->request->get['navbar']);
return $this->executeForward($resource, $method, $path,
$this->params);
}
protected function executeForward($resource, $method = 'GET',
$path, $params = [])
{
$class = '\\Gantry\\Admin\\Controller\\Html\\' .
strtr(ucwords(strtr($resource, '/', ' ')), '
', '\\');
if (!class_exists($class)) {
throw new \RuntimeException('Page not found', 404);
}
/** @var HtmlController $controller */
$controller = new $class($this->container);
// Execute action.
$response = $controller->execute($method, $path, $params);
if (!$response instanceof Response) {
$response = new HtmlResponse($response);
}
return $response;
}
}
PK%d�[��_iEE/classes/Gantry/Admin/Controller/Html/Export.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Component\Admin\HtmlController;
use Gantry\Framework\Exporter;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Symfony\Component\Yaml\Yaml;
class Export extends HtmlController
{
public function index()
{
if (!class_exists('Gantry\Framework\Exporter')) {
$this->forbidden();
}
if (!class_exists('ZipArchive')) {
throw new \RuntimeException('Please enable PHP ZIP
extension to use this feature.');
}
$exporter = new Exporter;
$exported = $exporter->all();
$zipname =
$exported['export']['theme']['name'] .
'-export.zip';
$tmpname = tempnam(sys_get_temp_dir(), 'zip');
$zip = new \ZipArchive();
$zip->open($tmpname, \ZipArchive::CREATE);
$zip->addFromString("export.yaml",
Yaml::dump($exported['export'], 10, 2));
unset($exported['export']);
foreach ($exported['positions'] as $key => $position)
{
foreach ($position['items'] as $module => $data) {
$zip->addFromString("positions/{$key}/{$module}.yaml",
Yaml::dump($data, 10, 2));
}
$position['ordering'] =
array_keys($position['items']);
unset($position['items']);
$zip->addFromString("positions/{$key}.yaml",
Yaml::dump($position, 10, 2));
}
foreach ($exported['outlines'] as $outline =>
&$data) {
if (!empty($data['config'])) {
foreach ($data['config'] as $name => $config)
{
if (in_array($name, ['particles',
'page'])) {
foreach ($config as $sub => $subconfig) {
$zip->addFromString("outlines/{$outline}/{$name}/{$sub}.yaml",
Yaml::dump($subconfig, 10, 2));
}
} else {
$zip->addFromString("outlines/{$outline}/{$name}.yaml",
Yaml::dump($config, 10, 2));
}
}
}
unset($data['config']);
}
$zip->addFromString("outlines/outlines.yaml",
Yaml::dump($exported['outlines'], 10, 2));
foreach ($exported['menus'] as $menu => $data) {
$zip->addFromString("menus/{$menu}.yaml",
Yaml::dump($data, 10, 2));
}
foreach ($exported['content'] as $id => $data) {
$zip->addFromString("content/{$id}.yaml",
Yaml::dump($data, 10, 2));
}
if (!empty($exported['categories'])) {
$zip->addFromString("content/categories.yaml",
Yaml::dump($exported['categories'], 10, 2));
}
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
foreach ($exported['files'] as $stream => $files) {
foreach ($files as $path => $uri) {
$filename = $locator->findResource($uri);
if (file_exists($filename)) {
$zip->addFile($filename,
"files/{$stream}/{$path}");
}
}
}
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' .
$zipname);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($tmpname));
@ob_end_clean();
flush();
readfile($tmpname);
unlink($tmpname);
exit;
}
}
PK%d�[�?�C}
}
/classes/Gantry/Admin/Controller/Html/Import.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Filesystem\Folder;
use Gantry\Framework\Importer;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Symfony\Component\Yaml\Yaml;
class Import extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
],
'POST' => [
'/' => 'import',
]
];
public function index()
{
return
$this->render('@gantry-admin/pages/import/import.html.twig',
$this->params);
}
public function import()
{
if (!isset($_FILES['file']['error']) ||
is_array($_FILES['file']['error'])) {
throw new \RuntimeException('No file sent', 400);
}
// Check $_FILES['file']['error'] value.
switch ($_FILES['file']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new \RuntimeException('No file sent', 400);
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new \RuntimeException('Exceeded filesize
limit.', 400);
default:
throw new \RuntimeException('Unkown errors',
400);
}
$filename = $_FILES['file']['tmp_name'];
if (!is_uploaded_file($filename)) {
throw new \RuntimeException('No file sent', 400);
}
$zip = new \ZipArchive;
if ($zip->open($filename) !== true || !($export =
Yaml::parse($zip->getFromName('export.yaml'))) ||
!isset($export['gantry'])) {
throw new \RuntimeException('Uploaded file is not Gantry 5
export file', 400);
}
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$folder =
$locator->findResource('gantry-cache://import', true, true);
if (is_dir($folder)) Folder::delete($folder);
$zip->extractTo($folder);
$zip->close();
$importer = new Importer($folder);
$importer->all();
if (is_dir($folder)) Folder::delete($folder);
$this->params['success'] = true;
return
$this->render('@gantry-admin/pages/import/import.html.twig',
$this->params);
}
}
PK%d�[�^�ww0classes/Gantry/Admin/Controller/Html/Install.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Component\Admin\HtmlController;
use Gantry\Framework\ThemeInstaller;
class Install extends HtmlController
{
public function index()
{
if (!$this->authorize('updates.manage') ||
!class_exists('\Gantry\Framework\ThemeInstaller')) {
$this->forbidden();
}
$installer = new ThemeInstaller();
$installer->initialized = true;
$installer->loadExtension($this->container['theme.name']);
$installer->installDefaults();
$installer->installSampleData();
$installer->finalize();
$this->params['actions'] = $installer->actions;
return
$this->render('@gantry-admin/pages/install/install.html.twig',
$this->params);
}
}
PK%d�[
����F�F-classes/Gantry/Admin/Controller/Html/Menu.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Config\BlueprintSchema;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\Config;
use Gantry\Component\Menu\Item;
use Gantry\Component\Request\Input;
use Gantry\Component\Response\HtmlResponse;
use Gantry\Component\Response\JsonResponse;
use Gantry\Component\Response\Response;
use Gantry\Framework\Menu as MenuObject;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Menu extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'item',
'/*' => 'item',
'/*/**' => 'item',
'/particle' => 'particle',
'/particle/*' =>
'validateParticle',
'/select' => 'undefined',
'/select/particle' =>
'selectParticle',
'/select/module' => 'selectModule',
'/select/widget' => 'selectWidget',
'/edit' => 'undefined',
'/edit/*' => 'edit',
'/edit/*/**' => 'editItem',
],
'POST' => [
'/' => 'save',
'/*' => 'save',
'/*/**' => 'item',
'/particle' => 'particle',
'/particle/*' =>
'validateParticle',
'/select' => 'undefined',
'/select/particle' =>
'selectParticle',
'/select/module' => 'selectModule',
'/select/widget' => 'selectWidget',
'/widget' => 'widget',
'/edit' => 'undefined',
'/edit/*' => 'edit',
'/edit/*/**' => 'editItem',
'/edit/*/validate' => 'validate',
],
'PUT' => [
'/*' => 'replace'
],
'PATCH' => [
'/*' => 'update'
],
'DELETE' => [
'/*' => 'destroy'
]
];
public function execute($method, array $path, array $params)
{
if (!$this->authorize('menu.manage')) {
$this->forbidden();
}
return parent::execute($method, $path, $params);
}
public function item($id = null)
{
// Load the menu.
try {
$resource = $this->loadResource($id,
$this->build($this->request->post));
} catch (\Exception $e) {
return
$this->render('@gantry-admin/pages/menu/menu.html.twig',
$this->params);
}
// All extra arguments become the path.
$path = array_slice(func_get_args(), 1);
// Get menu item and make sure it exists.
$item = $resource[implode('/', $path)];
if (!$item) {
throw new \RuntimeException('Menu item not found',
404);
}
// Fill parameters to be passed to the template file.
$this->params['id'] = $resource->name();
$this->params['menus'] = $resource->getMenus();
$this->params['default_menu'] =
$resource->hasDefaultMenu() ? $resource->getDefaultMenuName() :
false;
$this->params['menu'] = $resource;
$this->params['path'] = implode('/', $path);
// Detect special case to fetch only single column group.
$group = $this->request->get['group'];
if (empty($this->params['ajax']) ||
empty($this->request->get['inline'])) {
// Handle special case to fetch only one column group.
if (count($path) > 0) {
$this->params['columns'] =
$resource[$path[0]];
}
if (count($path) > 1) {
$this->params['column'] = isset($group) ?
(int) $group : $resource[implode('/', array_slice($path, 0,
2))]->group;
$this->params['override'] = $item;
}
return
$this->render('@gantry-admin/pages/menu/menu.html.twig',
$this->params);
} else {
// Get layout name.
$layout = $this->layoutName(count($path) + (int)
isset($group));
$this->params['item'] = $item;
$this->params['group'] = isset($group) ? (int)
$group : $resource[implode('/', array_slice($path, 0,
2))]->group;
return $this->render('@gantry-admin/menu/' .
$layout . '.html.twig', $this->params) ?:
' ';
}
}
public function edit($id)
{
$resource = $this->loadResource($id);
$input = $this->build($this->request->post);
if ($input) {
$resource->config()->merge(['settings' =>
$input['settings']]);
}
// Fill parameters to be passed to the template file.
$this->params['id'] = $resource->name();
$this->params['blueprints'] =
$this->loadBlueprints();
$this->params['data'] = ['settings' =>
$resource->settings()];
return
$this->render('@gantry-admin/pages/menu/edit.html.twig',
$this->params);
}
public function save($id = null)
{
$resource = $this->loadResource($id);
$data = $this->build($this->request->post);
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$filename =
$locator->findResource("gantry-config://menu/{$resource->name()}.yaml",
true, true);
// Fire save event.
$event = new Event;
$event->gantry = $this->container;
$event->theme = $this->container['theme'];
$event->controller = $this;
$event->resource = $id;
$event->menu = $data;
$this->container->fireEvent('admin.menus.save',
$event);
$file = YamlFile::instance($filename);
$file->settings(['inline' => 99]);
$file->save($data->toArray());
$file->free();
}
public function editItem($id)
{
// All extra arguments become the path.
$path = array_slice(func_get_args(), 1);
$keyword = end($path);
// Special case: validate instead of fetching menu item.
if ($this->method == 'POST' && $keyword ==
'validate') {
$params = array_slice(func_get_args(), 0, -1);
return call_user_func_array([$this, 'validateitem'],
$params);
}
$path = html_entity_decode(implode('/', $path),
ENT_COMPAT | ENT_HTML5, 'UTF-8');
// Load the menu.
$resource = $this->loadResource($id);
// Get menu item and make sure it exists.
/** @var Item $item */
$item = $resource[$path];
if (!$item) {
throw new \RuntimeException('Menu item not found',
404);
}
$data =
$this->request->post->getJsonArray('item');
if ($data) {
$item->update($data);
}
// Load blueprints for the menu item.
$blueprints = $this->loadBlueprints('menuitem');
$this->params = [
'id' => $resource->name(),
'path' => $path,
'blueprints' => ['fields' =>
$blueprints['form/fields/items/fields']],
'data' => $item->toArray() +
['path' => $path],
] + $this->params;
return
$this->render('@gantry-admin/pages/menu/menuitem.html.twig',
$this->params);
}
public function particle()
{
$data = $this->request->post['item'];
if ($data) {
$data = json_decode($data, true);
} else {
$data = $this->request->post->getArray();
}
$name = isset($data['particle']) ?
$data['particle'] : null;
$block = BlueprintForm::instance('menu/block.yaml',
'gantry-admin://blueprints');
$blueprints =
$this->container['particles']->getBlueprintForm($name);
// Load particle blueprints and default settings.
$validator = $this->loadBlueprints('menu');
$callable = function () use ($validator) {
return $validator;
};
// Create configuration from the defaults.
$item = new Config($data, $callable);
$item->def('type', 'particle');
$item->def('title',
$blueprints->get('name'));
$item->def('options.type',
$blueprints->get('type', 'particle'));
$item->def('options.particle', []);
$item->def('options.block', []);
$this->params += [
'item' => $item,
'block' => $block,
'data' => ['particles' =>
[$name => $item->options['particle']]],
'particle' => $blueprints,
'parent' => 'settings',
'prefix' => "particles.{$name}.",
'route' =>
"configurations.default.settings",
'action' =>
"menu/particle/{$name}"
];
return
$this->render('@gantry-admin/pages/menu/particle.html.twig',
$this->params);
}
public function validateParticle($name)
{
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
// Load particle blueprints and default settings.
$validator = new BlueprintSchema;
$validator->embed('options',
$this->container['particles']->get($name));
$blueprints =
$this->container['particles']->getBlueprintForm($name);
// Create configuration from the defaults.
$data = new Config([],
function () use ($validator) {
return $validator;
}
);
$data->set('type', 'particle');
$data->set('particle', $name);
$data->set('title',
$this->request->post['title'] ?:
$blueprints->post['name']);
$data->set('options.particle',
$this->request->post->getArray("particles.{$name}"));
$data->def('options.particle.enabled', 1);
$data->set('enabled',
$data->get('options.particle.enabled'));
$block =
$this->request->post->getArray('block');
foreach ($block as $key => $param) {
if ($param === '') {
unset($block[$key]);
}
}
$data->join('options.block', $block);
// TODO: validate
// Fill parameters to be passed to the template file.
$this->params['item'] = (object) $data->toArray();
$html =
$this->render('@gantry-admin/menu/item.html.twig',
$this->params);
return new JsonResponse(['item' =>
$data->toArray(), 'html' => $html]);
}
public function selectModule()
{
return
$this->render('@gantry-admin/modals/module-picker.html.twig',
$this->params);
}
public function selectWidget()
{
$this->params['next'] = 'menu/widget';
return
$this->render('@gantry-admin/modals/widget-picker.html.twig',
$this->params);
}
public function widget()
{
$data = $this->request->post->getJson('item');
$path = [$data->widget];
$this->params['scope'] = 'menu';
return $this->executeForward('widget',
'POST', $path, $this->params);
}
public function selectParticle()
{
$groups = [
'Particles' => ['particle' => []],
];
$particles = [
'position' => [],
'spacer' => [],
'system' => [],
'particle' => [],
];
$particles = array_replace($particles, $this->getParticles());
unset($particles['atom'],
$particles['position']);
foreach ($particles as &$group) {
asort($group);
}
foreach ($groups as $section => $children) {
foreach ($children as $key => $child) {
$groups[$section][$key] = $particles[$key];
}
}
$this->params += [
'particles' => $groups,
'route' => 'menu/particle',
];
return
$this->render('@gantry-admin/modals/particle-picker.html.twig',
$this->params);
}
public function validate($id)
{
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
// Load particle blueprints and default settings.
$validator = $this->loadBlueprints('menu');
$callable = function () use ($validator) {
return $validator;
};
// Create configuration from the defaults.
$data = new Config($this->request->post->getArray(),
$callable);
// TODO: validate
return new JsonResponse(['settings' => (array)
$data->get('settings')]);
}
public function validateitem($id)
{
// All extra arguments become the path.
$path = array_slice(func_get_args(), 1);
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
// Load the menu.
$resource = $this->loadResource($id);
// Load particle blueprints and default settings.
$validator = $this->loadBlueprints('menuitem');
$callable = function () use ($validator) {
return $validator;
};
// Create configuration from the defaults.
$data = new Config($this->request->post->getArray(),
$callable);
// TODO: validate
$item = $resource[implode('/', $path)];
$item->update($data->toArray());
// Fill parameters to be passed to the template file.
$this->params['id'] = $resource->name();
$this->params['item'] = $item;
$this->params['group'] = isset($group) ? $group :
$resource[implode('/', array_slice($path, 0, 2))]->group;
if (!$item->title) {
throw new \RuntimeException('Title from the Menu Item
should not be empty', 400);
}
$html =
$this->render('@gantry-admin/menu/item.html.twig',
$this->params);
return new JsonResponse(['path' =>
implode('/', $path), 'item' => $data->toArray(),
'html' => $html]);
}
protected function layoutName($level)
{
switch ($level) {
case 0:
return 'base';
case 1:
return 'columns';
default:
return 'list';
}
}
/**
* Load resource.
*
* @param string $id
* @param Config $config
*
* @return \Gantry\Component\Menu\AbstractMenu
* @throws \RuntimeException
*/
protected function loadResource($id, Config $config = null)
{
/** @var MenuObject $menus */
$menus = $this->container['menu'];
return $menus->instance(['menu' => $id,
'admin' => true], $config);
}
/**
* Load blueprints.
*
* @param string $name
*
* @return BlueprintForm
*/
protected function loadBlueprints($name = 'menu')
{
return BlueprintForm::instance("menu/{$name}.yaml",
'gantry-admin://blueprints');
}
public function build(Input $input)
{
try {
$items = $input->get('items');
if ($items && $items[0] !== '{' &&
$items[0] !== '[') {
$items = urldecode((string)base64_decode($items));
}
$items = json_decode($items, true);
$settings = $input->getJsonArray('settings');
$order = $input->getJsonArray('ordering');
} catch (\Exception $e) {
throw new \RuntimeException('Invalid menu structure',
400);
}
if (!$items && !$settings && !$order) {
return null;
}
krsort($order);
$ordering = ['' => []];
foreach ($order as $path => $columns) {
foreach ($columns as $column => $colitems) {
$list = [];
foreach ($colitems as $item) {
$name = trim(substr($item, strlen($path)),
'/');
if (isset($ordering[$item])) {
$list[$name] = $ordering[$item];
unset($ordering[$item]);
} else {
$list[$name] = '';
}
}
if (count($columns) > 1) {
$ordering[$path][$column] = $list;
} else {
$ordering[$path] = $list;
}
}
}
$data = new Config([]);
$data->set('settings', $settings);
$data->set('ordering', $ordering['']);
$data->set('items', $items);
return $data;
}
protected function getParticles()
{
$particles = $this->container['particles']->all();
$list = [];
foreach ($particles as $name => $particle) {
$type = isset($particle['type']) ?
$particle['type'] : 'particle';
$particleName = isset($particle['name']) ?
$particle['name'] : $name;
$particleIcon = isset($particle['icon']) ?
$particle['icon'] : null;
$list[$type][$name] = ['name' => $particleName,
'icon' => $particleIcon];
}
return $list;
}
protected function executeForward($resource, $method = 'GET',
$path, $params = [])
{
$class = '\\Gantry\\Admin\\Controller\\Json\\' .
strtr(ucwords(strtr($resource, '/', ' ')), '
', '\\');
if (!class_exists($class)) {
throw new \RuntimeException('Page not found', 404);
}
/** @var HtmlController $controller */
$controller = new $class($this->container);
// Execute action.
$response = $controller->execute($method, $path, $params);
if (!$response instanceof Response) {
$response = new HtmlResponse($response);
}
return $response;
}
}
PK%d�[�,�ȵ*�*2classes/Gantry/Admin/Controller/Html/Positions.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Component\Admin\HtmlController;
use Gantry\Component\Config\BlueprintSchema;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\Config;
use Gantry\Component\Position\Module;
use Gantry\Component\Position\Position;
use Gantry\Component\Response\JsonResponse;
use Gantry\Framework\Assignments;
use Gantry\Framework\Positions as PositionsObject;
class Positions extends HtmlController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/*' => 'undefined',
'/*/add' =>
'selectParticle',
],
'POST' => [
'/' => 'save',
'/create' => 'create',
'/*' => 'undefined',
'/*/rename' => 'rename',
'/*/duplicate' => 'duplicate',
'/*/delete' => 'delete',
'/*/edit' => 'undefined',
'/*/edit/particle' => 'particle',
'/*/edit/particle/*' =>
'validateParticle',
'/edit' => 'undefined',
'/edit/particle' => 'particle',
]
];
public function index()
{
$this->params['positions'] =
$this->container['positions'];
return
$this->render('@gantry-admin/pages/positions/positions.html.twig',
$this->params);
}
public function create()
{
// Create only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
/** @var PositionsObject $position */
$positions = $this->container['positions'];
$title = (string)
$this->request->post->get('title',
'Untitled');
$key = (string) $this->request->post['key'];
$id = $positions->create($title, $key);
$html =
$this->render('@gantry-admin/layouts/position.html.twig',
['position' => ['name' => $id, 'title'
=> $title]]);
return new JsonResponse(['html' =>
sprintf("Position '%s' created.", $id), 'id'
=> "position-{$id}", 'key' => $id,
'position' => $html]);
}
public function rename($old)
{
// Rename only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
$title = (string) $this->request->post['title'];
$key = (string) $this->request->post['key'];
$data = (string) $this->request->post['data'];
/** @var PositionsObject $positions */
$positions = $this->container['positions'];
$position = $positions[$old];
$exists = isset($position);
if (!$exists) {
if (!$data) {
throw new \RuntimeException(sprintf("Position
'%s' not found", $old), 404);
}
$position = new Position($key ?: $old);
}
if (strlen($title)) {
$position->title = (string) $title;
}
if ($exists && strlen($key)) {
$position = $position->rename($key);
} else {
$position->save();
}
if ($data) {
$data = ['title' => $position->title] +
json_decode($data, true);
$position = new Position($position->name, $data);
}
$html =
$this->render('@gantry-admin/layouts/position.html.twig',
['position' => $position]);
return new JsonResponse(['html' =>
sprintf("Position saved"), 'id' =>
"position-{$position->name}", 'key' =>
$position->name, 'position' => $html]);
}
public function duplicate($position)
{
// Duplicate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
/** @var PositionsObject $positions */
$positions = $this->container['positions'];
$id = $positions->duplicate($position);
return new JsonResponse(['html' =>
sprintf("Position duplicated as '%s'.", $id)]);
}
public function delete($position)
{
// Delete only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
/** @var PositionsObject $positions */
$positions = $this->container['positions'];
$positions->delete($position);
return new JsonResponse(['html' =>
sprintf("Position '%s' deleted.", $position),
'position' => $position]);
}
public function save()
{
// Save only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
$data =
$this->request->post->getJsonArray('positions');
/** @var PositionsObject $position */
$positions = $this->container['positions'];
$positions->import($data);
return new JsonResponse(['html' =>
sprintf("Positions saved.")]);
}
public function particle($position = null)
{
if (!$position) {
$position = $this->request->post['position'];
}
$data = $this->request->post['item'];
if ($data) {
$data = json_decode($data, true);
} else {
$data = $this->request->post->getArray();
}
$name = isset($data['options']['type']) ?
$data['options']['type'] :
(isset($data['particle']) ? $data['particle'] : null);
$blueprints =
$this->container['particles']->getBlueprintForm($name);
$chromeBlueprints =
BlueprintForm::instance('position/chrome.yaml',
'gantry-admin://blueprints');
$data['title'] = isset($data['title']) ?
$data['title'] : $blueprints['name'];
$data['chrome'] = isset($data['chrome']) ?
$data['chrome'] : [];
$data['options'] = isset($data['options']) ?
$data['options'] : [];
$data['options']['type'] = $name;
$attributes =
isset($data['options']['attributes']) ?
$data['options']['attributes'] : [];
$assignments = new Assignments();
$this->params += [
'item' => $data,
'data' => [
'particles' => [$name => $attributes],
'chrome' => $data['chrome'],
'assignments' =>
isset($data['assignments']) ? $data['assignments'] :
'all'
],
'particle' => $blueprints,
'chrome' => $chromeBlueprints,
'assignments' => $assignments->get(),
'parent' => 'settings',
'prefix' => "particles.{$name}.",
'route' =>
"configurations.default.settings",
'action' =>
"positions/{$position}/edit/particle/{$name}"
];
return
$this->render('@gantry-admin/pages/positions/particle.html.twig',
$this->params);
}
public function validateParticle($position, $name)
{
// Validate only exists for JSON.
if (empty($this->params['ajax'])) {
$this->undefined();
}
if (!$this->request->post->get('_end')) {
throw new \OverflowException("Incomplete data received.
Please increase the value of 'max_input_vars' variable (in
php.ini or .htaccess)", 400);
}
// Load particle blueprints and default settings.
$validator = new BlueprintSchema;
$validator->embed('options',
$this->container['particles']->get($name));
$blueprints =
$this->container['particles']->getBlueprintForm($name);
// Create configuration from the defaults.
$data = new Config([],
function () use ($validator) {
return $validator;
}
);
$data->set('position', $position);
$data->set('id', $id =
$this->request->post['id']);
$data->set('type', 'particle');
$data->set('title',
$this->request->post['title'] ?:
$blueprints->post['name']);
$data->set('chrome',
$this->request->post->getArray('chrome'));
$data->set('options.type', $name);
$data->set('options.attributes',
$this->request->post->getArray("particles.{$name}"));
$data->def('options.attributes.enabled', 1);
$assignments = (new
Assignments())->filter($this->request->post->getArray('assignments'),
true);
if (!$assignments) {
// Use special syntax for no assignments.
$assignments = 'none';
} elseif ($assignments === ['page' => [true]]) {
// Use special syntax for assigned to all pages. This is a
special case and hardcoded for now.
$assignments = 'all';
}
$data->set('assignments', $assignments);
// TODO: validate
// Fill parameters to be passed to the template file.
$this->params['position'] = $position;
$this->params['item'] = (object) $data->toArray();
$this->params['module'] = new Module($id, $position,
$data->toArray());
$html =
$this->render('@gantry-admin/pages/positions/item.html.twig',
$this->params);
return new JsonResponse(['item' =>
$data->toArray(), 'html' => $html, 'position'
=> $position]);
}
public function selectParticle($position)
{
$groups = [
'Particles' => ['particle' => []],
];
$particles = [
'position' => [],
'spacer' => [],
'system' => [],
'particle' => [],
];
$particles = array_replace($particles, $this->getParticles());
unset($particles['atom'],
$particles['position']);
foreach ($particles as &$group) {
asort($group);
}
foreach ($groups as $section => $children) {
foreach ($children as $key => $child) {
$groups[$section][$key] = $particles[$key];
}
}
$this->params += [
'particles' => $groups,
'route' =>
"positions/{$position}/edit/particle",
];
return
$this->render('@gantry-admin/modals/particle-picker.html.twig',
$this->params);
}
protected function getParticles()
{
$particles = $this->container['particles']->all();
$list = [];
foreach ($particles as $name => $particle) {
$type = isset($particle['type']) ?
$particle['type'] : 'particle';
$particleName = isset($particle['name']) ?
$particle['name'] : $name;
$particleIcon = isset($particle['icon']) ?
$particle['icon'] : null;
$list[$type][$name] = ['name' => $particleName,
'icon' => $particleIcon];
}
return $list;
}
}
PK%d�[�����/classes/Gantry/Admin/Controller/Html/Themes.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Html;
use Gantry\Admin\ThemeList;
use Gantry\Component\Admin\HtmlController;
class Themes extends HtmlController
{
public function index()
{
$this->params['themes'] = (new
ThemeList)->getThemes();
return
$this->render('@gantry-admin/pages/themes/themes.html.twig',
$this->params);
}
}
PK%d�[��z66.classes/Gantry/Admin/Controller/Json/Atoms.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Response\JsonResponse;
/**
* Class Atoms
* @package Gantry\Admin\Controller\Json
*/
class Atoms extends JsonController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/*' => 'index',
'/instance' => 'atom'
],
'POST' => [
'/' => 'index',
'/*' => 'index',
'/instance' => 'atom'
]
];
public function index()
{
$path = implode('/', func_get_args());
$post = $this->request->request;
$outline = $post['outline'];
$type = $post['subtype'];
$inherit = $post['inherit'];
$id = $post['id'];
if (!$outline) {
throw new \RuntimeException('Outline not given',
400);
}
$this->container['outline'] = $outline;
$this->container['configuration'] = $outline;
$atoms = new \Gantry\Framework\Atoms((array)
$this->container['config']->get('page.head.atoms'));
if ($inherit) {
$atoms->inheritAll($outline);
}
$item = (object) $atoms->id($id);
if ($path === 'list') {
$list = $atoms->type($type);
if (empty($item->id)) {
$item = (object)reset($list);
}
}
$selected = !empty($item->id) ? $item->id : null;
$type = isset($item->type) ? $item->type : $type;
$item->attributes = isset($item->attributes) ? (array)
$item->attributes : [];
$blueprints =
$this->container['particles']->getBlueprintForm($type);
$blueprints->set('form/fields/_inherit',
['type' => 'gantry.inherit']);
$params = [
'gantry' => $this->container,
'parent' => 'settings',
'route' =>
"configurations.{$outline}.settings",
'inherit' => $inherit ? $outline : null,
'title' => isset($item->title) ?
$item->title : '',
'blueprints' =>
$blueprints->get('form'),
'item' => $item,
'data' => ['particles' =>
[$type => $item->attributes]],
'prefix' => "particles.{$type}.",
'editable' => true,
'overrideable' => false,
'skip' => ['enabled']
];
$html['g-settings-atom'] =
$this->render('@gantry-admin/pages/configurations/layouts/particle-card.html.twig',
$params);
if (isset($list)) {
$html['g-inherit-atom'] =
$this->renderAtomsInput($inherit ? $outline : null, $type, $selected,
$list);
}
return new JsonResponse(['json' => $item,
'html' => $html]);
}
public function atom()
{
$post = $this->request->request;
$outline = $post['outline'];
$id = $post['id'];
if (!$outline) {
throw new \RuntimeException('Outline not given',
400);
}
$this->container['outline'] = $outline;
$this->container['configuration'] = $outline;
$atoms = new \Gantry\Framework\Atoms((array)
$this->container['config']->get('page.head.atoms'));
$item = (object) $atoms->id($id);
if (empty($item->id)) {
throw new \RuntimeException('Atom was not found from the
outline', 404);
}
$name = $item->type;
$prefix = "particles.{$name}";
$blueprints =
$this->container['particles']->getBlueprintForm($name);
$blueprints->set('form/fields/_inherit',
['type' => 'gantry.inherit']);
$item->attributes = isset($item->attributes) ? (array)
$item->attributes : [];
$this->params['id'] = $name;
$this->params += [
'item' => $item,
'data' => ['particles' =>
[$name => $item->attributes]],
'prefix' => "particles.{$name}.",
'particle' => $blueprints,
'parent' => 'settings',
'route' =>
"configurations.{$outline}.settings",
'action' => str_replace('.',
'/', 'configurations.' . $outline .
'.layout.' . $prefix . '.validate'),
'skip' => ['enabled'],
'editable' => false,
'overrideable' => false,
];
$html =
$this->render('@gantry-admin/modals/atom-preview.html.twig',
$this->params);
return new JsonResponse(['html' => $html]);
}
/**
* Render input field for particle picker.
*
* @param string $outline
* @param string $type
* @param string $selected
* @param array $instances
* @return string
*/
protected function renderAtomsInput($outline, $type, $selected, array
$instances)
{
$params = [
'layout' => 'input',
'scope' => 'inherit.',
'field' => [
'name' => 'atom',
'type' => 'gantry.atoms',
'id' => 'g-inherit-atom',
'outline' => $outline,
'atoms' => $instances,
'atom' => $type
],
'value' => $selected
];
return
$this->render('@gantry-admin/forms/fields/gantry/atoms.html.twig',
$params);
}
}
PK%d�[7��]��2classes/Gantry/Admin/Controller/Json/Changelog.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Remote\Response as RemoteResponse;
use Gantry\Component\Response\JsonResponse;
class Changelog extends JsonController
{
protected $url =
'https://raw.githubusercontent.com/gantry/gantry5';
protected $fullurl =
'https://github.com/gantry/gantry5/blob/develop';
protected $issues =
'https://github.com/gantry/gantry5/issues';
protected $contrib = 'https://github.com';
protected $file = 'CHANGELOG.md';
protected $platforms = ['common' => 'share-alt',
'joomla' => '', 'wordpress' =>
'', 'grav' => ''];
protected $httpVerbs = [
'POST' => [
'/' => 'index'
]
];
public function index()
{
$version = $this->request->post['version'];
$lookup = $version;
if ($version == '@version@') {
$version = 'develop';
$lookup = '';
}
if (substr($version, 0, 4) == 'dev-') {
$version = preg_replace('/^dev-/i', '',
$version);
$lookup = '';
}
$url = $this->url . '/' . $version .
'/' . $this->file;
$changelog = RemoteResponse::get($url);
if ($changelog) {
$found = preg_match("/(#\\s" . $lookup .
".+?\\n.*?)(?=\\n{1,}#|$)/uis", $changelog, $changelog);
if ($found) {
$changelog =
\Parsedown::instance()->parse($changelog[0]);
// auto-link issues
$changelog = preg_replace("/#(\\d{1,})/uis",
'<a target="_blank" rel="noopener"
href="' . $this->issues .
'/$1">#$1</a>', $changelog);
// auto-link contributors
$changelog = preg_replace("/@([\\w]+)[^\\w]/uis",
'<a target="_blank" rel="noopener"
href="' . $this->contrib . '/$1">@$1</a>
', $changelog);
// add icons for platforms
foreach($this->platforms as $platform => $icon) {
$changelog = preg_replace('/(<a
href="\#' . $platform . '">)/uis',
'$1<i class="fa fa-' . ($icon ?: $platform) .
'" aria-hidden="true"></i> ',
$changelog);
}
} else {
$changelog = 'No changelog for version
<strong>' . $version . '</strong> was found.';
}
}
$response = [
'html' =>
$this->render('@gantry-admin/ajax/changelog.html.twig', [
'changelog' => $changelog,
'version' => $version,
'url' => $url,
'fullurl' => $this->fullurl .
'/' . $this->file
])
];
return new JsonResponse($response);
}
}
PK%d�[�)����8classes/Gantry/Admin/Controller/Json/Confirmdeletion.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Response\JsonResponse;
class Confirmdeletion extends JsonController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index'
]
];
public function index()
{
$pageType =
$this->request->get->get('page_type',
'OUTLINE');
$response = ['html' =>
$this->render('@gantry-admin/ajax/confirm-deletion.html.twig',
['page_type' => $pageType])];
return new JsonResponse($response);
}
}
PK%d�[�����0classes/Gantry/Admin/Controller/Json/Devprod.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Response\JsonResponse;
use RocketTheme\Toolbox\Event\Event;
class Devprod extends JsonController
{
public function store()
{
$production =
intval((bool)$this->request->post['mode']);
// Fire save event.
$event = new Event;
$event->gantry = $this->container;
$event->controller = $this;
$event->data = ['production' => $production];
$this->container->fireEvent('admin.global.save',
$event);
$response = [
'mode' => $production,
'title' => $production ? 'Production' :
'Development',
'html' => $production ? 'Production mode
enabled' : 'Development mode enabled',
];
return new JsonResponse($response);
}
}
PK%d�[
PQ�>�>3classes/Gantry/Admin/Controller/Json/Filepicker.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Response\JsonResponse;
use RocketTheme\Toolbox\File\File;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Filepicker extends JsonController
{
protected $base = false;
protected $value = false;
protected $filter = false;
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/*' => 'index',
'/display' => 'undefined',
'/display/**' => 'displayFile',
'/download' => 'undefined',
'/download/**' => 'downloadFile',
],
'POST' => [
'/' => 'index',
'/*' => 'index',
'/subfolder' => 'subfolder',
'/subfolder/*' => 'subfolder',
'/upload' => 'undefined',
'/upload/**' => 'upload'
],
'DELETE' => [
'/' => 'undefined',
'/**' => 'delete'
]
];
public function index()
{
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$bookmarks = [];
$drives = ['/'];
$subfolder = false;
$this->base = $locator->base;
if ($this->method == 'POST') {
$root = $this->request->post['root'];
$drives = isset($root) ? ($root !== 'false' ?
(array) $root : ['/']) : ['/'];
$subfolder =
$this->request->post['subfolder'] ? true : false;
$filter = $this->request->post['filter'];
$this->filter = isset($filter) ? ($filter !==
'false' ? $filter : false) : false;
$this->value =
$this->request->post['value'] ?: '';
}
foreach ($drives as $drive) {
// cleanup of the path so it's chrooted.
$drive = str_replace('..', '', $drive);
$isStream = $locator->isStream($drive);
$path = rtrim($this->base, '/') .
'/' . ltrim($drive, '/');
// It's a stream but the scheme doesn't exist. we
skip it.
if (!$isStream && (strpos($drive, '://') ||
!file_exists($path))) {
continue;
}
if ($isStream && !$locator->findResources($drive)) {
continue;
}
$key = $isStream ? $drive : preg_replace('#/{2,}+#',
'/', $drive);
if (!array_key_exists($key, $bookmarks)) {
$bookmarks[$key] = $isStream
? [$locator->getIterator($drive)]
: [rtrim(Folder::getRelativePath($path), '/')
. '/'];
}
}
if (!count($bookmarks)) {
throw new \RuntimeException(sprintf('%s "%s" not
found', count($drives) > 1 ? 'directories' :
'directory', implode('", "', $drives)), 404);
}
$folders = [];
$active = [];
$index = 0;
$activeFallback = '';
// iterating the folder and collecting subfolders and files
foreach ($bookmarks as $key => $bookmark) {
$folders[$key] = [];
if (!$index) {
$activeFallback = $key;
}
foreach ($bookmark as $folder) {
$isStream = $this->isStream($folder);
if ($isStream) {
unset($bookmarks[$key]);
$iterator = new \IteratorIterator($folder);
$folder = $key;
} else {
$iterator = new \DirectoryIterator($this->base .
'/' . ltrim($folder, '/'));
}
$folders[$key][$folder] = new \ArrayObject();
if (!$index && !$this->value) {
$active[] = $folder;
}
/** @var \SplFileInfo $info */
foreach ($iterator as $info) {
// no dot files nor files beginning with dot
if ($info->isDot() ||
substr($info->getFilename(), 0, 1) == '.') {
continue;
}
$file = new \stdClass();
$this->attachData($file, $info, $folder);
if ($file->dir) {
if ($file->pathname == dirname($this->value))
{
$active[] = $file->pathname;
}
$folders[$key][$folder]->append($file);
} else {
/*if ($filter && !preg_match("/"
. $filter . "/i", $file->filename)) {
continue;
}
if ((!$index && !$this->value) ||
(in_array(dirname($file->pathname), $active))) {
$files->append($file);
}*/
}
}
if ($isStream) {
$bookmarks[$key][] = $key;
}
$index++;
}
}
if (!count($active)) {
$active[] = $activeFallback;
}
$lastItem = end($active);
$files = $this->listFiles($lastItem);
$response = [];
reset($active);
if (!$subfolder) {
$response['html'] = $this->render(
'@gantry-admin/ajax/filepicker.html.twig', [
'active' => $active,
'base' => $this->base,
'bookmarks' => $bookmarks,
'folders' => $folders,
'files' => $files,
'filter' => $this->filter,
'value' => $this->value
]
);
} else {
$response['subfolder'] =
!$folders[$key][$folder]->count()
? false
: $this->render(
'@gantry-admin/ajax/filepicker/subfolders.html.twig',
['folder' => $folders[$key][$folder]]
);
$response['files'] = $this->render(
'@gantry-admin/ajax/filepicker/files.html.twig',
['files' => $files, 'value' =>
$this->value]
);
}
return new JsonResponse($response);
}
protected function attachData(&$node, $iteration, $folder)
{
foreach (
['getFilename', 'getExtension',
'getPerms', 'getMTime', 'getBasename',
'getPathname', 'getSize', 'getType',
'isReadable', 'isWritable',
'isDir', 'isFile'] as $method
) {
$keyMethod =
strtolower(preg_replace("/^(is|get)/", '', $method));
$node->{$keyMethod} = $iteration->{$method}();
if ($method == 'getPathname') {
$node->{$keyMethod} = $this->isStream($folder) ?
$iteration->getUrl() : Folder::getRelativePath($node->{$keyMethod});
} else {
if ($method == 'getExtension') {
$node->isImage =
in_array(strtolower($node->{$keyMethod}), ['jpg',
'jpeg', 'png', 'gif', 'ico',
'svg', 'bmp', 'webp']);
}
}
}
}
protected function listFiles($folder)
{
$isStream = $this->isStream($folder);
$locator = $this->container['locator'];
$iterator = $isStream ? new
\IteratorIterator($locator->getIterator($folder)) : new
\DirectoryIterator($this->base . '/' . ltrim($folder,
'/'));
$files = new \ArrayObject();
/** @var \SplFileInfo $info */
foreach ($iterator as $info) {
// no dot files nor files beginning with dot
if ($info->isDot() || substr($info->getFilename(), 0, 1)
== '.') {
continue;
}
$file = new \stdClass();
$this->attachData($file, $info, $folder);
if (!$file->dir) {
if ($this->filter && !preg_match("/" .
$this->filter . "/i", $file->filename)) {
continue;
}
$file->isInCustom = false;
if ($isStream) {
$stream = explode('://', $folder);
$stream = array_shift($stream) .
'://';
$customLocation = $locator->findResource($stream,
true, true);
if (substr($info->getPathname(), 0,
strlen($customLocation)) === $customLocation) {
$file->isInCustom = true;
}
}
$files->append($file);
}
}
$files->asort();
return $files;
}
public function subfolder()
{
$response = [];
$response['html'] = 'subfolder';
return new JsonResponse($response);
}
public function displayFile()
{
$path = implode('/', func_get_args());
$this->doDownload($path, false);
}
protected function doDownload($path, $download)
{
if (!$path) {
throw new \RuntimeException('No file specified',
400);
}
// TODO: handle streams
$targetPath = GANTRY5_ROOT . '/' . $path;
if (!file_exists($targetPath)) {
throw new \RuntimeException(sprintf('File not found:
%s', $path), 404);
}
$hash = md5_file($path);
// Handle 304 Not Modified
if
(isset($this->request->server['HTTP_IF_NONE_MATCH'])) {
$etag =
stripslashes($this->request->server['HTTP_IF_NONE_MATCH']);
if ($etag == $hash) {
header('Last-Modified: ' . gmdate('D, d M Y
H:i:s', filemtime($path)) . ' GMT', true, 304);
// Give fast response.
flush();
exit();
}
}
// Set file headers.
header('ETag: ' . $hash);
header('Pragma: public');
header('Last-Modified: ' . gmdate('D, d M Y
H:i:s', filemtime($path)) . ' GMT');
// Get the image file information.
$info = getimagesize($path);
$isImage = (bool)$info;
if (!$download && $isImage) {
$fileType = $info['mime'];
// Force re-validate.
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0,
pre-check=0');
header('Content-type: ' . $fileType);
header('Content-Disposition: inline; filename="'
. basename($path) . '"');
} else {
// Force file download.
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0,
pre-check=0');
header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header('Content-Type: application/octet-stream');
header('Content-Type: application/download');
header('Content-Disposition: attachment;
filename="' . basename($path) . '"');
}
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($path));
flush();
// Output the file contents.
@readfile($path);
flush();
exit();
}
public function downloadFile()
{
$path = implode('/', func_get_args());
$this->doDownload($path, true);
}
public function upload()
{
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$path = implode('/', func_get_args());
if (base64_decode($path, true) !== false) {
$path = urldecode(base64_decode($path));
}
$stream = explode('://', $path);
$scheme = $stream[0];
$isStream = $locator->schemeExists($scheme);
if ($isStream) {
$targetPath = dirname($locator->findResource($path, true,
true));
} else {
$targetPath = dirname(GANTRY5_ROOT . '/' . $path);
}
if (!isset($_FILES['file']['error']) ||
is_array($_FILES['file']['error'])) {
throw new \RuntimeException('No file sent', 400);
}
// Check $_FILES['file']['error'] value.
switch ($_FILES['file']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new \RuntimeException('No file sent', 400);
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new \RuntimeException('Exceeded filesize
limit.', 400);
default:
throw new \RuntimeException('Unkown errors',
400);
}
$maxSize =
$this->returnBytes(min(ini_get('post_max_size'),
ini_get('upload_max_filesize')));
if ($_FILES['file']['size'] > $maxSize) {
throw new \RuntimeException('Exceeded filesize limit. File
is ' . $_FILES['file']['size'] . ', maximum
allowed is ' . $maxSize, 400);
}
// Check extension
$fileParts = pathinfo($_FILES['file']['name']);
$fileExt = strtolower($fileParts['extension']);
// TODO: check if download is of supported type.
// Upload it
$destination = sprintf('%s/%s', $targetPath,
$_FILES['file']['name']);
$destination = preg_replace('#//#', '/',
$destination);
Folder::create($targetPath);
if
(!move_uploaded_file($_FILES['file']['tmp_name'],
$destination)) {
throw new \RuntimeException('Failed to move uploaded
file.', 500);
}
$finfo = new \stdClass();
$this->attachData($finfo, new \SplFileInfo($destination),
$targetPath);
return new JsonResponse(['success' => 'File
uploaded successfully', 'finfo' => $finfo,
'url' => $path]);
}
protected function returnBytes($size_str)
{
switch (strtolower(substr($size_str, -1))) {
case 'm':
case 'mb':
return (int)$size_str * 1048576;
case 'k':
case 'kb':
return (int)$size_str * 1024;
case 'g':
case 'gb':
return (int)$size_str * 1073741824;
default:
return $size_str;
}
}
public function delete()
{
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$path = implode('/', func_get_args());
if (base64_decode($path, true) !== false) {
$path = urldecode(base64_decode($path));
}
$stream = explode('://', $path);
$scheme = $stream[0];
if (!$path) {
throw new \RuntimeException('No file specified for
delete', 400);
}
$isStream = $locator->schemeExists($scheme);
if ($isStream) {
$targetPath = $locator->findResource($path, true, true);
} else {
$targetPath = GANTRY5_ROOT . '/' . $path;
}
$file = File::instance($targetPath);
if (!$file->exists()) {
throw new \RuntimeException(sprintf('File not found:
%s', $targetPath), 404);
}
try {
$file->delete();
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('File could not be
deleted: %s', $targetPath), 500);
}
$file->free();
return new JsonResponse(['success', 'File deleted:
' . $targetPath]);
}
private function isStream($folder)
{
return $folder instanceof UniformResourceIterator ||
strpos($folder, '://');
}
}
PK%d�[��l�
�
3classes/Gantry/Admin/Controller/Json/Fontpicker.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Response\JsonResponse;
use RocketTheme\Toolbox\File\JsonFile;
class Fontpicker extends JsonController
{
protected $google_fonts =
'gantry-admin://js/google-fonts.json';
protected $httpVerbs = [
'GET' => [
'/' => 'index'
]
];
public function index()
{
$this->params['fonts'] = $this->loadGoogleFonts();
$this->params['variantsMap'] =
$this->variantsMap();
$response = [
'html' =>
$this->render('@gantry-admin/ajax/fontpicker.html.twig',
$this->params)
];
return new JsonResponse($response);
}
public function loadGoogleFonts()
{
$data = new \stdClass();
$file = JsonFile::instance($this->google_fonts);
$fonts = $file->content()['items'];
$file->free();
$data->categories = [];
$data->subsets = [];
// create list of unique categories and subsets
array_walk($fonts, function (&$item) use ($data) {
if (!in_array($item->category, $data->categories)) {
$data->categories[] = $item->category;
}
$data->subsets = array_unique(array_merge($data->subsets,
$item->subsets));
});
asort($data->categories);
asort($data->subsets);
$data->families = $fonts;
$data->local_families = $this->loadLocalFonts();
if (count($data->local_families)) {
array_unshift($data->categories, 'local-fonts');
}
$data->count = count($data->families);
return $data;
}
public function loadLocalFonts()
{
$local_fonts =
$this->container['theme']->details()->get('configuration.fonts',
[]);
$map = [];
foreach ($local_fonts as $name => $variants) {
if (is_array($variants)) {
$list = array_keys($variants);
} else {
$list = ['regular'];
}
$map[] = ['family' => $name, 'variants'
=> $list, 'category' => 'local-fonts'];
}
return $map;
}
protected function variantsMap()
{
return [
'100' => 'Thin 100',
'100italic' => 'Thin 100 Italic',
'200' => 'Extra-Light 200',
'200italic' => 'Extra-Light 200 Italic',
'300' => 'Light 300',
'300italic' => 'Light 300 Italic',
'400' => 'Normal 400',
'regular' => 'Normal 400',
'400italic' => 'Normal 400 Italic',
'italic' => 'Normal 400 Italic',
'500' => 'Medium 500',
'500italic' => 'Medium 500 Italic',
'600' => 'Semi-Bold 600',
'600italic' => 'Semi-Bold 600 Italic',
'700' => 'Bold 700',
'700italic' => 'Bold 700 Italic',
'800' => 'Extra-Bold 800',
'800italic' => 'Extra-Bold 800 Italic',
'900' => 'Ultra-Bold 900',
'900italic' => 'Ultra-Bold 900 Italic'
];
}
}
PK%d�[�u#S�F�F.classes/Gantry/Admin/Controller/Json/Icons.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Response\JsonResponse;
class Icons extends JsonController
{
public function index()
{
$response = [];
// Font Awesome Icons list [v4.7.0 - 730 icons]
// NOTE: To get an updated list of icons:
// 1. Go to: http://fontawesome.io/icons/
// 2. Open Console in Deveveloper Tools
// 3. Type this JS snippet: var list = [];
document.querySelectorAll('.fontawesome-icon-list
i').forEach(function(icon, index){ var name =
icon.className.replace(/^fa\s/, ''); list.push(name); }); var
output = '$list = ["' + list.join('",
"') + '"];'; console.log(output); copy(output);
console.info('The output has been copied to the clipboard, you can now
CMD + V / CTRL + V to update the icons variable');
// 4. Press Enter and replace the line below
$list = ["fa-address-book",
"fa-address-book-o", "fa-address-card",
"fa-address-card-o", "fa-bandcamp",
"fa-bath", "fa-bathtub",
"fa-drivers-license", "fa-drivers-license-o",
"fa-eercast", "fa-envelope-open",
"fa-envelope-open-o", "fa-etsy",
"fa-free-code-camp", "fa-grav",
"fa-handshake-o", "fa-id-badge",
"fa-id-card", "fa-id-card-o", "fa-imdb",
"fa-linode", "fa-meetup", "fa-microchip",
"fa-podcast", "fa-quora", "fa-ravelry",
"fa-s15", "fa-shower", "fa-snowflake-o",
"fa-superpowers", "fa-telegram",
"fa-thermometer", "fa-thermometer-0",
"fa-thermometer-1", "fa-thermometer-2",
"fa-thermometer-3", "fa-thermometer-4",
"fa-thermometer-empty", "fa-thermometer-full",
"fa-thermometer-half", "fa-thermometer-quarter",
"fa-thermometer-three-quarters", "fa-times-rectangle",
"fa-times-rectangle-o", "fa-user-circle",
"fa-user-circle-o", "fa-user-o", "fa-vcard",
"fa-vcard-o", "fa-window-close",
"fa-window-close-o", "fa-window-maximize",
"fa-window-minimize", "fa-window-restore",
"fa-wpexplorer", "fa-address-book",
"fa-address-book-o", "fa-address-card",
"fa-address-card-o", "fa-adjust",
"fa-american-sign-language-interpreting", "fa-anchor",
"fa-archive", "fa-area-chart", "fa-arrows",
"fa-arrows-h", "fa-arrows-v",
"fa-asl-interpreting",
"fa-assistive-listening-systems", "fa-asterisk",
"fa-at", "fa-audio-description",
"fa-automobile", "fa-balance-scale",
"fa-ban", "fa-bank", "fa-bar-chart",
"fa-bar-chart-o", "fa-barcode", "fa-bars",
"fa-bath", "fa-bathtub", "fa-battery",
"fa-battery-0", "fa-battery-1",
"fa-battery-2", "fa-battery-3",
"fa-battery-4", "fa-battery-empty",
"fa-battery-full", "fa-battery-half",
"fa-battery-quarter", "fa-battery-three-quarters",
"fa-bed", "fa-beer", "fa-bell",
"fa-bell-o", "fa-bell-slash",
"fa-bell-slash-o", "fa-bicycle",
"fa-binoculars", "fa-birthday-cake",
"fa-blind", "fa-bluetooth", "fa-bluetooth-b",
"fa-bolt", "fa-bomb", "fa-book",
"fa-bookmark", "fa-bookmark-o", "fa-braille",
"fa-briefcase", "fa-bug", "fa-building",
"fa-building-o", "fa-bullhorn",
"fa-bullseye", "fa-bus", "fa-cab",
"fa-calculator", "fa-calendar",
"fa-calendar-check-o", "fa-calendar-minus-o",
"fa-calendar-o", "fa-calendar-plus-o",
"fa-calendar-times-o", "fa-camera",
"fa-camera-retro", "fa-car",
"fa-caret-square-o-down", "fa-caret-square-o-left",
"fa-caret-square-o-right", "fa-caret-square-o-up",
"fa-cart-arrow-down", "fa-cart-plus",
"fa-cc", "fa-certificate", "fa-check",
"fa-check-circle", "fa-check-circle-o",
"fa-check-square", "fa-check-square-o",
"fa-child", "fa-circle", "fa-circle-o",
"fa-circle-o-notch", "fa-circle-thin",
"fa-clock-o", "fa-clone", "fa-close",
"fa-cloud", "fa-cloud-download",
"fa-cloud-upload", "fa-code", "fa-code-fork",
"fa-coffee", "fa-cog", "fa-cogs",
"fa-comment", "fa-comment-o",
"fa-commenting", "fa-commenting-o",
"fa-comments", "fa-comments-o", "fa-compass",
"fa-copyright", "fa-creative-commons",
"fa-credit-card", "fa-credit-card-alt",
"fa-crop", "fa-crosshairs", "fa-cube",
"fa-cubes", "fa-cutlery", "fa-dashboard",
"fa-database", "fa-deaf", "fa-deafness",
"fa-desktop", "fa-diamond",
"fa-dot-circle-o", "fa-download",
"fa-drivers-license", "fa-drivers-license-o",
"fa-edit", "fa-ellipsis-h", "fa-ellipsis-v",
"fa-envelope", "fa-envelope-o",
"fa-envelope-open", "fa-envelope-open-o",
"fa-envelope-square", "fa-eraser",
"fa-exchange", "fa-exclamation",
"fa-exclamation-circle", "fa-exclamation-triangle",
"fa-external-link", "fa-external-link-square",
"fa-eye", "fa-eye-slash", "fa-eyedropper",
"fa-fax", "fa-feed", "fa-female",
"fa-fighter-jet", "fa-file-archive-o",
"fa-file-audio-o", "fa-file-code-o",
"fa-file-excel-o", "fa-file-image-o",
"fa-file-movie-o", "fa-file-pdf-o",
"fa-file-photo-o", "fa-file-picture-o",
"fa-file-powerpoint-o", "fa-file-sound-o",
"fa-file-video-o", "fa-file-word-o",
"fa-file-zip-o", "fa-film", "fa-filter",
"fa-fire", "fa-fire-extinguisher", "fa-flag",
"fa-flag-checkered", "fa-flag-o", "fa-flash",
"fa-flask", "fa-folder", "fa-folder-o",
"fa-folder-open", "fa-folder-open-o",
"fa-frown-o", "fa-futbol-o", "fa-gamepad",
"fa-gavel", "fa-gear", "fa-gears",
"fa-gift", "fa-glass", "fa-globe",
"fa-graduation-cap", "fa-group",
"fa-hand-grab-o", "fa-hand-lizard-o",
"fa-hand-paper-o", "fa-hand-peace-o",
"fa-hand-pointer-o", "fa-hand-rock-o",
"fa-hand-scissors-o", "fa-hand-spock-o",
"fa-hand-stop-o", "fa-handshake-o",
"fa-hard-of-hearing", "fa-hashtag",
"fa-hdd-o", "fa-headphones", "fa-heart",
"fa-heart-o", "fa-heartbeat", "fa-history",
"fa-home", "fa-hotel", "fa-hourglass",
"fa-hourglass-1", "fa-hourglass-2",
"fa-hourglass-3", "fa-hourglass-end",
"fa-hourglass-half", "fa-hourglass-o",
"fa-hourglass-start", "fa-i-cursor",
"fa-id-badge", "fa-id-card", "fa-id-card-o",
"fa-image", "fa-inbox", "fa-industry",
"fa-info", "fa-info-circle",
"fa-institution", "fa-key", "fa-keyboard-o",
"fa-language", "fa-laptop", "fa-leaf",
"fa-legal", "fa-lemon-o", "fa-level-down",
"fa-level-up", "fa-life-bouy",
"fa-life-buoy", "fa-life-ring",
"fa-life-saver", "fa-lightbulb-o",
"fa-line-chart", "fa-location-arrow",
"fa-lock", "fa-low-vision", "fa-magic",
"fa-magnet", "fa-mail-forward",
"fa-mail-reply", "fa-mail-reply-all",
"fa-male", "fa-map", "fa-map-marker",
"fa-map-o", "fa-map-pin", "fa-map-signs",
"fa-meh-o", "fa-microchip", "fa-microphone",
"fa-microphone-slash", "fa-minus",
"fa-minus-circle", "fa-minus-square",
"fa-minus-square-o", "fa-mobile",
"fa-mobile-phone", "fa-money", "fa-moon-o",
"fa-mortar-board", "fa-motorcycle",
"fa-mouse-pointer", "fa-music", "fa-navicon",
"fa-newspaper-o", "fa-object-group",
"fa-object-ungroup", "fa-paint-brush",
"fa-paper-plane", "fa-paper-plane-o",
"fa-paw", "fa-pencil", "fa-pencil-square",
"fa-pencil-square-o", "fa-percent",
"fa-phone", "fa-phone-square", "fa-photo",
"fa-picture-o", "fa-pie-chart", "fa-plane",
"fa-plug", "fa-plus", "fa-plus-circle",
"fa-plus-square", "fa-plus-square-o",
"fa-podcast", "fa-power-off", "fa-print",
"fa-puzzle-piece", "fa-qrcode",
"fa-question", "fa-question-circle",
"fa-question-circle-o", "fa-quote-left",
"fa-quote-right", "fa-random", "fa-recycle",
"fa-refresh", "fa-registered", "fa-remove",
"fa-reorder", "fa-reply", "fa-reply-all",
"fa-retweet", "fa-road", "fa-rocket",
"fa-rss", "fa-rss-square", "fa-s15",
"fa-search", "fa-search-minus",
"fa-search-plus", "fa-send", "fa-send-o",
"fa-server", "fa-share", "fa-share-alt",
"fa-share-alt-square", "fa-share-square",
"fa-share-square-o", "fa-shield", "fa-ship",
"fa-shopping-bag", "fa-shopping-basket",
"fa-shopping-cart", "fa-shower",
"fa-sign-in", "fa-sign-language",
"fa-sign-out", "fa-signal", "fa-signing",
"fa-sitemap", "fa-sliders", "fa-smile-o",
"fa-snowflake-o", "fa-soccer-ball-o",
"fa-sort", "fa-sort-alpha-asc",
"fa-sort-alpha-desc", "fa-sort-amount-asc",
"fa-sort-amount-desc", "fa-sort-asc",
"fa-sort-desc", "fa-sort-down",
"fa-sort-numeric-asc", "fa-sort-numeric-desc",
"fa-sort-up", "fa-space-shuttle",
"fa-spinner", "fa-spoon", "fa-square",
"fa-square-o", "fa-star", "fa-star-half",
"fa-star-half-empty", "fa-star-half-full",
"fa-star-half-o", "fa-star-o",
"fa-sticky-note", "fa-sticky-note-o",
"fa-street-view", "fa-suitcase", "fa-sun-o",
"fa-support", "fa-tablet", "fa-tachometer",
"fa-tag", "fa-tags", "fa-tasks",
"fa-taxi", "fa-television", "fa-terminal",
"fa-thermometer", "fa-thermometer-0",
"fa-thermometer-1", "fa-thermometer-2",
"fa-thermometer-3", "fa-thermometer-4",
"fa-thermometer-empty", "fa-thermometer-full",
"fa-thermometer-half", "fa-thermometer-quarter",
"fa-thermometer-three-quarters", "fa-thumb-tack",
"fa-thumbs-down", "fa-thumbs-o-down",
"fa-thumbs-o-up", "fa-thumbs-up",
"fa-ticket", "fa-times", "fa-times-circle",
"fa-times-circle-o", "fa-times-rectangle",
"fa-times-rectangle-o", "fa-tint",
"fa-toggle-down", "fa-toggle-left",
"fa-toggle-off", "fa-toggle-on",
"fa-toggle-right", "fa-toggle-up",
"fa-trademark", "fa-trash", "fa-trash-o",
"fa-tree", "fa-trophy", "fa-truck",
"fa-tty", "fa-tv", "fa-umbrella",
"fa-universal-access", "fa-university",
"fa-unlock", "fa-unlock-alt", "fa-unsorted",
"fa-upload", "fa-user", "fa-user-circle",
"fa-user-circle-o", "fa-user-o",
"fa-user-plus", "fa-user-secret",
"fa-user-times", "fa-users", "fa-vcard",
"fa-vcard-o", "fa-video-camera",
"fa-volume-control-phone", "fa-volume-down",
"fa-volume-off", "fa-volume-up",
"fa-warning", "fa-wheelchair",
"fa-wheelchair-alt", "fa-wifi",
"fa-window-close", "fa-window-close-o",
"fa-window-maximize", "fa-window-minimize",
"fa-window-restore", "fa-wrench",
"fa-american-sign-language-interpreting",
"fa-asl-interpreting",
"fa-assistive-listening-systems",
"fa-audio-description", "fa-blind",
"fa-braille", "fa-cc", "fa-deaf",
"fa-deafness", "fa-hard-of-hearing",
"fa-low-vision", "fa-question-circle-o",
"fa-sign-language", "fa-signing", "fa-tty",
"fa-universal-access", "fa-volume-control-phone",
"fa-wheelchair", "fa-wheelchair-alt",
"fa-hand-grab-o", "fa-hand-lizard-o",
"fa-hand-o-down", "fa-hand-o-left",
"fa-hand-o-right", "fa-hand-o-up",
"fa-hand-paper-o", "fa-hand-peace-o",
"fa-hand-pointer-o", "fa-hand-rock-o",
"fa-hand-scissors-o", "fa-hand-spock-o",
"fa-hand-stop-o", "fa-thumbs-down",
"fa-thumbs-o-down", "fa-thumbs-o-up",
"fa-thumbs-up", "fa-ambulance",
"fa-automobile", "fa-bicycle", "fa-bus",
"fa-cab", "fa-car", "fa-fighter-jet",
"fa-motorcycle", "fa-plane", "fa-rocket",
"fa-ship", "fa-space-shuttle", "fa-subway",
"fa-taxi", "fa-train", "fa-truck",
"fa-wheelchair", "fa-wheelchair-alt",
"fa-genderless", "fa-intersex", "fa-mars",
"fa-mars-double", "fa-mars-stroke",
"fa-mars-stroke-h", "fa-mars-stroke-v",
"fa-mercury", "fa-neuter", "fa-transgender",
"fa-transgender-alt", "fa-venus",
"fa-venus-double", "fa-venus-mars",
"fa-file", "fa-file-archive-o",
"fa-file-audio-o", "fa-file-code-o",
"fa-file-excel-o", "fa-file-image-o",
"fa-file-movie-o", "fa-file-o",
"fa-file-pdf-o", "fa-file-photo-o",
"fa-file-picture-o", "fa-file-powerpoint-o",
"fa-file-sound-o", "fa-file-text",
"fa-file-text-o", "fa-file-video-o",
"fa-file-word-o", "fa-file-zip-o",
"fa-circle-o-notch", "fa-cog", "fa-gear",
"fa-refresh", "fa-spinner",
"fa-check-square", "fa-check-square-o",
"fa-circle", "fa-circle-o",
"fa-dot-circle-o", "fa-minus-square",
"fa-minus-square-o", "fa-plus-square",
"fa-plus-square-o", "fa-square",
"fa-square-o", "fa-cc-amex",
"fa-cc-diners-club", "fa-cc-discover",
"fa-cc-jcb", "fa-cc-mastercard",
"fa-cc-paypal", "fa-cc-stripe", "fa-cc-visa",
"fa-credit-card", "fa-credit-card-alt",
"fa-google-wallet", "fa-paypal",
"fa-area-chart", "fa-bar-chart",
"fa-bar-chart-o", "fa-line-chart",
"fa-pie-chart", "fa-bitcoin", "fa-btc",
"fa-cny", "fa-dollar", "fa-eur",
"fa-euro", "fa-gbp", "fa-gg",
"fa-gg-circle", "fa-ils", "fa-inr",
"fa-jpy", "fa-krw", "fa-money",
"fa-rmb", "fa-rouble", "fa-rub",
"fa-ruble", "fa-rupee", "fa-shekel",
"fa-sheqel", "fa-try", "fa-turkish-lira",
"fa-usd", "fa-won", "fa-yen",
"fa-align-center", "fa-align-justify",
"fa-align-left", "fa-align-right", "fa-bold",
"fa-chain", "fa-chain-broken",
"fa-clipboard", "fa-columns", "fa-copy",
"fa-cut", "fa-dedent", "fa-eraser",
"fa-file", "fa-file-o", "fa-file-text",
"fa-file-text-o", "fa-files-o",
"fa-floppy-o", "fa-font", "fa-header",
"fa-indent", "fa-italic", "fa-link",
"fa-list", "fa-list-alt", "fa-list-ol",
"fa-list-ul", "fa-outdent", "fa-paperclip",
"fa-paragraph", "fa-paste", "fa-repeat",
"fa-rotate-left", "fa-rotate-right",
"fa-save", "fa-scissors", "fa-strikethrough",
"fa-subscript", "fa-superscript", "fa-table",
"fa-text-height", "fa-text-width", "fa-th",
"fa-th-large", "fa-th-list", "fa-underline",
"fa-undo", "fa-unlink",
"fa-angle-double-down", "fa-angle-double-left",
"fa-angle-double-right", "fa-angle-double-up",
"fa-angle-down", "fa-angle-left",
"fa-angle-right", "fa-angle-up",
"fa-arrow-circle-down", "fa-arrow-circle-left",
"fa-arrow-circle-o-down", "fa-arrow-circle-o-left",
"fa-arrow-circle-o-right", "fa-arrow-circle-o-up",
"fa-arrow-circle-right", "fa-arrow-circle-up",
"fa-arrow-down", "fa-arrow-left",
"fa-arrow-right", "fa-arrow-up", "fa-arrows",
"fa-arrows-alt", "fa-arrows-h",
"fa-arrows-v", "fa-caret-down",
"fa-caret-left", "fa-caret-right",
"fa-caret-square-o-down", "fa-caret-square-o-left",
"fa-caret-square-o-right", "fa-caret-square-o-up",
"fa-caret-up", "fa-chevron-circle-down",
"fa-chevron-circle-left", "fa-chevron-circle-right",
"fa-chevron-circle-up", "fa-chevron-down",
"fa-chevron-left", "fa-chevron-right",
"fa-chevron-up", "fa-exchange",
"fa-hand-o-down", "fa-hand-o-left",
"fa-hand-o-right", "fa-hand-o-up",
"fa-long-arrow-down", "fa-long-arrow-left",
"fa-long-arrow-right", "fa-long-arrow-up",
"fa-toggle-down", "fa-toggle-left",
"fa-toggle-right", "fa-toggle-up",
"fa-arrows-alt", "fa-backward",
"fa-compress", "fa-eject", "fa-expand",
"fa-fast-backward", "fa-fast-forward",
"fa-forward", "fa-pause", "fa-pause-circle",
"fa-pause-circle-o", "fa-play",
"fa-play-circle", "fa-play-circle-o",
"fa-random", "fa-step-backward",
"fa-step-forward", "fa-stop",
"fa-stop-circle", "fa-stop-circle-o",
"fa-youtube-play", "fa-500px", "fa-adn",
"fa-amazon", "fa-android", "fa-angellist",
"fa-apple", "fa-bandcamp", "fa-behance",
"fa-behance-square", "fa-bitbucket",
"fa-bitbucket-square", "fa-bitcoin",
"fa-black-tie", "fa-bluetooth",
"fa-bluetooth-b", "fa-btc", "fa-buysellads",
"fa-cc-amex", "fa-cc-diners-club",
"fa-cc-discover", "fa-cc-jcb",
"fa-cc-mastercard", "fa-cc-paypal",
"fa-cc-stripe", "fa-cc-visa", "fa-chrome",
"fa-codepen", "fa-codiepie",
"fa-connectdevelop", "fa-contao", "fa-css3",
"fa-dashcube", "fa-delicious",
"fa-deviantart", "fa-digg", "fa-dribbble",
"fa-dropbox", "fa-drupal", "fa-edge",
"fa-eercast", "fa-empire", "fa-envira",
"fa-etsy", "fa-expeditedssl", "fa-fa",
"fa-facebook", "fa-facebook-f",
"fa-facebook-official", "fa-facebook-square",
"fa-firefox", "fa-first-order", "fa-flickr",
"fa-font-awesome", "fa-fonticons",
"fa-fort-awesome", "fa-forumbee",
"fa-foursquare", "fa-free-code-camp",
"fa-ge", "fa-get-pocket", "fa-gg",
"fa-gg-circle", "fa-git", "fa-git-square",
"fa-github", "fa-github-alt",
"fa-github-square", "fa-gitlab", "fa-gittip",
"fa-glide", "fa-glide-g", "fa-google",
"fa-google-plus", "fa-google-plus-circle",
"fa-google-plus-official", "fa-google-plus-square",
"fa-google-wallet", "fa-gratipay", "fa-grav",
"fa-hacker-news", "fa-houzz", "fa-html5",
"fa-imdb", "fa-instagram",
"fa-internet-explorer", "fa-ioxhost",
"fa-joomla", "fa-jsfiddle", "fa-lastfm",
"fa-lastfm-square", "fa-leanpub",
"fa-linkedin", "fa-linkedin-square",
"fa-linode", "fa-linux", "fa-maxcdn",
"fa-meanpath", "fa-medium", "fa-meetup",
"fa-mixcloud", "fa-modx", "fa-odnoklassniki",
"fa-odnoklassniki-square", "fa-opencart",
"fa-openid", "fa-opera", "fa-optin-monster",
"fa-pagelines", "fa-paypal", "fa-pied-piper",
"fa-pied-piper-alt", "fa-pied-piper-pp",
"fa-pinterest", "fa-pinterest-p",
"fa-pinterest-square", "fa-product-hunt",
"fa-qq", "fa-quora", "fa-ra",
"fa-ravelry", "fa-rebel", "fa-reddit",
"fa-reddit-alien", "fa-reddit-square",
"fa-renren", "fa-resistance", "fa-safari",
"fa-scribd", "fa-sellsy", "fa-share-alt",
"fa-share-alt-square", "fa-shirtsinbulk",
"fa-simplybuilt", "fa-skyatlas", "fa-skype",
"fa-slack", "fa-slideshare", "fa-snapchat",
"fa-snapchat-ghost", "fa-snapchat-square",
"fa-soundcloud", "fa-spotify",
"fa-stack-exchange", "fa-stack-overflow",
"fa-steam", "fa-steam-square",
"fa-stumbleupon", "fa-stumbleupon-circle",
"fa-superpowers", "fa-telegram",
"fa-tencent-weibo", "fa-themeisle",
"fa-trello", "fa-tripadvisor", "fa-tumblr",
"fa-tumblr-square", "fa-twitch",
"fa-twitter", "fa-twitter-square", "fa-usb",
"fa-viacoin", "fa-viadeo",
"fa-viadeo-square", "fa-vimeo",
"fa-vimeo-square", "fa-vine", "fa-vk",
"fa-wechat", "fa-weibo", "fa-weixin",
"fa-whatsapp", "fa-wikipedia-w",
"fa-windows", "fa-wordpress",
"fa-wpbeginner", "fa-wpexplorer",
"fa-wpforms", "fa-xing", "fa-xing-square",
"fa-y-combinator", "fa-y-combinator-square",
"fa-yahoo", "fa-yc", "fa-yc-square",
"fa-yelp", "fa-yoast", "fa-youtube",
"fa-youtube-play", "fa-youtube-square",
"fa-ambulance", "fa-h-square", "fa-heart",
"fa-heart-o", "fa-heartbeat",
"fa-hospital-o", "fa-medkit",
"fa-plus-square", "fa-stethoscope",
"fa-user-md", "fa-wheelchair",
"fa-wheelchair-alt"];
$options = [
'fw' => 'Fixed Width',
'spin' => 'Spinning',
'larger' => ['' => '- Size -
', 'lg' => 'Large', '2x' =>
'2x', '3x' => '3x', '4x' =>
'4x', '5x' => '5x'],
'rotation' => ['' => '- Rotation
-', 'flip-horizontal' => 'Horizontal Flip',
'flip-vertical' => 'Vertical Flip',
'rotate-90' => 'Rotate 90°', 'rotate-180'
=> 'Rotate 180°', 'rotate-270' => 'Rotate
270°']
];
$list = array_unique($list);
sort($list);
$response['html'] =
$this->render('@gantry-admin/ajax/icons.html.twig',
['icons' => $list, 'options' => $options,
'total' => count($list)]);
return new JsonResponse($response);
}
}
PK%d�[�DEL L
0classes/Gantry/Admin/Controller/Json/Layouts.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Layout\Layout;
use Gantry\Component\Response\JsonResponse;
/**
* Class Layouts
* @package Gantry\Admin\Controller\Json
*/
class Layouts extends JsonController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/*' => 'index',
'/particle' => 'particle'
],
'POST' => [
'/' => 'index',
'/*' => 'index',
'/particle' => 'particle'
]
];
public function index()
{
$path = implode('/', func_get_args());
$post = $this->request->request;
$outline = $post['outline'];
$type = $post['type'];
$subtype = $post['subtype'];
$inherit = $post['inherit'];
$clone = $post['mode'] === 'clone';
$id = $post['id'];
$this->container['outline'] = $outline;
$this->container['configuration'] = $outline;
$layout = Layout::instance($outline);
if ($inherit) {
$layout->inheritAll();
}
if ($path == 'list' &&
!$layout->isLayoutType($type)) {
$instance = $this->getParticleInstances($outline, $subtype,
null);
$id = $instance['selected'];
}
$item = $layout->find($id);
$type = isset($item->type) ? $item->type : $type;
$subtype = isset($item->subtype) ? $item->subtype : $subtype;
$item->attributes = isset($item->attributes) ? (array)
$item->attributes : [];
$block = $layout->block($id);
$block = isset($block->attributes) ? (array)
$block->attributes : [];
$params = [
'gantry' => $this->container,
'parent' => 'settings',
'route' =>
"configurations.{$outline}.settings",
'inherit' => $inherit ? $outline : null,
];
if ($layout->isLayoutType($type)) {
$name = $type;
$particle = false;
$defaults = [];
$blueprints =
BlueprintForm::instance("layout/{$name}.yaml",
'gantry-admin://blueprints');
} else {
$name = $subtype;
$particle = true;
$defaults =
$this->container['config']->get("particles.{$name}");
$item->attributes = $item->attributes + $defaults;
$blueprints =
$this->container['particles']->getBlueprintForm($name);
$blueprints->set('form/fields/_inherit',
['type' => 'gantry.inherit']);
}
$paramsParticle = [
'title' => isset($item->title) ?
$item->title : '',
'blueprints' =>
$blueprints->get('form'),
'item' => $item,
'data' => ['particles' =>
[$name => $item->attributes]],
'defaults' => ['particles' =>
[$name => $defaults]],
'prefix' => "particles.{$name}.",
'editable' => $particle,
'overrideable' => $particle,
'skip' => ['enabled']
] + $params;
$html['g-settings-particle'] =
$this->render('@gantry-admin/pages/configurations/layouts/particle-card.html.twig',
$paramsParticle);
$html['g-settings-block-attributes'] =
$this->renderBlockFields($block, $params);
if ($path == 'list') {
$html['g-inherit-particle'] =
$this->renderParticlesInput($inherit || $clone ? $outline : null,
$subtype, $post['selected']);
}
return new JsonResponse(['json' => $item,
'html' => $html]);
}
public function particle()
{
$post = $this->request->request;
$outline = $post['outline'];
$id = $post['id'];
$this->container['outline'] = $outline;
$this->container['configuration'] = $outline;
$layout = Layout::instance($outline);
$particle = clone $layout->find($id);
if (!isset($particle->type)) {
throw new \RuntimeException('Particle was not found from
the outline', 404);
}
$particle->block = $layout->block($id);
$name = $particle->subtype;
$prefix = "particles.{$name}";
$defaults = (array)
$this->container['config']->get($prefix);
$attributes = (array) $particle->attributes + $defaults;
$particleBlueprints =
$this->container['particles']->getBlueprintForm($name);
$particleBlueprints->set('form/fields/_inherit',
['type' => 'gantry.inherit']);
$blockBlueprints =
BlueprintForm::instance('layout/block.yaml',
'gantry-admin://blueprints');
// TODO: Use blueprints to merge configuration.
$particle->attributes = (object) $attributes;
$this->params['id'] = $name;
$this->params += [
'extra' => $blockBlueprints,
'item' => $particle,
'data' => ['particles' =>
[$name => $attributes]],
'defaults' => ['particles' =>
[$name => $defaults]],
'prefix' => "particles.{$name}.",
'particle' => $particleBlueprints,
'parent' => 'settings',
'route' =>
"configurations.{$outline}.settings",
'action' => str_replace('.',
'/', 'configurations.' . $outline .
'.layout.' . $prefix . '.validate'),
'skip' => ['enabled'],
'editable' => false,
'overrideable' => true,
];
$html =
$this->render('@gantry-admin/pages/configurations/layouts/particle-preview.html.twig',
$this->params);
return new JsonResponse(['html' => $html]);
}
/**
* Render block settings.
*
* @param array $block
* @param array $params
* @return string
*/
protected function renderBlockFields(array $block, array $params)
{
$blockBlueprints =
BlueprintForm::instance('layout/block.yaml',
'gantry-admin://blueprints');
$paramsBlock = [
'title' =>
$this->container['translator']->translate('GANTRY5_PLATFORM_BLOCK'),
'blueprints' => ['fields' =>
$blockBlueprints->get('form/fields/block_container/fields')],
'data' => ['block' => $block],
'prefix' => 'block.',
] + $params;
return
$this->render('@gantry-admin/forms/fields.html.twig',
$paramsBlock);
}
/**
* Gets the list of available particle instances for an outline
*
* @param string $outline
* @param string $particle
* @param string $selected
* @return string
*/
protected function getParticleInstances($outline, $particle, $selected)
{
$list = $outline ?
$this->container['outlines']->getParticleInstances($outline,
$particle, false) : [];
$selected = isset($list[$selected]) ? $selected : key($list);
return ['list' => $list, 'selected' =>
$selected];
}
/**
* Render input field for particle picker.
*
* @param string $outline
* @param string $particle
* @param string $selected
* @return string
*/
protected function renderParticlesInput($outline, $particle, $selected)
{
$instances = $this->getParticleInstances($outline, $particle,
$selected);
$params = [
'layout' => 'input',
'scope' => 'inherit.',
'field' => [
'name' => 'particle',
'type' => 'gantry.particles',
'id' => 'g-inherit-particle',
'outline' => $outline,
'particles' => $instances['list'],
'particle' => $particle
],
'value' => $instances['selected']
];
return
$this->render('@gantry-admin/forms/fields/gantry/particles.html.twig',
$params);
}
}
PK%d�[�e��))1classes/Gantry/Admin/Controller/Json/Particle.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Config\BlueprintSchema;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\Config;
use Gantry\Component\Response\JsonResponse;
class Particle extends JsonController
{
protected $httpVerbs = [
'GET' => [
'/' =>
'selectParticle',
'/module' => 'selectModule'
],
'POST' => [
'/' => 'undefined',
'/*' => 'particle',
'/*/validate' => 'validate',
],
'PUT' => [
'/*' => 'replace'
],
'PATCH' => [
'/*' => 'update'
],
'DELETE' => [
'/*' => 'destroy'
]
];
/**
* Return a modal for selecting a particle.
*
* @return string
*/
public function selectParticle()
{
$groups = [
'Particles' => ['particle' => []],
];
$particles = [
'position' => [],
'spacer' => [],
'system' => [],
'particle' => [],
];
$particles = array_replace($particles, $this->getParticles());
unset($particles['atom'],
$particles['position']);
foreach ($particles as &$group) {
asort($group);
}
foreach ($groups as $section => $children) {
foreach ($children as $key => $child) {
$groups[$section][$key] = $particles[$key];
}
}
$this->params['particles'] = $groups;
return new JsonResponse(['html' =>
$this->render('@gantry-admin/modals/particle-picker.html.twig',
$this->params)]);
}
/**
* Return a modal content for selecting module.
*
* @return mixed
*/
public function selectModule()
{
return new JsonResponse(['html' =>
$this->render('@gantry-admin/modals/module-picker.html.twig',
$this->params)]);
}
/**
* Return form for the particle (filled with data coming from POST).
*
* @param string $name
* @return mixed
*/
public function particle($name)
{
$data = $this->request->post['item'];
if ($data) {
$data = json_decode($data, true);
} else {
$data = $this->request->post->getArray();
}
// TODO: add support for other block types as well, like menu.
// $block = BlueprintForm::instance('layout/block.yaml',
'gantry-admin://blueprints');
$blueprints =
$this->container['particles']->getBlueprintForm($name);
// Load particle blueprints and default settings.
$validator = $this->loadBlueprints('menu');
$callable = function () use ($validator) {
return $validator;
};
// Create configuration from the defaults.
$item = new Config($data, $callable);
$item->def('type', 'particle');
$item->def('title',
$blueprints->get('name'));
$item->def('options.type',
$blueprints->get('type', 'particle'));
$item->def('options.particle', []);
$item->def('options.block', []);
$this->params += [
'item' => $item,
// 'block' => $block,
'data' => ['particles' =>
[$name => $item->options['particle']]],
'particle' => $blueprints,
'parent' => 'settings',
'prefix' => "particles.{$name}.",
'route' =>
"configurations.default.settings",
'action' =>
"particle/{$name}/validate"
];
return new JsonResponse(['html' =>
$this->render('@gantry-admin/modals/particle.html.twig',
$this->params)]);
}
/**
* Validate data for the particle.
*
* @param string $name
* @return JsonResponse
*/
public function validate($name)
{
// Load particle blueprints and default settings.
$validator = new BlueprintSchema;
$validator->embed('options',
$this->container['particles']->get($name));
$blueprints =
$this->container['particles']->getBlueprintForm($name);
// Create configuration from the defaults.
$data = new Config([],
function () use ($validator) {
return $validator;
}
);
$data->set('type', 'particle');
$data->set('particle', $name);
$data->set('title',
$this->request->post['title'] ?:
$blueprints->get('name'));
$data->set('options.particle',
$this->request->post->getArray("particles.{$name}"));
$data->def('options.particle.enabled', 1);
$block =
$this->request->post->getArray('block');
foreach ($block as $key => $param) {
if ($param === '') {
unset($block[$key]);
}
}
if ($block) {
$data->join('options.block', $block);
}
// TODO: validate
// Fill parameters to be passed to the template file.
$this->params['item'] = (object) $data->toArray();
return new JsonResponse(['item' =>
$data->toArray()]);
}
protected function getParticles()
{
$particles = $this->container['particles']->all();
$list = [];
foreach ($particles as $name => $particle) {
$type = isset($particle['type']) ?
$particle['type'] : 'particle';
$particleName = isset($particle['name']) ?
$particle['name'] : $name;
$particleIcon = isset($particle['icon']) ?
$particle['icon'] : null;
$list[$type][$name] = ['name' => $particleName,
'icon' => $particleIcon];
}
return $list;
}
/**
* Load blueprints.
*
* @param string $name
*
* @return BlueprintForm
*/
protected function loadBlueprints($name = 'menu')
{
return BlueprintForm::instance("menu/{$name}.yaml",
'gantry-admin://blueprints');
}
}
PK%d�[�P_�%%0classes/Gantry/Admin/Controller/Json/Unsaved.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin\Controller\Json;
use Gantry\Component\Admin\JsonController;
use Gantry\Component\Response\JsonResponse;
class Unsaved extends JsonController
{
protected $httpVerbs = [
'GET' => [
'/' => 'index'
]
];
public function index()
{
$response = ['html' =>
$this->render('@gantry-admin/ajax/unsaved.html.twig')];
return new JsonResponse($response);
}
}
PK%d�[譤��&classes/Gantry/Admin/EventListener.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Admin;
use Gantry\Component\Layout\Layout;
use Gantry\Joomla\CacheHelper;
use Gantry\Joomla\Manifest;
use Gantry\Joomla\StyleHelper;
use Joomla\Registry\Registry;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\Event\EventSubscriberInterface;
use RocketTheme\Toolbox\File\IniFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class EventListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'admin.init.theme' =>
['onAdminThemeInit', 0],
'admin.global.save' => ['onGlobalSave',
0],
'admin.styles.save' => ['onStylesSave',
0],
'admin.settings.save' =>
['onSettingsSave', 0],
'admin.layout.save' => ['onLayoutSave',
0],
'admin.assignments.save' =>
['onAssignmentsSave', 0],
'admin.menus.save' => ['onMenusSave', 0]
];
}
public function onAdminThemeInit(Event $event)
{
\JPluginHelper::importPlugin('gantry5');
// Trigger the onGantryThemeInit event.
$dispatcher = \JEventDispatcher::getInstance();
$dispatcher->trigger('onGantry5AdminInit',
['theme' => $event->theme]);
}
public function onGlobalSave(Event $event)
{
\JPluginHelper::importPlugin('gantry5');
// Trigger the onGantryThemeUpdateCss event.
$dispatcher = \JEventDispatcher::getInstance();
$dispatcher->trigger('onGantry5SaveConfig',
[$event->data]);
}
public function onStylesSave(Event $event)
{
\JPluginHelper::importPlugin('gantry5');
// Trigger the onGantryThemeUpdateCss event.
$dispatcher = \JEventDispatcher::getInstance();
$dispatcher->trigger('onGantry5UpdateCss',
['theme' => $event->theme]);
}
public function onSettingsSave(Event $event)
{
}
public function onLayoutSave(Event $event)
{
/** @var Layout $layout */
$layout = $event->layout;
if ($layout->name[0] !== '_' &&
$layout->name !== 'default') {
$preset = isset($layout->preset['name']) ?
$layout->preset['name'] : 'default';
// Update Joomla template style.
StyleHelper::update($layout->name, $preset);
}
$theme = $event->gantry['theme.name'];
$positions =
$event->gantry['outlines']->positions();
$positions['debug'] = 'Debug';
$manifest = new Manifest($theme);
$manifest->setPositions(array_keys($positions));
$manifest->save();
$translations = [];
foreach ($positions as $key => $translation) {
// Encode translation key in Joomla way.
$key = preg_replace('/[^A-Z0-9_\-]/', '_',
strtoupper("TPL_{$theme}_POSITION_{$key}"));
$translations[$key] = $translation;
}
/** @var UniformResourceLocator $locator */
$locator = $event->gantry['locator'];
$filename =
"gantry-theme://language/en-GB/en-GB.tpl_{$theme}_positions.ini";
$ini = IniFile::instance($locator->findResource($filename, true,
true));
$ini->save($translations);
$ini->free();
}
public function onAssignmentsSave(Event $event)
{
}
public function onMenusSave(Event $event)
{
$defaults = [
'id' => 0,
'layout' => 'list',
'target' => '_self',
'dropdown' => '',
'icon' => '',
'image' => '',
'subtitle' => '',
'icon_only' => false,
'visible' => true,
'group' => 0,
'columns' => [],
'link_title' => '',
'hash' => '',
'class' => ''
];
$gantry = $event->gantry;
$menu = $event->menu;
// Save global menu settings into Joomla.
/** @var \JTableMenuType $table */
$menuType = \JTable::getInstance('MenuType');
if (!$menuType->load(['menutype' =>
$event->resource])) {
throw new \RuntimeException("Saving menu failed: Menu type
{$event->resource} not found.", 400);
}
$options = [
'title' => $menu['settings.title'],
'description' =>
$menu['settings.description']
];
if ($gantry->authorize('menu.edit') &&
!$menuType->save($options)) {
throw new \RuntimeException('Saving menu failed: '.
$menuType->getError(), 400);
}
unset($menu['settings']);
/** @var \JTableMenu $table */
$table = \JTable::getInstance('menu');
foreach ($menu['items'] as $key => $item) {
$id = !empty($item['id']) ? (int)
$item['id'] : 0;
if ($id && $table->load($item['id'])) {
$params = new Registry($table->params);
// Menu item exists in Joomla, let's update it
instead.
unset($item['type'], $item['link']);
$item['id'] = (int) $id;
$title = $menu["items.{$key}.title"];
$browserNav = intval($menu["items.{$key}.target"]
=== '_blank');
$options = [
// Disabled as the option has different meaning in
Joomla than in Gantry, see issue #1656.
// 'menu-anchor_css' =>
$menu["items.{$key}.class"],
'menu_image' =>
$menu["items.{$key}.image"],
'menu_text' =>
intval(!$menu["items.{$key}.icon_only"]),
'menu_show' =>
intval($menu["items.{$key}.enabled"]),
];
$modified = false;
if ($table->title != $title) {
$table->title = $title;
$modified = true;
}
if ($table->browserNav != $browserNav) {
$table->browserNav = $browserNav;
$modified = true;
}
foreach ($options as $var => $value) {
if ($params->get($var) !== $value) {
$params->set($var, $value);
$modified = true;
}
}
if ($modified &&
$gantry->authorize('menu.edit')) {
$table->params = (string) $params;
if (!$table->check() || !$table->store()) {
throw new \RuntimeException("Failed to save
/{$key}: {$table->getError()}", 400);
}
}
// Avoid saving values which are also stored in Joomla.
unset($item['title'],
$item['anchor_class'], $item['image'],
$item['icon_only'], $item['target']);
if (version_compare(JVERSION, '3.5.1',
'>=')) {
unset($item['enabled']);
}
}
// Do not save default values.
foreach ($defaults as $var => $value) {
if (isset($item[$var]) && $item[$var] == $value) {
unset($item[$var]);
}
}
// Do not save derived values.
unset($item['path'], $item['alias'],
$item['parent_id'], $item['level'],
$item['group']);
// Particles have no link.
if (isset($item['type']) &&
$item['type'] === 'particle') {
unset($item['link']);
}
// Because of ordering we need to save all menu items,
including those from Joomla which have no data except id.
$event->menu["items.{$key}"] = $item;
}
// Clean the cache.
CacheHelper::cleanMenu();
}
}
PK%d�[uTQ'classes/Gantry/Admin/Page.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\ConfigFileFinder;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Theme as SiteTheme;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Page
{
protected $container;
protected $files;
protected $blocks;
public function __construct($container)
{
$this->container = $container;
}
public function all()
{
if (!$this->blocks)
{
$files = $this->locateBlocks();
$this->blocks = [];
foreach ($files as $key => $fileArray) {
$filename = key($fileArray);
$file = CompiledYamlFile::instance(GANTRY5_ROOT .
'/' . $filename);
$this->blocks[$key] = $file->content();
$file->free();
}
}
return $this->blocks;
}
public function group()
{
$blocks = $this->all();
$list = [];
foreach ($blocks as $name => $setting) {
$type = isset($setting['type']) ?
$setting['type'] : '';
$list[$type][$name] = $setting;
}
return $this->sort($list);
}
public function get($id)
{
if ($this->blocks[$id]) {
return $this->blocks[$id];
}
$files = $this->locateBlocks();
if (empty($files[$id])) {
throw new \RuntimeException(sprintf("Settings for
'%s' not found.", $id), 404);
}
$filename = key($files[$id]);
$file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' .
$filename);
$setting = $file->content();
$file->free();
return $setting;
}
/**
* @param string $id
* @return BlueprintForm
*/
public function getBlueprintForm($id)
{
return BlueprintForm::instance($id,
'gantry-blueprints://page');
}
protected function sort(array $blocks)
{
$list = [];
/** @var SiteTheme $theme */
$theme = $this->container['theme'];
$ordering = (array) $theme->details()['admin.page'];
if (!count($ordering)) {
$ordering = ['global' => ['head',
'assets', 'body', 'generics']];
}
ksort($blocks);
foreach ($ordering as $name => $order) {
if (isset($blocks[$name])) {
$list[$name] = $this->sortItems($blocks[$name], (array)
$order);
}
}
$list += $blocks;
return $list;
}
protected function sortItems(array $items, array $ordering)
{
$list = [];
ksort($items);
foreach ($ordering as $name) {
if (isset($items[$name])) {
$list[$name] = $items[$name];
}
}
$list += $items;
return $list;
}
protected function locateBlocks()
{
if (!$this->files) {
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$paths =
$locator->findResources('gantry-blueprints://page');
$this->files = (new ConfigFileFinder)->listFiles($paths);
}
return $this->files;
}
}
PK%d�[�Ht���"classes/Gantry/Admin/Particles.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\ConfigFileFinder;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Theme as SiteTheme;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Particles
{
protected $container;
protected $files;
protected $particles;
public function __construct($container)
{
$this->container = $container;
}
public function overrides($outline, $particle = null)
{
if ($outline === 'default') {
return true;
}
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
if ($particle) {
// PHP 5.4
$resource =
$locator->findResources("gantry-theme://config/{$outline}/particles/{$particle}.yaml");
return !empty($resource);
}
// PHP 5.4
$resource =
$locator->findResources("gantry-theme://config/{$outline}/particles");
return !empty($resource);
}
public function all()
{
if (null === $this->particles) {
$platform = $this->container['platform'];
$files = $this->locateParticles();
$this->particles = [];
foreach ($files as $key => $fileArray) {
$filename = key($fileArray);
$file = CompiledYamlFile::instance(GANTRY5_ROOT .
'/' . $filename);
$particle = $file->content();
$file->free();
if (!isset($particle['dependencies']) ||
$platform->checkDependencies($particle['dependencies'])) {
$this->particles[$key] = $particle;
}
}
}
return $this->particles;
}
public function group($exclude = [])
{
$particles = $this->all();
$list = [];
foreach ($particles as $name => $particle) {
$type = isset($particle['type']) ?
$particle['type'] : 'particle';
if (in_array($type, $exclude)) {
continue;
}
if (in_array($type, ['spacer', 'system']))
{
$type = 'position';
}
$list[$type][$name] = $particle;
}
return $this->sort($list);
}
public function get($id)
{
if (isset($this->particles[$id])) {
return $this->particles[$id];
}
$files = $this->locateParticles();
if (empty($files[$id])) {
throw new \RuntimeException(sprintf("Settings for
'%s' not found.", $id), 404);
}
$filename = key($files[$id]);
$file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' .
$filename);
$particle = $file->content();
$particle['subtype'] = $id; // TODO: can this be done
better or is it fine like that?
$file->free();
return $particle;
}
/**
* @param string $id
* @return BlueprintForm
*/
public function getBlueprintForm($id)
{
return BlueprintForm::instance($id,
'gantry-blueprints://particles');
}
protected function sort(array $blocks)
{
$list = [];
/** @var SiteTheme $theme */
$theme = $this->container['theme'];
$ordering = (array)
$theme->details()['admin.settings'] ?: [
'particle' => [],
'position' => ['position',
'spacer', 'messages', 'content'],
'atom' => []
];
ksort($blocks);
foreach ($ordering as $name => $order) {
if (isset($blocks[$name])) {
$list[$name] = $this->sortItems($blocks[$name], (array)
$order);
}
}
$list += $blocks;
return $list;
}
protected function sortItems(array $items, array $ordering)
{
$list = [];
ksort($items);
foreach ($ordering as $name) {
if (isset($items[$name])) {
$list[$name] = $items[$name];
}
}
$list += $items;
return $list;
}
protected function locateParticles()
{
if (!$this->files) {
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$paths =
$locator->findResources('gantry-blueprints://particles');
$this->files = (new ConfigFileFinder)->listFiles($paths);
}
return $this->files;
}
}
PK%d�[�w�22classes/Gantry/Admin/Router.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Admin;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Request\Request;
use Gantry\Component\Response\JsonResponse;
use Gantry\Component\Response\Response;
use Gantry\Component\Router\Router as BaseRouter;
use Gantry\Joomla\StyleHelper;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Gantry administration router for Joomla.
*/
class Router extends BaseRouter
{
public function boot()
{
\JHtml::_('behavior.keepalive');
$app = \JFactory::getApplication();
$input = $app->input;
// TODO: Remove style variable.
$style = $input->getInt('style');
$theme = $input->getCmd('theme');
$path = array_filter(explode('/',
$input->getString('view', '')), function($var) {
return $var !== ''; });
$this->setTheme($theme, $style);
/** @var Request $request */
$request = $this->container['request'];
$this->method = $request->getMethod();
$this->path = $path ?:
(isset($this->container['theme.name']) ?
['configurations', true] : ['themes']);
$this->resource = array_shift($this->path);
$this->format = $input->getCmd('format',
'html');
$ajax = ($this->format == 'json');
$this->params = [
'user' => \JFactory::getUser(),
'ajax' => $ajax,
'location' => $this->resource,
'method' => $this->method,
'format' => $this->format,
'params' =>
$request->post->getJsonArray('params')
];
return $this;
}
public function setTheme($theme, $style)
{
if ($style) {
\JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_templates/tables');
$table = \JTable::getInstance('Style',
'TemplatesTable');
$table->load(['id' => $style,
'client_id' => 0]);
$theme = $table->template;
}
if (!$theme) {
$theme = StyleHelper::getDefaultStyle()->template;
}
$path = JPATH_SITE . '/templates/' . $theme;
if (!is_file("{$path}/gantry/theme.yaml")) {
$theme = null;
$this->container['streams']->register();
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
CompiledYamlFile::$defaultCachePath =
$locator->findResource('gantry-cache://theme/compiled/yaml',
true, true);
CompiledYamlFile::$defaultCaching =
$this->container['global']->get('compile_yaml',
1);
}
$this->container['base_url'] = \JUri::base(true) .
'/index.php?option=com_gantry5';
$this->container['ajax_suffix'] =
'&format=json';
$token = \JSession::getFormToken();
$this->container['routes'] = [
'1' =>
"&view=%s&theme={$theme}&{$token}=1",
'themes' => '&view=themes',
'picker/layouts' =>
"&view=layouts&theme={$theme}&{$token}=1",
];
if (!$theme) {
return $this;
}
$this->container['theme.path'] = $path;
$this->container['theme.name'] = $theme;
// Load language file for the template.
$languageFile = 'tpl_' . $theme;
$lang = \JFactory::getLanguage();
$lang->load($languageFile, JPATH_SITE)
|| $lang->load($languageFile, $path)
|| $lang->load($languageFile, $path, 'en-GB');
return $this;
}
protected function checkSecurityToken()
{
return \JSession::checkToken('get');
}
/**
* Send response to the client.
*
* @param Response $response
* @return string
*/
protected function send(Response $response)
{
$app = \JFactory::getApplication();
$document = \JFactory::getDocument();
$document->setCharset($response->charset);
$document->setMimeEncoding($response->mimeType);
// Output HTTP header.
$app->setHeader('Status', $response->getStatus());
$app->setHeader('Content-Type', $response->mimeType
. '; charset=' . $response->charset);
foreach ($response->getHeaders() as $key => $values) {
$replace = true;
foreach ($values as $value) {
$app->setHeader($key, $value, $replace);
$replace = false;
}
}
if ($response instanceof JsonResponse) {
$app->setHeader('Expires', 'Wed, 17 Aug 2005
00:00:00 GMT', true);
$app->setHeader('Last-Modified', gmdate('D, d
M Y H:i:s') . ' GMT', true);
$app->setHeader('Cache-Control', 'no-store,
no-cache, must-revalidate, post-check=0, pre-check=0', false);
$app->setHeader('Pragma', 'no-cache');
$app->sendHeaders();
}
// Output Gantry response.
echo $response;
if ($response instanceof JsonResponse) {
$app->close();
}
}
}
PK%d�[\��Ɵ
�
classes/Gantry/Admin/Styles.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\ConfigFileFinder;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Theme as SiteTheme;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Styles
{
protected $container;
protected $files;
protected $blocks;
public function __construct($container)
{
$this->container = $container;
}
public function all()
{
if (!$this->blocks)
{
$files = $this->locateBlocks();
$this->blocks = [];
foreach ($files as $key => $fileArray) {
$filename = key($fileArray);
$file = CompiledYamlFile::instance(GANTRY5_ROOT .
'/' . $filename);
$this->blocks[$key] = $file->content();
$file->free();
}
}
return $this->blocks;
}
public function group()
{
$blocks = $this->all();
$list = [];
foreach ($blocks as $name => $style) {
$type = isset($style['type']) ?
$style['type'] : 'block';
$list[$type][$name] = $style;
}
return $this->sort($list);
}
public function get($id)
{
if ($this->blocks[$id]) {
return $this->blocks[$id];
}
$files = $this->locateBlocks();
if (empty($files[$id])) {
throw new \RuntimeException(sprintf("Settings for
'%s' not found.", $id), 404);
}
$filename = key($files[$id]);
$file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' .
$filename);
$particle = $file->content();
$file->free();
return $particle;
}
/**
* @param string $id
* @return BlueprintForm
*/
public function getBlueprintForm($id)
{
return BlueprintForm::instance($id,
'gantry-blueprints://styles');
}
protected function sort(array $blocks)
{
$list = [];
/** @var SiteTheme $theme */
$theme = $this->container['theme'];
$ordering = (array) $theme->details()['admin.styles'];
ksort($blocks);
foreach ($ordering as $name => $order) {
if (isset($blocks[$name])) {
$list[$name] = $this->sortItems($blocks[$name], (array)
$order);
}
}
$list += $blocks;
return $list;
}
protected function sortItems(array $items, array $ordering)
{
$list = [];
ksort($items);
foreach ($ordering as $name) {
if (isset($items[$name])) {
$list[$name] = $items[$name];
}
}
$list += $items;
return $list;
}
protected function locateBlocks()
{
if (!$this->files) {
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$paths =
$locator->findResources('gantry-blueprints://styles');
$this->files = (new ConfigFileFinder)->listFiles($paths);
}
return $this->files;
}
}
PK%d�[�Y�zppclasses/Gantry/Admin/Theme.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Admin;
use Gantry\Component\Config\CompiledConfig;
use Gantry\Component\Config\ConfigFileFinder;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Theme\AbstractTheme;
use Gantry\Framework\Platform;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Theme extends AbstractTheme
{
/**
* @see AbstractTheme::init()
*/
protected function init()
{
$gantry = static::gantry();
// Add particles, styles and defaults into DI.
$gantry['particles'] = function ($c) {
return new Particles($c);
};
$gantry['styles'] = function ($c) {
return new Styles($c);
};
$gantry['page'] = function ($c) {
return new Page($c);
};
$gantry['defaults'] = function($c) {
/** @var UniformResourceLocator $locator */
$locator = $c['locator'];
$cache =
$locator->findResource('gantry-cache://theme/compiled/config',
true, true);
$paths =
$locator->findResources('gantry-config://default');
$files = (new ConfigFileFinder)->locateFiles($paths);
$config = new CompiledConfig($cache, $files, GANTRY5_ROOT);
$config->setBlueprints(function() use ($c) {
return $c['blueprints'];
});
return $config->load(true);
};
// Initialize admin streams.
/** @var Platform $patform */
$patform = $gantry['platform'];
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$nucleus =
$patform->getEnginePaths('nucleus')[''];
if (strpos($this->path, '://')) {
$relpath = $this->path;
} else {
$relpath = Folder::getRelativePath($this->path);
}
$patform->set(
'streams.gantry-admin.prefixes', [
'' =>
['gantry-theme://admin', $relpath, $relpath .
'/common', 'gantry-engine://admin'],
'assets/' => array_merge([$relpath, $relpath .
'/common'], $nucleus, ['gantry-assets://'])
]
);
// Add admin paths.
foreach
($patform->get('streams.gantry-admin.prefixes') as $prefix
=> $paths) {
$locator->addPath('gantry-admin', $prefix,
$paths);
}
// Fire admin init event.
$event = new Event;
$event->gantry = $gantry;
$event->theme = $this;
$gantry->fireEvent('admin.init.theme', $event);
}
/**
* @see AbstractTheme::getCachePath()
*
* @param string $path
* @return string
*/
protected function getCachePath($path = '')
{
$gantry = static::gantry();
/** @var Platform $patform */
$patform = $gantry['platform'];
// Initialize theme cache stream.
return $patform->getCachePath() . '/admin' . ($path ?
'/' . $path : '');
}
/**
* @see AbstractTheme::setTwigLoaderPaths()
*
* @param \Twig_LoaderInterface $loader
*/
protected function setTwigLoaderPaths(\Twig_LoaderInterface $loader)
{
if (!($loader instanceof \Twig_Loader_Filesystem)) {
return;
}
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$loader->setPaths($locator->findResources('gantry-admin://templates'));
$loader->setPaths($locator->findResources('gantry-admin://templates'),
'gantry-admin');
}
}
PK%d�[܁l"classes/Gantry/Admin/ThemeList.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Admin;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Theme\ThemeDetails;
use Gantry\Framework\Gantry;
use Joomla\Registry\Registry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class ThemeList
{
/**
* @var ThemeDetails[]
*/
protected static $items;
/**
* @var array
*/
protected static $styles;
/**
* @return array
*/
public static function getThemes()
{
if (!is_array(static::$items)) {
static::loadThemes();
}
$list = [];
foreach (static::$items as $item) {
$details = static::getTheme($item['name']);
if ($details) {
$list[$item['name']] = $details;
}
}
return $list;
}
/**
* @param string $name
* @return mixed
*/
public static function getTheme($name)
{
$styles = static::getStyles($name);
return reset($styles);
}
/**
* @param string $template
* @return array
*/
public static function getStyles($template = null, $force = false)
{
if ($force || !is_array(static::$styles)) {
static::loadStyles();
}
if ($template) {
return isset(static::$styles[$template]) ?
static::$styles[$template] : [];
}
$list = [];
foreach (static::$styles as $styles) {
$list += $styles;
}
ksort($list);
return $list;
}
protected static function loadThemes()
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
/** @var array|ThemeDetails[] $list */
$list = [];
$files = Folder::all('gantry-themes://',
['recursive' => false, 'files' => false]);
natsort($files);
foreach ($files as $theme) {
if ($locator('gantry-themes://' . $theme .
'/gantry/theme.yaml')) {
$details = new ThemeDetails($theme);
$details->addStreams();
$details['name'] = $theme;
$details['title'] =
$details['details.name'];
$details['preview_url'] = null;
$details['admin_url'] =
$gantry['platform']->getThemeAdminUrl($theme);
$details['params'] = [];
$list[$details->name] = $details;
}
}
// Add Thumbnails links after adding all the paths to the locator.
foreach ($list as $details) {
$details['thumbnail'] =
$details->getUrl("details.images.thumbnail");
}
static::$items = $list;
}
protected static function loadStyles()
{
$gantry = Gantry::instance();
$db = \JFactory::getDbo();
$query = $db
->getQuery(true)
->select('s.id, e.extension_id, s.template AS name,
s.title, s.params')
->from('#__template_styles AS s')
->where('s.client_id = 0')
->where('e.enabled = 1')
->where('e.state = 0')
->leftJoin('#__extensions AS e ON e.element=s.template
AND e.type='
. $db->quote('template') . ' AND
e.client_id=s.client_id')
->order('s.id');
$db->setQuery($query);
$styles = (array) $db->loadObjectList();
if (!is_array(static::$items)) {
static::loadThemes();
}
/** @var array|ThemeDetails[] $list */
$list = [];
foreach ($styles as $style)
{
$details = isset(static::$items[$style->name]) ?
static::$items[$style->name] : null;
if (!$details) {
continue;
}
$params = new Registry($style->params);
$details = clone $details;
$details['id'] = $style->id;
$details['extension_id'] = $style->extension_id;
$details['style'] = $style->title;
$details['preview_url'] =
$gantry['platform']->getThemePreviewUrl($style->id);
$details['params'] = $params->toArray();
$list[$style->name][$style->id] = $details;
}
static::$styles = $list;
}
}
PK%d�[�(r��1classes/Gantry/Component/Admin/HtmlController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Admin;
use Gantry\Component\Controller\HtmlController as BaseController;
abstract class HtmlController extends BaseController
{
/**
* @param string|array $file
* @param array $context
* @return string
*/
public function render($file, array $context = [])
{
return
$this->container['admin.theme']->render($file, $context);
}
/**
* @param string $action
* @param string $id
* @return boolean
*/
public function authorize($action, $id = null)
{
return
$this->container['platform']->authorize($action, $id);
}
}
PK%d�[��p���1classes/Gantry/Component/Admin/JsonController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Admin;
use Gantry\Component\Controller\JsonController as BaseController;
abstract class JsonController extends BaseController
{
/**
* @param string|array $file
* @param array $context
* @return string
*/
public function render($file, array $context = [])
{
return
$this->container['admin.theme']->render($file, $context);
}
/**
* @param string $action
* @param string $id
* @return boolean
*/
public function authorize($action, $id = null)
{
return
$this->container['platform']->authorize($action, $id);
}
}
PK%d�[ܵ����<classes/Gantry/Component/Assignments/AbstractAssignments.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Assignments;
use Gantry\Component\Config\CompiledConfig;
use Gantry\Component\Config\ConfigFileFinder;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class AbstractAssignments
{
/**
* @var string
*/
protected $configuration;
/**
* @var string
*/
protected $className =
'\Gantry\%s\Assignments\Assignments%s';
/**
* @var string
*/
protected $platform;
/**
* @var AssignmentFilter
*/
protected $filter;
/**
* @var array
*/
protected $candidates;
/**
* @var array
*/
protected $page;
/** @var callable */
protected $specialFilterMethod;
/**
* @param string $configuration
*/
public function __construct($configuration = null)
{
$this->configuration = $configuration;
}
/**
* Get list of assignment items.
*/
public function get()
{
return $this->getTypes();
}
/**
* Set (save) assignments.
*
* @param array $data
*/
public function set(array $data)
{
$this->save($data);
}
/**
* Select assigned outline.
*
* @param string $default
* @return string
*/
public function select($default = 'default')
{
$scores = $this->scores();
return key($scores) ?: $default;
}
/**
* List matching outlines sorted by score.
*
* @param array $candidates
* @return array
*/
public function scores(array $candidates = null)
{
$this->init();
$candidates = $candidates ?: $this->candidates;
return $this->filter->scores($candidates, $this->page,
$this->specialFilterMethod);
}
/**
* List matching outlines with matched assignments.
*
* @param array $candidates
* @return array
*/
public function matches(array $candidates = null)
{
$this->init();
$candidates = $candidates ?: $this->candidates;
return $this->filter->matches($candidates, $this->page,
$this->specialFilterMethod);
}
/**
* Load all assignments.
*
* @return array
*/
public function loadAssignments()
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Find all the assignment files.
$paths = $locator->findResources("gantry-config://");
$files = (new
ConfigFileFinder)->locateFileInFolder('assignments', $paths);
// Make sure that base or system outlines aren't in the list.
foreach ($files as $key => $array) {
$key = (string)$key;
if ($key === 'default' || strpos($key, '_')
=== 0) {
unset($files[$key]);
}
}
$cache =
$locator->findResource('gantry-cache://theme/compiled/config',
true, true);
$config = new CompiledConfig($cache, [$files], GANTRY5_ROOT);
return $config->load()->toArray();
}
/**
* Get all assignments for the current page.
*
* @return array
*/
public function getPage()
{
$list = [];
foreach($this->types() as $class => $type) {
$class = is_numeric($class) ? sprintf($this->className,
$this->platform, ucfirst($type)) : $class;
if (!class_exists($class)) {
throw new \RuntimeException("Assignment type {$type}
is missing");
}
/** @var AssignmentsInterface $instance */
$instance = new $class;
$list[$type] = $instance->getRules();
unset($instance);
}
return $list;
}
/**
* Filter assignments data.
*
* @param array $data
* @param bool $minimize
* @return array
*/
public function filter(array $data, $minimize = false)
{
$types = [];
foreach ($this->types() as $type) {
$types[$type] = [];
}
$data = array_replace($types, $data);
foreach ($data as $tname => &$type) {
if (is_array($type)) {
foreach ($type as $gname => &$group) {
if (is_array($group)) {
foreach ($group as $key => $value) {
if (!$value) {
unset($group[$key]);
} else {
$group[$key] = (bool) $value;
}
}
if (empty($group)) {
unset($type[$gname]);
}
} else {
$group = (bool) $group;
}
}
unset($group);
if ($minimize && empty($type)) {
unset($data[$tname]);
}
} else {
$type = (bool) $type;
}
}
return $data;
}
/**
* Save assignments for the configuration.
*
* @param array $data
*/
public function save(array $data)
{
$data = $this->filter($data);
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Save layout into custom directory for the current theme.
$save_dir =
$locator->findResource("gantry-config://{$this->configuration}",
true, true);
$filename = "{$save_dir}/assignments.yaml";
$file = YamlFile::instance($filename);
$file->save($data);
$file->free();
}
/**
* Get list of all assignment types for assignments form.
*
* @return array
*/
public function getTypes()
{
$list = [];
foreach ($this->types() as $class => $type) {
$class = is_numeric($class) ? sprintf($this->className,
$this->platform, ucfirst($type)) : $class;
if (!class_exists($class)) {
throw new \RuntimeException("Assignment type
'{$type}' is missing");
}
/** @var AssignmentsInterface $instance */
$instance = new $class;
$list[$type] =
$instance->listRules($this->configuration);
unset($instance);
}
return $list;
}
/**
* Get selected assignment option.
*
* @return string
*/
public function getAssignment()
{
return 'default';
}
/**
* Set extra options for assignments.
*
* @param $value
*/
public function setAssignment($value)
{
}
/**
* Get extra options for assignments.
*
* @return array
*/
public function assignmentOptions()
{
return [];
}
protected function init()
{
if (!$this->filter) {
$this->filter = new AssignmentFilter;
$this->candidates = $this->loadAssignments();
$this->page = $this->getPage();
}
}
/**
* Return list of assignment types.
*
* @return array
*/
abstract public function types();
}
PK%d�[�d�//9classes/Gantry/Component/Assignments/AssignmentFilter.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Assignments;
/**
* Class AssignmentFilter
* @package Gantry\Assignments
*/
class AssignmentFilter
{
protected $method;
/**
* Return all matching candidates with their score. Candidates are
ordered by their scores.
*
* @param array $candidates In format of
candidates[name][section][rule].
* @param array $page In format of page[section][rule].
* @return array
*/
public function scores(array &$candidates, array &$page,
callable $function = null)
{
$matches = $this->matches($candidates, $page, $function);
$scores = [];
foreach ($matches as $type => $candidate) {
$scores[$type] = $this->getScore($candidate) +
(isset($candidate['language']) ? 0.01 : 0);
}
// Always return matches by score in alphabetical order.
ksort($scores, SORT_STRING);
arsort($scores, SORT_NUMERIC);
return $scores;
}
/**
* Returns all matching candidates with matching rules.
*
* @param array $candidates In format of
candidates[name][section][rule].
* @param array $page In format of page[section][rule].
* @return array
*/
public function matches(array $candidates, array &$page, callable
$function = null)
{
$matches = [];
foreach ($candidates as $type => $candidate) {
if (!is_array($candidate)) {
if ($candidate === true && $page) {
$matches[$type] = $page;
}
continue;
}
foreach ($candidate as $section => $list) {
if (!is_array($list)) {
if ($list === true && !empty($page[$section]))
{
$matches[$type][$section] = $page[$section];
}
continue;
}
foreach ($list as $name => $rules) {
if (!empty($page[$section][$name])) {
if (!is_array($rules)) {
$match = $rules === true ?
$page[$section][$name] : [];
} else {
$match =
\array_intersect_key($page[$section][$name], $rules);
}
if ($match) {
$matches[$type][$section][$name] = $match;
}
}
}
}
if (isset($matches[$type]) && $function &&
call_user_func($function, $candidate, $matches[$type], $page) === false) {
unset($matches[$type]);
}
}
return $matches;
}
/**
* Returns the calculated score for the assignment.
*
* @param array $matches
* @param string $method
* @return int
*/
public function getScore(array &$matches, $method =
'max')
{
$this->method = 'calc' . ucfirst($method);
if (!method_exists($this, $this->method)) {
$this->method = 'calcMax';
}
return $this->calcArray(0, $matches);
}
/**
* @param float $carry
* @param float|array $item
* @return float
* @internal
*/
protected function calcArray($carry, $item)
{
if (is_array($item)) {
return array_reduce($item, [$this, 'calcArray'],
$carry);
}
$method = $this->method;
return $this->{$method}($carry, (float) $item);
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcOr($carry, $item)
{
return (float) ($carry || $item);
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcMin($carry, $item)
{
return $carry ? min($carry, $item) : $item;
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcMax($carry, $item)
{
return max($carry, $item);
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcSum($carry, $item)
{
return $carry + $item;
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcMul($carry, $item)
{
return $carry ? $carry * $item : $item;
}
}
PK%d�[3�U���=classes/Gantry/Component/Assignments/AssignmentsInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Assignments;
interface AssignmentsInterface
{
/**
* Returns list of rules which apply to the current page.
*
* @return array
*/
public function getRules();
/**
* List all the rules available.
*
* @param string $configuration
* @return array
*/
public function listRules($configuration);
}
PK%d�[�)!�992classes/Gantry/Component/Collection/Collection.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Collection;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
use RocketTheme\Toolbox\ArrayTraits\Countable;
use RocketTheme\Toolbox\ArrayTraits\Export;
class Collection implements CollectionInterface
{
use ArrayAccess, Countable, Export;
/**
* @var array
*/
protected $items = [];
public static function __set_state($variables)
{
$instance = new static();
$instance->items = $variables['items'];
return $instance;
}
/**
*
* Create a copy of this collection.
*
* @return static
*/
public function copy()
{
return clone $this;
}
/**
* @param $item
* @return $this
*/
public function add($item)
{
$this->items[] = $item;
return $this;
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->items);
}
}
PK%d�[�?�~~;classes/Gantry/Component/Collection/CollectionInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Collection;
interface CollectionInterface extends \IteratorAggregate, \ArrayAccess,
\Countable
{
public function toArray();
/**
* @param $item
*/
public function add($item);
/**
* @return \ArrayIterator
*/
public function getIterator();
/**
* @param $offset
*
* @return bool
*/
public function offsetExists($offset);
/**
* @param $offset
* @param $value
*/
public function offsetSet($offset, $value);
/**
* @param $offset
*
* @return mixed
*/
public function offsetGet($offset);
/**
* @param $offset
*/
public function offsetUnset($offset);
/**
* @return int
*/
public function count();
}
PK&d�[�c��9$9$1classes/Gantry/Component/Config/BlueprintForm.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\Blueprints\BlueprintForm as BaseBlueprintForm;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* The Config class contains configuration information.
*
* @author RocketTheme
*/
class BlueprintForm extends BaseBlueprintForm
{
/**
* @var string
*/
protected $context = 'gantry-blueprints://';
/**
* @var BlueprintSchema
*/
protected $schema;
/**
* @param string $filename
* @param string $context
* @return BlueprintForm
*/
public static function instance($filename, $context = null)
{
/** @var BlueprintForm $instance */
$instance = new static($filename);
if ($context) {
$instance->setContext($context);
}
return $instance->load()->init();
}
/**
* Get nested structure containing default values defined in the
blueprints.
*
* Fields without default value are ignored in the list.
*
* @return array
*/
public function getDefaults()
{
return $this->schema()->getDefaults();
}
/**
* Merge two arrays by using blueprints.
*
* @param array $data1
* @param array $data2
* @param string $name Optional
* @param string $separator Optional
* @return array
*/
public function mergeData(array $data1, array $data2, $name = null,
$separator = '.')
{
return $this->schema()->mergeData($data1, $data2, $name,
$separator);
}
/**
* Return data fields that do not exist in blueprints.
*
* @param array $data
* @param string $prefix
* @return array
*/
public function extra(array $data, $prefix = '')
{
return $this->schema()->extra($data, $prefix);
}
/**
* Validate data against blueprints.
*
* @param array $data
* @throws \RuntimeException
*/
public function validate(array $data)
{
$this->schema()->validate($data);
}
/**
* Filter data by using blueprints.
*
* @param array $data
* @return array
*/
public function filter(array $data)
{
return $this->schema()->filter($data);
}
/**
* @return BlueprintSchema
*/
public function schema()
{
if (!isset($this->schema)) {
$this->schema = new BlueprintSchema;
$this->schema->embed('', $this->items);
$this->schema->init();
}
return $this->schema;
}
/**
* @param string $filename
* @return string
*/
protected function loadFile($filename)
{
$file = CompiledYamlFile::instance($filename);
$content = $file->content();
$file->free();
return $content;
}
/**
* @param string|array $path
* @param string $context
* @return array
*/
protected function getFiles($path, $context = null)
{
if (is_string($path) && !strpos($path, '://')) {
// Resolve filename.
if (isset($this->overrides[$path])) {
$path = $this->overrides[$path];
} else {
if ($context === null) {
$context = $this->context;
}
if ($context && $context[strlen($context)-1] !==
'/') {
$context .= '/';
}
$path = $context . $path;
if (!preg_match('/\.yaml$/', $path)) {
$path .= '.yaml';
}
}
}
if (is_string($path) && strpos($path, '://')) {
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
$files = $locator->findResources($path);
} else {
$files = (array) $path;
}
return $files;
}
/**
* @param array $field
* @param string $property
* @param array $call
*/
protected function dynamicData(array &$field, $property, array
&$call)
{
$params = $call['params'];
if (is_array($params)) {
$function = array_shift($params);
} else {
$function = $params;
$params = [];
}
list($o, $f) = preg_split('/::/', $function, 2);
if (!$f) {
if (function_exists($o)) {
$data = call_user_func_array($o, $params);
}
} else {
if (method_exists($o, $f)) {
$data = call_user_func_array(array($o, $f), $params);
}
}
// If function returns a value,
if (isset($data)) {
if (isset($field[$property]) &&
is_array($field[$property]) && is_array($data)) {
// Combine field and @data-field together.
$field[$property] += $data;
} else {
// Or create/replace field with @data-field.
$field[$property] = $data;
}
}
}
/**
* @param array $field
* @param string $property
* @param array $call
*/
protected function dynamicConfig(array &$field, $property, array
&$call)
{
$value = $call['params'];
$default = isset($field[$property]) ? $field[$property] : null;
$config = Gantry::instance()['config']->get($value,
$default);
if (!is_null($config)) {
$field[$property] = $config;
}
}
/**
* Get blueprints by using slash notation for nested arrays/objects.
*
* @param array $path
* @param string $separator
* @return array
*/
public function resolve(array $path, $separator = '/')
{
$fields = false;
$parts = [];
$current = $this['form/fields'];
$result = [null, null, null];
$prefix = '';
while (($field = current($path)) !== false) {
if (!$fields && isset($current['fields'])) {
if (!empty($current['array'])) {
$result = [$current, $parts, $path ?
implode($separator, $path) : null];
// Skip item offset.
$parts[] = array_shift($path);
}
$current = $current['fields'];
$prefix = '';
$fields = true;
} elseif (isset($current[$prefix . $field])) {
$parts[] = array_shift($path);
$current = $current[$prefix . $field];
$prefix = '';
$fields = false;
} elseif (isset($current['.' . $prefix . $field])) {
$parts[] = array_shift($path);
$current = $current['.' . $prefix . $field];
$prefix = '';
$fields = false;
} elseif ($field && $this->fieldExists($prefix .
$field, $current)) {
$parts[] = array_shift($path);
$prefix = "{$prefix}{$field}.";
$fields = false;
} else {
// Check if there's a container with the field.
$current = $this->resolveContainer($current, $prefix,
$field);
// No containers with the field found.
if (!$current) {
break;
}
$prefix = '';
$fields = false;
}
}
if (!$fields && !empty($current['array'])) {
$result = [$current, $parts, $path ? implode($separator, $path)
: null];
}
return $result;
}
protected function resolveContainer($current, $prefix, $fieldName)
{
foreach ($current as $field) {
$type = isset($field['type']) ?
$field['type'] : 'container._implicit';
$container = (0 === strpos($type, 'container.'));
if (!$container || !isset($field['fields'])) {
continue;
}
$current_fields = $field['fields'];
if (isset($current_fields[$prefix . $fieldName]) ||
isset($current_fields['.' . $prefix . $fieldName])
|| $this->fieldExists($prefix . $fieldName,
$current_fields)) {
return $current_fields;
}
$current_fields = $this->resolveContainer($current_fields,
$prefix, $fieldName);
if ($current_fields !== null) {
return $current_fields;
}
}
return null;
}
protected function fieldExists($prefix, $list)
{
foreach ($list as $field => $data) {
$pos = strpos($field, $prefix);
if ($pos === 0 || ($pos === 1 && $field[0] ===
'.')) {
return true;
}
}
return false;
}
}
PK&d�[ù���3classes/Gantry/Component/Config/BlueprintSchema.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\Blueprints\BlueprintSchema as BlueprintSchemaBase;
/**
* Blueprint schema handles the internal logic of blueprints.
*
* @author RocketTheme
* @license MIT
*/
class BlueprintSchema extends BlueprintSchemaBase
{
protected $configuration;
protected $ignoreFormKeys = [
'title' => true,
'help' => true,
'placeholder' => true,
'fields' => true
];
protected $types = [
'container.set' => [
'input@' => false
],
'container.tabs' => [
'input@' => false
],
'separator.note' => [
'input@' => false
],
'separator.separator' => [
'input@' => false
],
'key' => [
'input@' => false
],
'collection.list' => [
'array' => true
]
];
/**
* Constructor.
*
* @param array $serialized Serialized content if available.
*/
public function __construct($serialized = null)
{
parent::__construct($serialized);
$this->configuration = new
Config(isset($serialized['configuration']) ?
$serialized['configuration'] : []);
}
/**
* Convert object into an array.
*
* @return array
*/
public function getState()
{
return parent::getState() + ['configuration' =>
$this->configuration->toArray()];
}
/**
* Get nested structure containing default values defined in the
blueprints.
*
* Fields without default value are ignored in the list.
*
* @return array
*/
public function getDefaults()
{
return array_merge_recursive($this->configuration->toArray(),
$this->buildDefaults($this->nested));
}
/**
* Embed an array to the blueprint.
*
* @param $name
* @param array $value
* @param string $separator
* @param bool $merge Merge fields instead replacing them.
* @return $this
*/
public function embed($name, array $value, $separator = '.',
$merge = false)
{
parent::embed($name, $value, $separator, $merge);
if (isset($value['configuration'])) {
$this->configuration->set($name,
$value['configuration'], $separator);
}
return $this;
}
/**
* Validate data against blueprints.
*
* @param array $data
* @throws \RuntimeException
*/
public function validate(array $data)
{
try {
$messages = $this->validateArray($data, $this->nested);
} catch (\RuntimeException $e) {
throw (new ValidationException($e->getMessage(),
$e->getCode(), $e))->setMessages();
}
if (!empty($messages)) {
throw (new ValidationException())->setMessages($messages);
}
}
/**
* Filter data by using blueprints.
*
* @param array $data
* @return array
*/
public function filter(array $data)
{
return $this->filterArray($data, $this->nested);
}
/**
* @param array $data
* @param array $rules
* @returns array
* @throws \RuntimeException
* @internal
*/
protected function validateArray(array $data, array $rules)
{
$messages = $this->checkRequired($data, $rules);
foreach ($data as $key => $field) {
$val = isset($rules[$key]) ? $rules[$key] :
(isset($rules['*']) ? $rules['*'] : null);
$rule = is_string($val) ? $this->items[$val] : null;
if ($rule) {
// Item has been defined in blueprints.
$messages += Validation::validate($field, $rule);
} elseif (is_array($field) && is_array($val)) {
// Array has been defined in blueprints.
$messages += $this->validateArray($field, $val);
} elseif (isset($rules['validation']) &&
$rules['validation'] == 'strict') {
// Undefined/extra item.
throw new \RuntimeException(sprintf('%s is not defined
in blueprints', $key));
}
}
return $messages;
}
/**
* @param array $data
* @param array $rules
* @return array
* @internal
*/
protected function filterArray(array $data, array $rules)
{
$results = array();
foreach ($data as $key => $field) {
$val = isset($rules[$key]) ? $rules[$key] :
(isset($rules['*']) ? $rules['*'] : null);
$rule = is_string($val) ? $this->items[$val] : null;
if ($rule) {
// Item has been defined in blueprints.
$field = Validation::filter($field, $rule);
} elseif (is_array($field) && is_array($val)) {
// Array has been defined in blueprints.
$field = $this->filterArray($field, $val);
} elseif (isset($rules['validation']) &&
$rules['validation'] == 'strict') {
$field = null;
}
if (isset($field) && (!is_array($field) ||
!empty($field))) {
$results[$key] = $field;
}
}
return $results;
}
/**
* @param array $data
* @param array $fields
* @return array
*/
protected function checkRequired(array $data, array $fields)
{
$messages = [];
foreach ($fields as $name => $field) {
if (!is_string($field)) {
continue;
}
$field = $this->items[$field];
if (isset($field['validate']['required'])
&&
$field['validate']['required'] === true
&& !isset($data[$name])) {
$value = isset($field['label']) ?
$field['label'] : $field['name'];
// TODO: translate
$message = sprintf("Please fill up required field
'%s'.", $value);
$messages[$field['name']][] = $message;
}
}
return $messages;
}
/**
* @param array $field
* @param string $property
* @param array $call
*/
protected function dynamicConfig(array &$field, $property, array
&$call)
{
$value = $call['params'];
$default = isset($field[$property]) ? $field[$property] : null;
$config = Gantry::instance()['config']->get($value,
$default);
if (!is_null($config)) {
$field[$property] = $config;
}
}
}
PK&d�[�-��0classes/Gantry/Component/Config/CompiledBase.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\File\PhpFile;
/**
* The Compiled base class.
*/
abstract class CompiledBase
{
/**
* @var int Version number for the compiled file.
*/
public $version = 1;
/**
* @var string Filename (base name) of the compiled configuration.
*/
public $name;
/**
* @var string|bool Configuration checksum.
*/
public $checksum;
/**
* @var string Cache folder to be used.
*/
protected $cacheFolder;
/**
* @var array List of files to load.
*/
protected $files;
/**
* @var string
*/
protected $path;
/**
* @var mixed Configuration object.
*/
protected $object;
/**
* @param string $cacheFolder Cache folder to be used.
* @param array $files List of files as returned from
ConfigFileFinder class.
* @param string $path Base path for the file list.
* @throws \BadMethodCallException
*/
public function __construct($cacheFolder, array $files, $path =
GANTRY5_ROOT)
{
if (!$cacheFolder) {
throw new \BadMethodCallException('Cache folder not
defined.');
}
$this->cacheFolder = $cacheFolder;
$this->files = $files;
$this->path = $path ? rtrim($path, '\\/') .
'/' : '';
}
/**
* Get filename for the compiled PHP file.
*
* @param string $name
* @return $this
*/
public function name($name = null)
{
if (!$this->name) {
$this->name = $name ?:
md5(json_encode(array_keys($this->files)));
}
return $this;
}
/**
* Function gets called when cached configuration is saved.
*/
public function modified() {}
/**
* Load the configuration.
*
* @return mixed
*/
public function load()
{
if ($this->object) {
return $this->object;
}
$filename = $this->createFilename();
if (!$this->loadCompiledFile($filename) &&
$this->loadFiles()) {
$this->saveCompiledFile($filename);
}
return $this->object;
}
/**
* Returns checksum from the configuration files.
*
* You can set $this->checksum = false to disable this check.
*
* @return bool|string
*/
public function checksum()
{
if (!isset($this->checksum)) {
$this->checksum = md5(json_encode($this->files) .
$this->version);
}
return $this->checksum;
}
protected function createFilename()
{
return
"{$this->cacheFolder}/{$this->name()->name}.php";
}
/**
* Create configuration object.
*
* @param array $data
*/
abstract protected function createObject(array $data = []);
/**
* Finalize configuration object.
*/
abstract protected function finalizeObject();
/**
* Load single configuration file and append it to the correct
position.
*
* @param string $name Name of the position.
* @param string $filename File to be loaded.
*/
abstract protected function loadFile($name, $filename);
/**
* Load and join all configuration files.
*
* @return bool
* @internal
*/
protected function loadFiles()
{
$this->createObject();
$list = array_reverse($this->files);
foreach ($list as $files) {
foreach ($files as $name => $item) {
$this->loadFile($name, $this->path .
$item['file']);
}
}
$this->finalizeObject();
return true;
}
/**
* Load compiled file.
*
* @param string $filename
* @return bool
* @internal
*/
protected function loadCompiledFile($filename)
{
$gantry = Gantry::instance();
/** @var Config $global */
$global = $gantry['global'];
if (!$global->get('compile_yaml', 1)) {
return false;
}
if (!file_exists($filename)) {
return false;
}
$cache = include $filename;
if (
!is_array($cache)
|| !isset($cache['checksum'])
|| !isset($cache['data'])
|| !isset($cache['@class'])
|| $cache['@class'] != get_class($this)
) {
return false;
}
// Load real file if cache isn't up to date (or is invalid).
if ($cache['checksum'] !== $this->checksum()) {
return false;
}
$this->createObject($cache['data']);
$this->finalizeObject();
return true;
}
/**
* Save compiled file.
*
* @param string $filename
* @throws \RuntimeException
* @internal
*/
protected function saveCompiledFile($filename)
{
$gantry = Gantry::instance();
/** @var Config $global */
$global = $gantry['global'];
if (!$global->get('compile_yaml', 1)) {
return;
}
$file = PhpFile::instance($filename);
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
if ($file->locked() === false) {
// File was already locked by another process.
return;
}
$cache = [
'@class' => get_class($this),
'timestamp' => time(),
'checksum' => $this->checksum(),
'files' => $this->files,
'data' => $this->getState()
];
$file->save($cache);
$file->unlock();
$file->free();
$this->modified();
}
protected function getState()
{
return $this->object->toArray();
}
}
PK&d�[�ԂDD6classes/Gantry/Component/Config/CompiledBlueprints.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
/**
* The Compiled Blueprints class.
*/
class CompiledBlueprints extends CompiledBase
{
/**
* @var int Version number for the compiled file.
*/
public $version = 3;
/**
* @var BlueprintSchema Blueprints object.
*/
protected $object;
/**
* Create configuration object.
*
* @param array $data
*/
protected function createObject(array $data = [])
{
$this->object = new BlueprintSchema($data);
}
/**
* Finalize configuration object.
*/
protected function finalizeObject()
{
}
/**
* Load single configuration file and append it to the correct
position.
*
* @param string $name Name of the position.
* @param array $files Files to be loaded.
*/
protected function loadFile($name, $files)
{
// Load blueprint file.
$blueprint = new BlueprintForm($files);
$this->object->embed($name,
$blueprint->load()->toArray(), '/', true);
}
/**
* Load and join all configuration files.
*
* @return bool
* @internal
*/
protected function loadFiles()
{
$this->createObject();
// Convert file list into parent list.
$list = [];
foreach ($this->files as $files) {
foreach ($files as $name => $item) {
$list[$name][] = $this->path . $item['file'];
}
}
// Load files.
foreach ($list as $name => $files) {
$this->loadFile($name, $files);
}
$this->finalizeObject();
return true;
}
protected function getState()
{
return $this->object->getState();
}
}
PK&d�[��ͭ
2classes/Gantry/Component/Config/CompiledConfig.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Component\File\CompiledYamlFile;
/**
* The Compiled Configuration class.
*/
class CompiledConfig extends CompiledBase
{
/**
* @var int Version number for the compiled file.
*/
public $version = 2;
/**
* @var Config Configuration object.
*/
protected $object;
/**
* @var callable Blueprints loader.
*/
protected $callable;
/**
* @var bool
*/
protected $withDefaults;
/**
* Get filename for the compiled PHP file.
*
* @param string $name
* @return $this
*/
public function name($name = null)
{
if (!$this->name) {
$this->name = $name ?:
md5(json_encode(array_keys($this->files)) . (int)
$this->withDefaults);
}
return $this;
}
/**
* Set blueprints for the configuration.
*
* @param callable $blueprints
* @return $this
*/
public function setBlueprints(callable $blueprints)
{
$this->callable = $blueprints;
return $this;
}
/**
* @param bool $withDefaults
* @return mixed
*/
public function load($withDefaults = false)
{
$this->withDefaults = $withDefaults;
return parent::load();
}
/**
* Create configuration object.
*
* @param array $data
*/
protected function createObject(array $data = [])
{
if ($this->withDefaults && empty($data) &&
is_callable($this->callable)) {
$blueprints = $this->callable;
$data = $blueprints()->getDefaults();
}
$this->object = new Config($data, $this->callable);
}
/**
* Finalize configuration object.
*/
protected function finalizeObject()
{
}
/**
* Load single configuration file and append it to the correct
position.
*
* @param string $name Name of the position.
* @param string $filename File to be loaded.
*/
protected function loadFile($name, $filename)
{
$file = CompiledYamlFile::instance($filename);
$this->object->join($name, $file->content(),
'/');
$file->free();
}
}
PK&d�[Ѱ�Pdd*classes/Gantry/Component/Config/Config.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
/**
* The Config class contains configuration information.
*
* @author RocketTheme
*/
class Config implements \ArrayAccess, \Countable, \Iterator,
ExportInterface
{
use NestedArrayAccessWithGetters, Iterator, Export;
/**
* @var array
*/
protected $items;
/**
* @var BlueprintSchema|BlueprintForm|callable
*/
protected $blueprint;
/**
* Constructor to initialize array.
*
* @param array $items Initial items inside the iterator.
* @param callable $blueprints Function to load Blueprints for the
configuration.
*/
public function __construct(array $items, callable $blueprint = null)
{
$this->items = $items;
$this->blueprint = $blueprint;
}
/**
* Join nested values together by using blueprints.
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $value Value to be joined.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function join($name, $value, $separator = '.')
{
$old = $this->get($name, null, $separator);
if ($old !== null) {
if (!is_array($old)) {
throw new \RuntimeException("Value is not array in
{$name}: " . print_r($old, true));
}
if (is_object($value)) {
$value = (array) $value;
} elseif (!is_array($value)) {
throw new \RuntimeException("Value is not array in
{$name}: " . print_r($value, true));
}
$value = $this->blueprint()->mergeData($old, $value,
$name, $separator);
}
$this->set($name, $value, $separator);
return $this;
}
/**
* Get nested structure containing default values defined in the
blueprints.
*
* Fields without default value are ignored in the list.
* @return array
*/
public function getDefaults()
{
return $this->blueprint()->getDefaults();
}
/**
* Set default values by using blueprints.
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $value Value to be joined.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function joinDefaults($name, $value, $separator = '.')
{
if (is_object($value)) {
$value = (array) $value;
}
$old = $this->get($name, null, $separator);
if ($old !== null) {
$value = $this->blueprint()->mergeData($value, $old,
$name, $separator);
}
$this->set($name, $value, $separator);
return $this;
}
/**
* Get value from the configuration and join it with given data.
*
* @param string $name Dot separated path to the requested
value.
* @param array $value Value to be joined.
* @param string $separator Separator, defaults to '.'
* @return array
* @throws \RuntimeException
*/
public function getJoined($name, $value, $separator = '.')
{
if (is_object($value)) {
$value = (array) $value;
} elseif (!is_array($value)) {
throw new \RuntimeException("Value is not array in
'{$name}': " . print_r($value, true));
}
$old = $this->get($name, null, $separator);
if ($old === null) {
// No value set; no need to join data.
return $value;
}
if (!is_array($old)) {
throw new \RuntimeException("Value is not array in
'{$name}': " . print_r($value, true));
}
// Return joined data.
return $this->blueprint()->mergeData($old, $value, $name,
$separator);
}
/**
* Merge two configurations together.
*
* @param array $data
* @return $this
*/
public function merge(array $data)
{
$this->items =
$this->blueprint()->mergeData($this->items, $data);
return $this;
}
/**
* Set default values to the configuration if variables were not set.
*
* @param array $data
* @return $this
*/
public function setDefaults(array $data)
{
$this->items = $this->blueprint()->mergeData($data,
$this->items);
return $this;
}
/**
* Make a flat list from the configuration.
*
* @param string $name Dot separated path to the requested value.
* @param string $separator Separator, defaults to '.'
* @param string $prefix Name prefix.
* @return array
*/
public function flatten($name = null, $separator = '.',
$prefix = '')
{
$element = $name ? $this->offsetGet($name) : $this->items;
if (!is_array($element)) {
return [$name, $element];
}
if (strlen($separator) == 2 && in_array($separator,
['][', ')(', '}{'])) {
$separator = [$separator[1], $separator[0]];
}
return $this->flattenNested('', $element, $separator,
$prefix);
}
/**
* @param string $name
* @param array $element
* @param string $separator
* @param string $prefix
* @return array
* @internal
*/
protected function flattenNested($name, &$element, $separator,
$prefix)
{
$list = [];
foreach ($element as $key => $value) {
$new = $name ? $name : $prefix;
if (is_array($separator)) {
$new .= $separator[0] . $key . $separator[1];
} else {
$new .= ($new ? $separator : '') . $key;
}
if (!is_array($value) || empty($value)) {
$list[$new] = $value;
} else {
$list += $this->flattenNested($new, $value, $separator,
$prefix);
}
}
return $list;
}
/**
* Return blueprint.
*
* @return BlueprintSchema|BlueprintForm
* @since 5.4.7
*/
public function blueprint()
{
if (!$this->blueprint){
$this->blueprint = new BlueprintSchema;
} elseif (is_callable($this->blueprint)) {
// Lazy load blueprints.
$blueprint = $this->blueprint;
$this->blueprint = $blueprint();
}
return $this->blueprint;
}
/**
* Return blueprints.
*
* @return BlueprintSchema
* @deprecated 5.4.7
*/
public function blueprints()
{
return $this->blueprint();
}
/**
* Count items in nested array.
*
* @param string $path
* @param string $separator
* @return int
*/
public function count($path = null, $separator = '.')
{
$items = $path ? $this->get($path, null, $separator) :
$this->items;
return is_array($items) ? count($items) : 0;
}
}
PK&d�[ҽ`\!\!4classes/Gantry/Component/Config/ConfigFileFinder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Component\Filesystem\Folder;
/**
* The Configuration & Blueprints Finder class.
*/
class ConfigFileFinder
{
protected $base = '';
/**
* @param string $base
* @return $this
*/
public function setBase($base)
{
$this->base = $base ? "{$base}/" : '';
return $this;
}
/**
* Return all locations for all the files with a timestamp.
*
* @param array $paths List of folders to look from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
*/
public function locateFiles(array $paths, $pattern =
'|\.yaml$|', $levels = -1)
{
$list = [];
foreach ($paths as $folder) {
$list += $this->detectRecursive($folder, $pattern, $levels);
}
return $list;
}
/**
* Return all locations for all the files with a timestamp.
*
* @param array $paths List of folders to look from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
*/
public function getFiles(array $paths, $pattern =
'|\.yaml$|', $levels = -1)
{
$list = [];
foreach ($paths as $folder) {
$path = trim(Folder::getRelativePath($folder), '/');
$files = $this->detectRecursive($folder, $pattern, $levels);
$list += $files[trim($path, '/')];
}
return $list;
}
/**
* Return all paths for all the files with a timestamp.
*
* @param array $paths List of folders to look from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
*/
public function listFiles(array $paths, $pattern =
'|\.yaml$|', $levels = -1)
{
$list = [];
foreach ($paths as $folder) {
$list = array_merge_recursive($list,
$this->detectAll($folder, $pattern, $levels));
}
return $list;
}
/**
* Find filename from a list of folders.
*
* Note: Only finds the last override.
*
* @param string $filename
* @param array $folders
* @return array
*/
public function locateFileInFolder($filename, array $folders)
{
$list = [];
foreach ($folders as $folder) {
$list += $this->detectInFolder($folder, $filename);
}
return $list;
}
/**
* Find filename from a list of folders.
*
* @param array $folders
* @param string $filename
* @return array
*/
public function locateInFolders(array $folders, $filename = null)
{
$list = [];
foreach ($folders as $folder) {
$path = trim(Folder::getRelativePath($folder), '/');
$list[$path] = $this->detectInFolder($folder, $filename);
}
return $list;
}
/**
* Return all existing locations for a single file with a timestamp.
*
* @param array $paths Filesystem paths to look up from.
* @param string $name Configuration file to be located.
* @param string $ext File extension (optional, defaults to
.yaml).
* @return array
*/
public function locateFile(array $paths, $name, $ext =
'.yaml')
{
$filename = preg_replace('|[.\/]+|', '/',
$name) . $ext;
$list = [];
foreach ($paths as $folder) {
$path = trim(Folder::getRelativePath($folder), '/');
if (is_file("{$folder}/{$filename}")) {
$modified = filemtime("{$folder}/{$filename}");
} else {
$modified = 0;
}
$basename = $this->base . $name;
$list[$path] = [$basename => ['file' =>
"{$path}/{$filename}", 'modified' => $modified]];
}
return $list;
}
/**
* Detects all directories with a configuration file and returns them
with last modification time.
*
* @param string $folder Location to look up from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
* @internal
*/
protected function detectRecursive($folder, $pattern, $levels)
{
$path = trim(Folder::getRelativePath($folder), '/');
if (is_dir($folder)) {
// Find all system and user configuration files.
$options = [
'levels' => $levels,
'compare' => 'Filename',
'pattern' => $pattern,
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function
(\RecursiveDirectoryIterator $file) use ($path) {
return ['file' =>
"{$path}/{$file->getSubPathname()}", 'modified'
=> $file->getMTime()];
}
],
'key' => 'SubPathname'
];
$list = Folder::all($folder, $options);
ksort($list);
} else {
$list = [];
}
return [$path => $list];
}
/**
* Detects all directories with the lookup file and returns them with
last modification time.
*
* @param string $folder Location to look up from.
* @param string $lookup Filename to be located (defaults to directory
name).
* @return array
* @internal
*/
protected function detectInFolder($folder, $lookup = null)
{
$folder = rtrim($folder, '/');
$path = trim(Folder::getRelativePath($folder), '/');
$base = $path === $folder ? '' : ($path ? substr($folder,
0, -strlen($path)) : $folder . '/');
$list = [];
if (is_dir($folder)) {
$iterator = new \DirectoryIterator($folder);
/** @var \DirectoryIterator $directory */
foreach ($iterator as $directory) {
if (!$directory->isDir() || $directory->isDot()) {
continue;
}
$name = $directory->getBasename();
$find = ($lookup ?: $name) . '.yaml';
$filename = "{$path}/{$name}/{$find}";
if (file_exists($base . $filename)) {
$basename = $this->base . $name;
$list[$basename] = ['file' => $filename,
'modified' => filemtime($base . $filename)];
}
}
}
return $list;
}
/**
* Detects all plugins with a configuration file and returns them with
last modification time.
*
* @param string $folder Location to look up from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
* @internal
*/
protected function detectAll($folder, $pattern, $levels)
{
$path = trim(Folder::getRelativePath($folder), '/');
if (is_dir($folder)) {
// Find all system and user configuration files.
$options = [
'levels' => $levels,
'compare' => 'Filename',
'pattern' => $pattern,
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function
(\RecursiveDirectoryIterator $file) use ($path) {
return
["{$path}/{$file->getSubPathname()}" =>
$file->getMTime()];
}
],
'key' => 'SubPathname'
];
$list = Folder::all($folder, $options);
ksort($list);
} else {
$list = [];
}
return $list;
}
}
PK&d�[��VV.classes/Gantry/Component/Config/Validation.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
/**
* Data validation.
*
* @author RocketTheme
* @license MIT
*/
class Validation
{
/**
* Validate value against a blueprint field definition.
*
* @param $value
* @param array $field
* @return array
*/
public static function validate($value, array $field)
{
$messages = [];
$validate = isset($field['validate']) ? (array)
$field['validate'] : [];
// If value isn't required, we will stop validation if empty
value is given.
if (empty($validate['required']) && ($value ===
null || $value === '')) {
return $messages;
}
if (!isset($field['type'])) {
$field['type'] = 'input.text';
}
// Special case for files, value is never empty and errors with
code 4 instead.
if (empty($validate['required']) &&
$field['type'] === 'input.file' &&
isset($value['error'])
&& ($value['error'] ===
UPLOAD_ERR_NO_FILE || \in_array(UPLOAD_ERR_NO_FILE,
$value['error'], true))) {
return $messages;
}
// Validate type with fallback type text.
$type = (string)
isset($field['validate']['type']) ?
$field['validate']['type'] : $field['type'];
$method = 'type_'.strtr($type, '-.',
'__');
if (!method_exists(__CLASS__, $method)) {
$method = 'type_Input_Text';
}
$name = ucfirst(isset($field['label']) ?
$field['label'] : $field['name']);
// TODO: translate
$message = (string)
isset($field['validate']['message'])
? sprintf($field['validate']['message'])
: sprintf('Invalid input in field: ') . '
"' . $name . '"';
$success = self::$method($value, $validate, $field);
if (!$success) {
$messages[$field['name']][] = $message;
}
// Check individual rules.
foreach ($validate as $rule => $params) {
$method = 'validate_' . ucfirst(strtr($rule,
'-.', '__'));
if (method_exists(__CLASS__, $method)) {
$success = self::$method($value, $params);
if (!$success) {
$messages[$field['name']][] = $message;
}
}
}
return $messages;
}
/**
* Filter value against a blueprint field definition.
*
* @param mixed $value
* @param array $field
* @return mixed Filtered value.
*/
public static function filter($value, array $field)
{
$validate = isset($field['validate']) ? (array)
$field['validate'] : [];
// If value isn't required, we will return null if empty value
is given.
if (($value === null || $value === '') &&
empty($validate['required'])) {
return null;
}
if (!isset($field['type'])) {
$field['type'] = 'input.text';
}
// Special case for files, value is never empty and errors with
code 4 instead.
if (empty($validate['required']) &&
$field['type'] === 'input.file' &&
isset($value['error'])
&& ($value['error'] === UPLOAD_ERR_NO_FILE ||
\in_array(UPLOAD_ERR_NO_FILE, $value['error'], true))) {
return null;
}
// Validate type with fallback type text.
$type = (string)
isset($field['validate']['type']) ?
$field['validate']['type'] : $field['type'];
$method = 'filter_' . ucfirst(str_replace('-',
'_', $type));
if (!method_exists(__CLASS__, $method)) {
$method = 'filter_Input_Text';
}
return self::$method($value, $validate, $field);
}
/**
* HTML5 input: text
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Text($value, array $params, array
$field)
{
if (!\is_string($value) && !is_numeric($value)) {
return false;
}
$value = (string)$value;
if (isset($params['min']) && \strlen($value) <
$params['min']) {
return false;
}
if (isset($params['max']) && \strlen($value) >
$params['max']) {
return false;
}
$min = isset($params['min']) ? $params['min'] :
0;
if (isset($params['step']) && (strlen($value) -
$min) % $params['step'] === 0) {
return false;
}
if ((!isset($params['multiline']) ||
!$params['multiline']) && preg_match('/\R/um',
$value)) {
return false;
}
return true;
}
protected static function filter_Input_Text($value, array $params,
array $field)
{
return (string) $value;
}
protected static function filter_Input_CommaList($value, array $params,
array $field)
{
return \is_array($value) ? $value :
preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
}
protected static function type_Input_CommaList($value, array $params,
array $field)
{
return \is_array($value) ? true : self::type_Input_Text($value,
$params, $field);
}
/**
* HTML5 input: textarea
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Textarea_Textarea($value, array $params,
array $field)
{
if (!isset($params['multiline'])) {
$params['multiline'] = true;
}
return self::type_Input_Text($value, $params, $field);
}
/**
* HTML5 input: password
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Password($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field);
}
/**
* HTML5 input: hidden
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Hidden($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field);
}
/**
* Custom input: checkbox list
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Checkboxes_Checkboxes($value, array
$params, array $field)
{
// Set multiple: true so checkboxes can easily use min/max counts
to control number of options required
$field['multiple'] = true;
return self::typeArray((array) $value, $params, $field);
}
protected static function filter_Checkboxes_Checkboxes($value, array
$params, array $field)
{
return self::filterArray($value, $params, $field);
}
/**
* HTML5 input: checkbox
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Checkbox($value, array $params, array
$field)
{
$value = (string) $value;
if (!isset($field['value'])) {
$field['value'] = 1;
}
if ($value && $value != $field['value']) {
return false;
}
return true;
}
/**
* HTML5 input: radio
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Radio($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
/**
* Custom input: toggle
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Toggle_Toggle($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
/**
* Custom input: file
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_File($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
protected static function filter_Input_File($value, array $params,
array $field)
{
if (isset($field['multiple']) &&
$field['multiple'] === true) {
return (array) $value;
}
if (\is_array($value)) {
return reset($value);
}
return $value;
}
/**
* HTML5 input: select
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Select_Select($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
/**
* HTML5 input: number
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Number($value, array $params, array
$field)
{
if (!is_numeric($value)) {
return false;
}
if (isset($params['min']) && $value <
$params['min']) {
return false;
}
if (isset($params['max']) && $value >
$params['max']) {
return false;
}
$min = isset($params['min']) ? $params['min'] :
0;
return !(isset($params['step']) && fmod($value -
$min, $params['step']) === 0);
}
protected static function filter_Input_Number($value, array $params,
array $field)
{
return (string)(int)$value !== (string)(float)$value ? (float)
$value : (int) $value;
}
protected static function filter_Input_DateTime($value, array $params,
array $field)
{
$converted = new \DateTime($value);
return $converted->format('Y-m-d H:i:s');
}
/**
* HTML5 input: range
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Range($value, array $params, array
$field)
{
return self::type_Input_Number($value, $params, $field);
}
protected static function filter_Input_Range($value, array $params,
array $field)
{
return self::filter_Input_Number($value, $params, $field);
}
/**
* HTML5 input: color
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Color($value, array $params, array
$field)
{
return preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u',
$value);
}
/**
* HTML5 input: email
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Email($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field) &&
filter_var($value, FILTER_VALIDATE_EMAIL);
}
/**
* HTML5 input: url
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Url($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field) &&
filter_var($value, FILTER_VALIDATE_URL);
}
/**
* HTML5 input: datetime
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Datetime($value, array $params, array
$field)
{
if ($value instanceof \DateTime) {
return true;
}
if (!\is_string($value)) {
return false;
}
if (!isset($params['format'])) {
return false !== strtotime($value);
}
$dateFromFormat =
\DateTime::createFromFormat($params['format'], $value);
return $dateFromFormat && $value ===
date($params['format'], $dateFromFormat->getTimestamp());
}
/**
* HTML5 input: datetime-local
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_DatetimeLocal($value, array $params,
array $field)
{
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: date
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Date($value, array $params, array
$field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m-d';
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: time
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Time($value, array $params, array
$field)
{
if (!isset($params['format'])) {
$params['format'] = 'H:i';
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: month
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Month($value, array $params, array
$field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m';
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: week
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Week($value, array $params, array
$field)
{
if (!isset($params['format']) &&
!preg_match('/^\d{4}-W\d{2}$/u', $value)) {
return false;
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* Custom input: array
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeArray($value, array $params, array $field)
{
if (!\is_array($value)) {
return false;
}
if (isset($field['multiple'])) {
if (isset($params['min']) && \count($value)
< $params['min']) {
return false;
}
if (isset($params['max']) && \count($value)
> $params['max']) {
return false;
}
$min = isset($params['min']) ?
$params['min'] : 0;
if (isset($params['step']) && (\count($value)
- $min) % $params['step'] === 0) {
return false;
}
}
$options = isset($field['options']) ?
array_keys($field['options']) : [];
$values = isset($field['use']) &&
$field['use'] === 'keys' ? array_keys($value) : $value;
return !($options && array_diff($values, $options));
}
protected static function filterArray($value, $params, $field)
{
$values = (array) $value;
$options = isset($field['options']) ?
array_keys($field['options']) : [];
$multi = isset($field['multiple']) ?
$field['multiple'] : false;
if (\count($values) === 1 && isset($values[0]) &&
$values[0] === '') {
return null;
}
if ($options) {
$useKey = isset($field['use']) &&
$field['use'] === 'keys';
foreach ($values as $key => $val) {
$values[$key] = $useKey ? (bool) $val : $val;
}
}
if ($multi) {
foreach ($values as $key => $val) {
if (\is_array($val)) {
$val = implode(',', $val);
}
$values[$key] = array_map('trim',
explode(',', $val));
}
}
return $values;
}
public static function type_Input_Yaml($value, $params)
{
try {
Yaml::parse($value);
return true;
} catch (ParseException $e) {
return false;
}
}
public static function filter_Input_Yaml($value, $params)
{
try {
return (array) Yaml::parse($value);
} catch (ParseException $e) {
return null;
}
}
/**
* Custom input: ignore (will not validate)
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Novalidate($value, array $params, array
$field)
{
return true;
}
public static function filter_Novalidate($value, array $params, array
$field)
{
return $value;
}
// HTML5 attributes (min, max and range are handled inside the types)
public static function validate_Required($value, $params)
{
if (is_scalar($value)) {
return (bool) $params !== true || $value !== '';
}
return (bool) $params !== true || !empty($value);
}
public static function validate_Pattern($value, $params)
{
return (bool) preg_match("`^{$params}$`u", $value);
}
// Internal types
public static function validate_Alpha($value, $params)
{
return ctype_alpha($value);
}
public static function validate_Alnum($value, $params)
{
return ctype_alnum($value);
}
public static function type_Bool($value, $params)
{
return \is_bool($value) || $value == 1 || $value == 0;
}
public static function validate_Bool($value, $params)
{
return \is_bool($value) || $value == 1 || $value == 0;
}
protected static function filter_Bool($value, $params)
{
return (bool) $value;
}
public static function validate_Digit($value, $params)
{
return ctype_digit($value);
}
public static function validate_Float($value, $params)
{
return \is_float(filter_var($value, FILTER_VALIDATE_FLOAT));
}
protected static function filter_Float($value, $params)
{
return (float) $value;
}
public static function validate_Hex($value, $params)
{
return ctype_xdigit($value);
}
public static function validate_Int($value, $params)
{
return is_numeric($value) && (int) $value == $value;
}
protected static function filter_Int($value, $params)
{
return (int) $value;
}
public static function validate_Array($value, $params)
{
return \is_array($value)
|| ($value instanceof \ArrayAccess
&& $value instanceof \Traversable
&& $value instanceof \Countable);
}
public static function validate_Json($value, $params)
{
return (bool) (@json_decode($value));
}
}
PK&d�[��"7classes/Gantry/Component/Config/ValidationException.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
class ValidationException extends \RuntimeException
{
protected $messages = [];
public function setMessages(array $messages = []) {
$this->messages = $messages;
// TODO: add translation.
$this->message = sprintf('Form validation failed:') .
' ' . $this->message;
foreach ($messages as $variable => &$list) {
$list = array_unique($list);
foreach ($list as $message) {
$this->message .= "<br/>$message";
}
}
return $this;
}
public function getMessages()
{
return $this->messages;
}
}
PK&d�[#NJ���7classes/Gantry/Component/Content/Block/ContentBlock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
/**
* Class to create nested blocks of content.
*
* $innerBlock = ContentBlock::create();
* $innerBlock->setContent('my inner content');
* $outerBlock = ContentBlock::create();
* $outerBlock->setContent(sprintf('Inside my outer block I have
%s.', $innerBlock->getToken()));
* $outerBlock->addBlock($innerBlock);
* echo $outerBlock;
*
* @package Gantry\Component\Content\Block
* @since 5.4.3
*/
class ContentBlock implements ContentBlockInterface
{
protected $version = 1;
protected $id;
protected $tokenTemplate = '@@BLOCK-%s@@';
protected $content = '';
protected $blocks = [];
/**
* @param string $id
* @return static
* @since 5.4.3
*/
public static function create($id = null)
{
return new static($id);
}
/**
* @param array $serialized
* @return ContentBlockInterface
* @since 5.4.3
*/
public static function fromArray(array $serialized)
{
try {
$type = isset($serialized['_type']) ?
$serialized['_type'] : null;
$id = isset($serialized['id']) ?
$serialized['id'] : null;
if (!$type || !$id || !is_a($type,
'Gantry\Component\Content\Block\ContentBlockInterface', true)) {
throw new \RuntimeException('Bad data');
}
/** @var ContentBlockInterface $instance */
$instance = new $type($id);
$instance->build($serialized);
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Cannot unserialize
Block: %s', $e->getMessage()), $e->getCode(), $e);
}
return $instance;
}
/**
* Block constructor.
*
* @param string $id
* @since 5.4.3
*/
public function __construct($id = null)
{
$this->id = $id ? (string) $id : $this->generateId();
}
/**
* @return string
* @since 5.4.3
*/
public function getId()
{
return $this->id;
}
/**
* @return string
* @since 5.4.3
*/
public function getToken()
{
return sprintf($this->tokenTemplate, $this->getId());
}
/**
* @return array
* @since 5.4.3
*/
public function toArray()
{
$blocks = [];
/**
* @var string $id
* @var ContentBlockInterface $block
*/
foreach ($this->blocks as $block) {
$blocks[$block->getId()] = $block->toArray();
}
$array = [
'_type' => get_class($this),
'_version' => $this->version,
'id' => $this->id,
];
if ($this->content) {
$array['content'] = $this->content;
}
if ($blocks) {
$array['blocks'] = $blocks;
}
return $array;
}
/**
* @return string
* @since 5.4.3
*/
public function toString()
{
if (!$this->blocks) {
return (string) $this->content;
}
$tokens = [];
$replacements = [];
foreach ($this->blocks as $block) {
$tokens[] = $block->getToken();
$replacements[] = $block->toString();
}
return str_replace($tokens, $replacements, (string)
$this->content);
}
/**
* @return string
* @since 5.4.3
*/
public function __toString()
{
try {
return $this->toString();
} catch (\Exception $e) {
return sprintf('Error while rendering block: %s',
$e->getMessage());
}
}
/**
* @param array $serialized
* @since 5.4.3
*/
public function build(array $serialized)
{
$this->checkVersion($serialized);
$this->id = isset($serialized['id']) ?
$serialized['id'] : $this->generateId();
if (isset($serialized['content'])) {
$this->setContent($serialized['content']);
}
$blocks = isset($serialized['blocks']) ? (array)
$serialized['blocks'] : [];
foreach ($blocks as $block) {
$this->addBlock(self::fromArray($block));
}
}
/**
* @param string $content
* @return $this
* @since 5.4.3
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* @param ContentBlockInterface $block
* @return $this
* @since 5.4.3
*/
public function addBlock(ContentBlockInterface $block)
{
$this->blocks[$block->getId()] = $block;
return $this;
}
/**
* @return string
* @since 5.4.3
*/
public function serialize()
{
return serialize($this->toArray());
}
/**
* @param string $serialized
* @since 5.4.3
*/
public function unserialize($serialized)
{
$array = unserialize($serialized);
$this->build($array);
}
/**
* @return string
* @since 5.4.3
*/
protected function generateId()
{
return uniqid('', true);
}
/**
* @param array $serialized
* @throws \RuntimeException
* @since 5.4.3
*/
protected function checkVersion(array $serialized)
{
$version = isset($serialized['_version']) ? (string)
$serialized['_version'] : 1;
if ($version != $this->version) {
throw new \RuntimeException(sprintf('Unsupported version
%s', $version));
}
}
}PK&d�[{�?:xx@classes/Gantry/Component/Content/Block/ContentBlockInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
/**
* @since 5.4.3
*/
interface ContentBlockInterface extends \Serializable
{
public static function create($id = null);
public static function fromArray(array $serialized);
public function __construct($id = null);
public function getId();
public function getToken();
public function toArray();
public function build(array $serialized);
public function setContent($content);
public function addBlock(ContentBlockInterface $block);
}PK&d�[��ue�2�24classes/Gantry/Component/Content/Block/HtmlBlock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
use Gantry\Framework\Document;
use Gantry\Framework\Gantry;
use Gantry\Framework\Theme;
/**
* Class HtmlBlock
* @package Gantry\Component\Content\Block
* @since 5.4.3
*/
class HtmlBlock extends ContentBlock implements HtmlBlockInterface
{
protected $version = 1;
protected $frameworks = [];
protected $styles = [];
protected $scripts = [];
protected $html = [];
/**
* @return array
* @since 5.4.3
*/
public function getAssets()
{
$assets = $this->getAssetsFast();
$this->sortAssets($assets['styles']);
$this->sortAssets($assets['scripts']);
$this->sortAssets($assets['html']);
return $assets;
}
/**
* @return array
* @since 5.4.3
*/
public function getFrameworks()
{
$assets = $this->getAssetsFast();
return array_keys($assets['frameworks']);
}
/**
* @param string $location
* @return array
* @since 5.4.3
*/
public function getStyles($location = 'head')
{
$styles = $this->getAssetsInLocation('styles',
$location);
if (!$styles) {
return [];
}
$gantry = Gantry::instance();
/** @var Theme $theme */
$theme = isset($gantry['theme']) ?
$gantry['theme'] : null;
/** @var Document $document */
$document = $gantry['document'];
foreach ($styles as $key => $style) {
if (isset($style['href'])) {
$url = $style['href'];
if ($theme && preg_match('|\.scss$|',
$url)) {
// Compile SCSS files.
$url = $theme->css(basename($url,
'.scss'));
}
// Deal with streams and relative paths.
$url = $document->url($url, false, null, false);
$styles[$key]['href'] = $url;
}
}
return $styles;
}
/**
* @param string $location
* @return array
* @since 5.4.3
*/
public function getScripts($location = 'head')
{
$scripts = $this->getAssetsInLocation('scripts',
$location);
if (!$scripts) {
return [];
}
$gantry = Gantry::instance();
/** @var Document $document */
$document = $gantry['document'];
foreach ($scripts as $key => $script) {
if (isset($script['src'])) {
// Deal with streams and relative paths.
$scripts[$key]['src'] =
$document->url($script['src'], false, null, false);
}
}
return $scripts;
}
/**
* @param string $location
* @return array
* @since 5.4.3
*/
public function getHtml($location = 'bottom')
{
return $this->getAssetsInLocation('html', $location);
}
/**
* @return array
* @since 5.4.3
*/
public function toArray()
{
$array = parent::toArray();
if ($this->frameworks) {
$array['frameworks'] = $this->frameworks;
}
if ($this->styles) {
$array['styles'] = $this->styles;
}
if ($this->scripts) {
$array['scripts'] = $this->scripts;
}
if ($this->html) {
$array['html'] = $this->html;
}
return $array;
}
/**
* @param array $serialized
* @since 5.4.3
*/
public function build(array $serialized)
{
parent::build($serialized);
$this->frameworks = isset($serialized['frameworks']) ?
(array) $serialized['frameworks'] : [];
$this->styles = isset($serialized['styles']) ? (array)
$serialized['styles'] : [];
$this->scripts = isset($serialized['scripts']) ?
(array) $serialized['scripts'] : [];
$this->html = isset($serialized['html']) ? (array)
$serialized['html'] : [];
}
/**
* @param string $framework
* @return $this
* @since 5.4.3
*/
public function addFramework($framework)
{
$this->frameworks[$framework] = 1;
return $this;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*
* @example $block->addStyle('assets/js/my.js');
* @example $block->addStyle(['href' =>
'assets/js/my.js', 'media' => 'screen']);
* @since 5.4.3
*/
public function addStyle($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['href' => (string) $element];
}
if (empty($element['href'])) {
return false;
}
if (!isset($this->styles[$location])) {
$this->styles[$location] = [];
}
$id = !empty($element['id']) ? ['id' =>
(string) $element['id']] : [];
$href = $element['href'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/css';
$media = !empty($element['media']) ? (string)
$element['media'] : null;
unset($element['tag'], $element['id'],
$element['rel'], $element['content'],
$element['href'], $element['type'],
$element['media']);
$this->styles[$location][md5($href) . sha1($href)] = [
':type' => 'file',
':priority' => (int) $priority,
'href' => $href,
'type' => $type,
'media' => $media,
'element' => $element
] + $id;
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addInlineStyle($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['content' => (string) $element];
}
if (empty($element['content'])) {
return false;
}
if (!isset($this->styles[$location])) {
$this->styles[$location] = [];
}
$content = (string) $element['content'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/css';
$this->styles[$location][md5($content) . sha1($content)] = [
':type' => 'inline',
':priority' => (int) $priority,
'content' => $content,
'type' => $type
];
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addScript($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['src' => (string) $element];
}
if (empty($element['src'])) {
return false;
}
if (!isset($this->scripts[$location])) {
$this->scripts[$location] = [];
}
$src = $element['src'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/javascript';
$defer = isset($element['defer']) ? true : false;
$async = isset($element['async']) ? true : false;
$handle = !empty($element['handle']) ? (string)
$element['handle'] : '';
$this->scripts[$location][md5($src) . sha1($src)] = [
':type' => 'file',
':priority' => (int) $priority,
'src' => $src,
'type' => $type,
'defer' => $defer,
'async' => $async,
'handle' => $handle
];
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addInlineScript($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['content' => (string) $element];
}
if (empty($element['content'])) {
return false;
}
if (!isset($this->scripts[$location])) {
$this->scripts[$location] = [];
}
$content = (string) $element['content'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/javascript';
$this->scripts[$location][md5($content) . sha1($content)] = [
':type' => 'inline',
':priority' => (int) $priority,
'content' => $content,
'type' => $type
];
return true;
}
/**
* @param string $html
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addHtml($html, $priority = 0, $location =
'bottom')
{
if (empty($html) || !is_string($html)) {
return false;
}
if (!isset($this->html[$location])) {
$this->html[$location] = [];
}
$this->html[$location][md5($html) . sha1($html)] = [
':priority' => (int) $priority,
'html' => $html
];
return true;
}
/**
* @param string $location
* @deprecated Temporarily needed in WP
* @since 5.4.3
*/
public function clearStyles($location = 'head')
{
foreach ($this->blocks as $block) {
if (method_exists($block, 'clearStyles')) {
$block->clearStyles($location);
}
}
unset($this->styles[$location]);
}
/**
* @param string $location
* @deprecated Temporarily needed in WP
* @since 5.4.3
*/
public function clearScripts($location = 'head')
{
foreach ($this->blocks as $block) {
if (method_exists($block, 'clearScripts')) {
$block->clearScripts($location);
}
}
unset($this->scripts[$location]);
}
/**
* @return array
* @since 5.4.3
*/
protected function getAssetsFast()
{
$assets = [
'frameworks' => $this->frameworks,
'styles' => $this->styles,
'scripts' => $this->scripts,
'html' => $this->html
];
foreach ($this->blocks as $block) {
if ($block instanceof HtmlBlock) {
$blockAssets = $block->getAssetsFast();
$assets['frameworks'] +=
$blockAssets['frameworks'];
foreach ($blockAssets['styles'] as $location
=> $styles) {
if (!isset($assets['styles'][$location])) {
$assets['styles'][$location] = $styles;
} elseif ($styles) {
$assets['styles'][$location] += $styles;
}
}
foreach ($blockAssets['scripts'] as $location
=> $scripts) {
if (!isset($assets['scripts'][$location])) {
$assets['scripts'][$location] = $scripts;
} elseif ($scripts) {
$assets['scripts'][$location] +=
$scripts;
}
}
foreach ($blockAssets['html'] as $location =>
$htmls) {
if (!isset($assets['html'][$location])) {
$assets['html'][$location] = $htmls;
} elseif ($htmls) {
$assets['html'][$location] += $htmls;
}
}
}
}
return $assets;
}
/**
* @param string $type
* @param string $location
* @return array
* @since 5.4.3
*/
protected function getAssetsInLocation($type, $location)
{
$assets = $this->getAssetsFast();
if (empty($assets[$type][$location])) {
return [];
}
$styles = $assets[$type][$location];
$this->sortAssetsInLocation($styles);
return $styles;
}
/**
* @param array $items
* @since 5.4.3
*/
protected function sortAssetsInLocation(array &$items)
{
$count = 0;
foreach ($items as &$item) {
$item[':order'] = ++$count;
}
uasort(
$items,
function ($a, $b) {
return ($a[':priority'] ==
$b[':priority']) ? $a[':order'] -
$b[':order'] : $b[':priority'] -
$a[':priority'];
}
);
}
/**
* @param array $array
* @since 5.4.3
*/
protected function sortAssets(array &$array)
{
foreach ($array as $location => &$items) {
$this->sortAssetsInLocation($items);
}
}
}PK&d�[�v*B��=classes/Gantry/Component/Content/Block/HtmlBlockInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
/**
* @since 5.4.3
*/
interface HtmlBlockInterface extends ContentBlockInterface
{
public function getAssets();
public function addFramework($framework);
public function addStyle($element, $priority = 0, $location =
'head');
public function addInlineStyle($element, $priority = 0, $location =
'head');
public function addScript($element, $priority = 0, $location =
'head');
public function addInlineScript($element, $priority = 0, $location =
'head');
public function addHtml($html, $priority = 0, $location =
'bottom');
}
PK&d�[ �Q��i�i:classes/Gantry/Component/Content/Document/HtmlDocument.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Document;
use Gantry\Component\Content\Block\ContentBlock;
use Gantry\Component\Content\Block\HtmlBlock;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Url\Url;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class HtmlDocument
{
use GantryTrait;
public static $timestamp_age = 604800;
public static $urlFilterParams;
/**
* @var array|HtmlBlock[]
*/
protected static $stack;
protected static $frameworks = [];
protected static $scripts = [];
protected static $styles = [];
protected static $availableFrameworks = [
'jquery' => 'registerJquery',
'jquery.framework' => 'registerJquery',
'jquery.ui.core' =>
'registerJqueryUiSortable',
'jquery.ui.sortable' =>
'registerJqueryUiSortable',
'bootstrap.2' => 'registerBootstrap2',
'bootstrap.3' => 'registerBootstrap3',
'mootools' => 'registerMootools',
'mootools.framework' => 'registerMootools',
'mootools.core' => 'registerMootools',
'mootools.more' => 'registerMootoolsMore',
'lightcase' => 'registerLightcase',
'lightcase.init' => 'registerLightcaseInit',
];
public function __construct()
{
static::$stack = [];
static::push();
}
/**
* Create new local instance of document allowing asset caching.
*/
public static function push()
{
array_unshift(static::$stack, new HtmlBlock());
}
/**
* Return local instance of document allowing it to be cached.
*
* @return HtmlBlock
*/
public static function pop()
{
return array_shift(static::$stack);
}
/**
* @param ContentBlock $block
* @return $this
*/
public function addBlock(ContentBlock $block)
{
static::$stack[0]->addBlock($block);
return $this;
}
/**
* @param string $framework
* @return bool
*/
public static function addFramework($framework)
{
if (!isset(static::$availableFrameworks[$framework])) {
return false;
}
static::getObject();
static::$stack[0]->addFramework($framework);
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addStyle($element, $priority = 0, $location =
'head')
{
static::getObject();
return static::$stack[0]->addStyle($element, $priority,
$location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addInlineStyle($element, $priority = 0,
$location = 'head')
{
static::getObject();
return static::$stack[0]->addInlineStyle($element, $priority,
$location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addScript($element, $priority = 0, $location =
'head')
{
static::getObject();
return static::$stack[0]->addScript($element, $priority,
$location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addInlineScript($element, $priority = 0,
$location = 'head')
{
static::getObject();
return static::$stack[0]->addInlineScript($element, $priority,
$location);
}
/**
* @param string $html
* @param int $priority
* @param string $location
* @return bool
*/
public static function addHtml($html, $priority = 0, $location =
'bottom')
{
static::getObject();
return static::$stack[0]->addHtml($html, $priority, $location);
}
/**
* @param array $element
* @param string $location
* @param int $priority
* @return bool
*/
public static function addHeaderTag(array $element, $location =
'head', $priority = 0)
{
$success = false;
switch ($element['tag']) {
case 'link':
if (!empty($element['rel']) &&
$element['rel'] === 'stylesheet') {
$success = static::addStyle($element, $priority,
$location);
}
break;
case 'style':
$success = static::addInlineStyle($element, $priority,
$location);
break;
case 'script':
if (!empty($element['src'])) {
$success = static::addScript($element, $priority,
$location);
} elseif (!empty($element['content'])) {
$success = static::addInlineScript($element, $priority,
$location);
}
break;
}
return $success;
}
public static function getStyles($location = 'head')
{
static::getObject();
$styles = static::$stack[0]->getStyles($location);
$output = [];
foreach ($styles as $style) {
switch ($style[':type']) {
case 'file':
$attribs = '';
if ($style['media']) {
$attribs .= ' media="' .
static::escape($style['media']) . '"';
}
$output[] = sprintf(
'<link rel="stylesheet"
href="%s" type="%s"%s />',
static::escape($style['href']),
static::escape($style['type']),
$attribs
);
break;
case 'inline':
$attribs = '';
if ($style['type'] !== 'text/css')
{
$attribs .= ' type="' .
static::escape($style['type']) . '"';
}
$output[] = sprintf(
'<style%s>%s</style>',
$attribs,
$style['content']
);
break;
}
}
return $output;
}
public static function getScripts($location = 'head')
{
static::getObject();
$scripts = static::$stack[0]->getScripts($location);
$output = [];
foreach ($scripts as $script) {
switch ($script[':type']) {
case 'file':
$attribs = '';
if ($script['async']) {
$attribs .= ' async="async"';
}
if ($script['defer']) {
$attribs .= ' defer="defer"';
}
$output[] = sprintf(
'<script type="%s"%s
src="%s"></script>',
static::escape($script['type']),
$attribs,
static::escape($script['src'])
);
break;
case 'inline':
$output[] = sprintf(
'<script
type="%s">%s</script>',
static::escape($script['type']),
$script['content']
);
break;
}
}
return $output;
}
public static function getHtml($location = 'bottom')
{
static::getObject();
$htmls = static::$stack[0]->getHtml($location);
$output = [];
foreach ($htmls as $html) {
$output[] = $html['html'];
}
return $output;
}
/**
* Escape string (emulates twig filter).
*
* @param string|object $string
* @param string $strategy
* @return string
*/
public static function escape($string, $strategy = 'html')
{
if (!is_string($string)) {
if (is_object($string) && method_exists($string,
'__toString')) {
$string = (string) $string;
} elseif (in_array($strategy, ['html',
'js', 'css', 'html_attr', 'url']))
{
return $string;
}
}
switch ($strategy) {
case 'html':
return htmlspecialchars($string, ENT_QUOTES |
ENT_SUBSTITUTE, 'UTF-8');
case 'js':
if (0 === strlen($string) ? false : (1 ===
preg_match('/^./su', $string) ? false : true)) {
throw new \RuntimeException('The string to escape
is not a valid UTF-8 string.');
}
$string = preg_replace_callback(
'#[^a-zA-Z0-9,\._]#Su',
'Gantry\\Component\\Content\\Document\\HtmlDocument::_escape_js_callback',
$string
);
return $string;
case 'css':
if (0 === strlen($string) ? false : (1 ===
preg_match('/^./su', $string) ? false : true)) {
throw new \RuntimeException('The string to escape
is not a valid UTF-8 string.');
}
$string = preg_replace_callback(
'#[^a-zA-Z0-9]#Su',
'Gantry\\Component\\Content\\Document\\HtmlDocument::_escape_css_callback',
$string
);
return $string;
case 'html_attr':
if (0 === strlen($string) ? false : (1 ===
preg_match('/^./su', $string) ? false : true)) {
throw new \RuntimeException('The string to escape
is not a valid UTF-8 string.');
}
$string = preg_replace_callback(
'#[^a-zA-Z0-9,\.\-_]#Su',
'Gantry\\Component\\Content\\Document\\HtmlDocument::_escape_html_attr_callback',
$string
);
return $string;
case 'url':
return rawurlencode($string);
default:
throw new \RuntimeException(sprintf('Invalid escaping
strategy "%s" (valid ones: html, js, css, html_attr, url).',
$strategy));
}
}
/**
* @param $framework
* @return bool
* @deprecated 5.3
*/
public static function load($framework)
{
return static::addFramework($framework);
}
/**
* Register assets.
*/
public static function registerAssets()
{
static::registerFrameworks();
}
public static function siteUrl()
{
return static::rootUri();
}
/**
* NOTE: In PHP this function can be called either from Gantry DI
container or statically.
*
* @return string
*/
public static function rootUri()
{
return '';
}
/**
* NOTE: In PHP this function can be called either from Gantry DI
container or statically.
*
* @param bool $addDomain
* @return string
*/
public static function domain($addDomain = false)
{
return '';
}
/**
* Return URL to the resource.
*
* @example {{
url('gantry-theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4')
}}
*
* NOTE: In PHP this function can be called either from Gantry DI
container or statically.
*
* @param string $url Resource to be located.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @param bool $allowNull True if non-existing files should return
null.
* @return string|null Returns url to the resource or null if
resource was not found.
*/
public static function url($url, $domain = false, $timestamp_age =
null, $allowNull = true)
{
if (!is_string($url) || $url === '') {
// Return null on invalid input.
return null;
}
if ($url[0] === '#' || $url[0] === '?') {
// Handle urls with query string or fragment only.
return str_replace(' ', '%20', $url);
}
$parts = Url::parse($url);
if (!is_array($parts)) {
// URL could not be parsed.
return $allowNull ? null : str_replace(' ',
'%20', $url);
}
// Make sure we always have scheme, host, port and path.
$scheme = isset($parts['scheme']) ?
$parts['scheme'] : '';
$host = isset($parts['host']) ? $parts['host']
: '';
$port = isset($parts['port']) ? $parts['port']
: '';
$path = isset($parts['path']) ? $parts['path']
: '';
if ($scheme && !$port) {
// If URL has a scheme, we need to check if it's one of
Gantry streams.
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
if (!$locator->schemeExists($scheme)) {
// If scheme does not exists as a stream, assume it's
external.
return str_replace(' ', '%20', $url);
}
// Attempt to find the resource (because of parse_url() we need
to put host back to path).
$newPath =
$locator->findResource("{$scheme}://{$host}{$path}", false);
if ($newPath === false) {
if ($allowNull) {
return null;
}
// Return location where the file would be if it was saved.
$path =
$locator->findResource("{$scheme}://{$host}{$path}", false,
true);
} else {
$path = $newPath;
}
} elseif ($host || $port) {
// If URL doesn't have scheme but has host or port, it is
external.
return str_replace(' ', '%20', $url);
}
// At this point URL is either relative or absolute path; let us
find if it is relative and not . or ..
if ($path && '/' !== $path[0] &&
'.' !== $path[0]) {
if ($timestamp_age === null) {
$timestamp_age = static::$timestamp_age;
}
if ($timestamp_age > 0) {
// We want to add timestamp to the URI: do it only for
existing files.
$realPath = @realpath(GANTRY5_ROOT . '/' .
$path);
if ($realPath && is_file($realPath)) {
$time = filemtime($realPath);
// Only append timestamp for files that are less than
the maximum age.
if ($time > time() - $timestamp_age) {
$parts['query'] =
(!empty($parts['query']) ?
"{$parts['query']}&" : '') .
sprintf('%x', $time);
}
}
}
// We need absolute URI instead of relative.
$path = rtrim(static::rootUri(), '/') . '/'
. $path;
}
// Set absolute URI.
$uri = $path;
// Add query string back.
if (!empty($parts['query'])) {
if (!$uri) $uri = static::rootUri();
$uri .= '?' . $parts['query'];
}
// Add fragment back.
if (!empty($parts['fragment'])) {
if (!$uri) $uri = static::rootUri();
$uri .= '#' . $parts['fragment'];
}
return static::domain($domain) . str_replace(' ',
'%20', $uri);
}
/**
* Filter stream URLs from HTML.
*
* @param string $html HTML input to be filtered.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @param bool $streamOnly Only touch streams.
* @return string Returns modified HTML.
*/
public static function urlFilter($html, $domain = false, $timestamp_age
= null, $streamOnly = false)
{
static::$urlFilterParams = [$domain, $timestamp_age, $streamOnly];
// Tokenize all PRE, CODE and SCRIPT tags to avoid modifying any
src|href|url in them
$tokens = [];
$html =
preg_replace_callback('#<(pre|code|script)(\s[^>]+)?>.*?</\\1>#ius',
function($matches) use (&$tokens) {
// Unfortunately uniqid() doesn't quite work in Windows,
so we need to work it around by adding some randomness.
$token = '@@'. uniqid(mt_rand(), true) .
'@@';
$match = $matches[0];
$tokens[$token] = $match;
return $token;
}, $html);
if ($streamOnly) {
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$schemes = $locator->getSchemes();
$list = [];
foreach ($schemes as $scheme) {
if (strpos($scheme, 'gantry-') === 0) {
$list[] = substr($scheme, 7);
}
}
if (empty($list)) {
return $html;
}
$match = '(gantry-(' . implode('|', $list).
')://.*?)';
} else {
$match = '(.*?)';
}
$html = preg_replace_callback('^(\s)(src|href)="' .
$match . '"^u', 'static::linkHandler', $html);
$html = preg_replace_callback('^(\s)url\(' . $match .
'\)^u', 'static::urlHandler', $html);
$html = static::replaceTokens($tokens, $html);
return $html;
}
/**
* @param array $matches
* @return string
* @internal
*/
public static function linkHandler(array $matches)
{
list($domain, $timestamp_age) = static::$urlFilterParams;
$url = trim($matches[3]);
$url = static::url($url, $domain, $timestamp_age, false);
return "{$matches[1]}{$matches[2]}=\"{$url}\"";
}
/**
* @param array $matches
* @return string
* @internal
*/
public static function urlHandler(array $matches)
{
list($domain, $timestamp_age) = static::$urlFilterParams;
$url = trim($matches[2], '"\'');
$url = static::url($url, $domain, $timestamp_age, false);
return "{$matches[1]}url({$url})";
}
/**
* This function is adapted from code coming from Twig.
*
* @param array $matches
* @return string
* @internal
*/
public static function _escape_js_callback($matches)
{
$char = $matches[0];
/*
* A few characters have short escape sequences in JSON and
JavaScript.
* Escape sequences supported only by JavaScript, not JSON, are
ommitted.
* \" is also supported but omitted, because the resulting
string is not HTML safe.
*/
static $shortMap = [
'\\' => '\\\\',
'/' => '\\/',
"\x08" => '\b',
"\x0C" => '\f',
"\x0A" => '\n',
"\x0D" => '\r',
"\x09" => '\t',
];
if (isset($shortMap[$char])) {
return $shortMap[$char];
}
// \uHHHH
$char = static::convert_encoding($char, 'UTF-16BE',
'UTF-8');
$char = strtoupper(bin2hex($char));
if (4 >= \strlen($char)) {
return sprintf('\u%04s', $char);
}
return sprintf('\u%04s\u%04s', substr($char, 0, -4),
substr($char, -4));
}
/**
* This function is adapted from code coming from Twig.
*
* @param $matches
* @return string
* @internal
*/
public static function _escape_css_callback($matches)
{
$char = $matches[0];
return sprintf('\\%X ', 1 === \strlen($char) ?
\ord($char) : static::ord($char));
}
/**
* This function is adapted from code coming from Twig and Zend
Framework.
*
* @param array $matches
* @return string
*
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc.
(https://www.zend.com)
* @license https://framework.zend.com/license/new-bsd New BSD
License
* @internal
*/
public static function _escape_html_attr_callback($matches)
{
$chr = $matches[0];
$ord = \ord($chr);
/*
* The following replaces characters undefined in HTML with the
* hex entity for the Unicode replacement character.
*/
if (($ord <= 0x1f && "\t" !== $chr &&
"\n" !== $chr && "\r" !== $chr) || ($ord >=
0x7f && $ord <= 0x9f)) {
return '�';
}
/*
* Check if the current character to escape has a name entity we
should
* replace it with while grabbing the hex value of the character.
*/
if (1 === \strlen($chr)) {
/*
* While HTML supports far more named entities, the lowest
common denominator
* has become HTML5's XML Serialisation which is
restricted to the those named
* entities that XML supports. Using HTML entities would result
in this error:
* XML Parsing Error: undefined entity
*/
static $entityMap = [
34 => '"', /* quotation mark */
38 => '&', /* ampersand */
60 => '<', /* less-than sign */
62 => '>', /* greater-than sign */
];
if (isset($entityMap[$ord])) {
return $entityMap[$ord];
}
return sprintf('&#x%02X;', $ord);
}
/*
* Per OWASP recommendations, we'll use hex entities for any
other
* characters where a named entity does not exist.
*/
return sprintf('&#x%04X;', static::ord($chr));
}
/**
* Replace tokens with strings.
*
* @param array $tokens
* @param $html
* @return string|NUll
*/
protected static function replaceTokens(array $tokens, $html)
{
foreach ($tokens as $token => $replacement) {
// We need to use callbacks to turn off backreferences ($1,
\\1) in the replacement string.
$callback = function() use ($replacement) { return
$replacement; };
$html = preg_replace_callback('#' .
preg_quote($token, '#') . '#u', $callback, $html);
}
return $html;
}
/**
* Register loaded frameworks.
*/
protected static function registerFrameworks()
{
foreach (static::$stack[0]->getFrameworks() as $framework) {
if (isset(static::$availableFrameworks[$framework])) {
call_user_func([get_called_class(),
static::$availableFrameworks[$framework]]);
}
}
}
protected static function registerJquery()
{
static::addScript(
[
'src' =>
'https://code.jquery.com/jquery-2.2.2.min.js',
'integrity' =>
'sha256-36cp2Co+/62rEAAYHLmRCPIych47CvdM+uTBJwSzWjI=',
'crossorigin' => 'anonymous'
],
11
);
}
protected static function registerJqueryUiSortable()
{
static::registerJquery();
static::addScript(
[
'src' =>
'https://code.jquery.com/ui/1.11.4/jquery-ui.min.js',
'integrity' =>
'sha256-xNjb53/rY+WmG+4L6tTl9m6PpqknWZvRt0rO1SRnJzw=',
'crossorigin' => 'anonymous'
],
11
);
}
protected static function registerBootstrap2()
{
static::registerJquery();
static::addScript(['src' =>
'https://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js'],
11);
}
protected static function registerBootstrap3()
{
static::registerJquery();
static::addScript(['src' =>
'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'],
11);
}
protected static function registerMootools()
{
static::addScript(['src' =>
'https://cdnjs.cloudflare.com/ajax/libs/mootools/1.5.2/mootools-core-compat.min.js'],
11);
}
protected static function registerMootoolsMore()
{
static::registerMootools();
static::addScript(['src' =>
'https://cdnjs.cloudflare.com/ajax/libs/mootools-more/1.5.2/mootools-more-compat-compressed.js'],
11);
}
protected static function registerLightcase()
{
static::registerJquery();
static::addScript(['src' =>
static::url('gantry-assets://js/lightcase.js', false, null,
false)], 11, 'footer');
static::addStyle(['href' =>
static::url('gantry-assets://css/lightcase.css', false, null,
false)], 11);
}
protected static function registerLightcaseInit()
{
static::registerLightcase();
static::addInlineScript(['content' =>
"jQuery(document).ready(function($) {
jQuery('[data-rel^=lightcase]').lightcase({maxWidth:
'100%', maxHeight: '100%', video: {width:
'1280', height: '720'}}); });"], 0,
'footer');
}
protected static function getObject()
{
static $object;
if (!$object) {
// We need to initialize document for backwards compatibility
(RokSprocket/RokGallery in WP).
$object = Gantry::instance()['document'];
}
return $object;
}
/**
* @param string $string
* @param string $to
* @param string $from
* @return false|string|string[]|null
* @internal
*/
private static function convert_encoding($string, $to, $from)
{
if (\function_exists('mb_convert_encoding')) {
return mb_convert_encoding($string, $to, $from);
}
if (\function_exists('iconv')) {
return iconv($from, $to, $string);
}
throw new \RuntimeException('No suitable convert encoding
function (use UTF-8 as your encoding or install the iconv or mbstring
extension).');
}
/**
* @param string $string
* @return false|int|mixed
* @internal
*/
private static function ord($string)
{
if (\function_exists('mb_ord')) {
return mb_ord($string, 'UTF-8');
}
$code = ($string = unpack('C*', substr($string, 0, 4))) ?
$string[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($string[2] - 0x80)
<< 12) + (($string[3] - 0x80) << 6) + $string[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($string[2] - 0x80)
<< 6) + $string[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $string[2] - 0x80;
}
return $code;
}
}
PK&d�[,���6classes/Gantry/Component/Controller/BaseController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
use Gantry\Framework\Request;
use RocketTheme\Toolbox\DI\Container;
use RuntimeException;
abstract class BaseController implements RestfulControllerInterface
{
/**
* @var string Default HTTP method.
*/
protected $method = 'GET';
/**
* @var Request
*/
protected $request;
/**
* @var array List of HTTP verbs and their actions.
*/
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/create' => 'create',
'/*' => 'display',
'/*/edit' => 'edit'
],
'POST' => [
'/' => 'store'
],
'PUT' => [
'/*' => 'replace'
],
'PATCH' => [
'/*' => 'update'
],
'DELETE' => [
'/*' => 'destroy'
]
];
/**
* @var array Parameters from router.
*/
protected $params = [];
/**
* @var Container
*/
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
$this->request = $container['request'];
}
/**
* Execute controller.
*
* @param string $method
* @param array $path
* @param array $params
* @return mixed
* @throws \RuntimeException
*/
public function execute($method, array $path, array $params)
{
$this->method = $method;
$this->setParams($params);
list($action, $path) = $this->resolveHttpVerb($method, $path);
if (!method_exists($this, $action)) {
$action = 'undefined';
}
return call_user_func_array([$this, $action], $path);
}
/**
* Set router parameters. Replaces the old parameters.
*
* @param array $params
* @return $this
*/
public function setParams(array $params)
{
$this->params = $params;
return $this;
}
/**
* @example GET /resources
*
* @return mixed
*/
public function index()
{
return $this->undefined();
}
/**
* @example GET /resources/:id
*
* @param string $id
* @return mixed
*/
public function display($id)
{
return $this->undefined();
}
/**
* Special sub-resource to create a new resource (returns a form).
*
* @example GET /resources/create
*
* @return mixed
*/
public function create()
{
return $this->undefined();
}
/**
* Special sub-resource to edit existing resource (returns a form).
*
* @example GET /resources/:id/edit
*
* @param string $id
* @return mixed
*/
public function edit($id)
{
return $this->undefined();
}
/**
* @example POST /resources
*
* @return mixed
*/
public function store()
{
return $this->undefined();
}
/**
* @example PUT /resources/:id
*
* @param string $id
* @return mixed
*/
public function replace($id)
{
return $this->undefined();
}
/**
* @example PATCH /resources/:id
*
* @param string $id
* @return mixed
*/
public function update($id)
{
return $this->undefined();
}
/**
* @example DELETE /resources/:id
*
* @param string $id
* @return mixed
*/
public function destroy($id)
{
return $this->undefined();
}
/**
* Catch all action for all undefined actions.
*
* @return mixed
* @throws RuntimeException
*/
public function undefined()
{
if (in_array($this->method, ['HEAD',
'GET'])) {
throw new RuntimeException('Page Not Found', 404);
}
throw new RuntimeException('Invalid Action', 405);
}
/**
* Catch all action for forbidden actions.
*
* @return mixed
* @throws RuntimeException
*/
public function forbidden()
{
throw new RuntimeException('Forbidden', 403);
}
/**
* Load resource.
*
* Function throws an exception if resource does not exist.
*
* @param string|int $id
* @throws \RuntimeException
*/
protected function loadResource($id)
{
throw new RuntimeException('Resource Not Found', 404);
}
/**
* Resolve HTTP verb.
*
* @param string $method
* @param array $items
* @return array [function, parameters]
*/
protected function resolveHttpVerb($method, array $items)
{
// HEAD has identical behavior to GET.
$method = ($method == 'HEAD') ? 'GET' :
$method;
if (!isset($this->httpVerbs[$method])) {
// HTTP method is not defined.
return ['undefined', $items];
}
$path = '';
$remaining = $items;
$variables = [];
$actions = $this->httpVerbs[$method];
// Build path for the verb and fetch all the variables.
while (($current = array_shift($remaining)) !== null) {
$test = "{$path}/{$current}";
if (!isset($actions[$test])) {
// Specific path not found, check if we have a variable.
$test = "{$path}/*";
if (isset($actions[$test])) {
// Variable found, save the value and move on.
$variables[] = $current;
} elseif (isset($actions[$test . '*'])) {
// Wildcard found, pass through rest of the variables.
$path = $test . '*';
$variables = array_merge($variables, [$current],
$remaining);
break;
} else {
// No matches; we are done here.
return ['undefined', $items];
}
}
// Path was found.
$path = $test;
}
// No matching path; check if we have verb for the root.
if (!$path && isset($actions['/'])) {
$path = '/';
}
// Get the action.
$action = $path ? $actions[$path] : 'undefined';
return [$action, $variables];
}
}
PK&d�[���006classes/Gantry/Component/Controller/HtmlController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
use Gantry\Component\Response\HtmlResponse;
use Gantry\Component\Response\Response;
abstract class HtmlController extends BaseController
{
/**
* Execute controller and returns Response object, defaulting to
HtmlResponse.
*
* @param string $method
* @param array $path
* @param array $params
* @return mixed
* @throws \RuntimeException
*/
public function execute($method, array $path, array $params)
{
$response = parent::execute($method, $path, $params);
if (!$response instanceof Response) {
$response = new HtmlResponse($response);
}
return $response;
}
}
PK&d�[0s���6classes/Gantry/Component/Controller/JsonController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
use Gantry\Component\Response\JsonResponse;
abstract class JsonController extends BaseController
{
/**
* Execute controller and returns JsonResponse object.
*
* @param string $method
* @param array $path
* @param array $params
* @return mixed
* @throws \RuntimeException
*/
public function execute($method, array $path, array $params)
{
$response = parent::execute($method, $path, $params);
if (!$response instanceof JsonResponse) {
$response = new JsonResponse($response);
}
return $response;
}
}
PK&d�[�VVaaBclasses/Gantry/Component/Controller/RestfulControllerInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
interface RestfulControllerInterface
{
/**
* @example GET /resources
*
* @return mixed
*/
public function index();
/**
* @example GET /resources/:id
*
* @param string $id
* @return mixed
*/
public function display($id);
/**
* Special sub-resource to create a new resource (returns a form).
*
* @example GET /resources/create
*
* @return mixed
*/
public function create();
/**
* Special sub-resource to edit existing resource (returns a form).
*
* @example GET /resources/:id/edit
*
* @param string $id
* @return mixed
*/
public function edit($id);
/**
* @example POST /resources
*
* @return mixed
*/
public function store();
/**
* @example PUT /resources/:id
*
* @param string $id
* @return mixed
*/
public function replace($id);
/**
* @example PATCH /resources/:id
*
* @param string $id
* @return mixed
*/
public function update($id);
/**
* @example DELETE /resources/:id
*
* @param string $id
* @return mixed
*/
public function destroy($id);
}
PK&d�[��7��.classes/Gantry/Component/File/CompiledFile.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\File;
use RocketTheme\Toolbox\File\PhpFile;
/**
* Class CompiledFile
* @package Grav\Common\File
*
* @property string $filename
* @property string $extension
* @property string $raw
* @property array|string $content
*/
trait CompiledFile
{
protected $cachePath;
protected $caching = true;
/**
* @param string $path
* @return $this
*/
public function setCachePath($path)
{
$this->cachePath = $path;
return $this;
}
public function caching($enabled = null)
{
if (null !== $enabled) {
$this->caching = (bool) $enabled;
}
return $this->caching;
}
/**
* Get/set parsed file contents.
*
* @param mixed $var
* @return string
* @throws \BadMethodCallException
*/
public function content($var = null)
{
if (!$this->cachePath) {
throw new \BadMethodCallException("Cache path not defined
for compiled file ({$this->filename})!");
}
try {
// If nothing has been loaded, attempt to get pre-compiled
version of the file first.
if ($var === null && $this->raw === null &&
$this->content === null) {
$modified = $this->modified();
if (!$modified || !$this->caching) {
return $this->decode($this->raw());
}
$key = md5($this->filename);
$file = PhpFile::instance($this->cachePath .
"/{$key}{$this->extension}.php");
$class = get_class($this);
$cache = $file->exists() ? $file->content() : null;
// Load real file if cache isn't up to date (or is
invalid).
if (!isset($cache['@class'])
|| $cache['@class'] != $class
|| $cache['modified'] != $modified
|| $cache['filename'] != $this->filename
) {
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will
check this in a bit.
}
// Decode RAW file into compiled array.
$data = $this->decode($this->raw());
$cache = [
'@class' => $class,
'filename' => $this->filename,
'modified' => $modified,
'data' => $data
];
// If compiled file wasn't already locked by
another process, save it.
if ($file->locked() !== false) {
$file->save($cache);
$file->unlock();
// Compile cached file into bytecode cache
if
(function_exists('opcache_invalidate')) {
// Silence error in case if
`opcache.restrict_api` directive is set.
@opcache_invalidate($file->filename(),
true);
} elseif
(function_exists('apc_compile_file')) {
// PHP 5.4
@apc_compile_file($file->filename());
}
}
}
$file->free();
$this->content = $cache['data'];
}
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Failed to read %s:
%s', basename($this->filename), $e->getMessage()), 500, $e);
}
return parent::content($var);
}
}
PK&d�[{BB2classes/Gantry/Component/File/CompiledYamlFile.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\File;
use RocketTheme\Toolbox\File\YamlFile;
class CompiledYamlFile extends YamlFile
{
use CompiledFile;
static public $defaultCachePath;
static public $defaultCaching = true;
protected function __construct()
{
parent::__construct();
$this->caching(static::$defaultCaching);
if (static::$defaultCachePath) {
$this->setCachePath(static::$defaultCachePath);
}
}
}
PK&d�[�{�+�+.classes/Gantry/Component/Filesystem/Folder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Filesystem;
/**
* Folder helper class.
*
* @author RocketTheme
* @license MIT
*/
abstract class Folder
{
/**
* Recursively find the last modified time under given path.
*
* @param string $path
* @return int
*/
public static function lastModifiedFolder($path)
{
$last_modified = 0;
$directory = new \RecursiveDirectoryIterator($path,
\RecursiveDirectoryIterator::SKIP_DOTS);
$iterator = new \RecursiveIteratorIterator($directory,
\RecursiveIteratorIterator::SELF_FIRST);
/** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $file) {
$dir_modified = $file->getMTime();
if ($dir_modified > $last_modified) {
$last_modified = $dir_modified;
}
}
return $last_modified;
}
/**
* Get relative path between target and base path. If path isn't
relative, return full path.
*
* @param string $path
* @param string $base
* @return string
*/
public static function getRelativePath($path, $base = GANTRY5_ROOT)
{
$base = preg_replace('![\\\/]+!', '/', $base);
$path = preg_replace('![\\\/]+!', '/', $path);
if (strpos($path, $base) === 0) {
$path = ltrim(substr($path, strlen($base)), '/');
}
return $path;
}
/**
* Get relative path between target and base path. If path isn't
relative, return full path.
*
* @param string $path
* @param string $base
* @return string
*/
public static function getRelativePathDotDot($path, $base)
{
$base = preg_replace('![\\\/]+!', '/', $base);
$path = preg_replace('![\\\/]+!', '/', $path);
if ($path === $base) {
return '';
}
$baseParts = explode('/', isset($base[0]) &&
'/' === $base[0] ? substr($base, 1) : $base);
$pathParts = explode('/', isset($path[0]) &&
'/' === $path[0] ? substr($path, 1) : $path);
array_pop($baseParts);
$lastPart = array_pop($pathParts);
foreach ($baseParts as $i => $directory) {
if (isset($pathParts[$i]) && $pathParts[$i] ===
$directory) {
unset($baseParts[$i], $pathParts[$i]);
} else {
break;
}
}
$pathParts[] = $lastPart;
$path = str_repeat('../', count($baseParts)) .
implode('/', $pathParts);
return '' === $path
|| '/' === $path[0]
|| false !== ($colonPos = strpos($path, ':'))
&& ($colonPos < ($slashPos = strpos($path, '/')) ||
false === $slashPos)
? "./$path" : $path;
}
/**
* Shift first directory out of the path.
*
* @param string $path
* @return string
*/
public static function shift(&$path)
{
$parts = explode('/', trim($path, '/'), 2);
$result = array_shift($parts);
$path = array_shift($parts);
return $result ?: null;
}
/**
* Return recursive list of all files and directories under given path.
*
* @param string $path
* @param array $params
* @return array
* @throws \RuntimeException
*/
public static function all($path, array $params = array())
{
if ($path === false) {
throw new \RuntimeException("Path to {$path} doesn't
exist.");
}
$compare = isset($params['compare']) ? 'get' .
$params['compare'] : null;
$pattern = isset($params['pattern']) ?
$params['pattern'] : null;
$filters = isset($params['filters']) ?
$params['filters'] : null;
$recursive = isset($params['recursive']) ?
$params['recursive'] : true;
$levels = isset($params['levels']) ?
$params['levels'] : -1;
$key = isset($params['key']) ? 'get' .
$params['key'] : null;
$value = isset($params['value']) ? 'get' .
$params['value'] : ($recursive ? 'getSubPathname' :
'getFilename');
$folders = isset($params['folders']) ?
$params['folders'] : true;
$files = isset($params['files']) ?
$params['files'] : true;
if ($recursive) {
$directory = new \RecursiveDirectoryIterator($path,
\RecursiveDirectoryIterator::SKIP_DOTS +
\FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
$iterator = new \RecursiveIteratorIterator($directory,
\RecursiveIteratorIterator::SELF_FIRST);
$iterator->setMaxDepth(max($levels, -1));
} else {
$iterator = new \FilesystemIterator($path);
}
$results = array();
/** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $file) {
// Ignore hidden files.
if ($file->getFilename()[0] == '.') {
continue;
}
if (!$folders && $file->isDir()) {
continue;
}
if (!$files && $file->isFile()) {
continue;
}
if ($compare && $pattern &&
!preg_match($pattern, $file->{$compare}())) {
continue;
}
$fileKey = $key ? $file->{$key}() : null;
$filePath = $file->{$value}();
if ($filters) {
if (isset($filters['key'])) {
$filter = $filters['key'];
$pre = !empty($filters['pre-key']) ?
$filters['pre-key'] : '';
if (is_callable($filter)) {
$fileKey = $pre . call_user_func($filter,
$fileKey);
} else {
$fileKey = $pre . preg_replace($filter,
'', $fileKey);
}
}
if (isset($filters['value'])) {
$filter = $filters['value'];
if (is_callable($filter)) {
$filePath = call_user_func($filter, $file);
} else {
$filePath = preg_replace($filter, '',
$filePath);
}
}
}
if ($fileKey !== null) {
$results[$fileKey] = $filePath;
} else {
$results[] = $filePath;
}
}
return $results;
}
/**
* Recursively copy directory in filesystem.
*
* @param string $source
* @param string $target
* @param string $ignore Ignore files matching pattern (regular
expression).
* @throws \RuntimeException
*/
public static function copy($source, $target, $ignore = null)
{
$source = rtrim($source, '\\/');
$target = rtrim($target, '\\/');
if (!is_dir($source)) {
throw new \RuntimeException('Cannot copy non-existing
folder.');
}
// Make sure that path to the target exists before copying.
self::create($target);
$success = true;
// Go through all sub-directories and copy everything.
$files = self::all($source);
foreach ($files as $file) {
if ($ignore && preg_match($ignore, $file)) {
continue;
}
$src = $source .'/'. $file;
$dst = $target .'/'. $file;
if (is_dir($src)) {
// Create current directory (if it doesn't exist).
if (!is_dir($dst)) {
$success &= @mkdir($dst, 0777, true);
}
} else {
// Or copy current file.
$success &= @copy($src, $dst);
}
}
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
// Make sure that the change will be detected when caching.
@touch(dirname($target));
}
/**
* Move directory in filesystem.
*
* @param string $source
* @param string $target
* @throws \RuntimeException
*/
public static function move($source, $target)
{
if (!is_dir($source)) {
throw new \RuntimeException('Cannot move non-existing
folder.');
}
// Make sure that path to the target exists before moving.
self::create(dirname($target));
// Just rename the directory.
$success = @rename($source, $target);
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
// Make sure that the change will be detected when caching.
@touch(dirname($source));
@touch(dirname($target));
}
/**
* Recursively delete directory from filesystem.
*
* @param string $target
* @param bool $include_target
* @throws \RuntimeException
*/
public static function delete($target, $include_target = true)
{
if (!$target) { return; }
if (!is_dir($target)) {
throw new \RuntimeException('Cannot delete non-existing
folder.');
}
$success = self::doDelete($target, $include_target);
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
// Make sure that the change will be detected when caching.
if ($include_target) {
@touch(dirname($target));
} else {
@touch($target);
}
}
/**
* @param string $folder
* @throws \RuntimeException
*/
public static function create($folder)
{
if (is_dir($folder)) {
return;
}
$success = @mkdir($folder, 0777, true);
if (!$success) {
// Take yet another look, make sure that the folder
doesn't exist.
clearstatcache(true, $folder);
if (is_dir($folder)) {
return;
}
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
}
/**
* @param string $folder
* @param bool $include_target
* @return bool
* @internal
*/
protected static function doDelete($folder, $include_target = true)
{
// Special case for symbolic links.
if ($include_target && is_link($folder)) {
return @unlink($folder);
}
// Go through all items in filesystem and recursively remove
everything.
$files = array_diff(scandir($folder), array('.',
'..'));
foreach ($files as $file) {
$path = "{$folder}/{$file}";
(is_dir($path)) ? self::doDelete($path) : @unlink($path);
}
return $include_target ? @rmdir($folder) : true;
}
}
PK&d�[ڀ}e
/classes/Gantry/Component/Filesystem/Streams.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Filesystem;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RocketTheme\Toolbox\StreamWrapper\ReadOnlyStream;
use RocketTheme\Toolbox\StreamWrapper\Stream;
class Streams
{
/**
* @var array
*/
protected $schemes = [];
/**
* @var array
*/
protected $registered;
/**
* @var UniformResourceLocator
*/
protected $locator;
public function __construct(UniformResourceLocator $locator = null)
{
if ($locator) {
$this->setLocator($locator);
}
}
/**
* @param UniformResourceLocator $locator
*/
public function setLocator(UniformResourceLocator $locator)
{
$this->locator = $locator;
// Set locator to both streams.
Stream::setLocator($locator);
ReadOnlyStream::setLocator($locator);
}
/**
* @return UniformResourceLocator
*/
public function getLocator()
{
return $this->locator;
}
public function add(array $schemes)
{
foreach ($schemes as $scheme => $config) {
$force = !empty($config['force']);
if (isset($config['paths'])) {
$this->locator->addPath($scheme, '',
$config['paths'], false, $force);
}
if (isset($config['prefixes'])) {
foreach ($config['prefixes'] as $prefix =>
$paths) {
$this->locator->addPath($scheme, $prefix, $paths,
false, $force);
}
}
$type = !empty($config['type']) ?
$config['type'] : 'ReadOnlyStream';
if ($type[0] != '\\') {
$type = '\\Rockettheme\\Toolbox\\StreamWrapper\\'
. $type;
}
$this->schemes[$scheme] = $type;
if (isset($this->registered)) {
$this->doRegister($scheme, $type);
}
}
}
public function register()
{
$this->registered = stream_get_wrappers();
foreach ($this->schemes as $scheme => $type) {
$this->doRegister($scheme, $type);
}
}
protected function doRegister($scheme, $type)
{
if (in_array($scheme, $this->registered)) {
stream_wrapper_unregister($scheme);
}
if (!stream_wrapper_register($scheme, $type)) {
throw new \InvalidArgumentException("Stream
'{$type}' could not be initialized.");
}
}
}
PK&d�[����WW/classes/Gantry/Component/Gantry/GantryTrait.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Gantry;
use Gantry\Framework\Gantry;
trait GantryTrait
{
/**
* @var Gantry
*/
private static $gantry;
/**
* Get global Gantry instance.
*
* @return Gantry
*/
public static function gantry()
{
// We cannot set variable directly for the trait as it doesn't
work in HHVM.
if (!self::$gantry) {
self::$gantry = Gantry::instance();
}
return self::$gantry;
}
}
PK&d�[�;o�,classes/Gantry/Component/Gettext/Gettext.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Gettext;
/**
* Class Gettext
* @package Gantry\Component\Gettext
*
* Examples on translating gettext in twig:
*
* {% trans string_var %}
* http://twig.sensiolabs.org/doc/extensions/i18n.html
*
* {% trans %}Hello {{ author.name }}{% endtrans %}
* http://symfony.com/doc/current/book/translation.html
*
* {{ 'Hello %name%'|trans({'%name%': name}) }}
* {{ trans('Hello %name%', {'%name%': name}) }}
*/
class Gettext
{
public $pos = 0;
public $str;
public $len;
public $endian = 'V';
public function parse($string)
{
$this->str = $string;
$this->len = strlen($string);
$magic = self::readInt() & 0xffffffff;
if ($magic === 0x950412de) {
// Low endian.
$this->endian = 'V';
} elseif ($magic === 0xde120495) {
// Big endian.
$this->endian = 'N';
} else {
throw new \Exception('Not a Gettext file (.mo)');
}
// Skip revision number.
self::readInt();
// Total count.
$total = self::readInt();
// Offset of original table.
$originals = self::readInt();
// Offset of translation table.
$translations = self::readInt();
$this->seek($originals);
$table_originals = self::readIntArray($total * 2);
$this->seek($translations);
$table_translations = self::readIntArray($total * 2);
$items = [];
for ($i = 0; $i < $total; $i++) {
$this->seek($table_originals[$i * 2 + 2]);
$original = $this->read($table_originals[$i * 2 + 1]);
if ($original) {
$this->seek($table_translations[$i * 2 + 2]);
$items[$original] = $this->read($table_translations[$i *
2 + 1]);
}
}
return $items;
}
/**
* @return int
*/
protected function readInt()
{
$read = $this->read(4);
if ($read === false) {
return false;
}
$read = unpack($this->endian, $read);
return array_shift($read);
}
/**
* @param $count
* @return array
*/
protected function readIntArray($count)
{
return unpack($this->endian . $count, $this->read(4 *
$count));
}
/**
* @param $bytes
* @return string
*/
private function read($bytes)
{
$data = substr($this->str, $this->pos, $bytes);
$this->seek($this->pos + $bytes);
return $data;
}
/**
* @param $pos
* @return mixed
*/
private function seek($pos)
{
$this->pos = max($this->len, $pos);
return $this->pos;
}
}
PK&d�[�xх����*classes/Gantry/Component/Layout/Layout.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Outlines;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Layout
*/
class Layout implements \ArrayAccess, \Iterator, ExportInterface
{
use ArrayAccess, Iterator, Export;
const VERSION = 7;
protected static $instances = [];
protected static $indexes = [];
protected $layout = ['wrapper', 'container',
'section', 'grid', 'block',
'offcanvas'];
public $name;
public $timestamp = 0;
public $preset = [];
public $equalized = [3 => 33.3, 6 => 16.7, 7 => 14.3, 8 =>
12.5, 9 => 11.1, 11 => 9.1, 12 => 8.3];
protected $exists;
protected $items;
protected $references;
protected $parents;
protected $blocks;
protected $types;
protected $inherit;
/**
* @return array
*/
public static function presets()
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
/** @var UniformResourceIterator $iterator */
$iterator = $locator->getIterator(
'gantry-layouts://',
UniformResourceIterator::CURRENT_AS_SELF |
UniformResourceIterator::UNIX_PATHS | UniformResourceIterator::SKIP_DOTS
);
$files = [];
/** @var UniformResourceIterator $info */
foreach ($iterator as $info) {
$name = $info->getBasename('.yaml');
if (!$info->isFile() || $info->getExtension() !==
'yaml' || $name[0] === '.') {
continue;
}
$files[] = $name;
}
sort($files);
$results = ['user' => [], 'system' =>
[]];
foreach ($files as $preset) {
$scope = $preset && $preset[0] !== '_' ?
'user' : 'system';
$results[$scope][$preset] =
ucwords(trim(preg_replace(['|_|', '|/|'], ['
', ' / '], $preset)));
}
return $results;
}
/**
* @param string $name
* @return array
* @throws \RuntimeException
*/
public static function preset($name)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-layouts://{$name}.yaml");
if (!$filename) {
throw new \RuntimeException(sprintf("Preset '%s'
not found", $name), 404);
}
$layout = LayoutReader::read($filename);
$layout['preset']['name'] = $name;
$layout['preset']['timestamp'] =
filemtime($filename);
return $layout;
}
/**
* @param string $name
* @return Layout
*/
public static function instance($name)
{
if (!isset(static::$instances[$name])) {
static::$instances[$name] = static::load($name);
}
return static::$instances[$name];
}
/**
* @param string $name
* @return Layout
*/
public static function index($name)
{
if (!isset(static::$indexes[$name])) {
static::$indexes[$name] = static::loadIndex($name, true);
}
return static::$indexes[$name];
}
/**
* @param string $name
* @param array $items
* @param array $preset
*/
public function __construct($name, array $items = null, array $preset =
null)
{
$this->name = $name;
$this->items = (array) $items;
$this->exists = $items !== null;
// Add preset data from the layout.
if ($preset) {
$this->preset = $preset;
} elseif (isset($this->items['preset'])) {
$this->preset = (array) $this->items['preset'];
}
unset($this->items['preset']);
$this->preset += [
'name' => '',
'timestamp' => 0,
'image' =>
'gantry-admin://images/layouts/default.png'
];
}
/**
* @return bool
*/
public function exists()
{
return $this->exists;
}
/**
* Initialize layout.
*
* @param bool $force
* @param bool $inherit
* @return $this
*/
public function init($force = false, $inherit = true)
{
if ($force || $this->references === null) {
$this->initReferences();
if ($inherit) {
$this->initInheritance();
}
}
return $this;
}
/**
* Build separate meta-information from the layout.
*
* @return array
*/
public function buildIndex()
{
return [
'name' => $this->name,
'timestamp' => $this->timestamp,
'version' => static::VERSION,
'preset' => $this->preset,
'positions' => $this->positions(),
'sections' => $this->sections(),
'particles' => $this->particles(),
'inherit' => $this->inherit()
];
}
/**
* @return $this
*/
public function clean()
{
$this->references = null;
$this->types = null;
$this->inherit = null;
$this->cleanLayout($this->items);
return $this;
}
/**
* @param string $old
* @param string $new
* @param array $ids
* @return $this
*/
public function updateInheritance($old, $new = null, $ids = null)
{
$this->init();
$inherit = $this->inherit();
if (!empty($inherit[$old])) {
foreach ($inherit[$old] as $id => $inheritId) {
$element = $this->find($id, false);
if ($element) {
$inheritId = isset($element->inherit->particle) ?
$element->inherit->particle : $id;
if ($new && ($ids === null ||
isset($ids[$inheritId]))) {
// Add or modify inheritance.
if (!isset($element->inherit)) {
$element->inherit = new \stdClass;
}
$element->inherit->outline = $new;
} else {
// Remove inheritance.
$element->inherit = new \stdClass;
unset($this->inherit[$element->id]);
}
} else {
// Element does not exist anymore, remove its
reference.
unset($this->inherit[$id]);
}
}
}
return $this;
}
/**
* Save layout.
*
* @param bool $cascade
* @return $this
*/
public function save($cascade = true)
{
if (!$this->name) {
throw new \LogicException('Cannot save unnamed
layout');
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Saving layout for outline
{$this->name}");
$name = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $this->name));
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// If there are atoms in the layout, copy them into outline
configuration.
$atoms = $this->atoms();
if (is_array($atoms) && $cascade) {
// Save layout into custom directory for the current theme.
$filename =
$locator->findResource("gantry-config://{$name}/page/head.yaml",
true, true);
$file = YamlFile::instance($filename);
$config = new Config($file->content());
$file->save($config->set('atoms',
json_decode(json_encode($atoms), true))->toArray());
$file->free();
}
// Remove atoms from the layout.
foreach ($this->items as $key => $section) {
if ($section->type === 'atoms') {
unset ($this->items[$key]);
}
}
// Make sure that base outline never uses inheritance.
if ($name === 'default') {
$this->inheritNothing();
}
$filename =
$locator->findResource("gantry-config://{$name}/layout.yaml",
true, true);
$file = CompiledYamlFile::instance($filename);
$file->settings(['inline' => 20]);
$file->save(LayoutReader::store($this->preset,
$this->items));
$file->free();
$this->timestamp = $file->modified();
$this->exists = true;
static::$instances[$this->name] = $this;
return $this;
}
public function export()
{
return LayoutReader::store($this->preset, $this->items);
}
/**
* Save index.
*
* @return $this
*/
public function saveIndex($index = null)
{
if (!$this->name) {
throw new \LogicException('Cannot save unnamed
layout');
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Saving layout index for outline
{$this->name}");
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-config://{$this->name}/index.yaml",
true, true);
$cache =
$locator->findResource("gantry-cache://{$this->name}/compiled/yaml",
true, true);
$file = CompiledYamlFile::instance($filename);
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
$index = $index ? $index : $this->buildIndex();
// If file wasn't already locked by another process, save it.
if ($file->locked() !== false) {
$file->setCachePath($cache)->settings(['inline'
=> 20]);
$file->save($index);
$file->unlock();
}
$file->free();
static::$indexes[$this->name] = $index;
return $this;
}
/**
* @return array
*/
public function getLayoutTypes()
{
return $this->layout;
}
/**
* @param string $type
* @return bool
*/
public function isLayoutType($type)
{
return in_array($type, $this->layout, true);
}
/**
* @param $id
* @return string|null
*/
public function getParentId($id)
{
return isset($this->parents[$id]) ? $this->parents[$id] :
null;
}
/**
* @return array
*/
public function references()
{
$this->init();
return $this->references;
}
/**
* @param string $type
* @param string $subtype
* @return array
*/
public function referencesByType($type = null, $subtype = null)
{
$this->init();
if (!$type) {
return $this->types;
}
if (!$subtype) {
return isset($this->types[$type]) ? $this->types[$type] :
[];
}
return isset($this->types[$type][$subtype]) ?
$this->types[$type][$subtype] : [];
}
/**
* Return list of positions (key) with their titles (value).
*
* @return array Array of position => title
*/
public function positions()
{
$positions = $this->referencesByType('position',
'position');
$list = [];
foreach($positions as $position) {
if (!isset($position->attributes->key)) {
continue;
}
$list[$position->attributes->key] = $position->title;
}
return $list;
}
/**
* Return list of positions (key) with their titles (value).
*
* @return array Array of position => title
*/
public function sections()
{
$list = [];
foreach ($this->referencesByType('section') as $type
=> $sections) {
foreach ($sections as $id => $section) {
$list[$id] = $section->title;
}
}
foreach ($this->referencesByType('offcanvas') as $type
=> $sections) {
foreach ($sections as $id => $section) {
$list[$id] = $section->title;
}
}
return $list;
}
/**
* Return list of particles with their titles.
*
* @param bool $grouped If true, group particles by type.
* @return array Array of position => title
*/
public function particles($grouped = true)
{
$blocks = $this->referencesByType('block',
'block');
$list = [];
foreach ($blocks as $blockId => $block) {
if (!empty($block->children)) {
foreach ($block->children as $id => $particle) {
if (!empty($particle->layout) ||
in_array($particle->type, $this->layout, true)) {
continue;
}
if ($grouped) {
$list[$particle->subtype][$particle->id] =
$particle->title;
} else {
$list[$particle->id] = $particle->title;
}
}
}
}
return $list;
}
/**
* @param string $outline
* @return array
*/
public function inherit($outline = null)
{
$this->init();
$list = [];
foreach ($this->inherit as $name => $item) {
if (isset($item->inherit->outline)) {
if (isset($item->inherit->particle)) {
$list[$item->inherit->outline][$name] =
$item->inherit->particle;
} else {
$list[$item->inherit->outline][$name] = $name;
}
}
}
return $outline ? (!empty($list[$outline]) ? $list[$outline] : [])
: $list;
}
/**
* Return atoms from the layout.
*
* @return array|null
* @deprecated
*/
public function atoms()
{
$list = null;
$atoms = array_filter($this->items, function ($section) {
return $section->type === 'atoms' &&
!empty($section->children);
});
$atoms = array_shift($atoms);
if (!empty($atoms->children)) {
$list = [];
foreach ($atoms->children as $grid) {
if (!empty($grid->children)) {
foreach ($grid->children as $block) {
if (isset($block->children[0])) {
$item = $block->children[0];
$list[] = ['title' =>
$item->title, 'type' => $item->subtype,
'attributes' => $item->attributes];
}
}
}
}
}
return $list;
}
/**
* @param string $id
* @param bool $createIfNotExists
* @return object
*/
public function find($id, $createIfNotExists = true)
{
$this->init();
if (!isset($this->references[$id])) {
return $createIfNotExists ? (object)['id' => $id,
'inherit' => new \stdClass] : null;
}
return $this->references[$id];
}
/**
* @param string $id
* @return null
*/
public function block($id)
{
$this->init();
return isset($this->blocks[$id]) ? $this->blocks[$id] : null;
}
public function clearSections()
{
$this->items = $this->clearChildren($this->items);
return $this;
}
protected function clearChildren(&$items)
{
foreach ($items as $key => $item) {
if (!empty($item->children)) {
$this->children =
$this->clearChildren($item->children);
}
if (empty($item->children) &&
in_array($item->type, ['grid', 'block',
'particle', 'position', 'spacer',
'system'], true)) {
unset($items[$key]);
}
}
return array_values($items);
}
public function copySections(array $old)
{
$this->init();
/** @var Layout $old */
$old = new static('tmp', $old);
$leftover = [];
// Copy normal sections.
$data = $old->referencesByType('section');
if (isset($this->types['section'])) {
$sections = $this->types['section'];
$this->copyData($data, $sections, $leftover);
}
// Copy offcanvas.
$data = $old->referencesByType('offcanvas');
if (isset($this->types['offcanvas'])) {
$offcanvas = $this->types['offcanvas'];
$this->copyData($data, $offcanvas, $leftover);
}
// Copy atoms.
$data = $old->referencesByType('atoms');
if (isset($this->types['atoms'])) {
$atoms = $this->types['atoms'];
$this->copyData($data, $atoms, $leftover);
}
return $leftover;
}
public function inheritAll()
{
foreach ($this->references() as $item) {
if (!empty($item->inherit->outline)) {
continue;
}
if (!$this->isLayoutType($item->type)) {
$item->inherit = (object) ['outline' =>
$this->name, 'include' => ['attributes',
'block']];
} elseif ($item->type === 'section' ||
$item->type === 'offcanvas') {
$item->inherit = (object) ['outline' =>
$this->name, 'include' => ['attributes',
'block', 'children']];
}
}
$this->init(true);
return $this;
}
public function inheritNothing()
{
foreach ($this->references() as $item) {
unset($item->inherit);
}
$this->init(true);
return $this;
}
protected function copyData(array $data, array $sections, array
&$leftover)
{
foreach ($data as $type => $items) {
foreach ($items as $item) {
$found = false;
if (isset($sections[$type])) {
foreach ($sections[$type] as $section) {
if ($section->id === $item->id) {
$found = true;
$section->inherit =
$this->cloneData($item->inherit);
$section->children =
$this->cloneData($item->children);
break;
}
}
}
if (!$found && !empty($item->children)) {
$leftover[$item->id] = $item->title;
}
}
}
}
/**
* Clone data which consists mixed set of arrays and stdClass objects.
*
* @param mixed $data
* @return mixed
*/
protected function cloneData($data)
{
if (!($isObject = is_object($data)) && !is_array($data)) {
return $data;
}
$clone = [];
foreach((array) $data as $key => $value) {
if (is_object($value) || is_array($value)) {
$clone[$key] = $this->cloneData($value);
} else {
$clone[$key] = $value;
}
}
return $isObject ? (object) $clone : $clone;
}
/**
* @param array $items
*/
protected function cleanLayout(array $items)
{
foreach ($items as $item) {
if (!empty($item->inherit->include)) {
$include = $item->inherit->include;
foreach ($include as $part) {
switch ($part) {
case 'attributes':
$item->attributes = new \stdClass();
break;
case 'block':
break;
case 'children':
$item->children = [];
break;
}
}
}
if (!empty($item->children)) {
$this->cleanLayout($item->children);
}
}
}
protected function initInheritance()
{
$index = null;
if ($this->name) {
$index = static::loadIndexFile($this->name);
}
$inheriting = $this->inherit();
if (GANTRY_DEBUGGER && $inheriting) {
\Gantry\Debugger::addMessage(sprintf("Layout from outline
%s inherits %s", $this->name, implode(", ",
array_keys($inheriting))));
}
foreach ($inheriting as $outlineId => $list) {
try {
$outline = $this->instance($outlineId);
} catch (\Exception $e) {
// Outline must have been deleted.
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Outline {$outlineId} is missing /
deleted", 'error');
$outline = null;
}
foreach ($list as $id => $inheritId) {
$item = $this->find($id);
$inheritId = !empty($item->inherit->particle) ?
$item->inherit->particle : $id;
$inherited = $outline ? $outline->find($inheritId) :
null;
$include = !empty($item->inherit->include) ? (array)
$item->inherit->include : [];
foreach ($include as $part) {
switch ($part) {
case 'attributes':
// Deep clone attributes.
$item->attributes =
isset($inherited->attributes) ?
$this->cloneData($inherited->attributes) : new \stdClass();
break;
case 'block':
$block = $this->block($id);
if (isset($block->attributes)) {
$inheritBlock = $outline ?
$this->cloneData($outline->block($inheritId)) : null;
$blockAttributes = $inheritBlock ?
array_diff_key((array)$inheritBlock->attributes, ['fixed'
=> 1, 'size' => 1]) : [];
$block->attributes =
(object)($blockAttributes + (array)$block->attributes);
}
break;
case 'children':
if (!empty($inherited->children)) {
// Deep clone children.
$item->children =
$this->cloneData($inherited->children);
$this->initReferences($item->children, $this->getParentId($id),
null,
['outline' => $outlineId,
'include' => ['attributes', 'block']],
$index);
} else {
$item->children = [];
}
break;
}
}
if (!$outline || !isset($inherited->attributes)) {
// Remove inheritance information if outline
doesn't exist.
$item->inherit = new \stdClass;
unset($this->inherit[$item->id]);
}
}
}
}
/**
* @param array $items
* @param object $parent
* @param object $block
* @param string $inherit
* @param array $index
*/
protected function initReferences(array $items = null, $parent = null,
$block = null, $inherit = null, array $index = null)
{
if ($items === null) {
$items = $this->items;
$this->references = [];
$this->types = [];
$this->inherit = [];
}
foreach ($items as $item) {
if (is_object($item)) {
$type = $item->type;
$subtype = !empty($item->subtype) ? $item->subtype :
$type;
if ($block) {
$this->parents[$item->id] = $parent;
}
if ($block) {
$this->blocks[$item->id] = $block;
}
if ($inherit && !$this->isLayoutType($type)) {
$item->inherit = (object) $inherit;
$item->inherit->particle = $item->id;
if
(isset($index['inherit'][$item->inherit->outline])
&& ($newId = array_search($item->id,
$index['inherit'][$item->inherit->outline], true))) {
$item->id = $newId;
} else {
$item->id = $this->id($type, $subtype);
}
}
if (isset($item->id)) {
if (isset($this->references[$item->id])) {
if ($type === 'block' || $type ===
'grid') {
$item->id = $this->id($type, $subtype);
}
// elseif (null === $inherit) {
// throw new \RuntimeException('Layout
reference conflict on #' . $item->id);
// }
}
$this->references[$item->id] = $item;
$this->types[$type][$subtype][$item->id] = $item;
if (!empty($item->inherit->outline)) {
$this->inherit[$item->id] = $item;
}
} else {
$this->types[$type][$subtype][] = $item;
}
if (isset($item->children) &&
is_array($item->children)) {
$this->initReferences($item->children, $type ===
'section' ? $item : $parent, $type === 'block' ? $item
: null, $inherit, $index);
}
}
}
}
/**
* @param string $type
* @param string $subtype
* @param string $id
* @return string
*/
protected function id($type, $subtype = null, $id = null)
{
$result = [];
if ($type !== 'particle') {
$result[] = $type;
}
if ($subtype && ($subtype !== $type || $subtype ===
'position')) {
$result[] = $subtype;
}
$key = implode('-', $result);
$key_id = $key . '-'. $id;
if (!$id || isset($this->references[$key_id])) {
while ($id = rand(1000, 9999)) {
$key_id = $key . '-'. $id;
if (!isset($this->references[$key_id])) {
break;
}
}
}
return $key_id;
}
/**
* Prepare block width sizes.
*
* @return $this
*/
public function prepareWidths()
{
$this->init();
$this->calcWidths($this->items);
return $this;
}
/**
* Recalculate block widths.
*
* @param array $items
* @internal
*/
protected function calcWidths(array &$items)
{
foreach ($items as $i => $item) {
if (empty($item->children)) {
continue;
}
$this->calcWidths($item->children);
$dynamicSize = 0;
$fixedSize = 0;
$childrenCount = 0;
foreach ($item->children as $child) {
if ($child->type !== 'block') {
continue;
}
$childrenCount++;
if (!isset($child->attributes->size)) {
$child->attributes->size = 100 /
count($item->children);
}
if (empty($child->attributes->fixed)) {
$dynamicSize += $child->attributes->size;
} else {
$fixedSize += $child->attributes->size;
}
}
if (!$childrenCount) {
continue;
}
$roundSize = round($dynamicSize, 1);
$equalized = isset($this->equalized[$childrenCount]) ?
$this->equalized[$childrenCount] : 0;
// force-casting string for testing comparison due to weird PHP
behavior that returns wrong result
if ($roundSize !== 100 && (string) $roundSize !==
(string) ($equalized * $childrenCount)) {
$fraction = 0;
$multiplier = (100 - $fixedSize) / ($dynamicSize ?: 1);
foreach ($item->children as $child) {
if ($child->type !== 'block') {
continue;
}
if (!empty($child->attributes->fixed)) {
continue;
}
// Calculate size for the next item by taking account
the rounding error from the last item.
// This will allow us to approximate cumulating error
and fix it when rounding error grows
// over the rounding treshold.
$size = ($child->attributes->size * $multiplier)
+ $fraction;
$newSize = round($size);
$fraction = $size - $newSize;
$child->attributes->size = $newSize;
}
}
}
}
/**
* @param string $name
* @param string $preset
* @return static
*/
public static function load($name, $preset = null)
{
if (!$name) {
throw new \BadMethodCallException('Layout needs to have a
name');
}
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$layout = null;
$filename =
$locator("gantry-config://{$name}/layout.yaml");
// If layout file doesn't exists, figure out what preset was
used.
if (!$filename) {
// Attempt to load the index file.
$indexFile =
$locator("gantry-config://{$name}/index.yaml");
if ($indexFile || !$preset) {
$index = static::loadIndex($name, true);
$preset = $index['preset']['name'];
}
try {
$layout = static::preset($preset);
} catch (\Exception $e) {
// Layout doesn't exist, do nothing.
}
} else {
$layout = LayoutReader::read($filename);
}
return new static($name, $layout);
}
protected static function loadIndexFile($name)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Attempt to load the index file.
$indexFile =
$locator("gantry-config://{$name}/index.yaml");
if ($indexFile) {
$file = CompiledYamlFile::instance($indexFile);
$index = (array)$file->content();
$file->free();
} else {
$index = [];
}
return $index;
}
/**
* @param string $name
* @param bool $autoSave
* @return array
*/
public static function loadIndex($name, $autoSave = false)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$index = static::loadIndexFile($name);
// Find out the currently used layout file.
$layoutFile =
$locator("gantry-config://{$name}/layout.yaml");
if (!$layoutFile) {
/** @var Outlines $outlines */
$outlines = $gantry['outlines'];
$preset = isset($index['preset']['name']) ?
$index['preset']['name'] : $outlines->preset($name);
}
// Get timestamp for the layout file.
$timestamp = $layoutFile ? filemtime($layoutFile) : 0;
// If layout index file doesn't exist or is not up to date,
rebuild it.
if (empty($index['timestamp']) ||
$index['timestamp'] != $timestamp ||
!isset($index['version']) || $index['version'] !=
static::VERSION) {
$layout = isset($preset) ? new static($name,
static::preset($preset)) : static::instance($name);
$layout->timestamp = $timestamp;
if ($autoSave) {
if (!$layout->timestamp) {
$layout->save();
}
$index = $layout->buildIndex();
$layout->saveIndex($index);
} else {
$index = $layout->buildIndex();
}
}
$index += [
'name' => $name,
'timestamp' => $timestamp,
'preset' => [
'name' => '',
'image' =>
'gantry-admin://images/layouts/default.png'
],
'positions' => [],
'sections' => [],
'inherit' => []
];
return $index;
}
public function check(array $children = null)
{
if ($children === null) {
$children = $this->items;
}
foreach ($children as $item) {
if (!$item instanceof \stdClass) {
throw new \RuntimeException('Invalid layout
element');
}
if (!isset($item->type)) {
throw new \RuntimeException('Type missing');
}
if (!isset($item->subtype)) {
throw new \RuntimeException('Subtype missing');
}
if (!isset($item->attributes)) {
throw new \RuntimeException('Attributes
missing');
}
if (!is_object($item->attributes)) {
throw new \RuntimeException('Attributes not
object');
}
if (isset($item->children)) {
if (!is_array($item->children)) {
throw new \RuntimeException('Children not
array');
}
$this->check($item->children);
}
}
}
}
PK&d�[.|�G
0classes/Gantry/Component/Layout/LayoutReader.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout;
use Gantry\Component\File\CompiledYamlFile;
/**
* Read layout from yaml file.
*/
class LayoutReader
{
/**
* Get layout version.
*
* @param array $data
* @return int
*/
public static function version(array &$data)
{
if (isset($data['version'])) {
return $data['version'];
}
return isset($data['children']) &&
is_array($data['children']) ? 0 : 1;
}
/**
* Make layout from array data.
*
* @param array $data
* @return array
*/
public static function data(array $data)
{
$version = static::version($data);
$reader = static::getClass($version, $data);
$result = $reader->load();
// Make sure that all preset values are set by defining defaults.
$result['preset'] += [
'name' => '',
'image' =>
'gantry-admin://images/layouts/default.png'
];
return $result;
}
/**
* Read layout from yaml file and return parsed version of it.
*
* @param string $file
* @return array
*/
public static function read($file)
{
if (!$file) {
return [];
}
$file = CompiledYamlFile::instance($file);
$content = (array) $file->content();
$file->free();
return static::data($content);
}
/**
* Convert layout into file format.
*
* @param array $preset
* @param array $structure
* @param int $version
* @return mixed
*/
public static function store(array $preset, array $structure, $version
= 2)
{
$reader = static::getClass($version);
return $reader->store($preset, $structure);
}
/**
* @param int $version
* @param array $data
* @return object
*/
protected static function getClass($version, array $data = [])
{
$class =
"Gantry\\Component\\Layout\\Version\\Format{$version}";
if (!class_exists($class)) {
throw new \RuntimeException('Layout file cound not be
read: unsupported version {$version}.');
}
return new $class($data);
}
}
PK&d�[Q�E���3classes/Gantry/Component/Layout/Version/Format0.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout\Version;
/**
* Read layout from Layout Manager yaml file.
*/
class Format0 extends Format1
{
/**
* @return array
*/
public function load()
{
$data = &$this->data;
$preset = isset($data['preset']) &&
is_array($data['preset']) ? $data['preset'] : [];
$result = is_array($data['children']) ?
$this->object($data['children']) : [];
$invisible = [
'offcanvas' =>
$this->parse('offcanvas', [], 0),
'atoms' => $this->parse('atoms', [],
0)
];
foreach ($result as $key => &$item) {
if (isset($invisible[$item->type])) {
$invisible[$item->type] = $item;
unset($result[$key]);
}
}
$result += $invisible;
$result = array_values($result);
return ['preset' => $preset] + $result;
}
protected function object(array $items, $container = true)
{
foreach ($items as &$item) {
$item = (object) $item;
if (isset($item->attributes) &&
(is_array($item->attributes) || is_object($item->attributes))) {
$item->attributes = (object) $item->attributes;
} else {
$item->attributes = (object) [];
}
if (!empty($item->children) &&
is_array($item->children)) {
$item->children = $this->object($item->children,
false);
}
$this->normalize($item, $container);
}
return $items;
}
}
PK&d�[��+�#�#3classes/Gantry/Component/Layout/Version/Format1.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout\Version;
/**
* Read layout from simplified yaml file.
*/
class Format1
{
protected $scopes = [0 => 'grid', 1 =>
'block'];
protected $data;
protected $keys = [];
public function __construct(array $data)
{
$this->data = $data;
}
public function load()
{
$data = &$this->data;
// Check if we have preset.
$preset = [];
if (isset($data['preset']) &&
is_array($data['preset']) &&
isset($data['layout']) &&
is_array($data['layout'])) {
$preset = $data['preset'];
$data = $data['layout'];
}
// We have user entered file; let's build the layout.
// Two last items are always offcanvas and atoms.
$offcanvas = isset($data['offcanvas']) ?
$data['offcanvas'] : [];
$atoms = isset($data['atoms']) ? $data['atoms']
: [];
unset($data['offcanvas'], $data['atoms']);
$data['offcanvas'] = $offcanvas;
if ($atoms) {
$data['atoms'] = $atoms;
}
$result = [];
foreach ($data as $field => $params) {
$child = $this->parse($field, (array) $params, 0);
unset($child->size);
$result[] = $child;
}
return ['preset' => $preset] + $result;
}
public function store(array $preset, array $structure)
{
return ['preset' => $preset, 'children'
=> $structure];
}
protected function normalize(&$item, $container = false)
{
if ($item->type === 'pagecontent') {
// Update pagecontent to match the new standards.
$item->type = 'system';
if (!$item->subtype || $item->subtype ==
'pagecontent') {
$item->subtype = 'content';
$item->title = 'Page Content';
} else {
$item->subtype ='messages';
$item->title = 'System Messages';
}
}
if ($item->type === 'section') {
// Update section to match the new standards.
$section = strtolower($item->title);
$item->id = $section;
$item->subtype = (in_array($section, ['aside',
'nav', 'article', 'header',
'footer', 'main']) ? $section : 'section');
} elseif ($item->type === 'offcanvas') {
$item->id = $item->subtype = $item->type;
unset ($item->attributes->name,
$item->attributes->boxed);
return;
} else {
// Update all ids to match the new standards.
$item->id = $this->id($item->type, $item->subtype);
}
if (!empty($item->attributes->extra)) {
foreach ($item->attributes->extra as $i => $extra) {
$v = reset($extra);
$k = key($extra);
if ($k === 'id') {
$item->id = preg_replace('/^g-/',
'', $v);
$item->attributes->id = $v;
unset ($item->attributes->extra[$i]);
}
}
if (empty($item->attributes->extra)) {
unset ($item->attributes->extra);
}
}
$item->subtype = $item->subtype ?: $item->type;
$item->layout = in_array($item->type, ['container',
'section', 'grid', 'block',
'offcanvas']);
if (isset($item->attributes->boxed)) {
// Boxed already set, just change boxed=0 to boxed=''
to use default settings.
$item->attributes->boxed = $item->attributes->boxed
?: '';
return;
}
if (!$container) {
return;
}
// Update boxed model to match the new standards.
if (isset($item->children) && count($item->children)
=== 1) {
$child = reset($item->children);
if ($item->type === 'container') {
// Remove parent container only if the only child is a
section.
if ($child->type === 'section') {
$child->attributes->boxed = 1;
$item = $child;
}
$item->attributes->boxed = '';
} elseif ($child->type === 'container') {
// Remove child container.
$item->attributes->boxed = '';
$item->children = $child->children;
}
}
}
/**
* @param int|string $field
* @param array $content
* @param int $scope
* @param bool|null $container
* @return array
*/
protected function parse($field, array $content, $scope, $container =
true)
{
if (is_numeric($field)) {
// Row or block
$type = $this->scopes[$scope];
$result = (object) ['id' => null, 'type'
=> $type, 'subtype' => $type, 'layout' =>
true, 'attributes' => (object) []];
$scope = ($scope + 1) % 2;
} elseif (substr($field, 0, 9) == 'container') {
// Container
$type = 'container';
$result = (object) ['id' => null, 'type'
=> $type, 'subtype' => $type, 'layout' =>
true, 'attributes' => (object) []];
$id = substr($field, 10) ?: null;
if ($id !== null) {
$result->attributes->id = $id;
}
} else {
// Section
$list = explode(' ', $field, 2);
$field = array_shift($list);
$size = ((float) array_shift($list)) ?: null;
$type = in_array($field, ['atoms',
'offcanvas']) ? $field : 'section';
$subtype = in_array($field, ['aside',
'nav', 'article', 'header',
'footer', 'main']) ? $field : 'section';
$result = (object) [
'id' => null,
'type' => $type,
'subtype' => $subtype,
'layout' => true,
'title' => ucfirst($field),
'attributes' => (object) ['id' =>
'g-' . $field]
];
if ($size) {
$result->size = $size;
}
}
if (!empty($content)) {
$result->children = [];
foreach ($content as $child => $params) {
if (is_array($params)) {
$child = $this->parse($child, $params, $scope,
false);
} else {
$child = $this->resolve($params, $scope);
}
if (!empty($child->size)) {
$result->attributes->size = $child->size;
}
unset($child->size);
$result->children[] = $child;
}
}
$this->normalize($result, $container);
return $result;
}
/**
* @param string $field
* @param int $scope
* @return array
*/
protected function resolve($field, $scope)
{
$list = explode(' ', $field, 2);
$list2 = explode('-', array_shift($list), 2);
$size = ((float) array_shift($list)) ?: null;
$type = array_shift($list2);
$subtype = array_shift($list2) ?: false;
$title = ucfirst($subtype ?: $type);
$attributes = new \stdClass;
$attributes->enabled = 1;
if ($subtype && $type === 'position') {
$attributes->key = $subtype;
$subtype = false;
}
$result = (object) ['id' => $this->id($type,
$subtype), 'title' => $title, 'type' => $type,
'subtype' => $subtype, 'attributes' =>
$attributes];
$this->normalize($result);
if ($scope > 1) {
if ($size) {
$result->attributes->size = $size;
}
return $result;
}
if ($scope <= 1) {
$result = (object) ['id' =>
$this->id('block'), 'type' => 'block',
'subtype' => 'block', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
if ($size) {
$result->attributes->size = $size;
}
}
if ($scope == 0) {
$result = (object) ['id' =>
$this->id('grid'), 'type' => 'grid',
'subtype' => 'grid', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
}
return $result;
}
protected function id($type, $subtype = null)
{
if ($type === 'atoms') {
return $type;
}
$result = [];
if ($type !== 'particle' && $type !==
'atom') {
$result[] = $type;
}
if ($subtype && $subtype !== $type) {
$result[] = $subtype;
}
$key = implode('-', $result);
while ($id = rand(1000, 9999)) {
if (!isset($this->keys[$key][$id])) {
break;
}
}
$this->keys[$key][$id] = true;
return $key . '-'. $id;
}
}
PK&d�[��]��E�E3classes/Gantry/Component/Layout/Version/Format2.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout\Version;
/**
* Read layout from simplified yaml file.
*/
class Format2
{
protected $scopes = [0 => 'grid', 1 =>
'block'];
protected $sections = ['wrapper', 'container',
'section', 'grid', 'block',
'offcanvas'];
protected $structures = ['div', 'section',
'aside', 'nav', 'article',
'header', 'footer', 'main'];
protected $data;
protected $structure;
protected $content;
protected $keys;
/**
* @param array $data
*/
public function __construct(array $data = [])
{
$this->data = $data;
}
/**
* @return array
*/
public function load()
{
$data = &$this->data;
// Parse layout.
$result = [];
foreach ($data['layout'] as $field => &$params) {
if (!is_array($params)) {
$params = [];
}
$child = $this->parse($field, $params);
unset($child->size);
$result[] = $child;
}
return ['preset' => $data['preset']] +
$result;
}
/**
* @param array $preset
* @param array $structure
* @return array
*/
public function store(array $preset, array $structure)
{
$this->structure = [];
$this->content = [];
$structure = ['children' =>
json_decode(json_encode($structure), true)];
$structure = $this->build($structure);
$result = [
'version' => 2,
'preset' => $preset,
'layout' => $structure
];
if ($this->structure) {
$result['structure'] = $this->structure;
}
if ($this->content) {
$result['content'] = $this->content;
}
return $result;
}
/**
* @param int|string $field
* @param array $content
* @param int $scope
* @param object $parent
* @return array
*/
protected function parse($field, array &$content, $scope = 0,
$parent = null)
{
if (is_numeric($field)) {
// Row or block
$result = (object)['id' =>
$this->id($this->scopes[$scope]), 'type' =>
$this->scopes[$scope], 'subtype' =>
$this->scopes[$scope], 'layout' => true,
'attributes' => (object)[]];
$scope = ($scope + 1) % 2;
} else {
list ($type, $subtype, $id, $size, $section_id, $boxed) =
$this->parseSectionString($field);
if ($type == 'grid') {
$scope = 1;
}
if ($type == 'block') {
$scope = 0;
}
// Build object.
$result =
isset($this->data['structure'][$section_id]) ? (array)
$this->data['structure'][$section_id] : [];
$result += [
'id' => $section_id,
'layout' => true,
'type' => $type,
'subtype' => $subtype,
'title' => $this->getTitle($type, $subtype,
$id),
'attributes' => []
];
if (isset($boxed) &&
!isset($result['attributes']['boxed'])) {
$result['attributes']['boxed'] =
$boxed;
}
if ($parent && $parent->type === 'block'
&& !empty($result['block'])) {
$parent->attributes = (object)
($result['block'] + (array) $parent->attributes);
}
unset ($result['block']);
$result = (object) $result;
$result->attributes = (object) $result->attributes;
if (isset($result->inherit)) {
$result->inherit = (object) $result->inherit;
}
if ($size) {
$result->size = $size;
}
if (($type === 'grid' || $type === 'block')
&& !isset($result->attributes->id)) {
$result->attributes->id = $section_id;
}
}
if (!empty($content)) {
$result->children = [];
foreach ($content as $child => &$params) {
if (!$params && !is_array($params)) {
$params = [];
}
if (is_array($params)) {
$child = $this->parse($child, $params, $scope,
$result);
} else {
$child = $this->resolve($params, $scope, $result);
}
if (!empty($child->size)) {
$result->attributes->size = $child->size;
}
unset($child->size);
$result->children[] = $child;
}
}
return $result;
}
/**
* @param string $field
* @param int $scope
* @param object $parent
* @return array
*/
protected function resolve($field, $scope, $parent)
{
list ($type, $subtype, $id, $size, $content_id) =
$this->parseContentString($field);
$title = $this->getTitle($type, $subtype, $id);
$result = isset($this->data['content'][$content_id]) ?
(array) $this->data['content'][$content_id] : [];
$result += ['id' => $this->id($type, $subtype,
$id), 'title' => $title, 'type' => $type,
'subtype' => $subtype, 'attributes' => []];
$result['attributes'] = (object)
($result['attributes'] + ['enabled' => 1]);
if (isset($result['inherit'])) {
$result['inherit'] = (object)
$result['inherit'];
}
if (isset($result['block'])) {
$block = $result['block'];
unset ($result['block']);
}
$result = (object) $result;
if ($type === 'position' &&
!isset($result->attributes->key) && !in_array($subtype,
['module', 'widget'])) {
$result->attributes->key = $id;
}
if ($scope > 1) {
if ($parent->type === 'block' &&
!empty($block)) {
$parent->attributes = (object) ($block + (array)
$parent->attributes);
}
if ($size) {
$result->attributes->size = $size;
}
}
if ($scope <= 1) {
$result = (object) ['id' =>
$this->id('block'), 'type' => 'block',
'subtype' => 'block', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
if (!empty($block)) {
$result->attributes = (object) $block;
}
if ($size) {
$result->attributes->size = $size;
}
}
if ($scope == 0) {
$result = (object) ['id' =>
$this->id('grid'), 'type' => 'grid',
'subtype' => 'grid', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
}
return $result;
}
/**
* @param array $content
* @return array|null
*/
protected function build(array &$content)
{
$result = [];
$ctype = isset($content['type']) ?
$content['type'] : null;
if (in_array($ctype, ['grid', 'block'])) {
if (empty($content['attributes']['id']) ||
$content['attributes']['id'] ===
$content['id']) {
unset ($content['attributes']['id']);
}
}
if ($ctype === 'block') {
if (empty($content['attributes']['extra']))
{
unset
($content['attributes']['extra']);
}
if (empty($content['attributes']['fixed']))
{
unset
($content['attributes']['fixed']);
}
}
if ($ctype === 'section') {
if (empty($content['attributes']['extra']))
{
unset
($content['attributes']['extra']);
}
}
if (!isset($content['children'])) {
$content['children'] = [];
}
unset ($content['layout']);
// Clean up all items for saving.
foreach ($content['children'] as &$child) {
$size = null;
$id = $child['id'];
$type = $child['type'];
$subtype = $child['subtype'];
$isSection = in_array($type, $this->sections);
if (empty($child['inherit']['outline']) ||
empty($child['inherit']['include'])) {
unset ($child['inherit']);
} else {
foreach ($child['inherit']['include']
as $include) {
switch ($include) {
case 'attributes':
unset($child['attributes']);
break;
case 'block':
if ($ctype === 'block') {
// Keep block size and fixed status.
$attributes =
!empty($content['attributes']) ? $content['attributes']
: [];
$content['attributes'] =
array_intersect_key($attributes, ['fixed' => 1,
'size' => 1]);
}
break;
case 'children':
$child['children'] = [];
break;
}
}
}
if (!$isSection) {
// Special handling for positions.
if ($type === 'position') {
// TODO: we may want to simplify position id, but we
need to take into account multiple instances of the same position key.
/*
if (!$subtype || $subtype === 'position') {
$id = 'position-' .
(isset($child['attributes']['key']) ?
$child['attributes']['key'] : rand(1000,9999));
unset
($child['attributes']['key']);
}
*/
unset
($child['attributes']['title']);
}
$value = $id;
if
(!empty($child['attributes']['enabled'])) {
unset
($child['attributes']['enabled']);
}
} else {
// Recursively handle structure.
$value = $this->build($child);
}
// Clean up defaults.
if (empty($child['title']) ||
$child['title'] === 'Untitled' ||
$child['title'] === $this->getTitle($type, $subtype, $id)) {
unset ($child['title']);
}
if (!$subtype || $subtype === $type) {
unset ($child['subtype']);
}
// Remove id and children as we store data in flat structure
with id being the key.
unset ($child['id'], $child['children']);
if ($type === 'offcanvas' &&
isset($child['attributes']['name'])) {
unset ($child['attributes']['name']);
}
if ($ctype === 'block') {
// Embed size into array key/value.
if
(isset($content['attributes']['size']) &&
$content['attributes']['size'] != 100) {
$size =
$content['attributes']['size'];
}
unset ($content['attributes']['size']);
// Embed parent block.
if (!empty($content['attributes'])) {
$child['block'] =
$content['attributes'];
unset ($content['attributes']);
}
}
if (isset($child['attributes']['size'])) {
if ($child['attributes']['size'] != 100
&& is_string($value)) {
$size =
$child['attributes']['size'];
}
unset ($child['attributes']['size']);
}
// Remove attributes if there aren't any.
if (empty($child['attributes'])) {
unset ($child['attributes']);
}
// Special handling for grid and block elements.
if (in_array($type, ['grid', 'block'])
&& count($child) === 1 && isset($child['type']))
{
$id = null;
}
// Check if type and subtype can be generated from the id.
if ($subtype &&
(preg_match("/^{$type}-{$subtype}(-|$)/", $id))
|| (in_array($type, ['section',
'particle']) &&
preg_match("/^{$subtype}(-|$)/", $id))) {
unset ($child['type'],
$child['subtype']);
} elseif (preg_match("/^{$type}(-|$)/", $id)) {
unset ($child['type']);
}
// Add item configuration if not empty.
if ($id && !empty($child)) {
if (!is_string($value)) {
$this->structure[$id] = $child;
} else {
$this->content[$id] = $child;
}
}
// Add item to the layout.
if (!is_string($value)) {
// Add structural item.
if ($id) {
// Sections and other complex items.
$id =
isset($child['attributes']['boxed']) ?
"/{$id}/" : $id;
$result[trim("{$id} {$size}")] = $value;
} elseif (!empty($value)) {
// Simple grid / block item.
$result[] = $value;
}
} else {
// Add content item.
$result[] = trim("{$value} {$size}");
}
}
// TODO: maybe collapse grid as well?
if ($ctype && in_array($ctype, ['block'])
&& count($result) <= 1 && key($result) === 0) {
unset ($this->structure[$content['id']]);
return reset($result) ?: null;
}
return $result;
}
/**
* @param string $string
* @return array
*/
protected function parseSectionString($string)
{
// Extract: "[section-id] [size]".
$list = explode(' ', $string, 2);
$section_id = array_shift($list);
$size = ((float) array_shift($list)) ?: null;
// Extract slashes from "/[section-id]/".
$boxedLeft = $section_id[0] === '/';
$boxedRight = $section_id[strlen($section_id)-1] === '/';
$boxed = ($boxedLeft && $boxedRight ? '' :
($boxedLeft ? '1' : ($boxedRight ? '0' : null)));
$section_id = trim($section_id, '/');
// Extract section id if it exists: "[section]-[id]".
$list = explode('-', $section_id, 2);
// Get section and its type.
$section = reset($list);
$type = (in_array($section, $this->sections)) ? $section :
'section';
$subtype = ($type !== 'section' || in_array($section,
$this->structures)) ? $section : 'section';
// Extract id.
if ($type == 'section' && in_array($section,
$this->structures)) {
$id = array_pop($list);
} else {
$id = $section_id;
}
return [$type, $subtype, $id, $size, $section_id, $boxed];
}
/**
* @param string $string
* @return array
*/
protected function parseContentString($string)
{
// Extract: "[type-subtype] [size]".
$list = explode(' ', $string, 2);
$content_id = array_shift($list);
$size = ((float) array_shift($list)) ?: null;
// Extract sub-type if it exists:
"[type]-[subtype]-[id]".
$list = explode('-', $content_id);
// Get type, subtype and id.
$type = reset($list);
$test = end($list);
$id = ((string)(int) $test === (string) $test) ? array_pop($list) :
null;
if (in_array($type, ['system', 'position',
'particle', 'spacer'])) {
array_shift($list);
} else {
$type = 'particle';
}
$subtype = implode('-', $list);
if ($type === 'position' && !in_array($subtype,
['module', 'widget'])) {
$id = ($subtype ?: $type) . ($id !== null ? "-{$id}"
: '');
$subtype = 'position';
}
return [$type, $subtype ?: $type, $id, $size, $content_id];
}
/**
* @param string $type
* @param string $subtype
* @param string $id
* @return string
*/
protected function getTitle($type, $subtype, $id)
{
if (in_array($type, $this->sections)) {
if ($type === 'offcanvas') {
return 'Offcanvas';
}
if ($type === 'grid' || $type === 'block')
{
return null;
}
return ucfirst((string)(int) $id === (string) $id ? ($subtype
?: $type) . "-{$id}" : $id);
}
if ($type === 'position' && !in_array($subtype,
['module', 'widget'])) {
return
ucfirst(preg_replace('/^position-(.*?[a-z])/ui', '\1',
$id));
}
if ($type === 'system') {
if ($subtype === 'messages') {
return 'System Messages';
}
if ($subtype === 'content') {
return 'Page Content';
}
}
return ucfirst($subtype ?: $type);
}
/**
* @param string $type
* @param string $subtype
* @param string $id
* @return string
*/
protected function id($type, $subtype = null, $id = null)
{
$result = [];
if ($type !== 'particle') {
$result[] = $type;
}
if ($subtype && $subtype !== $type) {
$result[] = $subtype;
}
$key = implode('-', $result);
if (!$id || isset($this->keys[$key][$id])) {
while ($id = rand(1000, 9999)) {
if (!isset($this->keys[$key][$id])) {
break;
}
}
}
$this->keys[$key][$id] = true;
return $key . '-'. $id;
}
}
PK&d�[j픞--.classes/Gantry/Component/Menu/AbstractMenu.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Menu;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Gantry\GantryTrait;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
use RocketTheme\Toolbox\ArrayTraits\Countable;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class AbstractMenu implements \ArrayAccess, \Iterator, \Countable
{
use GantryTrait, ArrayAccessWithGetters, Iterator, Export, Countable;
protected $default;
protected $base;
protected $active;
protected $params;
protected $override = false;
protected $config;
/**
* @var array|Item[]
*/
protected $items;
/**
* @var Config|null
*/
protected $pathMap;
protected $defaults = [
'menu' => '',
'base' => '/',
'startLevel' => 1,
'maxLevels' => 0,
'showAllChildren' => true,
'highlightAlias' => true,
'highlightParentAlias' => true
];
abstract public function __construct();
/**
* Return list of menus.
*
* @return array
*/
abstract public function getMenus();
/**
* Return default menu.
*
* @return string
*/
public function getDefaultMenuName()
{
return null;
}
/**
* Returns true if the platform implements a Default menu.
*
* @return boolean
*/
public function hasDefaultMenu()
{
return false;
}
/**
* Return active menu.
*
* @return string
*/
public function getActiveMenuName()
{
return null;
}
/**
* Returns true if the platform implements an Active menu.
*
* @return boolean
*/
public function hasActiveMenu()
{
return false;
}
/**
* @param array $params
* @param Config $menu
* @return AbstractMenu
*/
public function instance(array $params = [], Config $menu = null)
{
$params = $params + $this->defaults;
$menus = $this->getMenus();
if (!$menus) {
throw new \RuntimeException('Site does not have
menus', 404);
}
if (empty($params['menu'])) {
$params['menu'] = $this->getDefaultMenuName();
if (!$params['menu'] &&
!empty($params['admin'])) {
// In admin just select the first menu if there isn't
default menu to be selected.
$params['menu'] = reset($menus);
};
} elseif ($params['menu'] == '-active-') {
$params['menu'] = $this->getActiveMenuName();
}
if (!$params['menu']) {
throw new \RuntimeException('No menu selected', 404);
}
if (!in_array($params['menu'], $menus)) {
throw new \RuntimeException('Menu not found', 404);
}
$instance = clone $this;
$instance->params = $params;
if ($menu) {
$instance->override = true;
$instance->config = $menu;
} else {
$instance->config = null;
}
$config = $instance->config();
$items = isset($config['items']) ?
$config['items'] : [];
// Create menu structure.
$instance->init($params);
// Get menu items from the system (if not specified otherwise).
if ($config->get('settings.type') !==
'custom') {
$instance->getList($params, $items);
}
// Add custom menu items.
$instance->addCustom($params, $items);
// Sort menu items.
$instance->sortAll();
return $instance;
}
/**
* Get menu configuration.
*
* @return Config
*/
public function config()
{
if (!$this->config) {
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$menu = $this->params['menu'];
$file =
CompiledYamlFile::instance($locator("gantry-config://menu/{$menu}.yaml"));
$this->config = new Config($file->content());
$this->config->def('settings.title',
ucfirst($menu));
$file->free();
}
return $this->config;
}
public function name()
{
return $this->params['menu'];
}
public function root()
{
return $this->offsetGet('');
}
public function ordering()
{
$list = [];
foreach ($this->items as $name => $item) {
$groups = $item->groups();
if (count($groups) == 1 && empty($groups[0])) {
continue;
}
$list[$name] = [];
foreach ($groups as $col => $children) {
$list[$name][$col] = [];
foreach ($children as $child) {
$list[$name][$col][] = $child->path;
}
}
}
return $list;
}
public function items($withdefaults = true)
{
$list = [];
foreach ($this->items as $key => $item) {
if ($key !== '') {
$list[$item->path] = $item->toArray($withdefaults);
}
}
return $list;
}
public function settings()
{
return (array) $this->config()->get('settings');
}
/**
* @return object
*/
public function getBase()
{
return $this->offsetGet($this->base);
}
/**
* @return object
*/
public function getDefault()
{
return $this->offsetGet($this->default);
}
/**
* @return object
*/
public function getActive()
{
return $this->offsetGet($this->active);
}
/**
* @return string|null
*/
public function getCacheId()
{
return $this->active ?: '-inactive-';
}
public function isActive($item)
{
$active = $this->getActive();
if ($active && $item && ($active->path ===
$item->path || strpos($active->path, $item->path . '/')
=== 0)) {
return true;
}
return false;
}
public function isCurrent($item)
{
$active = $this->getActive();
return $item && $active && $item->path ===
$active->path;
}
public function init(&$params)
{
$this->items = ['' => new Item($this, '',
['layout' => 'horizontal'])];
}
public function add(Item $item)
{
$this->items[$item->path] = $item;
// If parent exists, assign menu item to its parent; otherwise
ignore menu item.
if (isset($this->items[$item->parent_id])) {
$this->items[$item->parent_id]->addChild($item);
} elseif (!$this->items['']->count()) {
$this->items[$item->parent_id] =
$this->items[''];
$this->items[$item->parent_id]->addChild($item);
}
return $this;
}
/**
* Get menu items from the platform.
*
* @param int $levels
* @return array
*/
abstract protected function getItemsFromPlatform($levels);
/**
* Get base menu item.
*
* If itemid is not specified or does not exist, return active menu
item.
* If there is no active menu item, fall back to home page for the
current language.
* If there is no home page, return null.
*
* @param string $path
*
* @return string
*/
abstract protected function calcBase($path);
/**
* Get a list of the menu items.
*
* @param array $params
* @param array $items
*/
abstract public function getList(array $params, array $items);
/**
* Add custom menu items.
*
* @param array $params
* @param array $items
*/
public function addCustom(array $params, array $items)
{
$start = $params['startLevel'];
$max = $params['maxLevels'];
$end = $max ? $start + $max - 1 : 0;
$config = $this->config();
$type = $config->get('settings.type');
// Add custom menu elements.
foreach ($items as $route => $item) {
if ($type !== 'custom' &&
(!isset($item['type']) || $item['type'] !==
'particle')) {
continue;
}
$tree = explode('/', $route);
$parentTree = $tree;
array_pop($parentTree);
// Enabled state should equal particle setting.
$item['enabled'] =
!isset($item['options']['particle']['enabled'])
||
!empty($item['options']['particle']['enabled']);
$item['level'] = $level = count($tree);
$item['parent_id'] = implode('/',
$parentTree);
if (($start && $start > $level)
|| ($end && $level > $end)
// TODO: Improve. In the mean time Item::add() handles this
part.
// || ($start > 1 && !in_array($tree[$start -
2], $tree))
) {
continue;
}
$item = new Item($this, $route, $item);
$this->add($item);
}
}
/**
* @param array $ordering
* @param string $path
* @param array $map
*/
public function sortAll(array $ordering = null, $path = '',
$map = null)
{
if ($ordering === null) {
$config = $this->config();
$ordering = $config['ordering'] ?
$config['ordering'] : [];
}
if (!isset($this->items[$path]) ||
!$this->items[$path]->hasChildren()) {
return;
}
if ($map === null) {
$map = $this->pathMap ? $this->pathMap->toArray() :
[];
}
$order = [];
$newMap = [];
$item = $this->items[$path];
if ($this->isAssoc($ordering)) {
foreach ($ordering as $key => $value) {
if ($map) {
$newMap = isset($map[$key]['children']) ?
$map[$key]['children'] : [];
$key = isset($map[$key]['path']) ?
basename($map[$key]['path']) : $key;
$order[$key] = $value;
}
if (is_array($value)) {
$this->sortAll($value, $path ? $path . '/'
. $key : $key, $newMap);
}
}
$item->sortChildren($order ?: $ordering);
} else {
foreach ($ordering as $i => $group) {
foreach ($group as $key => $value) {
if ($map) {
$newMap = isset($map[$key]['children']) ?
$map[$key]['children'] : [];
$key = isset($map[$key]['path']) ?
basename($map[$key]['path']) : $key;
$order[$i][$key] = $value;
}
if (is_array($value)) {
$this->sortAll($value, $path ? $path .
'/' . $key : $key, $newMap);
}
}
}
$item->groupChildren($order ?: $ordering);
}
}
protected function isAssoc(array $array)
{
return (array_values($array) !== $array);
}
}
PK&d�[��1D�&�&&classes/Gantry/Component/Menu/Item.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Menu;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
use RocketTheme\Toolbox\ArrayTraits\Export;
/**
* @property string $id
* @property string $type
* @property string $path
* @property string $alias
* @property string $title
* @property string $link
* @property string $parent_id
* @property string $layout
* @property int $browserNav
* @property bool $menu_text
* @property bool $visible
* @property int $group
* @property int $level
*/
class Item implements \ArrayAccess, \Iterator, \Serializable, \Countable
{
use ArrayAccessWithGetters, Export;
const VERSION = 1;
protected $items;
protected $menu;
protected $groups = [];
protected $children = [];
protected $url;
protected static $defaults = [
'id' => 0,
'type' => 'link',
'path' => null,
'alias' => null,
'title' => null,
'link' => null,
'parent_id' => null,
'layout' => 'list',
'target' => '_self',
'dropdown' => '',
'icon' => '',
'image' => '',
'subtitle' => '',
'hash' => '',
'class' => '',
'icon_only' => false,
'enabled' => true,
'visible' => true,
'group' => 0,
'columns' => [],
'level' => 0,
'link_title' => '',
'anchor_class' => ''
];
public function __construct(AbstractMenu $menu, $name, array $item =
[])
{
$this->menu = $menu;
$tree = explode('/', $name);
$alias = array_pop($tree);
$parent = implode('/', $tree);
// As we always calculate parent (it can change), prevent old one
from being inserted.
unset($item['parent_id']);
$this->items = $item + [
'id' => preg_replace('|[^a-z0-9]|i',
'-', $name) ?: 'root',
'path' => $name,
'alias' => $alias,
'title' => ucfirst($alias),
'link' => $name,
'parent_id' => $parent != '.' ? $parent
: '',
] + static::$defaults;
}
public function getDropdown()
{
if (!$this->items['dropdown']) {
return count($this->groups()) > 1 ? 'fullwidth'
: 'standard';
}
return $this->items['dropdown'];
}
public function serialize()
{
// FIXME: need to create collection class to gather the sibling
data.
return serialize([
'version' => static::VERSION,
'items' => $this->items,
'groups' => $this->groups,
'children' => $this->children,
'url' => $this->url
]);
}
public function unserialize($serialized)
{
// FIXME: need to create collection class to gather the sibling
data.
$data = unserialize($serialized);
if (!isset($data['version']) &&
$data['version'] === static::VERSION) {
throw new \UnexpectedValueException('Serialized data is
not valid');
}
$this->items = $data['items'];
$this->groups = $data['groups'];
$this->children = $data['children'];
$this->url = $data['url'];
}
/**
* @param string|null|bool $url
* @return string
*/
public function url($url = false)
{
if ($url !== false) {
$this->url = $url;
}
return $this->url;
}
/**
* @return AbstractMenu
* @deprecated Need to break relationship to the menu and use a
collection instead.
*/
protected function menu()
{
return $this->menu;
}
/**
* @return Item
*/
public function parent()
{
return $this->menu()[$this->items['parent_id']];
}
public function columnWidth($column)
{
if (isset($this->items['columns'][$column])) {
return $this->items['columns'][$column];
}
return 100 / count($this->groups());
}
public function groups()
{
if ($this->groups) {
$list = [];
foreach ($this->groups as $i => $group) {
$list[$i] = [];
foreach ($group as $path) {
$list[$i][] = $this->menu()[$path];
}
}
return $list;
}
return [$this->children()];
}
public function children()
{
$list = [];
foreach ($this as $child) {
$list[] = $child;
}
return $list;
}
public function hasChildren()
{
return !empty($this->children);
}
public function getGroup($i)
{
$groups = $this->groups();
$i = (int) $i;
return isset($groups[$i]) ? $groups[$i] : [];
}
public function update(array $data)
{
$this->items = array_replace($this->items, $data);
return $this;
}
public function addChild(Item $child)
{
$child->level = $this->level + 1;
$child->parent_id = $this->path;
$this->children[$child->alias] = $child->path;
return $this;
}
public function removeChild(Item $child)
{
unset($this->children[$child->alias]);
return $this;
}
public function sortChildren($ordering)
{
// Array with keys that point to the items.
$children =& $this->children;
if ($children) {
if (is_array($ordering)) {
// Remove extra items from ordering and reorder.
$children = array_replace(array_intersect_key($ordering,
$children), $children);
} else {
switch ((string) $ordering) {
case 'abc':
// Alphabetical ordering.
ksort($children, SORT_NATURAL);
break;
case 'cba':
// Reversed alphabetical ordering.
krsort($children, SORT_NATURAL);
break;
}
}
}
return $this;
}
public function reverse()
{
array_reverse($this->children, true);
array_reverse($this->groups, true);
return $this;
}
public function groupChildren(array $groups)
{
// Array with keys that point to the items.
$children =& $this->children;
if ($children) {
$menu = $this->menu();
$ordered = [];
// Create empty groups.
$this->groups = array_fill(0, max(1,
count($this->items['columns'])), []);
foreach ($groups as $i => $ordering) {
if (!is_array($ordering)) {
continue;
}
// Get the items for this group with proper ordering.
$group = array_replace(
array_intersect_key($ordering, $children),
array_intersect_key($children, $ordering)
);
// Assign each menu items to the group.
$group = array_map(
function($value) use ($i, $menu) {
$item = $menu[$value];
$item->group = $i;
return $value;
},
$group
);
// Update remaining children.
$children = array_diff_key($children, $ordering);
// Build child ordering.
$ordered += $group;
// Add items to the current group.
$this->groups[$i] = $group;
}
if ($children) {
// Add leftover children to the ordered list and to the
first group.
$ordered += $children;
$this->groups[0] += $children;
}
// Reorder children by their groups.
$children = $ordered;
}
return $this;
}
// Implements \Iterator
/**
* Returns the current child.
*
* @return Item
*/
public function current()
{
return $this->menu()[current($this->children)];
}
/**
* Returns the key of the current child.
*
* @return mixed Returns scalar on success, or NULL on failure.
*/
public function key()
{
return key($this->children);
}
/**
* Moves the current position to the next child.
*
* @return void
*/
public function next()
{
next($this->children);
}
/**
* Rewinds back to the first child.
*
* @return void
*/
public function rewind()
{
reset($this->children);
}
/**
* Count number of children.
*
* @return int
*/
public function count()
{
return count($this->children);
}
/**
* This method is called after Iterator::rewind() and Iterator::next()
to check if the current position is valid.
*
* @return bool Returns TRUE on success or FALSE on failure.
*/
public function valid()
{
return key($this->children) !== null;
}
/**
* Convert object into an array.
*
* @return array
*/
public function toArray($withDefaults = true)
{
$items = $this->items;
if (!$withDefaults) {
foreach (static::$defaults as $key => $value) {
if ($items[$key] === $value) {
unset($items[$key]);
}
}
}
return $items;
}
}
PK&d�[�{{GLGL6classes/Gantry/Component/Outline/OutlineCollection.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Outline;
use FilesystemIterator;
use Gantry\Component\Collection\Collection;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Layout\Layout;
use Gantry\Framework\Atoms;
use RocketTheme\Toolbox\DI\Container;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class OutlineCollection extends Collection
{
/**
* @var Container
*/
protected $container;
/**
* @var string
*/
protected $path;
/**
* @param Container $container
* @param array $items
*/
public function __construct(Container $container, $items = [])
{
$this->container = $container;
$this->items = $items;
}
/**
* @param string $id
* @return string|null
*/
public function name($id)
{
return isset($this->items[$id]) ? $this->items[$id] : null;
}
/**
* @param string $id
* @return string
*/
public function title($id)
{
return isset($this->items[$id]) ? $this->items[$id] : $id;
}
public function all()
{
return $this;
}
public function system()
{
foreach ($this->items as $key => $item) {
if (substr($key, 0, 1) !== '_') {
unset($this->items[$key]);
}
}
return $this;
}
public function user()
{
foreach ($this->items as $key => $item) {
if (substr($key, 0, 1) === '_' || $key ==
'default') {
unset($this->items[$key]);
}
}
return $this;
}
public function filter(array $include = null)
{
if ($include !== null) {
foreach ($this->items as $key => $item) {
if (!in_array($key, $include)) {
unset($this->items[$key]);
}
}
}
return $this;
}
/**
* Returns list of all positions defined in all outlines.
*
* @return array
*/
public function positions()
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
$list += $index['positions'];
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
}
}
return $list;
}
/**
* @param string $section
* @param bool $includeInherited
* @return array
*/
public function getOutlinesWithSection($section, $includeInherited =
true)
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
continue;
}
if (isset($index['sections'][$section])) {
if (!$includeInherited) {
foreach ($index['inherit'] as $outline =>
$items) {
if (is_array($items) && in_array($section,
$items)) {
continue 2;
}
}
}
$list[$name] = $title;
}
}
return $list;
}
/**
* @param string $particle
* @param bool $includeInherited
* @return array
*/
public function getOutlinesWithParticle($particle, $includeInherited =
true)
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
continue;
}
if (isset($index['particles'][$particle])) {
$ids = $index['particles'][$particle];
if (!$includeInherited &&
!empty($index['inherit'])) {
foreach ($index['inherit'] as $items) {
foreach ((array) $items as $id => $inheritId) {
unset($ids[$id]);
}
}
}
if ($ids) {
$list[$name] = $title;
}
}
}
return $list;
}
/**
* @param string $type
* @param bool $includeInherited
* @return array
*/
public function getOutlinesWithAtom($type, $includeInherited = true)
{
$list = [];
foreach ($this->items as $name => $title) {
$file =
CompiledYamlFile::instance("gantry-theme://config/{$name}/page/head.yaml");
$index = $file->content();
$file->free();
if (isset($index['atoms'])) {
foreach ($index['atoms'] as $atom) {
if (!empty($atom['id']) &&
$atom['type'] === $type && ($includeInherited ||
empty($atom['inherit']))) {
$list[$name] = $title;
}
}
}
}
return $list;
}
/**
* @param string $particle
* @param bool $includeInherited
* @return array
*/
public function getAllParticleInstances($particle, $includeInherited =
true)
{
$list = [];
foreach ($this->items as $name => $title) {
$list += $this->getParticleInstances($name, $particle,
$includeInherited);
}
return $list;
}
/**
* @param string $outline
* @param string $particle
* @param bool $includeInherited
* @return array
*/
public function getParticleInstances($outline, $particle,
$includeInherited = true)
{
$list = [];
$index = Layout::index($outline);
if (isset($index['particles'][$particle])) {
$list = $index['particles'][$particle];
if (!$includeInherited &&
!empty($index['inherit'])) {
foreach ($index['inherit'] as $items) {
foreach ((array) $items as $id => $inheritId) {
unset($list[$id]);
}
}
}
}
$layout = Layout::instance($outline);
foreach ($list as $id => $title) {
$item = clone $layout->find($id);
$block = $layout->block($id);
$item->block = isset($block->attributes) ?
$block->attributes : new \stdClass();
$list[$id] = $item;
}
return $list;
}
/**
* @param string $outline
* @param string $type
* @param bool $includeInherited
* @return array
*/
public function getAtomInstances($outline, $type, $includeInherited =
true)
{
$list = [];
$file =
CompiledYamlFile::instance("gantry-theme://config/{$outline}/page/head.yaml");
$head = $file->content();
$file->free();
if (isset($head['atoms'])) {
foreach ($head['atoms'] as $atom) {
if (!empty($atom['id']) &&
$atom['type'] === $type && ($includeInherited ||
empty($atom['inherit']['outline']))) {
$list[$atom['id']] = (object) $atom;
}
}
}
return $list;
}
/**
* Return list of outlines which are inheriting the specified atom.
*
* @param string $outline
* @param string $id
* @return array
*/
public function getInheritingOutlinesWithAtom($outline, $id = null)
{
$list = [];
foreach ($this->items as $name => $title) {
$file =
CompiledYamlFile::instance("gantry-theme://config/{$name}/page/head.yaml");
$head = $file->content();
$file->free();
if (isset($head['atoms'])) {
foreach ($head['atoms'] as $atom) {
if
(!empty($atom['inherit']['outline']) &&
$atom['inherit']['outline'] == $outline &&
(!$id || $atom['inherit']['atom'] == $id)) {
$list[$name] = $title;
}
}
}
}
return $list;
}
/**
* Return list of outlines which are inheriting the specified outline.
*
* You can additionally pass section or particle id to filter the
results for only that type.
*
* @param string $outline
* @param string|array $id
* @return array
*/
public function getInheritingOutlines($outline, $id = null)
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
continue;
}
if (!empty($index['inherit'][$outline]) &&
(!$id || array_intersect((array) $id,
$index['inherit'][$outline]))) {
$list[$name] = $title;
}
}
return $list;
}
/**
* Return list of outlines inherited by the specified outline.
*
* You can additionally pass section or particle id to filter the
results for only that type.
*
* @param string $outline
* @param string $id
* @return array
*/
public function getInheritedOutlines($outline, $id = null)
{
try {
$index = Layout::index($outline);
} catch (\Exception $e) {
// Layout cannot be read. We will just return nothing instead
of throwing an exception.
return [];
}
$list = [];
foreach ($index['inherit'] as $name => $inherited) {
if (!$id || array_intersect_key((array) $id, $inherited[$id]))
{
$list[$name] = isset($this->items[$name]) ?
$this->items[$name] : $name;
}
}
return $list;
}
/**
* @param int|string $id
* @return int|string
*/
public function preset($id)
{
return $id;
}
/**
* @param int|string $id
* @return Layout
*/
public function layout($id)
{
return Layout::load($id);
}
/**
* @param int|string $id
* @return array
*/
public function layoutPreset($id)
{
$layout = Layout::load($id);
$preset = $layout->preset;
unset($layout);
return $preset;
}
/**
* @param string $path
* @return $this
* @throws \RuntimeException
*/
public function load($path = 'gantry-config://')
{
$this->path = $path;
$iterator = $this->getFilesystemIterator($path);
$files = [];
/** @var FilesystemIterator $info */
foreach ($iterator as $name => $info) {
if (!$info->isDir() || $name[0] == '.' ||
!is_file($info->getPathname() . '/index.yaml')) {
continue;
}
$files[$name] = ucwords(trim(preg_replace(['|_|',
'|/|'], [' ', ' / '], $name)));
}
unset($files['default']);
unset($files['menu']);
asort($files);
$this->items = $this->addDefaults($files);
return $this;
}
/**
* @param string|null $id
* @param string $title
* @param string|array $preset
* @return string
* @throws \RuntimeException
*/
public function create($id, $title = null, $preset = null)
{
$title = $title ?: 'Untitled';
$name = ltrim(strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $id ?: $title)), '_');
if (!$name) {
throw new \RuntimeException("Outline needs a name",
400);
}
if ($name === 'default') {
throw new \RuntimeException("Outline cannot use reserved
name '{$name}'", 400);
}
$name = $this->findFreeName($name);
if (!$id) {
$title = ucwords(trim(preg_replace(['|_|',
'|/|'], [' ', ' / '], $name)));
}
if (!is_array($preset)) {
// Load preset.
$preset = Layout::preset($preset ?: 'default');
}
// Create layout and index for the new layout.
$layout = new Layout($name, $preset);
$layout->save()->saveIndex();
$this->items[$name] = $title;
return $name;
}
/**
* @param string $id
* @param string $title
* @param bool $inherit
* @return string
* @throws \RuntimeException
*/
public function duplicate($id, $title = null, $inherit = false)
{
if (!$this->canDuplicate($id)) {
throw new \RuntimeException("Outline '$id'
cannot be duplicated", 400);
}
$layout = Layout::load($id);
if ($inherit) {
$layout->inheritAll()->clean();
}
$new = $this->create(null, $title, $layout->toArray() +
['preset' => $layout->preset]);
if ($id === 'default') {
// For Base Outline we're done.
return $new;
}
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$path =
$locator->findResource("{$this->path}/{$id}");
if (!$path) {
// Nothing to copy.
return $new;
}
$newPath =
$locator->findResource("{$this->path}/{$new}", true, true);
try {
// Copy everything over except index, layout and assignments.
Folder::copy($path, $newPath,
'/^(index|layout|assignments)\..*$/');
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Duplicating Outline
failed: ', $e->getMessage()), 500, $e);
}
return $new;
}
/**
* @param string $id
* @param string $title
* @return string
* @throws \RuntimeException
*/
public function rename($id, $title)
{
if (!$this->canDelete($id)) {
throw new \RuntimeException("Outline '$id'
cannot be renamed", 400);
}
$gantry = $this->container;
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path =
$locator->findResource("{$this->path}/{$id}", true, true);
if (!$path || !is_dir($path)) {
throw new \RuntimeException('Outline not found',
404);
}
$folder = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $title));
if ($folder === 'default' || $folder[0] ===
'_') {
throw new \RuntimeException("Outline cannot use reserved
name '{$folder}'", 400);
}
$newPath =
$locator->findResource("{$this->path}/{$folder}", true,
true);
if (is_dir($newPath)) {
throw new \RuntimeException("Outline '$id'
already exists.", 400);
}
try {
foreach ($this->getInheritingOutlines($id) as $outline =>
$title) {
$this->layout($outline)->updateInheritance($id,
$folder)->save()->saveIndex();
}
foreach ($this->getInheritingOutlinesWithAtom($id) as
$outline => $title) {
Atoms::instance($outline)->updateInheritance($id,
$folder)->save();
}
Folder::move($path, $newPath);
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Renaming Outline
failed: %s', $e->getMessage()), 500, $e);
}
$this->items[$id] = $title;
return $folder;
}
/**
* @param string $id
* @throws \RuntimeException
*/
public function delete($id)
{
if (!$this->canDelete($id)) {
throw new \RuntimeException("Outline '$id'
cannot be deleted", 400);
}
$gantry = $this->container;
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path =
$locator->findResource("{$this->path}/{$id}", true, true);
if (!is_dir($path)) {
throw new \RuntimeException('Outline not found',
404);
}
foreach ($this->getInheritingOutlines($id) as $outline =>
$title) {
$this->layout($outline)->updateInheritance($id)->save()->saveIndex();
}
foreach ($this->getInheritingOutlinesWithAtom($id) as $outline
=> $title) {
Atoms::instance($outline)->updateInheritance($id)->save();
}
if (file_exists($path)) {
Folder::delete($path);
}
unset($this->items[$id]);
}
/**
* @param string $id
* @return boolean
*/
public function canDuplicate($id)
{
if (!isset($this->items[$id])) {
return false;
}
return true;
}
/**
* @param string $id
* @return boolean
*/
public function canDelete($id)
{
if (!$id || $id[0] === '_' || $id ===
'default') {
return false;
}
return true;
}
/**
* @param string $id
* @return boolean
*/
public function isDefault($id)
{
return $id === 'default';
}
/**
* @param array $outlines
* @return array
*/
protected function addDefaults(array $outlines)
{
return [
'default' => 'Base Outline',
'_body_only' => 'Body Only',
'_error' => 'Error',
'_offline' => 'Offline'
] + $outlines;
}
/**
* Find unused name with number appended to it when duplicating an
outline.
*
* @param string $id
* @return string
*/
protected function findFreeName($id)
{
if (!isset($this->items[$id])) {
return $id;
}
$name = $id;
$count = 0;
if (preg_match('|^(?:_)?(.*?)(?:_(\d+))?$|ui', $id,
$matches)) {
$matches += ['', '', ''];
list (, $name, $count) = $matches;
}
$count = max(1, $count);
do {
$count++;
} while (isset($this->items["{$name}_{$count}"]));
return "{$name}_{$count}";
}
protected function getFilesystemIterator($path)
{
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$custom = $locator->findResource($path, true, true);
if (is_dir($custom)) {
/** @var FilesystemIterator $iterator */
$iterator = new FilesystemIterator(
$custom,
FilesystemIterator::CURRENT_AS_SELF |
FilesystemIterator::KEY_AS_FILENAME |
FilesystemIterator::UNIX_PATHS |
FilesystemIterator::SKIP_DOTS
);
} else {
/** @var UniformResourceIterator $iterator */
$iterator = $locator->getIterator(
$path,
UniformResourceIterator::CURRENT_AS_SELF |
UniformResourceIterator::KEY_AS_FILENAME |
UniformResourceIterator::UNIX_PATHS |
UniformResourceIterator::SKIP_DOTS
);
}
return $iterator;
}
}
PK&d�[�T�ڍ�,classes/Gantry/Component/Position/Module.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Position;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Module implements \ArrayAccess
{
use NestedArrayAccessWithGetters, Export;
public $name;
public $position;
public $assigned;
protected $items;
/**
* Module constructor.
*
* @param string $name
* @param string $position
* @param array $data
*/
public function __construct($name, $position = null, array $data =
null)
{
$this->name = $name;
$this->position = $position;
if ($data) {
$this->init($data);
} else {
$this->load();
}
}
public function update(array $data)
{
$this->init($data);
return $this;
}
/**
* Save module.
*
* @param string $position
* @param string $name
* @return $this
*/
public function save($name = null, $position = null)
{
$this->name = $name ?: $this->name;
$this->position = $position ?: $this->position;
$items = $this->toArray();
unset($items['position'], $items['id']);
$file = $this->file(true);
$file->save($items);
return $this;
}
/**
* Delete module.
*
* @return $this
*/
public function delete()
{
$file = $this->file(true);
if ($file->exists()) {
$file->delete();
}
return $this;
}
/**
* Return true if module exists.
*
* @return bool
*/
public function exists()
{
return $this->name ? $this->file()->exists() : false;
}
public function toArray()
{
return ['position' => $this->position,
'id' => $this->name] + $this->items;
}
protected function load()
{
$file = $this->file();
$this->init($file->content());
$file->free();
}
protected function init($data)
{
unset($data['id'], $data['position']);
$this->items = $data;
if (isset($this->items['assignments'])) {
$assignments = $this->items['assignments'];
if (is_array($assignments)) {
$this->assigned = 'some';
} elseif ($assignments !== 'all') {
$this->assigned = 'none';
} else {
$this->assigned = 'all';
}
} else {
$this->assigned = 'all';
}
}
protected function file($save = false)
{
$position = $this->position ?: '_unassigned_';
$this->name = $this->name ?: ($save ?
$this->findFreeName() : null);
$name = $this->name ?: '_untitled_';
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
return
CompiledYamlFile::instance($locator->findResource("gantry-positions://{$position}/{$name}.yaml",
true, $save));
}
/**
* Find unused name with number appended.
*/
protected function findFreeName()
{
$position = $this->position ?: '_unassigned_';
$name = $this->get('type');
$name = $name == 'particle' ?
$this->get('options.type') : $name;
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
if
(!file_exists($locator->findResource("gantry-positions://{$position}/{$name}.yaml",
true, true))) {
return $name;
}
$count = 1;
do {
$count++;
} while
(file_exists($locator->findResource("gantry-positions://{$position}/{$name}_{$count}.yaml",
true, true)));
return "{$name}_{$count}";
}
}
PK&d�[�l*�)#)#.classes/Gantry/Component/Position/Position.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Position;
use Gantry\Component\Collection\Collection;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Symfony\Component\Yaml\Yaml;
class Position extends Collection
{
public $name;
public $title;
protected $modules = [];
/**
* Position constructor.
*
* @param string $name
* @param array $items
*/
public function __construct($name, array $items = null)
{
$this->name = $name;
$this->load($items);
}
/**
* Save position.
*
* @return $this
*/
public function save()
{
$file = $this->file(true);
$file->save($this->toArray());
return $this;
}
/**
* Clone position together with its modules. Returns new position.
*
* @param string $name
* @return Position
*/
public function duplicate($name)
{
$new = clone $this;
$new->name = $name;
$new->save();
foreach ($this as $module) {
$clone = clone $module;
$clone->position = $name;
$clone->save();
}
return $new;
}
/**
* Raname module key
*
* @param string $name
* @return static
*/
public function rename($name)
{
$new = $this->duplicate($name);
$this->delete();
return $new;
}
/**
* Delete position.
*
* @return $this
*/
public function delete()
{
$file = $this->file(true);
if ($file->exists()) {
$file->delete();
}
$folder = $this->folder(true);
if (is_dir($folder)) {
Folder::delete($folder);
}
return $this;
}
/**
* Update modules in the position.
*
* @param array $items
* @return $this
*/
public function update(array $items)
{
$list = [];
foreach ($items as $item) {
$name = ($item instanceof Module) ? $item->name : $item;
$list[] = $name;
if (!in_array($name, $this->items)) {
$this->add($item);
}
}
$remove = array_diff($this->items, $list);
foreach ($remove as $item) {
$module = $this->get($item);
if ($module->position === $this->name) {
$module->delete();
}
}
$this->items = $list;
return $this;
}
/**
* @param Module|string $item
* @param string $name Temporary name for the module.
* @return $this
*/
public function add($item, $name = null)
{
if ($item instanceof Module) {
$this->modules[$name ?: $item->name] = $item;
$item = $name ?: $item->name;
}
$this->items[] = $item;
return $this;
}
public function remove($item)
{
if ($item instanceof Module) {
$item = $item->name;
}
unset($this->modules[$item]);
$this->items = array_diff($this->items, $item);
return $this;
}
/**
* @param $name
* @return Module
*/
public function get($name)
{
if (!isset($this->modules[$name])) {
$this->modules[$name] = $this->loadModule($name);
}
return $this->modules[$name];
}
/**
* Returns the value at specified offset.
*
* @param string $offset The offset to retrieve.
* @return Module
*/
public function offsetGet($offset)
{
if (!isset($this->items[$offset])) {
return null;
}
$name = $this->items[$offset];
if (!isset($this->modules[$name])) {
$this->modules[$name] = $this->loadModule($name);
}
return $this->modules[$name];
}
/**
* Assigns a value to the specified offset.
*
* @param mixed $offset The offset to assign the value to.
* @param mixed $value The value to set.
*/
public function offsetSet($offset, $value)
{
if (!$value instanceof Position) {
throw new \InvalidArgumentException('Value has to be
instance of Position');
}
if (is_null($offset)) {
$this->items[] = $value->name;
$this->modules[$value->name] = $value;
} else {
$this->items[$offset] = $value->name;
$this->modules[$value->name] = $value;
}
}
/**
* Unsets an offset.
*
* @param mixed $offset The offset to unset.
*/
public function offsetUnset($offset)
{
parent::offsetUnset($offset);
if (!isset($this->items[$offset])) {
return;
}
$name = $this->items[$offset];
if (isset($this->modules[$name])) {
unset($this->modules[$name]);
}
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
$items = [];
foreach ($this->items as $key => $name) {
$items[] = $this->offsetGet($key);
}
return new \ArrayIterator($items);
}
/**
* @return array
*/
public function toArray($includeModules = false)
{
$array = [
'name' => $this->name,
'title' => $this->title,
];
if (!$includeModules) {
$array['ordering'] = $this->items;
} else {
$list = [];
foreach ($this->getIterator() as $key => $module) {
$list[$key] = $module->toArray();
}
$array['modules'] = $list;
}
return $array;
}
/**
* @param int $inline
* @param int $indent
* @param bool $includeModules
* @return string
*/
public function toYaml($inline = 3, $indent = 2, $includeModules =
false)
{
return Yaml::dump($this->toArray($includeModules), $inline,
$indent, true, false);
}
/**
* @param bool $includeModules
* @return string
*/
public function toJson($includeModules = false)
{
return json_encode($this->toArray($includeModules));
}
/**
* @return array
*/
public function listModules()
{
$list = [];
foreach ($this->items as $name) {
$list[] = "{$this->name}/{$name}";
}
return $list;
}
/**
* @param bool $save
* @return string
*/
public function folder($save = false)
{
return $this->locator()->findResource($this->path(), true,
$save);
}
/**
* @param $data
*/
protected function load($data)
{
if ($data === null) {
$file = $this->file();
$data = $file->content();
$file->free();
}
$this->title = isset($data['title']) ?
$data['title'] : $this->name;
if (isset($data['modules'])) {
foreach ($data['modules'] as $array) {
$this->add(new Module($array['id'],
$this->name, $array), $array['id'] ?: rand());
}
return;
}
// Sort modules by ordering, if items are not listed in ordering,
use alphabetical order.
$ordering = isset($data['ordering']) ?
array_flip($data['ordering']) : [];
$path = $this->locator()->findResource($this->path());
$files = $path ? Folder::all(
$path,
[
'compare' => 'Filename',
'pattern' => '|\.yaml$|',
'folders' => false,
'recursive' => false,
'key' => 'Filename',
'filters' => ['key' =>
'|\.yaml$|']
]
) : [];
ksort($files);
$this->items = array_keys($ordering + $files);
}
/**
* @param string $name
* @return $this
*/
protected function loadModule($name)
{
return new Module($name, $this->name);
}
/**
* @param bool $save
* @return CompiledYamlFile
*/
protected function file($save = false)
{
return
CompiledYamlFile::instance($this->locator()->findResource($this->path()
. '.yaml', true, $save));
}
/**
* @return UniformResourceLocator
*/
protected function locator()
{
return Gantry::instance()['locator'];
}
/**
* @return string
*/
protected function path()
{
return "gantry-positions://{$this->name}";
}
}
PK&d�[���../classes/Gantry/Component/Position/Positions.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Position;
use Gantry\Component\Collection\Collection;
use Gantry\Component\File\CompiledYamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RocketTheme\Toolbox\DI\Container;
class Positions extends Collection
{
/**
* @var array|Position[]
*/
protected $items;
/**
* @var string
*/
protected $path;
/**
* @var Container
*/
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* @param string $path
*
* @return $this
* @throws \RuntimeException
*/
public function load($path = 'gantry-positions://')
{
$this->path = $path;
$positions = [];
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
if ($locator->findResource($path)) {
/** @var UniformResourceIterator $iterator */
$iterator = $locator->getIterator($path);
/** @var UniformResourceIterator $info */
foreach ($iterator as $info) {
if (!$info->isFile() || $info->getExtension() !==
'yaml') {
continue;
}
$name = $info->getBasename('.yaml');
$position =
CompiledYamlFile::instance($info->getPathname())->content();
// Only use filesystem position if it it is properly set
up.
if ($position) {
$positions[$name] = new Position($name, $position);
}
}
}
// Add empty positions from the layouts.
foreach ($this->container['outlines']->positions()
as $name => $title) {
if (!isset($positions[$name])) {
$positions[$name] = new Position($name, ['title'
=> $title]);
}
}
ksort($positions);
$this->items = $positions;
return $this;
}
/**
* Updates all positions with their modules from an array and saves
them.
*
* @param array $data
* @return $this
*/
public function import(array $data)
{
foreach ($data as $pos) {
$list = [];
$position = $pos['name'];
foreach ($pos['modules'] as $item) {
$name = !empty($item['id']) ?
$item['id'] : '';
if ($name && !empty($item['position'])) {
$module =
$this[$item['position']]->get($name);
if ($position !== $item['position']) {
$module->delete();
}
} else {
$module = new Module($name, $position);
}
$module->update($item)->save($name, $position);
$list[] = $module;
}
$this[$pos['name']]->update($list)->save();
}
return $this;
}
/**
* @param Position $item
* @return $this
*/
public function add($item)
{
if ($item instanceof Position) {
$this->items[$item->name] = $item;
}
return $this;
}
/**
* @param string $title
* @param string $id
*
* @return string
* @throws \RuntimeException
*/
public function create($title = 'Untitled', $id = null)
{
$name = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $id ?: $title));
if (!$name) {
throw new \RuntimeException("Position needs a name",
400);
}
$name = $this->findFreeName($name);
$position = new Position($name, ['title' => $title]);
$position->save();
return $name;
}
/**
* @param string $id
* @param string $new
*
* @return string
* @throws \RuntimeException
*/
public function duplicate($id, $new = null)
{
if (!isset($this->items[$id])) {
throw new \RuntimeException(sprintf("Duplicating Position
failed: '%s' not found.", $id), 400);
}
$new = $this->findFreeName($new ?
strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $new)) :
$id);
$position = $this->items[$id];
$new = $position->duplicate($new);
return $new->name;
}
/**
* @param string $id
* @param string $new
*
* @return string
* @throws \RuntimeException
*/
public function rename($id, $new)
{
if (!isset($this->items[$id])) {
throw new \RuntimeException(sprintf("Renaming Position
failed: '%s' not found.", $id), 400);
}
$newId = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $new));
if (isset($this->items[$newId])) {
throw new \RuntimeException(sprintf("Renaming Position
failed: '%s' already exists.", $newId), 400);
}
$position = $this->items[$id];
$position->rename($new);
return $position->name;
}
/**
* @param string $id
*
* @throws \RuntimeException
*/
public function delete($id)
{
if (!isset($this->items[$id])) {
throw new \RuntimeException(sprintf("Deleting Position
failed: '%s' not found.", $id), 400);
}
$position = $this->items[$id];
$position->delete();
}
/**
* Find unused name with number appended to it when duplicating an
position.
*
* @param string $id
*
* @return string
*/
protected function findFreeName($id)
{
if (!isset($this->items[$id])) {
return $id;
}
$name = $id;
$count = 0;
if (preg_match('|^(?:_)?(.*?)(?:_(\d+))?$|ui', $id,
$matches)) {
$matches += ['', '', ''];
list (, $name, $count) = $matches;
}
$count = max(1, $count);
do {
$count++;
} while (isset($this->items["{$name}_{$count}"]));
return "{$name}_{$count}";
}
}
PK&d�[���O��,classes/Gantry/Component/Remote/Response.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Remote;
class Response
{
/**
* The callback for the progress
*
* @var callable Either a function or callback in array notation
*/
public static $callback = null;
/**
* Which method to use for HTTP calls, can be 'curl',
'fopen' or 'auto'. Auto is default and fopen is the
preferred method
*
* @var string
*/
private static $method = 'auto';
/**
* Default parameters for `curl` and `fopen`
*
* @var array
*/
private static $defaults = [
'curl' => [
CURLOPT_REFERER => 'Gantry5 Response',
CURLOPT_USERAGENT => 'Gantry5 Response',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HEADER => false,
/**
* Example of callback parameters from within your own class
*/
//CURLOPT_NOPROGRESS => false,
//CURLOPT_PROGRESSFUNCTION => [$this, 'progress']
],
'fopen' => [
'method' => 'GET',
'user_agent' => 'Gantry5 Response',
'max_redirects' => 5,
'follow_location' => 1,
'timeout' => 15,
/**
* Example of callback parameters from within your own class
*/
//'notification' => [$this, 'progress']
]
];
/**
* Sets the preferred method to use for making HTTP calls.
*
* @param string $method Default is `auto`
*
* @return Response
*/
public static function setMethod($method = 'auto')
{
if (!in_array($method, ['auto', 'curl',
'fopen'])) {
$method = 'auto';
}
self::$method = $method;
return new self();
}
/**
* Makes a request to the URL by using the preferred method
*
* @param string $uri URL to call
* @param array $options An array of parameters for both `curl` and
`fopen`
* @param callable $callback
*
* @return string The response of the request
*/
public static function get($uri = '', $options = [],
$callback = null)
{
if (!self::isCurlAvailable() && !self::isFopenAvailable())
{
throw new \RuntimeException('Could not start an HTTP
request. `allow_url_open` is disabled and `cURL` is not available');
}
$options = array_replace_recursive(self::$defaults, $options);
$method = 'get' . ucfirst(strtolower(self::$method));
self::$callback = $callback;
return static::$method($uri, $options, $callback);
}
/**
* Checks if cURL is available
*
* @return boolean
*/
public static function isCurlAvailable()
{
return function_exists('curl_version');
}
/**
* Checks if the remote fopen request is enabled in PHP
*
* @return boolean
*/
public static function isFopenAvailable()
{
return preg_match('/1|yes|on|true/i',
ini_get('allow_url_fopen'));
}
/**
* Progress normalized for cURL and fopen
*
* @return array Normalized array with useful data.
* Format: ['code' => int|false,
'filesize' => bytes, 'transferred' => bytes,
'percent' => int]
*/
public static function progress()
{
static $filesize = null;
$args = func_get_args();
$isCurlResource = is_resource($args[0]) &&
get_resource_type($args[0]) == 'curl';
$notification_code = !$isCurlResource ? $args[0] : false;
$bytes_transferred = $isCurlResource ? $args[2] : $args[4];
if ($isCurlResource) {
$filesize = $args[1];
} elseif ($notification_code == STREAM_NOTIFY_FILE_SIZE_IS) {
$filesize = $args[5];
}
if ($bytes_transferred > 0) {
if ($notification_code == STREAM_NOTIFY_PROGRESS |
STREAM_NOTIFY_COMPLETED || $isCurlResource) {
$progress = [
'code' => $notification_code,
'filesize' => $filesize,
'transferred' => $bytes_transferred,
'percent' => $filesize <= 0 ?
'-' : round(($bytes_transferred * 100) / $filesize, 1)
];
if (self::$callback !== null) {
call_user_func_array(self::$callback, [$progress]);
}
}
}
}
/**
* Automatically picks the preferred method
*
* @return string The response of the request
*/
private static function getAuto()
{
if (self::isFopenAvailable()) {
return self::getFopen(func_get_args());
}
if (self::isCurlAvailable()) {
return self::getCurl(func_get_args());
}
return '';
}
/**
* Starts a HTTP request via fopen
*
* @return string The response of the request
*/
private static function getFopen()
{
if (count($args = func_get_args()) == 1) {
$args = $args[0];
}
$uri = $args[0];
$options = $args[1];
$callback = $args[2];
if ($callback) {
$options['fopen']['notification'] =
['self', 'progress'];
}
$stream = stream_context_create(['http' =>
$options['fopen']], $options['fopen']);
$content = @file_get_contents($uri, false, $stream);
if ($content === false) {
throw new \RuntimeException("Error while trying to
download '$uri'");
}
return $content;
}
/**
* Starts a HTTP request via cURL
*
* @return string The response of the request
*/
private static function getCurl()
{
$args = func_get_args();
$args = count($args) > 1 ? $args : array_shift($args);
$uri = $args[0];
$options = $args[1];
$callback = $args[2];
$ch = curl_init($uri);
curl_setopt_array($ch, $options['curl']);
if ($callback) {
curl_setopt_array(
$ch,
[
CURLOPT_NOPROGRESS => false,
CURLOPT_PROGRESSFUNCTION => ['self',
'progress']
]
);
}
$response = curl_exec($ch);
if ($errno = curl_errno($ch)) {
$error_message = curl_strerror($errno);
throw new \RuntimeException("cURL error ({$errno}):\n
{$error_message}");
}
curl_close($ch);
return $response;
}
}
PK&d�[��N@*classes/Gantry/Component/Request/Input.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Request;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
class Input implements \ArrayAccess, \Iterator, ExportInterface
{
use NestedArrayAccessWithGetters, Iterator, Export;
/**
* @var array
*/
protected $items;
/**
* Constructor to initialize array.
*
* @param array $items Initial items inside the iterator.
*/
public function __construct(array &$items = [])
{
$this->items = &$items;
}
/**
* Returns input array. If there are any JSON encoded fields (key:
_json), those will be decoded as well.
*
* @param string $path Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return array
*/
public function getArray($path = null, $default = null, $separator =
'.')
{
$data = $path ? $this->get($path, $default, $separator) :
$this->items;
return (array) $this->getChildren($data);
}
/**
* Returns JSON decoded input array.
*
* @param string $path Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return array
*/
public function getJsonArray($path = null, $default = null, $separator
= '.')
{
return (array) $this->getJson($path, $default, $separator,
true);
}
/**
* Returns JSON decoded input. Accosiative arrays become objects.
*
* @param string|null $path Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @param bool $assoc True to return associative arrays
instead of objects.
* @return mixed
*/
public function getJson($path = null, $default = null, $separator =
'.', $assoc = false)
{
$data = $this->get($path, null, $separator);
if (!isset($data)) {
return $default;
}
if (!is_string($data)) {
throw new \RuntimeException(sprintf('%s::%s(%s) expects
input to be JSON encoded string', __CLASS__, __FUNCTION__, $path));
}
$data = json_decode($data, $assoc);
if (!isset($data)) {
throw new \RuntimeException(sprintf('%s::%s(): %s',
__CLASS__, __FUNCTION__, json_last_error_msg()));
}
return $data;
}
/**
* @param $current
* @return array|mixed
* @internal
*/
protected function getChildren(&$current)
{
if (!is_array($current)) {
return $current;
}
$array = [];
foreach ($current as $key => &$value) {
if ($key === '_json') {
$array += json_decode($value, true);
} else {
$array[$key] = $this->getChildren($value);
}
}
return $array;
}
}
PK&d�[(5���,classes/Gantry/Component/Request/Request.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Request;
class Request
{
/**
* @var string
*/
protected $method;
/**
* @var Input
*/
public $get;
/**
* @var Input
*/
public $post;
/**
* @var Input
*/
public $cookie;
/**
* @var Input
*/
public $server;
/**
* @var Input
*/
public $request;
public function __construct()
{
$this->init();
}
public function getMethod()
{
if (!$this->method) {
$method = $this->server['REQUEST_METHOD'] ?:
'GET';
if ('POST' === $method) {
$method =
$this->server['X-HTTP-METHOD-OVERRIDE'] ?: $method;
$method = $this->post['METHOD'] ?: $method;
}
$this->method = strtoupper($method);
}
return $this->method;
}
protected function init()
{
$this->get = new Input($_GET);
$this->post = new Input($_POST);
$this->cookie = new Input($_COOKIE);
$this->server = new Input($_SERVER);
$this->request = new Input($_REQUEST);
}
}
PK&d�[]�>J��2classes/Gantry/Component/Response/HtmlResponse.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class HtmlResponse extends Response
{
}
PK&d�[(�gg2classes/Gantry/Component/Response/JsonResponse.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class JsonResponse extends Response
{
public $mimeType = 'application/json';
protected $success = true;
protected $message;
protected $exceptions = [];
protected $messages = [];
protected $content = [];
/**
* @param string $content
* @param bool $success
* @return $this
*/
public function setContent($content, $success = true)
{
$this->success = (bool) $success;
if (is_array($content)) {
foreach ($content as $key => $value) {
$this->parseValue($key, $value);
}
} else {
$this->parseValue(null, $content);
}
return $this;
}
/**
* @return string
*/
public function __toString()
{
// Empty output buffer to make sure that the response is clean and
valid.
while (($output = ob_get_clean()) !== false) {
// In debug mode send also output buffers (debug dumps, PHP
notices and warnings).
if ($output && (GANTRY5_DEBUG || headers_sent())) {
$this->messages['php'][] = $output;
}
}
$json = [
'code' => $this->code,
'success' => $this->success
];
if ($this->messages) {
$json['messages'] = $this->messages;
}
if ($this->exceptions) {
$json['exceptions'] = $this->exceptions;
}
if (GANTRY5_DEBUG) {
$json['memory'] = ['peak' =>
memory_get_peak_usage(), 'current' => memory_get_usage()];
}
$json += $this->content;
return (string) json_encode($json);
}
protected function parseValue($key, $value)
{
if ($value instanceof \Exception) {
// Prepare the error response if we are dealing with an error.
$this->success = false;
$this->exceptions = $this->parseException($value);
} elseif ($value instanceof HtmlResponse) {
// Add HTML response (numeric keys are always integers).
$key = !$key || is_int($key) ? 'html' : $key;
$this->content[$key] = trim((string) $value);
} elseif (is_null($key)) {
// If the returned value was not an array, put the contents
into data variable.
$this->content['data'] = $value;
} elseif (is_int($key)) {
// If the key was an integer, also put the contents into data
variable.
$this->content['data'][$key] = $value;
} else {
$this->content[$key] = $value;
}
}
protected function parseException(\Exception $e)
{
$this->code = $e->getCode();
// Build data from exceptions.
$exceptions = [];
do {
$exception = [
'code' => $e->getCode(),
'message' => $e->getMessage()
];
if (GANTRY5_DEBUG) {
$exception += [
'type' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine()
];
}
$exceptions[] = $exception;
$e = $e->getPrevious();
}
while (GANTRY5_DEBUG && $e);
return $exceptions;
}
}
PK&d�[�~�776classes/Gantry/Component/Response/RedirectResponse.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class RedirectResponse extends Response
{
public function __construct($content = '', $status = 303)
{
parent::__construct('', $status);
$this->setHeader('Location', $content);
}
public function getContent()
{
return (string) $this->getHeaders()['Location'];
}
public function setContent($content)
{
$this->setHeader('Location', $content);
}
}
PK&d�[ʚ@%��.classes/Gantry/Component/Response/Response.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class Response
{
public $charset = 'utf-8';
public $mimeType = 'text/html';
protected $code = 200;
protected $message = 'OK';
protected $lifetime = 0;
protected $etag;
/**
* @var array Response headers.
*/
protected $headers = [];
/**
* @var string Response body.
*/
protected $content;
protected $responseCodes = [
200 => 'OK',
400 => 'Bad Request',
401 => 'Unauthorized',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
410 => 'Gone',
500 => 'Internal Server Error',
501 => 'Not Implemented',
503 => 'Service Temporarily Unavailable'
];
public function __construct($content = '', $status = 200)
{
if ($content) {
$this->setContent($content);
}
if ($status != 200) {
$this->setStatusCode($status);
}
}
/**
* @param int $seconds
* @return $this
*/
public function setLifetime($seconds)
{
$this->lifetime = $seconds;
return $this;
}
/**
* @param mixed $key
* @return $this
*/
public function setKey($key)
{
$this->etag = md5(json_encode($key));
return $this;
}
/**
* @return int
*/
public function getStatusCode()
{
return $this->code;
}
/**
* @param int $code
* @param string $message
* @return $this
*/
public function setStatusCode($code, $message = null)
{
if ($message) {
$this->code = $code;
$this->message = $message;
} else {
$this->code = isset($this->responseCodes[$code]) ? (int)
$code : 500;
$this->message = $this->responseCodes[$this->code];
}
return $this;
}
/**
* @return string
*/
public function getStatus()
{
$code = $this->getStatusCode();
return $code . ' ' .
(isset($this->responseCodes[$code]) ? $this->responseCodes[$code] :
'Unknown error');
}
/**
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
/**
* @param array $headers
* @param bool $replace
* @return $this
*/
public function setHeaders(array $headers, $replace = false)
{
foreach ($headers as $key => $values) {
$act = $replace;
foreach ((array) $values as $value) {
$this->setHeader($key, $value, $act);
$act = false;
}
}
return $this;
}
/**
* @return $this
*/
public function clearHeaders()
{
$this->headers = [];
return $this;
}
/**
* @param $name
* @param $value
* @param bool $replace
* @return $this
*/
public function setHeader($name, $value, $replace = false)
{
if ($replace) {
$this->headers[$name] = [$value];
} else {
$this->headers[$name][] = $value;
}
return $this;
}
/**
* @return string
*/
public function getContent()
{
return (string) $this->content;
}
/**
* @param string $content
* @return Response
* @throws \UnexpectedValueException
*/
public function setContent($content) {
if ($content !== null && !is_string($content) &&
!is_numeric($content) && !is_callable([$content,
'__toString'])) {
throw new \UnexpectedValueException(
sprintf('Content must be a string or object
implementing __toString()')
);
}
$this->content = $content;
return $this;
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->content;
}
}
PK&d�[V�99*classes/Gantry/Component/Router/Router.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Router;
use Gantry\Admin\EventListener;
use Gantry\Admin\Theme;
use Gantry\Component\Controller\BaseController;
use Gantry\Component\Response\HtmlResponse;
use Gantry\Component\Response\Response;
use Gantry\Component\Response\JsonResponse;
use Gantry\Framework\Services\ErrorServiceProvider;
use RocketTheme\Toolbox\DI\Container;
use RocketTheme\Toolbox\Event\EventDispatcher;
use Whoops\Exception\ErrorException;
abstract class Router implements RouterInterface
{
/**
* @var Container
*/
protected $container;
protected $format;
protected $resource;
protected $method;
protected $path;
protected $params;
public function __construct(Container $container)
{
$this->container = $container;
}
public function dispatch()
{
$this->boot();
$this->load();
// Render the page or execute the task.
try {
$response = static::execute($this->resource,
$this->method, $this->path, $this->params, $this->format);
} catch (ErrorException $e) {
throw $e;
} catch (\Exception $e) {
// Handle errors.
if ($this->container->debug()) {
throw $e;
}
$response = $this->getErrorResponse($e, $this->format ==
'json');
}
return $this->send($response);
}
public function execute($resource, $method = 'GET', $path,
$params = [], $format = 'html')
{
$class = '\\Gantry\\Admin\\Controller\\' .
ucfirst($format) . '\\' . strtr(ucwords(strtr($resource,
'/', ' ')), ' ', '\\');
// Protect against CSRF Attacks.
if (!in_array($method, ['GET', 'HEAD'], true)
&& !$this->checkSecurityToken()) {
throw new \RuntimeException('Invalid security token;
please reload the page and try again.', 403);
}
if (!class_exists($class)) {
if ($format === 'json') {
// Special case: All HTML requests can be returned also as
JSON.
$response = $this->execute($resource, $method, $path,
$params, 'html');
return $response instanceof JsonResponse ? $response : new
JsonResponse($response);
}
throw new \RuntimeException('Page Not Found', 404);
}
/** @var BaseController $controller */
$controller = new $class($this->container);
// Execute action.
$response = $controller->execute($method, $path, $params);
if (!$response instanceof Response) {
$response = new HtmlResponse($response);
}
return $response;
}
/**
* @return $this
*/
abstract protected function boot();
abstract protected function checkSecurityToken();
/**
* @return $this
*/
public function load()
{
static $loaded = false;
if ($loaded) {
return $this;
}
$loaded = true;
if (isset($this->container['theme.path']) &&
file_exists($this->container['theme.path'] .
'/includes/gantry.php')) {
include $this->container['theme.path'] .
'/includes/gantry.php';
}
if (isset($this->container['theme'])) {
// Initialize current theme if it is set.
$this->container['theme'];
} else {
// Otherwise initialize streams and error handler manually.
$this->container['streams']->register();
$this->container->register(new ErrorServiceProvider);
}
$this->container['admin.theme'] = function () {
return new Theme(GANTRYADMIN_PATH);
};
// Add event listener.
if (class_exists('Gantry\\Admin\\EventListener')) {
$listener = new EventListener;
/** @var EventDispatcher $events */
$events = $this->container['events'];
$events->addSubscriber($listener);
}
// Boot the service.
$this->container['admin.theme'];
return $this;
}
protected function getErrorResponse(\Exception $e, $json = false)
{
$response = new HtmlResponse;
$response->setStatusCode($e->getCode());
$params = [
'ajax' => $json,
'title' => $response->getStatus(),
'error' => $e,
];
$response->setContent($this->container['admin.theme']->render('@gantry-admin/error.html.twig',
$params));
if ($json) {
return new JsonResponse([$e, $response]);
}
return $response;
}
protected function send(Response $response) {
// Output HTTP header.
header("HTTP/1.1 {$response->getStatus()}", true,
$response->getStatusCode());
header("Content-Type: {$response->mimeType};
charset={$response->charset}");
foreach ($response->getHeaders() as $key => $values) {
foreach ($values as $value) {
header("{$key}: {$value}");
}
}
echo $response;
return true;
}
}
PK&d�[�M�6��3classes/Gantry/Component/Router/RouterInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Router;
interface RouterInterface
{
public function dispatch();
}
PK&d�[X}�q&q&3classes/Gantry/Component/Stylesheet/CssCompiler.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet;
use Gantry\Component\Config\Config;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Framework\Gantry;
use Leafo\ScssPhp\Colors;
use RocketTheme\Toolbox\File\PhpFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class CssCompiler implements CssCompilerInterface
{
use GantryTrait;
protected $type;
protected $name;
protected $debug = false;
protected $warnings = [];
/**
* @var array
*/
protected $fonts;
/**
* @var array
*/
protected $variables;
/**
* @var string
*/
protected $target = 'gantry-theme://css-compiled';
/**
* @var string
*/
protected $configuration = 'default';
/**
* @var array
*/
protected $paths;
/**
* @var array
*/
protected $files;
/**
* @var mixed
*/
protected $compiler;
/**
* @var bool
*/
protected $production;
public function __construct()
{
$gantry = static::gantry();
/** @var Config $global */
$global = $gantry['global'];
// In production mode we do not need to do any other checks.
$this->production = (bool)
$global->get('production');
}
public function getWarnings()
{
return $this->warnings;
}
/**
* @return string
*/
public function getTarget()
{
return $this->target;
}
/**
* @param string $target
* @return $this
*/
public function setTarget($target = null)
{
if ($target !== null) {
$this->target = (string) $target;
}
return $this;
}
/**
* @param string $configuration
* @return $this
*/
public function setConfiguration($configuration = null)
{
if ($configuration !== null) {
$this->configuration = $configuration;
}
return $this;
}
/**
* @param array $fonts
* @return $this
*/
public function setFonts(array $fonts = null)
{
if ($fonts !== null) {
// Normalize font data.
$list = [];
foreach ($fonts as $family => $data) {
$family = strtolower($family);
if (is_array($data)) {
// font: [400: url1, 500: url2, 700: url3]
$list[$family] = $data;
} else {
// font: url
$list[$family] = [400 => (string) $data];
}
}
$this->compiler->setFonts($list);
}
return $this;
}
/**
* @param array $paths
* @return $this
*/
public function setPaths(array $paths = null)
{
if ($paths !== null) {
$this->paths = $paths;
}
return $this;
}
/**
* @param array $files
* @return $this
*/
public function setFiles(array $files = null)
{
if ($files !== null) {
$this->files = $files;
}
return $this;
}
/**
* @param string $name
* @return string
*/
public function getCssUrl($name)
{
$out = $name . ($this->configuration !== 'default' ?
'_'. $this->configuration : '');
return "{$this->target}/{$out}.css";
}
/**
* @return $this
*/
public function compileAll()
{
foreach ($this->files as $file) {
$this->compileFile($file);
}
return $this;
}
public function needsCompile($in, $variables)
{
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$out = $this->getCssUrl($in);
$path = $locator->findResource($out);
// Check if CSS file exists at all.
if (!$path) {
$this->setVariables($variables());
return true;
}
if ($this->production) {
// Open the file to see if it contains development comment in
the beginning of the file.
$handle = fopen($path, 'rb');
$contents = fread($handle, 36);
fclose($handle);
if ($contents === '/* GANTRY5 DEVELOPMENT MODE
ENABLED.') {
$this->setVariables($variables());
return true;
}
// Compare checksum comment in the file.
if ($contents !== $this->checksum()) {
$this->setVariables($variables());
return true;
}
// In production mode we do not need to do any other checks.
return false;
}
$uri = basename($out);
$metaFile =
PhpFile::instance($locator->findResource("gantry-cache://theme/scss/{$uri}.php",
true, true));
// Check if meta file exists.
if (!$metaFile->exists()) {
$this->setVariables($variables());
return true;
}
$content = $metaFile->content();
$metaFile->free();
// Check if filename in meta file matches.
if (empty($content['file']) || $content['file']
!== $out) {
$this->setVariables($variables());
return true;
}
// Check if meta timestamp matches to CSS file.
if (filemtime($path) !== $content['timestamp']) {
$this->setVariables($variables());
return true;
}
$this->setVariables($variables());
// Check if variables have been changed.
$oldVariables = isset($content['variables']) ?
$content['variables'] : [];
if ($oldVariables != $this->getVariables()) {
return true;
}
// Preload all CSS files to locator cache.
foreach ($this->paths as $path) {
$locator->fillCache($path);
}
// Check if any of the imported files have been changed.
$imports = isset($content['imports']) ?
$content['imports'] : [];
if (!$imports) {
return $this->findImport($in) !== null;
}
foreach ($imports as $resource => $timestamp) {
$import = $locator->isStream($resource) ?
$locator->findResource($resource) : realpath($resource);
if (!$import || filemtime($import) !== $timestamp) {
return true;
}
}
return false;
}
public function setVariables(array $variables)
{
$this->variables = array_filter($variables);
foreach($this->variables as &$value) {
// Check variable against colors and units.
/* Test regex against these:
* Should only match the ones marked as +
* - family=Aguafina+Script
* - #zzzzzz
* - #fff
* + #ffaaff
* + 33em
* + 0.5px
* - 50 rem
* - rgba(323,323,2323)
* + rgba(125,200,100,0.3)
* - rgb(120,12,12)
*/
if
(preg_match('/(^(#([a-fA-F0-9]{6})|(rgba\(\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*((0.[0-9]+)|[01])\s*\)))|(\d+(\.\d+){0,1}(rem|em|ex|ch|vw|vh|vmin|vmax|%|px|cm|mm|in|pt|pc))$)/i',
$value)) {
continue;
}
// Check variable against predefined color names (we use Leafo
SCSS Color class to do that).
if (isset(Colors::$cssColors[strtolower($value)])) {
continue;
}
// All the unknown values need to be quoted.
$value = "'{$value}'";
}
return $this;
}
public function getVariables()
{
return $this->variables;
}
public function reset()
{
$this->compiler->reset();
return $this;
}
/**
* @param string $url
* @return null|string
*/
abstract public function findImport($url);
protected function checksum($len = 36)
{
static $checksum;
if (!$checksum) {
$checksum = md5(GANTRY5_VERSION . ' ' .
Gantry::instance()['theme']->version);
}
return '/*' . substr($checksum, 0, $len - 4) .
'*/';
}
protected function createMeta($out, $md5)
{
$gantry = Gantry::instance();
if ($this->production) {
return;
}
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$uri = basename($out);
$metaFile =
PhpFile::instance($locator->findResource("gantry-cache://theme/scss/{$uri}.php",
true, true));
$data = [
'file' => $out,
'timestamp' =>
filemtime($locator->findResource($out)),
'md5' => $md5,
'variables' => $this->getVariables(),
'imports' =>
$this->compiler->getParsedFiles()
];
// Attempt to lock the file for writing.
try {
$metaFile->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
// If meta file wasn't already locked by another process, save
it.
if ($metaFile->locked() !== false) {
$metaFile->save($data);
$metaFile->unlock();
}
$metaFile->free();
}
}
PK&d�[�03��<classes/Gantry/Component/Stylesheet/CssCompilerInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet;
interface CssCompilerInterface
{
/**
* @return array
*/
public function getWarnings();
/**
* @return string
*/
public function getTarget();
/**
* @param string $target
* @return $this
*/
public function setTarget($target = null);
/**
* @param string $configuration
* @return $this
*/
public function setConfiguration($configuration = null);
/**
* @param array $paths
* @return $this
*/
public function setPaths(array $paths = null);
/**
* @param array $files
* @return $this
*/
public function setFiles(array $files = null);
/**
* @param array $fonts
* @return $this
*/
public function setFonts(array $fonts);
/**
* @param string $name
* @return string
*/
public function getCssUrl($name);
public function getVariables();
public function setVariables(array $variables);
public function registerFunction($name, callable $callback);
public function unregisterFunction($name);
public function needsCompile($in, $variables);
public function compileFile($in);
/**
* @return $this
*/
public function reset();
/**
* @return $this
*/
public function compileAll();
public function resetCache();
}
PK&d�[�d瑄,�,5classes/Gantry/Component/Stylesheet/Scss/Compiler.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet\Scss;
use Gantry\Component\Filesystem\Folder;
use Gantry\Framework\Document;
use Gantry\Framework\Gantry;
use Leafo\ScssPhp\Compiler as BaseCompiler;
use Leafo\ScssPhp\Formatter\OutputBlock;
use Leafo\ScssPhp\Parser;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Compiler extends BaseCompiler
{
protected $basePath;
protected $fonts;
protected $usedFonts;
protected $streamNames;
protected $parsedFiles = [];
public function __construct()
{
parent::__construct();
$this->registerFunction('get-font-url', [$this,
'userGetFontUrl']);
$this->registerFunction('get-font-family', [$this,
'userGetFontFamily']);
$this->registerFunction('get-local-fonts', [$this,
'userGetLocalFonts']);
$this->registerFunction('get-local-font-weights',
[$this, 'userGetLocalFontWeights']);
$this->registerFunction('get-local-font-url', [$this,
'userGetLocalFontUrl']);
}
/**
* @param $basePath
*/
public function setBasePath($basePath)
{
/** @var Document $document */
$document = Gantry::instance()['document'];
$this->basePath = rtrim($document->rootUri(), '/')
. '/' . Folder::getRelativePath($basePath);
}
/**
* @param array $fonts
*/
public function setFonts(array $fonts)
{
$this->fonts = $fonts;
}
/**
* @param $args
* @return mixed
*/
public function compileArgs($args)
{
foreach ($args as &$arg) {
$arg = $this->compileValue($arg);
}
return $args;
}
/**
* Get variable
*
* @api
*
* @param string $name
* @param boolean $shouldThrow
* @param BaseCompiler\Environment $env
* @param bool $unreduced
*
* @return mixed
*/
public function get($name, $shouldThrow = true,
BaseCompiler\Environment $env = null, $unreduced = false)
{
try {
return parent::get($name, $shouldThrow, $env, $unreduced);
} catch (\Exception $e) {
echo $e->getMessage() . "\n";
return ['string', '', ['']];
}
}
/**
* @param array $args
* @return string
* @throws \Leafo\ScssPhp\Exception\CompilerException
*/
public function libUrl(array $args)
{
// Function has a single parameter.
$parsed = reset($args);
if (!$parsed) {
$this->throwError('url() is missing parameter');
}
// Compile parsed value to string.
$url = trim($this->compileValue($parsed),
'\'"');
// Handle ../ inside CSS files (points to current theme).
if (strpos($url, '../') === 0 && strpos($url,
'../', 3) === false) {
$url = 'gantry-theme://' . substr($url, 3);
}
// Generate URL, failed streams will be transformed to 404 URLs.
$url = Gantry::instance()['document']->url($url, null,
null, false);
// Changes absolute URIs to relative to make the path to work even
if the site gets moved.
if ($url && $url[0] === '/' &&
$this->basePath) {
$url = Folder::getRelativePathDotDot($url, $this->basePath);
}
// Make sure that all the URLs inside CSS are https compatible by
replacing http:// protocol with //.
if (strpos($url, 'http://') === 0) {
$url = str_replace('http://', '//', $url);
}
// Return valid CSS.
return "url('{$url}')";
}
/**
* get-font-url($my-font-variable);
*
* @param array $args
* @return string
*/
public function userGetFontUrl($args)
{
$value = trim($this->compileValue(reset($args)),
'\'"');
// It's a google font
if (0 === strpos($value, 'family=')) {
$fonts = $this->decodeFonts($value);
$font = reset($fonts);
// Only return url once per font.
if ($font && !isset($this->usedFonts[$font])) {
$this->usedFonts[$font] = true;
return
"url('//fonts.googleapis.com/css?{$value}')";
}
}
return false;
}
/**
* font-family: get-font-family($my-font-variable);
*
* @param array $args
* @return string
*/
public function userGetFontFamily($args)
{
$value = trim($this->compileValue(reset($args)),
'\'"');
return $this->encodeFonts($this->decodeFonts($value));
}
/**
* get-local-fonts($my-font-variable, $my-font-variable2, ...);
*
* @param array $args
* @return array
*/
public function userGetLocalFonts($args)
{
$args = $this->compileArgs($args);
$fonts = [];
foreach ($args as $value) {
// It's a local font, we need to load any of the mapped
fonts from the theme
$fonts = array_merge($fonts, $this->decodeFonts($value,
true));
}
$fonts = $this->getLocalFonts($fonts);
// Create a basic list of strings so that SCSS parser can parse the
list.
$list = [];
foreach ($fonts as $font => $data) {
$list[] = ['string', '"', [$font]];
}
return ['list', ',', $list];
}
/**
* get-local-font-weights(roboto);
*
* @param array $args
* @return array
*/
public function userGetLocalFontWeights($args)
{
$name = trim($this->compileValue(reset($args)),
'\'"');
$weights = isset($this->fonts[$name]) ?
array_keys($this->fonts[$name]) : [];
// Create a list of numbers so that SCSS parser can parse the list.
$list = [];
foreach ($weights as $weight) {
$list[] = ['string', '', [(int) $weight]];
}
return ['list', ',', $list];
}
/**
* get-local-font-url(roboto, 400);
*
* @param array $args
* @return string
*/
public function userGetLocalFontUrl($args)
{
$args = $this->compileArgs($args);
$name = isset($args[0]) ? trim($args[0], '\'"')
: '';
$weight = isset($args[1]) ? $args[1] : 400;
// Only return url once per font.
$weightName = $name . '-' . $weight;
if (isset($this->fonts[$name][$weight]) &&
!isset($this->usedFonts[$weightName])) {
$this->usedFonts[$weightName] = true;
return $this->fonts[$name][$weight];
}
return false;
}
/**
* Get local font data.
*
* @param array $fonts
* @return array
*/
protected function getLocalFonts(array $fonts)
{
$list = [];
foreach ($fonts as $family) {
$family = strtolower($family);
if (isset($this->fonts[$family])) {
$list[$family] = $this->fonts[$family];
}
}
return $list;
}
/**
* Convert array of fonts into a CSS parameter string.
*
* @param array $fonts
* @return string
*/
protected function encodeFonts(array $fonts)
{
array_walk($fonts, function(&$val) {
// Check if font family is one of the 4 default ones, otherwise
add quotes.
if (!\in_array($val, ['cursive', 'serif',
'sans-serif', 'monospace'], true)) {
$val = '"' . $val . '"';
}
});
return implode(', ', $fonts);
}
/**
* Convert string into array of fonts.
*
* @param string $string
* @param bool $localOnly
* @return array
*/
protected function decodeFonts($string, $localOnly = false)
{
if (0 === strpos($string, 'family=')) {
if ($localOnly) {
// Do not return external fonts.
return [];
}
// Matches google font family name
preg_match('/^family=([^&:]+).*$/ui', $string,
$matches);
return [urldecode($matches[1])];
}
// Filter list of fonts and quote them.
$list = (array) explode(',', $string);
array_walk($list, function(&$val) {
$val = trim($val, "'\" \t\n\r\0\x0B");
});
array_filter($list);
return $list;
}
public function reset()
{
$this->usedFonts = [];
return $this;
}
/**
* Instantiate parser
*
* @param string $path
*
* @return \Leafo\ScssPhp\Parser
*/
protected function parserFactory($path)
{
$parser = new Parser($path, count($this->sourceNames),
$this->encoding);
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
$this->sourceNames[] = $locator->isStream($path) ?
$locator->findResource($path, false) : $path;
$this->streamNames[] = $path;
$this->addParsedFile($path);
return $parser;
}
/**
* Adds to list of parsed files
*
* @api
*
* @param string $path
*/
public function addParsedFile($path)
{
if ($path && file_exists($path)) {
$this->parsedFiles[$path] = filemtime($path);
}
}
/**
* Returns list of parsed files
*
* @api
*
* @return array
*/
public function getParsedFiles()
{
return $this->parsedFiles;
}
/**
* Clean parset files.
*
* @api
*/
public function cleanParsedFiles()
{
$this->parsedFiles = [];
}
/**
* Handle import loop
*
* @param string $name
*
* @throws \Exception
*/
protected function handleImportLoop($name)
{
for ($env = $this->env; $env; $env = $env->parent) {
$file = $this->streamNames[$env->block->sourceIndex];
if (realpath($file) === $name) {
$this->throwError('An @import loop has been found:
%s imports %s', $file, basename($file));
break;
}
}
}
/**
* Override function to improve the logic.
*
* @param string $path
* @param OutputBlock $out
*
* @throws \Exception
*/
protected function importFile($path, OutputBlock $out)
{
$this->addParsedFile($path);
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
// see if tree is cached
$realPath = $locator($path);
if (isset($this->importCache[$realPath])) {
$this->handleImportLoop($realPath);
$tree = $this->importCache[$realPath];
} else {
$code = file_get_contents($realPath);
$parser = $this->parserFactory($path);
$tree = $parser->parse($code);
$this->importCache[$realPath] = $tree;
}
$dirname = dirname($path);
array_unshift($this->importPaths, $dirname);
$this->compileChildrenNoReturn($tree->children, $out);
array_shift($this->importPaths);
}
}
PK&d�[�}��4classes/Gantry/Component/Stylesheet/ScssCompiler.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet;
use Gantry\Component\Stylesheet\Scss\Compiler;
use Gantry\Framework\Document;
use Gantry\Framework\Gantry;
use Leafo\ScssPhp\Exception\CompilerException;
use RocketTheme\Toolbox\File\File;
use RocketTheme\Toolbox\File\JsonFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class ScssCompiler extends CssCompiler
{
/**
* @var string
*/
public $type = 'scss';
/**
* @var string
*/
public $name = 'SCSS';
/**
* @var Compiler
*/
protected $compiler;
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->compiler = new Compiler();
if ($this->production) {
$this->compiler->setFormatter('Leafo\ScssPhp\Formatter\Crunched');
} else {
$this->compiler->setFormatter('Leafo\ScssPhp\Formatter\Expanded');
// Work around bugs in SCSS compiler.
// TODO: Pass our own SourceMapGenerator instance instead.
$this->compiler->setSourceMap(Compiler::SOURCE_MAP_INLINE);
$this->compiler->setSourceMapOptions([
'sourceMapBasepath' => '/',
'sourceRoot' => '/',
]);
$this->compiler->setLineNumberStyle(Compiler::LINE_COMMENTS);
}
}
public function compile($in)
{
return $this->compiler->compile($in);
}
public function resetCache()
{
}
/**
* @param string $in Filename without path or extension.
* @return bool True if the output file was saved.
* @throws \RuntimeException
*/
public function compileFile($in)
{
// Buy some extra time as compilation may take a lot of time in
shared environments.
@set_time_limit(30);
@set_time_limit(60);
@set_time_limit(90);
@set_time_limit(120);
ob_start();
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$out = $this->getCssUrl($in);
$path = $locator->findResource($out, true, true);
$file = File::instance($path);
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
if ($file->locked() === false) {
// File was already locked by another process, lets avoid
compiling the same file twice.
return false;
}
// Set the lookup paths.
$this->compiler->setBasePath($path);
$this->compiler->setImportPaths([[$this,
'findImport']]);
// Run the compiler.
$this->compiler->setVariables($this->getVariables());
$scss = '@import "' . $in . '.scss"';
try {
$css = $this->compiler->compile($scss);
} catch (CompilerException $e) {
throw new \RuntimeException("CSS Compilation on file
'{$in}.scss' failed on error: {$e->getMessage()}", 500,
$e);
}
if (strpos($css, $scss) === 0) {
$css = '/* ' . $scss . ' */';
}
// Extract map from css and save it as separate file.
if ($pos = strrpos($css, '/*# sourceMappingURL=')) {
$map = json_decode(urldecode(substr($css, $pos + 43, -3)),
true);
/** @var Document $document */
$document = $gantry['document'];
foreach ($map['sources'] as &$source) {
$source = $document->url($source, null, -1);
}
unset($source);
$mapFile = JsonFile::instance($path . '.map');
$mapFile->save($map);
$mapFile->free();
$css = substr($css, 0, $pos) . '/*#
sourceMappingURL=' . basename($out) . '.map */';
}
$warnings = trim(ob_get_clean());
if ($warnings) {
$this->warnings[$in] = explode("\n", $warnings);
}
if (!$this->production) {
$warning = <<<WARN
/* GANTRY5 DEVELOPMENT MODE ENABLED.
WARNING: This file is automatically generated by Gantry5. Any
modifications to this file will be lost!
For more information on modifying CSS, please read:
http://docs.gantry.org/gantry5/configure/styles
http://docs.gantry.org/gantry5/tutorials/adding-a-custom-style-sheet
*/
WARN;
$css = $warning . "\n\n" . $css;
} else {
$css = "{$this->checksum()}\n{$css}";
}
$file->save($css);
$file->unlock();
$file->free();
$this->createMeta($out, md5($css));
$this->compiler->cleanParsedFiles();
return true;
}
/**
* @param string $name Name of function to register to the
compiler.
* @param callable $callback Function to run when called by the
compiler.
* @return $this
*/
public function registerFunction($name, callable $callback)
{
$this->compiler->registerFunction($name, $callback);
return $this;
}
/**
* @param string $name Name of function to unregister.
* @return $this
*/
public function unregisterFunction($name)
{
$this->compiler->unregisterFunction($name);
return $this;
}
/**
* @param string $url
* @return null|string
* @internal
*/
public function findImport($url)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Ignore vanilla css and external requests.
if (preg_match('/\.css$|^https?:\/\//', $url)) {
return null;
}
// Try both normal and the _partial filename.
$files = array($url, preg_replace('/[^\/]+$/',
'_\0', $url));
foreach ($this->paths as $base) {
foreach ($files as $file) {
if (!preg_match('|\.scss$|', $file)) {
$file .= '.scss';
}
if ($locator->findResource($base . '/' .
$file)) {
return $base . '/' . $file;
}
}
}
return null;
}
}
PK&d�[�i}},classes/Gantry/Component/System/Messages.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Component\System;
class Messages
{
protected $messages = [];
public function add($message, $type = 'warning')
{
$this->messages[] = ['type' => $type,
'message' => $message];
return $this;
}
public function get()
{
return $this->messages;
}
public function clean()
{
$this->messages = [];
return $this;
}
}
PK&d�[�Y�220classes/Gantry/Component/Theme/AbstractTheme.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Twig\TwigCacheFilesystem;
use Gantry\Component\Twig\TwigExtension;
use Gantry\Framework\Platform;
use Gantry\Framework\Services\ErrorServiceProvider;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class AbstractTheme
* @package Gantry\Component
*
* @property string $path
* @property string $layout
*/
abstract class AbstractTheme
{
use GantryTrait;
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $path;
/**
* @var \Twig_Environment
*/
protected $renderer;
/**
* Construct theme object.
*
* @param string $path
* @param string $name
*/
public function __construct($path, $name = null)
{
if (!is_dir($path)) {
throw new \LogicException('Theme not found!');
}
$this->name = $name ? $name : basename($path);
$this->path = $path;
$this->init();
}
/**
* Get context for render().
*
* @param array $context
* @return array
*/
public function getContext(array $context)
{
$context['theme'] = $this;
return $context;
}
/**
* Define twig environment.
*
* @param \Twig_Environment $twig
* @param \Twig_LoaderInterface $loader
* @return \Twig_Environment
*/
public function extendTwig(\Twig_Environment $twig,
\Twig_LoaderInterface $loader = null)
{
if
($twig->hasExtension('Gantry\Component\Twig\TwigExtension')) {
return $twig;
}
if (!$loader) {
$loader = $twig->getLoader();
}
$this->setTwigLoaderPaths($loader);
$twig->addExtension(new TwigExtension);
if (method_exists($this, 'toGrid')) {
$filter = new \Twig_SimpleFilter('toGrid', [$this,
'toGrid']);
$twig->addFilter($filter);
}
return $twig;
}
/**
* Return renderer.
*
* @return \Twig_Environment
*/
public function renderer()
{
if (!$this->renderer) {
$gantry = static::gantry();
/** @var Config $global */
$global = $gantry['global'];
$cachePath = $global->get('compile_twig', 1) ?
$this->getCachePath('twig') : null;
$cache = $cachePath ? new TwigCacheFilesystem($cachePath,
\Twig_Cache_Filesystem::FORCE_BYTECODE_INVALIDATION) : null;
$debug = $gantry->debug();
$production = (bool) $global->get('production',
1);
$loader = new \Twig_Loader_Filesystem();
$params = [
'cache' => $cache,
'debug' => $debug,
'auto_reload' => !$production,
'autoescape' => 'html'
];
$twig = new \Twig_Environment($loader, $params);
$this->setTwigLoaderPaths($loader);
if ($debug) {
$twig->addExtension(new \Twig_Extension_Debug());
}
$this->renderer = $this->extendTwig($twig, $loader);
}
return $this->renderer;
}
/**
* Render a template file by using given context.
*
* @param string $file
* @param array $context
* @return string
*/
public function render($file, array $context = [])
{
// Include Gantry specific things to the context.
$context = $this->getContext($context);
return $this->renderer()->render($file, $context);
}
/**
* Compile and render twig string.
*
* @param string $string
* @param array $context
* @return string
*/
public function compile($string, array $context = [])
{
$renderer = $this->renderer();
$template = $renderer->createTemplate($string);
// Include Gantry specific things to the context.
$context = $this->getContext($context);
return $template->render($context);
}
/**
* Initialize theme.
*/
protected function init()
{
$gantry = static::gantry();
$gantry['streams']->register();
// Only add error service if development or debug mode has been
enabled or user is admin.
if (!$gantry['global']->get('production', 0)
|| $gantry->debug() || $gantry->admin()) {
$gantry->register(new ErrorServiceProvider);
}
// Initialize theme cache stream.
$cachePath = $this->getCachePath();
Folder::create($cachePath);
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$locator->addPath('gantry-cache', 'theme',
[$cachePath], true, true);
CompiledYamlFile::$defaultCachePath =
$locator->findResource('gantry-cache://theme/compiled/yaml',
true, true);
CompiledYamlFile::$defaultCaching =
$gantry['global']->get('compile_yaml', 1);
}
/**
* Set twig lookup paths to the loader.
*
* @param \Twig_LoaderInterface $loader
* @return \Twig_Loader_Filesystem|null
* @internal
*/
protected function setTwigLoaderPaths(\Twig_LoaderInterface $loader)
{
if ($loader instanceof \Twig_Loader_Chain) {
$new = new \Twig_Loader_Filesystem();
$loader->addLoader($new);
$loader = $new;
} elseif (!($loader instanceof \Twig_Loader_Filesystem)) {
return null;
}
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$loader->setPaths($locator->findResources('gantry-engine://templates'),
'nucleus');
$loader->setPaths($locator->findResources('gantry-particles://'),
'particles');
return $loader;
}
/**
* Get path to Twig cache.
*
* @param string $path
* @return string
*/
protected function getCachePath($path = '')
{
$gantry = static::gantry();
/** @var Platform $patform */
$patform = $gantry['platform'];
// Initialize theme cache stream.
return $patform->getCachePath() . '/' . $this->name
. ($path ? '/' . $path : '');
}
/**
* @deprecated 5.0.2
*/
public function debug()
{
return static::gantry()->debug();
}
/**
* @deprecated 5.1.5
*/
public function add_to_context(array $context)
{
return $this->getContext($context);
}
/**
* @deprecated 5.1.5
*/
public function add_to_twig(\Twig_Environment $twig,
\Twig_LoaderInterface $loader = null)
{
return $this->extendTwig($twig, $loader);
}
}
PK&d�[�����/classes/Gantry/Component/Theme/ThemeDetails.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Streams;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class ThemeDetails
* @package Gantry\Component\Theme
*/
class ThemeDetails implements \ArrayAccess
{
use NestedArrayAccessWithGetters, Export;
protected $items;
protected $parent;
/**
* Create new theme details.
*
* @param string $theme
*/
public function __construct($theme)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-themes://{$theme}/gantry/theme.yaml");
if (!$filename) {
throw new \RuntimeException(sprintf('Theme %s not
found', $theme), 404);
}
$cache =
$locator->findResource("gantry-cache://{$theme}/compiled/yaml",
true, true);
$file = CompiledYamlFile::instance($filename);
$this->items = $file->setCachePath($cache)->content();
$file->free();
$this->offsetSet('name', $theme);
$parent = (string)
$this->get('configuration.theme.parent', $theme);
$parent = $parent != $theme ? $parent : null;
$this->offsetSet('parent', $parent);
}
/**
* @return string
*/
public function addStreams()
{
$gantry = Gantry::instance();
// Initialize theme stream.
$streamName =
$this->addStream($this->offsetGet('name'),
$this->getPaths());
// Initialize parent theme streams.
$loaded = [$this->offsetGet('name')];
$details = $this;
while ($details = $details->parent()) {
if (in_array($details->name, $loaded)) {
break;
}
$this->addStream($details->name,
$details->getPaths(false));
$loaded[] = $details->name;
}
/** @var Streams $streams */
$streams = $gantry['streams'];
$streams->register();
return $streamName;
}
/**
* Get parent theme details if theme has a parent.
*
* @return ThemeDetails|null
* @throws \RuntimeException
*/
public function parent()
{
$parent = $this->offsetGet('parent');
if (!$this->parent && $parent) {
try {
$this->parent = new ThemeDetails($parent);
} catch (\RuntimeException $e) {
throw new \RuntimeException(sprintf('Parent theme %s
not found', $parent), 404);
}
}
return $this->parent;
}
/**
* Get all possible paths to the theme.
*
* @return array
*/
public function getPaths($overrides = true)
{
$paths = array_merge(
$overrides ? (array)
$this->get('configuration.theme.overrides',
'gantry-theme://custom') : [],
['gantry-theme://'],
(array) $this->get('configuration.theme.base',
'gantry-theme://common')
);
$parent = $this->offsetGet('parent');
if ($parent) {
// Stream needs to be valid URL.
$streamName = 'gantry-themes-' .
preg_replace('|[^a-z\d+.-]|ui', '-', $parent);
$paths[] = "{$streamName}://";
}
return $this->parsePaths($paths);
}
/**
* Convert theme path into stream URI.
*
* @param string $path
* @return string
*/
public function getUrl($path)
{
$uri = (string) $this->offsetGet($path);
if (strpos($uri, 'gantry-theme://') === 0) {
list (, $uri) = explode('://', $uri, 2);
}
if (!strpos($uri, '://')) {
$name = $this->offsetGet('name');
// Stream needs to be valid URL.
$streamName = 'gantry-themes-' .
preg_replace('|[^a-z\d+.-]|ui', '-', $name);
$uri = "{$streamName}://{$uri}";
}
return $uri;
}
/**
* Turn list of theme paths to be universal, so they can be used
outside of the theme.
*
* @param array $items
* @return array
*/
public function parsePaths(array $items)
{
foreach ($items as &$item) {
$item = $this->parsePath($item);
}
return $items;
}
/**
* Convert theme paths to be universal, so they can be used outside of
the theme.
*
* @param string $path
* @return string
*/
public function parsePath($path)
{
if (strpos($path, 'gantry-theme://') === 0) {
list (, $path) = explode('://', $path, 2);
}
if (!strpos($path, '://')) {
$name = $this->offsetGet('name');
$path = "gantry-themes://{$name}/{$path}";
}
return $path;
}
/**
* @return string|null
* @deprecated 5.1.5
*/
public function getParent()
{
return $this->offsetGet('parent');
}
/**
* @param string $name
* @param array $paths
* @return string|null
*/
protected function addStream($name, $paths)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
/** @var Streams $streams */
$streams = $gantry['streams'];
// Add theme stream.
$streamName = 'gantry-themes-' .
preg_replace('|[^a-z\d+.-]|ui', '-', $name);
if (!$locator->schemeExists($streamName)) {
$streams->add([$streamName => ['paths' =>
$paths]]);
}
return $streamName;
}
}
PK&d�[1���%�%1classes/Gantry/Component/Theme/ThemeInstaller.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Layout\Layout;
use Gantry\Framework\Gantry;
use Gantry\Framework\Platform;
use Gantry\Framework\Services\ErrorServiceProvider;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class ThemeInstaller
{
/**
* Set to true if in Gantry.
*
* @var bool
*/
public $initialized = false;
public $actions = [];
protected $name;
protected $outlines;
protected $script;
public function __construct($extension = null)
{
if ($extension) {
$this->name = $extension;
}
}
abstract public function getPath();
/**
* Get list of available outlines.
*
* @param array $filter
* @return array
*/
public function getOutlines(array $filter = null)
{
if (!isset($this->outlines)) {
$this->outlines = [];
$path = $this->getPath();
// If no outlines are given, try loading outlines.yaml file.
$file = YamlFile::instance($path .
'/install/outlines.yaml');
if ($file->exists()) {
// Load the list from the yaml file.
$this->outlines = (array) $file->content();
$file->free();
} elseif (is_dir($path . '/install/outlines')) {
// Build the list from the install folder.
// recurse = false, full=true
$folders = Folder::all($path .
'/install/outlines', ['folders' => true,
'recursive' => false]);
foreach ($folders as $folder) {
$this->outlines[basename($folder)] = [];
}
}
// Always include system outlines.
$this->outlines += ['default' => [],
'_body_only' => [], '_error' => [],
'_offline' => []];
}
return is_array($filter) ? array_intersect_key($this->outlines,
array_flip($filter)) : $this->outlines;
}
public function getOutline($name)
{
$list = $this->getOutlines([$name]);
return reset($list);
}
public function installDefaults()
{
$installerScript = $this->getInstallerScript();
if ($installerScript && method_exists($installerScript,
'installDefaults')) {
$installerScript->installDefaults($this);
} else {
$this->createDefaults();
}
}
public function installSampleData()
{
$installerScript = $this->getInstallerScript();
if ($installerScript && method_exists($installerScript,
'installSampleData')) {
$installerScript->installSampleData($this);
} else {
$this->createSampleData();
}
}
public function createDefaults()
{
$this->createOutlines();
}
public function createSampleData()
{
}
public function render($template, $context = [])
{
try {
$loader = new \Twig_Loader_Filesystem();
$loader->setPaths([$this->getPath() .
'/install/templates']);
$params = [
'cache' => null,
'debug' => false,
'autoescape' => 'html'
];
$twig = new \Twig_Environment($loader, $params);
$name = $this->name;
$context += [
'name' => $this->translate($name),
'actions' => $this->actions
];
return $twig->render($template, $context);
} catch (\Exception $e) {
return '';
}
}
/**
* Set available outlines.
*
* @param array $outlines If parameter isn't provided, outlines
list get reloaded from the disk.
* @return $this
*/
public function setOutlines(array $outlines = null)
{
$this->outlines = $outlines;
return $this;
}
/**
* @param array $filter
*/
public function createOutlines(array $filter = null)
{
$outlines = $this->getOutlines($filter);
foreach ($outlines as $folder => $params) {
$this->createOutline($folder, $params);
}
}
/**
* @param string $folder
* @param array $params
* @return string|bool
*/
public function createOutline($folder, array $params = [])
{
if (!$folder) {
throw new \RuntimeException('Cannot create outline without
folder name');
}
$this->initialize();
$created = false;
$params += [
'preset' => null,
'title' => null
];
$title = $params['title'] ?: ucwords(trim(strtr($folder,
['_' => ' '])));
$preset = $params['preset'] ?: 'default';
// Copy configuration for the new layout.
if (($this->copyCustom($folder, $folder) || $created)) {
// Update layout and save it.
$layout = Layout::load($folder, $preset);
$layout->save()->saveIndex();
if ($created) {
$this->actions[] = ['action' =>
'outline_created', 'text' =>
$this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_CREATED',
$title)];
} else {
$this->actions[] = ['action' =>
'outline_updated', 'text' =>
$this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_UPDATED',
$title)];
}
}
return $folder;
}
public function initialize()
{
if ($this->initialized) {
return;
}
$name = $this->name;
$path = $this->getPath();
// Remove compiled CSS files if they exist.
$cssPath = $path . '/custom/css-compiled';
if (is_dir($cssPath)) {
Folder::delete($cssPath);
} elseif (is_file($cssPath)) {
@unlink($cssPath);
}
// Remove wrongly named file if it exists.
$md5path = $path . '/MD5SUM';
if (is_file($md5path)) {
@unlink($md5path);
}
// Restart Gantry and initialize it.
$gantry = Gantry::restart();
$gantry['theme.name'] = $name;
$gantry['streams']->register();
// Only add error service if debug mode has been enabled.
if ($gantry->debug()) {
$gantry->register(new ErrorServiceProvider);
}
/** @var Platform $patform */
$patform = $gantry['platform'];
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Initialize theme stream.
$details = new ThemeDetails($name);
$locator->addPath('gantry-theme', '',
$details->getPaths(), false, true);
// Initialize theme cache stream and clear theme cache.
$cachePath = $patform->getCachePath() . '/' . $name;
if (is_dir($cachePath)) {
Folder::delete($cachePath);
}
Folder::create($cachePath);
$locator->addPath('gantry-cache', 'theme',
[$cachePath], true, true);
CompiledYamlFile::$defaultCachePath =
$locator->findResource('gantry-cache://theme/compiled/yaml',
true, true);
CompiledYamlFile::$defaultCaching =
$gantry['global']->get('compile_yaml', 1);
$this->initialized = true;
}
public function finalize()
{
// Copy standard outlines if they haven't been copied already.
$this->copyCustom('default', 'default');
$this->copyCustom('_body_only',
'_body_only');
$this->copyCustom('_error', '_error');
$this->copyCustom('_offline', '_offline');
$this->initialize();
}
/**
* @param string $layout
* @param string $id
* @return bool True if files were copied over.
*/
protected function copyCustom($layout, $id)
{
$path = $this->getPath();
// Only copy files if the target id doesn't exist.
$dst = $path . '/custom/config/' . $id;
if (!$layout || !$id || is_dir($dst)) {
return false;
}
// New location for G5.3.2+
$src = $path . '/install/outlines/' . $layout;
if (!is_dir($src)) {
// Old and deprecated location.
$src = $path . '/install/layouts/' . $layout;
}
try {
is_dir($src) ? Folder::copy($src, $dst) : Folder::create($dst);
} catch (\Exception $e) {
throw new \RuntimeException("Creating configuration for
outline '{$layout}' failed: {$e->getMessage()}", 500,
$e);
}
return true;
}
protected function translate($text)
{
$translator = Gantry::instance()['translator'];
$args = func_get_args();
return call_user_func_array([$translator, 'translate'],
$args);
}
protected function getInstallerScript()
{
if (!$this->script) {
$className = ucfirst($this->name) .
'InstallerScript';
if (!class_exists($className)) {
$path = "{$this->getPath()}/install.php";
if (is_file($path)) {
require_once $path;
}
}
if (class_exists($className)) {
$this->script = new $className;
}
}
return $this->script;
}
}
PK&d�[��IA��1classes/Gantry/Component/Theme/ThemeInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\Config\Config;
use Gantry\Component\Layout\Layout;
use Gantry\Component\Stylesheet\CssCompilerInterface;
/**
* Class ThemeTrait
* @package Gantry\Framework\Base
*
* @property string $path
* @property string $layout
*/
interface ThemeInterface
{
// AbstractTheme class
/**
* Get context for render().
*
* @param array $context
* @return array
*/
public function getContext(array $context);
/**
* Define twig environment.
*
* @param \Twig_Environment $twig
* @param \Twig_LoaderInterface $loader
* @return \Twig_Environment
*/
public function extendTwig(\Twig_Environment $twig,
\Twig_LoaderInterface $loader = null);
/**
* Returns renderer.
*
* @return \Twig_Environment
*/
public function renderer();
/**
* Render a template file.
*
* @param string $file
* @param array $context
* @return string
*/
public function render($file, array $context = array());
// ThemeTrait class
/**
* Update all CSS files in the theme.
*
* @param array $outlines
* @return array List of CSS warnings.
*/
public function updateCss(array $outlines = null);
/**
* Set current layout.
*
* @param string $name
* @param bool $force
* @return $this
*/
public function setLayout($name = null, $force = false);
/**
* Get current preset.
*
* @param bool $forced If true, return only forced preset or null.
* @return string|null $preset
*/
public function preset($forced = false);
/**
* Set preset to be used.
*
* @param string $name
* @return $this
*/
public function setPreset($name = null);
/**
* Return CSS compiler used in the theme.
*
* @return CssCompilerInterface
* @throws \RuntimeException
*/
public function compiler();
/**
* Returns URL to CSS file.
*
* If file does not exist, it will be created by using CSS compiler.
*
* @param string $name
* @return string
*/
public function css($name);
/**
* Return all CSS variables.
*
* @return array
*/
public function getCssVariables();
/**
* Returns style presets for the theme.
*
* @return Config
*/
public function presets();
/**
* Return name of the used layout preset.
*
* @return string
* @throws \RuntimeException
*/
public function type();
/**
* Load current layout and its configuration.
*
* @param string $name
* @return Layout
* @throws \LogicException
*/
public function loadLayout($name = null);
/**
* Check whether layout has content bock.
*
* @return bool
*/
public function hasContent();
/**
* Returns all non-empty segments from the layout.
*
* @return array
*/
public function segments();
/**
* Returns details of the theme.
*
* @return ThemeDetails
*/
public function details();
/**
* Returns configuration of the theme.
*
* @return array
*/
public function configuration();
/**
* Function to convert block sizes into CSS classes.
*
* @param $text
* @return string
*/
public function toGrid($text);
}
PK&d�[b����Z�Z-classes/Gantry/Component/Theme/ThemeTrait.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\Config\Config;
use Gantry\Component\Content\Block\ContentBlock;
use Gantry\Component\Content\Block\HtmlBlock;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Layout\Layout;
use Gantry\Component\Stylesheet\CssCompilerInterface;
use Gantry\Framework\Document;
use Gantry\Framework\Menu;
use Gantry\Framework\Services\ConfigServiceProvider;
use RocketTheme\Toolbox\File\PhpFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class ThemeTrait
* @package Gantry\Component
*
* @property string $path
* @property string $layout
*/
trait ThemeTrait
{
use GantryTrait;
protected $layoutObject;
protected $atoms;
protected $segments;
protected $preset;
protected $cssCache;
/**
* @var CssCompilerInterface
*/
protected $compiler;
protected $equalized = [3 => 33.3, 6 => 16.7, 7 => 14.3, 8
=> 12.5, 9 => 11.1, 11 => 9.1, 12 => 8.3];
/**
* @var ThemeDetails
*/
protected $details;
/**
* Register Theme stream.
*
* @param string $savePath
*/
public function registerStream($savePath = null)
{
$streamName = $this->details()->addStreams();
/** @var UniformResourceLocator $locator */
$locator = self::gantry()['locator'];
$locator->addPath('gantry-theme', '',
array_merge((array) $savePath, [[$streamName, '']]));
}
/**
* Update all CSS files in the theme.
*
* @param array $outlines
* @return array List of CSS warnings.
*/
public function updateCss(array $outlines = null)
{
$gantry = static::gantry();
$compiler = $this->compiler();
if (is_null($outlines)) {
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path = $locator->findResource($compiler->getTarget(),
true, true);
// Make sure that all the CSS files get deleted.
if (is_dir($path)) {
Folder::delete($path, false);
}
$outlines = $gantry['outlines'];
}
// Make sure that PHP has the latest data of the files.
clearstatcache();
$warnings = [];
foreach ($outlines as $outline => $title) {
$config = ConfigServiceProvider::load($gantry, $outline);
$compiler->reset()->setConfiguration($outline)->setVariables($config->flatten('styles',
'-'));
$results = $compiler->compileAll()->getWarnings();
if ($results) {
$warnings[$outline] = $results;
}
}
return $warnings;
}
/**
* Set layout to be used.
*
* @param string $name
* @param bool $force
* @return $this
*/
public function setLayout($name = null, $force = false)
{
$gantry = static::gantry();
// Force new layout to be set.
if ($force) {
unset($gantry['configuration']);
}
// Set default name only if configuration has not been set before.
if ($name === null &&
!isset($gantry['configuration'])) {
$name = 'default';
}
$outline = isset($gantry['configuration']) ?
$gantry['configuration'] : null;
// Set configuration if given.
if ($name && $name != $outline) {
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Using Gantry outline {$name}");
$gantry['configuration'] = $name;
unset($gantry['config']);
$gantry['config'] =
ConfigServiceProvider::load($gantry, $name);
}
return $this;
}
/**
* Get current preset.
*
* @param bool $forced If true, return only forced preset or null.
* @return string|null $preset
*/
public function preset($forced = false)
{
$presets = $this->presets()->toArray();
$preset = $this->preset;
if (!$preset && !$forced) {
$preset =
static::gantry()['config']->get('styles.preset',
'-undefined-');
}
if ($preset && !isset($presets[$preset])) {
$preset = null;
}
return $preset;
}
/**
* Set preset to be used.
*
* @param string $name
* @return $this
*/
public function setPreset($name = null)
{
// Set preset if given.
if ($name) {
$this->preset = $name;
}
return $this;
}
/**
* Return CSS compiler used in the theme.
*
* @return CssCompilerInterface
* @throws \RuntimeException
*/
public function compiler()
{
if (!$this->compiler) {
$compilerClass = (string)
$this->details()->get('configuration.css.compiler',
'\Gantry\Component\Stylesheet\ScssCompiler');
if (!class_exists($compilerClass)) {
throw new \RuntimeException('CSS compiler used by the
theme not found');
}
$details = $this->details();
/** @var CssCompilerInterface $compiler */
$this->compiler = new $compilerClass();
$this->compiler
->setTarget($details->get('configuration.css.target'))
->setPaths($details->get('configuration.css.paths'))
->setFiles($details->get('configuration.css.files'))
->setFonts($details->get('configuration.fonts'));
}
$preset = $this->preset(true);
if ($preset) {
$this->compiler->setConfiguration($preset);
} else {
$gantry = static::gantry();
$this->compiler->setConfiguration(isset($gantry['configuration'])
? $gantry['configuration'] : 'default');
}
return $this->compiler->reset();
}
/**
* Returns URL to CSS file.
*
* If file does not exist, it will be created by using CSS compiler.
*
* @param string $name
* @return string
*/
public function css($name)
{
if (!isset($this->cssCache[$name])) {
$compiler = $this->compiler();
if ($compiler->needsCompile($name, [$this,
'getCssVariables'])) {
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer("css-{$name}", "Compiling CSS:
{$name}") && \Gantry\Debugger::addMessage("Compiling CSS:
{$name}");
$compiler->compileFile($name);
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer("css-{$name}");
}
$this->cssCache[$name] = $compiler->getCssUrl($name);
}
return $this->cssCache[$name];
}
public function getCssVariables()
{
if ($this->preset) {
$variables = $this->presets()->flatten($this->preset .
'.styles', '-');
} else {
$gantry = self::gantry();
$variables =
$gantry['config']->flatten('styles', '-');
}
return $variables;
}
/**
* Returns style presets for the theme.
*
* @return Config
*/
public function presets()
{
static $presets;
if (!$presets) {
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-theme://gantry/presets.yaml");
$file = CompiledYamlFile::instance($filename);
$presets = new Config($file->content());
$file->free();
}
return $presets;
}
/**
* Return name of the used layout preset.
*
* @return string
* @throws \RuntimeException
*/
public function type()
{
if (!$this->layoutObject) {
throw new \RuntimeException('Function called too
early');
}
$name = isset($this->layoutObject->preset['name'])
? $this->layoutObject->preset['name'] :
'unknown';
return $name;
}
/**
* Load current layout and its configuration.
*
* @param string $name
* @return Layout
* @throws \LogicException
*/
public function loadLayout($name = null)
{
if (!$name) {
try {
$name = static::gantry()['configuration'];
} catch (\Exception $e) {
throw new \LogicException('Gantry: Outline has not
been defined yet', 500);
}
}
if (!isset($this->layoutObject) ||
$this->layoutObject->name != $name) {
$layout = Layout::instance($name);
if (!$layout->exists()) {
$layout = Layout::instance('default');
}
// TODO: Optimize
$this->layoutObject = $layout->init();
}
return $this->layoutObject;
}
/**
* Check whether layout has content bock.
*
* @return bool
*/
public function hasContent()
{
$layout = $this->loadLayout();
$content = $layout->referencesByType('system',
'content');
return !empty($content);
}
/**
* Load atoms and assets from the page settings.
*
* @since 5.4.9
*/
public function loadAtoms()
{
if (!isset($this->atoms)) {
$this->atoms = true;
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer('atoms', "Preparing
atoms");
$gantry = static::gantry();
/** @var Config $config */
$config = $gantry['config'];
/** @var \Gantry\Framework\Document $document */
$document = $gantry['document'];
$atoms = (array) $config->get('page.head.atoms');
foreach ($atoms as $data) {
$atom = [
'type' => 'atom',
'subtype' => $data['type'],
] + $data;
try {
$block = $this->getContent($atom);
$document->addBlock($block);
} catch (\Exception $e) {
if ($gantry->debug()) {
throw new \RuntimeException("Rendering Atom
'{$atom['subtype']}' failed on error:
{$e->getMessage()}", 500, $e);
}
}
}
$assets = (array) $config->get('page.assets');
if ($assets) {
$atom = [
'id' => 'page-assets',
'title' => 'Page Assets',
'type' => 'atom',
'subtype' => 'assets',
'attributes' => $assets +
['enabled' => 1]
];
try {
$block = $this->getContent($atom);
$document->addBlock($block);
} catch (\Exception $e) {
if ($gantry->debug()) {
throw new \RuntimeException("Rendering CSS/JS
Assets failed on error: {$e->getMessage()}", 500, $e);
}
}
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer('atoms');
}
}
/**
* Returns all non-empty segments from the layout.
*
* @return array
*/
public function segments()
{
if (!isset($this->segments)) {
$this->segments = $this->loadLayout()->toArray();
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer('segments', "Preparing
layout");
$this->prepareLayout($this->segments);
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer('segments');
}
return $this->segments;
}
/**
* Prepare layout for rendering. Initializes all CSS/JS in particles.
*/
public function prepare()
{
$this->segments();
}
/**
* Returns details of the theme.
*
* @return ThemeDetails
*/
public function details()
{
if (!$this->details) {
$this->details = new ThemeDetails($this->name);
}
return $this->details;
}
/**
* Returns configuration of the theme.
*
* @return array
*/
public function configuration()
{
return (array) $this->details()['configuration'];
}
/**
* Function to convert block sizes into CSS classes.
*
* @param $text
* @return string
*/
public function toGrid($text)
{
if (!$text) {
return '';
}
$number = round($text, 1);
$number = max(5, $number);
$number = (string) ($number == 100 ? 100 : min(95, $number));
static $sizes = array(
'33.3' => 'size-33-3',
'16.7' => 'size-16-7',
'14.3' => 'size-14-3',
'12.5' => 'size-12-5',
'11.1' => 'size-11-1',
'9.1' => 'size-9-1',
'8.3' => 'size-8-3'
);
return isset($sizes[$number]) ? ' ' . $sizes[$number] :
'size-' . (int) $number;
}
/**
* Magic setter method
*
* @param mixed $offset Asset name value
* @param mixed $value Asset value
*/
public function __set($offset, $value)
{
if ($offset == 'title') {
$offset = 'name';
}
$this->details()->offsetSet('details.' . $offset,
$value);
}
/**
* Magic getter method
*
* @param mixed $offset Asset name value
* @return mixed Asset value
*/
public function __get($offset)
{
if ($offset == 'title') {
$offset = 'name';
}
$value = $this->details()->offsetGet('details.' .
$offset);
if ($offset == 'version' && is_int($value)) {
$value .= '.0';
}
return $value;
}
/**
* Magic method to determine if the attribute is set
*
* @param mixed $offset Asset name value
* @return boolean True if the value is set
*/
public function __isset($offset)
{
if ($offset == 'title') {
$offset = 'name';
}
return $this->details()->offsetExists('details.' .
$offset);
}
/**
* Magic method to unset the attribute
*
* @param mixed $offset The name value to unset
*/
public function __unset($offset)
{
if ($offset == 'title') {
$offset = 'name';
}
$this->details()->offsetUnset('details.' .
$offset);
}
/**
* Prepare layout by loading all the positions and particles.
*
* Action is needed before displaying the layout as it recalculates
block widths based on the visible content.
*
* @param array $items
* @param bool $temporary
* @param bool $sticky
* @internal
*/
protected function prepareLayout(array &$items, $temporary = false,
$sticky = false)
{
foreach ($items as $i => &$item) {
// Non-numeric items are meta-data which should be ignored.
if (((string)(int) $i !== (string) $i) || !is_object($item)) {
continue;
}
if (!empty($item->children)) {
$fixed = true;
foreach ($item->children as $child) {
$fixed &= !empty($child->attributes->fixed);
}
$this->prepareLayout($item->children, $fixed,
$temporary);
}
// TODO: remove hard coded types.
switch ($item->type) {
case 'system':
break;
case 'atom':
case 'particle':
case 'position':
case 'spacer':
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer($item->id, "Rendering
{$item->id}");
$item->content = $this->renderContent($item,
['prepare_layout' => true]);
// Note that content can also be null (postpone
rendering).
if ($item->content === '') {
unset($items[$i]);
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer($item->id);
break;
default:
if ($sticky) {
$item->attributes->sticky = 1;
break;
}
if (empty($item->children)) {
unset($items[$i]);
break;
}
$dynamicSize = 0;
$fixedSize = 0;
$childrenCount = count($item->children);
foreach ($item->children as $child) {
if (!isset($child->attributes->size)) {
$child->attributes->size = 100 /
count($item->children);
}
if (empty($child->attributes->fixed)) {
$dynamicSize += $child->attributes->size;
} else {
$fixedSize += $child->attributes->size;
}
}
$roundSize = round($dynamicSize, 1);
$equalized = isset($this->equalized[$childrenCount])
? $this->equalized[$childrenCount] : 0;
// force-casting string for testing comparison due to
weird PHP behavior that returns wrong result
if ($roundSize != 100 && (string) $roundSize !=
(string) ($equalized * $childrenCount)) {
$fraction = 0;
$multiplier = (100 - $fixedSize) / ($dynamicSize ?:
1);
foreach ($item->children as $child) {
if (!empty($child->attributes->fixed)) {
continue;
}
// Calculate size for the next item by taking
account the rounding error from the last item.
// This will allow us to approximate cumulating
error and fix it when rounding error grows
// over the rounding treshold.
$size = ($child->attributes->size *
$multiplier) + $fraction;
$newSize = round($size);
$fraction = $size - $newSize;
$child->attributes->size = $newSize;
}
}
}
}
}
/**
* Renders individual content block, like particle or position.
*
* Function is used to pre-render content.
*
* @param object|array $item
* @param array $options
* @return string|null
*/
public function renderContent($item, $options = [])
{
$gantry = static::gantry();
$content = $this->getContent($item, $options);
/** @var Document $document */
$document = $gantry['document'];
$document->addBlock($content);
$html = $content->toString();
return !strstr($html, '@@DEFERRED@@') ? $html : null;
}
/**
* Renders individual content block, like particle or position.
*
* Function is used to pre-render content.
*
* @param object|array $item
* @param array $options
* @return ContentBlock
* @since 5.4.3
*/
public function getContent($item, $options = [])
{
if (is_array($item)) {
$item = (object) $item;
}
$gantry = static::gantry();
/** @var Config $global */
$global = $gantry['global'];
$production = (bool) $global->get('production');
$subtype = $item->subtype;
$enabled =
$gantry['config']->get("particles.{$subtype}.enabled",
1);
if (!$enabled) {
return new HtmlBlock;
}
$attributes = isset($item->attributes) ? $item->attributes :
[];
$particle =
$gantry['config']->getJoined("particles.{$subtype}",
$attributes);
$cached = false;
$cacheKey = [];
// Enable particle caching only in production mode.
if ($production && isset($particle['caching'])) {
$caching = $particle['caching'] + ['type'
=> 'dynamic'];
switch ($caching['type']) {
case 'static':
$cached = true;
break;
case 'config_matches':
if
(isset($particle['caching']['values'])) {
$values = (array)
$particle['caching']['values'];
$compare = array_intersect_key($particle, $values);
$cached = ($values === $compare);
}
break;
case 'menu':
/** @var Menu $menu */
$menu = $gantry['menu'];
$cacheId = $menu->getCacheId();
// FIXME: menu caching needs to handle dynamic modules
inside menu: turning it off for now.
if (false && $cacheId !== null) {
$cached = true;
$cacheKey['menu_cache_key'] = $cacheId;
}
break;
}
}
if ($cached) {
$cacheKey['language'] =
$gantry['page']->language;
$cacheKey['attributes'] = $particle;
$cacheKey += (array) $item;
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$key = md5(json_encode($cacheKey));
$filename =
$locator->findResource("gantry-cache://theme/html/{$key}.php",
true, true);
$file = PhpFile::instance($filename);
if ($file->exists()) {
try {
return ContentBlock::fromArray((array)
$file->content());
} catch (\Exception $e) {
// Invalid cache, continue to rendering.
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage(sprintf('Failed to load %s %s
cache', $item->type, $item->id), 'debug');
}
}
}
// Create new document context for assets.
$context = $this->getContext(['segment' => $item,
'enabled' => 1, 'particle' => $particle] +
$options);
/** @var Document $document */
$document = $gantry['document'];
$document->push();
$html =
trim($this->render("@nucleus/content/{$item->type}.html.twig",
$context));
$content = $document->pop()->setContent($html);
if (isset($file)) {
// Save HTML and assets into the cache.
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage(sprintf('Caching %s %s',
$item->type, $item->id), 'debug');
$file->save($content->toArray());
}
return $content;
}
}
PK&d�[$�E��
�
2classes/Gantry/Component/Translator/Translator.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Translator;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Translator implements TranslatorInterface
{
protected $default = 'en';
protected $active = 'en';
protected $sections = [];
protected $translations = [];
protected $untranslated = [];
public function translate($string)
{
if (preg_match('|^GANTRY5(_[A-Z0-9]+){2,}$|', $string)) {
list(, $section, $code) = explode('_', $string, 3);
$string = ($this->find($this->active, $section, $string)
?: $this->find($this->default, $section, $string)) ?: $string;
}
if (func_num_args() === 1) {
return $string;
}
$args = func_get_args();
$args[0] = $string;
return call_user_func_array('sprintf', $args);
}
/**
* Set new active language if given and return previous active
language.
*
* @param string $language Language code. If not given, current
language is kept.
* @return string Previously active language.
*/
public function active($language = null)
{
$previous = $this->active;
if ($language) {
$this->active = $language;
}
return $previous;
}
public function untranslated()
{
return $this->untranslated;
}
protected function find($language, $section, $string)
{
if (!isset($this->sections[$language][$section])) {
$translations = $this->load($language, $section);
if (isset($this->translations[$language])) {
$this->translations[$language] += $translations;
} else {
$this->translations[$language] = $translations;
}
$this->sections[$language][$section] =
!empty($translations);
}
if (!isset($this->translations[$language][$string])) {
$this->untranslated[$language][$section][$string] = null;
return null;
}
return $this->translations[$language][$string];
}
protected function load($language, $section)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$section = strtolower($section);
if ($section === 'engine') {
// TODO: add support for other engines than nucleus.
$section = 'nucleus';
}
$filename = 'gantry-admin://translations/' . $language .
'/' . $section . '.yaml';
$file = CompiledYamlFile::instance($filename);
if (!$file->exists() && ($pos = strpos($language,
'-')) > 0) {
$filename = 'gantry-admin://translations/' .
substr($language, 0, $pos) . '/' . $section . '.yaml';
$file = CompiledYamlFile::instance($filename);
}
$cachePath =
$locator->findResource('gantry-cache://translations', true,
true);
$translations = (array)
$file->setCachePath($cachePath)->content();
$file->free();
return $translations;
}
}
PK&d�[�f��GG;classes/Gantry/Component/Translator/TranslatorInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Translator;
interface TranslatorInterface
{
/**
* @param string $string
* @return string
*/
public function translate($string);
/**
* Set new active language if given and return previous active
language.
*
* @param string $language Language code. If not given, current
language is kept.
* @return string Previously active language.
*/
public function active($language = null);
}
PK&d�[�Ϸ�5classes/Gantry/Component/Twig/Node/TwigNodeAssets.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeAssets extends \Twig_Node implements
\Twig_NodeCaptureInterface
{
protected $tagName = 'assets';
public function __construct(\Twig_Node $body = null,
\Twig_Node_Expression $location = null, \Twig_Node_Expression $variables =
null, $lineno = 0, $tag = null)
{
parent::__construct(['body' => $body,
'location' => $location, 'variables' =>
$variables], [], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this)
->write("\$assetFunction =
\$this->env->getFunction('parse_assets')->getCallable();\n")
->write('$assetVariables = ')
->subcompile($this->getNode('variables'))
->raw(";\n")
->write("if (\$assetVariables &&
!is_array(\$assetVariables)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} with x %}: x is not an array');\n")
->outdent()
->write("}\n")
->write('$location = ')
->subcompile($this->getNode('location'))
->raw(";\n")
->write("if (\$location &&
!is_string(\$location)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} in x %}: x is not a string');\n")
->outdent()
->write("}\n")
->write("\$priority =
isset(\$assetVariables['priority']) ?
\$assetVariables['priority'] : 0;\n")
->write("ob_start();\n")
->subcompile($this->getNode('body'))
->write("\$content = ob_get_clean();\n")
->write("\$assetFunction(\$content, \$location,
\$priority);\n");
}
}
PK&d�[���y��7classes/Gantry/Component/Twig/Node/TwigNodeMarkdown.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeMarkdown extends \Twig_Node implements
\Twig_NodeOutputInterface
{
public function __construct(\Twig_Node $body, $lineno, $tag =
'markdown')
{
parent::__construct(['body' => $body], [], $lineno,
$tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('ob_start();' . PHP_EOL)
->subcompile($this->getNode('body'))
->write('$content = ob_get_clean();' . PHP_EOL)
->write('preg_match("/^\s*/", $content,
$matches);' . PHP_EOL)
->write('$lines = explode("\n",
$content);' . PHP_EOL)
->write('$content = preg_replace(\'/^\' .
$matches[0]. \'/\', "", $lines);' . PHP_EOL)
->write('$content = join("\n",
$content);' . PHP_EOL)
->write('echo
$this->env->getExtension(\'Gantry\Component\Twig\TwigExtension\')->markdownFunction($content);'
. PHP_EOL);
}
}
PK&d�[7n^c��8classes/Gantry/Component/Twig/Node/TwigNodePageblock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodePageblock extends \Twig_Node implements
\Twig_NodeCaptureInterface
{
protected $tagName = 'pageblock';
public function __construct(\Twig_Node $body = null,
\Twig_Node_Expression $location = null, \Twig_Node_Expression $variables =
null, $lineno = 0, $tag = null)
{
parent::__construct(['body' => $body,
'location' => $location, 'variables' =>
$variables], [], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this)
->write('$pageblockVariables = ')
->subcompile($this->getNode('variables'))
->raw(";\n")
->write("if (\$pageblockVariables &&
!is_array(\$pageblockVariables)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} with x %}: x is not an array');\n")
->outdent()
->write("}\n")
->write('$location = ')
->subcompile($this->getNode('location'))
->raw(";\n")
->write("if (\$location &&
!is_string(\$location)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} in x %}: x is not a string');\n")
->outdent()
->write("}\n")
->write("\$priority =
isset(\$pageblockVariables['priority']) ?
\$pageblockVariables['priority'] : 0;\n")
->write("ob_start();\n")
->subcompile($this->getNode('body'))
->write("\$content = ob_get_clean();\n")
->write("Gantry\Framework\Gantry::instance()['document']->addHtml(\$content,
\$priority, \$location);\n");
}
}
PK&d�[�ܽ���6classes/Gantry/Component/Twig/Node/TwigNodeScripts.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeScripts extends TwigNodeAssets
{
protected $tagName = 'scripts';
}
PK&d�[JtE5��5classes/Gantry/Component/Twig/Node/TwigNodeStyles.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeStyles extends TwigNodeScripts
{
protected $tagName = 'styles';
}
PK&d�[�$�� 5classes/Gantry/Component/Twig/Node/TwigNodeSwitch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeSwitch extends \Twig_Node
{
public function __construct(\Twig_Node $value, \Twig_Node $cases,
\Twig_Node $default = null, $lineno = 0, $tag = null)
{
parent::__construct(array('value' => $value,
'cases' => $cases, 'default' => $default),
array(), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('switch (')
->subcompile($this->getNode('value'))
->raw(") {\n")
->indent();
foreach ($this->getNode('cases') as $case) {
if (!$case->hasNode('body')) {
continue;
}
foreach ($case->getNode('values') as $value) {
$compiler
->write('case ')
->subcompile($value)
->raw(":\n");
}
$compiler
->write("{\n")
->indent()
->subcompile($case->getNode('body'))
->write("break;\n")
->outdent()
->write("}\n");
}
if ($this->hasNode('default') &&
$this->getNode('default') !== null) {
$compiler
->write("default:\n")
->write("{\n")
->indent()
->subcompile($this->getNode('default'))
->outdent()
->write("}\n");
}
$compiler
->outdent()
->write("}\n");
}
}
PK&d�[�K��4classes/Gantry/Component/Twig/Node/TwigNodeThrow.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeThrow extends \Twig_Node
{
public function __construct(
$code,
\Twig_Node $message,
$lineno = 0,
$tag = null
)
{
parent::__construct(['message' => $message],
['code' => $code], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
* @throws \LogicException
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
$compiler
->write('throw new \RuntimeException(')
->subcompile($this->getNode('message'))
->write(', ')
->write($this->getAttribute('code') ?: 500)
->write(");\n");
}
}
PK&d�[Bh���7classes/Gantry/Component/Twig/Node/TwigNodeTryCatch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeTryCatch extends \Twig_Node
{
public function __construct(\Twig_Node $try, \Twig_Node $catch = null,
$lineno = 0, $tag = null)
{
parent::__construct(array('try' => $try,
'catch' => $catch), array(), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
$compiler
->write('try {')
;
$compiler
->indent()
->subcompile($this->getNode('try'))
;
if ($this->hasNode('catch') && null !==
$this->getNode('catch')) {
$compiler
->outdent()
->write('} catch (\Exception $e) {' .
"\n")
->indent()
->write('if
($context[\'gantry\']->debug()) throw $e;' .
"\n")
->write('GANTRY_DEBUGGER &&
method_exists(\'Gantry\\Debugger\', \'addException\')
&& \Gantry\Debugger::addException($e);' . "\n")
->write('$context[\'e\'] = $e;' .
"\n")
->subcompile($this->getNode('catch'))
;
}
$compiler
->outdent()
->write("}\n");
}
}
PK&d�[��5��
�
?classes/Gantry/Component/Twig/TokenParser/TokenParserAssets.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeScripts;
/**
* Adds javascript / style assets to head/footer/custom location.
*
* {% assets in 'head' with { priority: 2 } %}
* <script type="text/javascript" src="{{
url('gantry-theme://js/my.js') }}"></script>
* <link rel="stylesheet" href="{{
url('gantry-assets://css/font-awesome.min.css') }}"
type="text/css"/>
* {% endassets -%}
*/
class TokenParserAssets extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
list($location, $variables) = $this->parseArguments($token);
$content = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeScripts($content, $location, $variables,
$lineno, $this->getTag());
}
/**
* @param \Twig_Token $token
* @return array
*/
protected function parseArguments(\Twig_Token $token)
{
$stream = $this->parser->getStream();
$location = null;
if ($stream->nextIf(\Twig_Token::OPERATOR_TYPE, 'in'))
{
$location =
$this->parser->getExpressionParser()->parseExpression();
} else {
$lineno = $token->getLine();
$location = new
\Twig_Node_Expression_Constant('head', $lineno);
}
if ($stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) {
$variables =
$this->parser->getExpressionParser()->parseExpression();
} else {
$lineno = $token->getLine();
$variables = new \Twig_Node_Expression_Array([], $lineno);
$variables->setAttribute('priority', 0);
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return [$location, $variables];
}
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endassets');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'assets';
}
}
PK&d�[B�$��Aclasses/Gantry/Component/Twig/TokenParser/TokenParserMarkdown.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeMarkdown;
/**
* Adds ability to inline markdown between tags.
*
* {% markdown %}
* This is **bold** and this _underlined_
*
* 1. This is a bullet list
* 2. This is another item in that same list
* {% endmarkdown %}
*/
class TokenParserMarkdown extends \Twig_TokenParser
{
/**
* {@inheritdoc}
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this,
'decideMarkdownEnd'), true);
$this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeMarkdown($body, $lineno, $this->getTag());
}
/**
* Decide if current token marks end of Markdown block.
*
* @param \Twig_Token $token
* @return bool
*/
public function decideMarkdownEnd(\Twig_Token $token)
{
return $token->test('endmarkdown');
}
/**
* {@inheritdoc}
*/
public function getTag()
{
return 'markdown';
}
}
PK&d�[I��\ \ Bclasses/Gantry/Component/Twig/TokenParser/TokenParserPageblock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodePageblock;
/**
* Adds javascript / style assets to head/footer/custom location.
*
* {% pageblock in 'bottom' with { priority: 0 } %}
* <div>Bottom HTML</div>
* {% endpageblock -%}
*/
class TokenParserPageblock extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
list($location, $variables) = $this->parseArguments($token);
$content = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodePageblock($content, $location, $variables,
$lineno, $this->getTag());
}
/**
* @param \Twig_Token $token
* @return array
*/
protected function parseArguments(\Twig_Token $token)
{
$stream = $this->parser->getStream();
$lineno = $token->getLine();
$location = new
\Twig_Node_Expression_Constant($stream->expect(\Twig_Token::NAME_TYPE)->getValue(),
$lineno);
if ($stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) {
$variables =
$this->parser->getExpressionParser()->parseExpression();
} else {
$lineno = $token->getLine();
$variables = new \Twig_Node_Expression_Array([], $lineno);
$variables->setAttribute('priority', 0);
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return [$location, $variables];
}
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endpageblock');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'pageblock';
}
}
PK&d�[
FX���@classes/Gantry/Component/Twig/TokenParser/TokenParserScripts.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
/**
* Adds scripts to head/footer/custom location.
*
* {% scripts in 'head' with { priority: 2 } %}
* <script type="text/javascript" src="{{
url('gantry-theme://js/my.js') }}"></script>
* {% endscripts -%}
*/
class TokenParserScripts extends TokenParserAssets
{
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endscripts');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'scripts';
}
}
PK&d�[�++B��?classes/Gantry/Component/Twig/TokenParser/TokenParserStyles.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
/**
* Adds stylesheets to document.
*
* {% styles with { priority: 2 } %}
* <link rel="stylesheet" href="{{
url('gantry-assets://css/font-awesome.min.css') }}"
type="text/css"/>
* {% endstyles -%}
*/
class TokenParserStyles extends TokenParserAssets
{
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endstyles');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'styles';
}
}
PK&d�[���#��?classes/Gantry/Component/Twig/TokenParser/TokenParserSwitch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeSwitch;
/**
* Adds ability use elegant switch instead of ungainly if statements
*
* {% switch type %}
* {% case 'foo' %}
* {{ my_data.foo }}
* {% case 'bar' %}
* {{ my_data.bar }}
* {% default %}
* {{ my_data.default }}
* {% endswitch %}
*/
class TokenParserSwitch extends \Twig_TokenParser
{
/**
* {@inheritdoc}
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$name =
$this->parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
// There can be some whitespace between the {% switch %} and first
{% case %} tag.
while ($stream->getCurrent()->getType() ===
\Twig_Token::TEXT_TYPE &&
trim($stream->getCurrent()->getValue()) === '') {
$stream->next();
}
$stream->expect(\Twig_Token::BLOCK_START_TYPE);
$expressionParser = $this->parser->getExpressionParser();
$default = null;
$cases = [];
$end = false;
while (!$end) {
$next = $stream->next();
switch ($next->getValue()) {
case 'case':
$values = [];
while (true) {
$values[] =
$expressionParser->parsePrimaryExpression();
// Multiple allowed values?
if ($stream->test(\Twig_Token::OPERATOR_TYPE,
'or')) {
$stream->next();
} else {
break;
}
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this,
'decideIfFork'));
$cases[] = new \Twig_Node([
'values' => new \Twig_Node($values),
'body' => $body
]);
break;
case 'default':
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$default = $this->parser->subparse(array($this,
'decideIfEnd'));
break;
case 'endswitch':
$end = true;
break;
default:
throw new \Twig_Error_Syntax(sprintf('Unexpected
end of template. Twig was looking for the following tags "case",
"default", or "endswitch" to close the
"switch" block started at line %d)', $lineno), -1);
}
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeSwitch($name, new \Twig_Node($cases), $default,
$lineno, $this->getTag());
}
/**
* Decide if current token marks switch logic.
*
* @param \Twig_Token $token
* @return bool
*/
public function decideIfFork(\Twig_Token $token)
{
return $token->test(array('case', 'default',
'endswitch'));
}
/**
* Decide if current token marks end of swtich block.
*
* @param \Twig_Token $token
* @return bool
*/
public function decideIfEnd(\Twig_Token $token)
{
return $token->test(array('endswitch'));
}
/**
* {@inheritdoc}
*/
public function getTag()
{
return 'switch';
}
}
PK&d�[�ʱtt>classes/Gantry/Component/Twig/TokenParser/TokenParserThrow.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeThrow;
/**
* Handles try/catch in template file.
*
* <pre>
* {% throw 404 'Not Found' %}
* </pre>
*/
class TokenParserThrow extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$code =
$stream->expect(\Twig_Token::NUMBER_TYPE)->getValue();
$message =
$this->parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeThrow($code, $message, $lineno,
$this->getTag());
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'throw';
}
}
PK&d�[�TLLAclasses/Gantry/Component/Twig/TokenParser/TokenParserTryCatch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeTryCatch;
/**
* Handles try/catch in template file.
*
* <pre>
* {% try %}
* <li>{{ user.get('name') }}</li>
* {% catch %}
* {{ e.message }}
* {% endcatch %}
* </pre>
*/
class TokenParserTryCatch extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$try = $this->parser->subparse([$this,
'decideCatch']);
$stream->next();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$catch = $this->parser->subparse([$this,
'decideEnd']);
$stream->next();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeTryCatch($try, $catch, $lineno,
$this->getTag());
}
public function decideCatch(\Twig_Token $token)
{
return $token->test(array('catch'));
}
public function decideEnd(\Twig_Token $token)
{
return $token->test(array('endtry')) ||
$token->test(array('endcatch'));
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'try';
}
}
PK&d�[�
�5classes/Gantry/Component/Twig/TwigCacheFilesystem.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig;
/**
* Class TwigCacheFilesystem
* @package Gantry\Component\Twig
*
* Replaces \Twig_Cache_Filesystem, needed for being able to change PHP
versions on fly.
*/
class TwigCacheFilesystem implements \Twig_CacheInterface
{
const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
/**
* @param $directory string The root cache directory
* @param $options int A set of options
*/
public function __construct($directory, $options = 0)
{
$this->directory = rtrim($directory,
'\/').'/';
$this->options = $options;
}
/**
* {@inheritdoc}
*/
public function generateKey($name, $className)
{
$hash = hash('sha256', $className . '-' .
PHP_VERSION);
return
$this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
/**
* {@inheritdoc}
*/
public function load($key)
{
@include_once $key;
}
/**
* {@inheritdoc}
*/
public function write($key, $content)
{
$dir = dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true) &&
!is_dir($dir)) {
throw new \RuntimeException(sprintf('Unable to create
the cache directory (%s).', $dir));
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in
the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) &&
@rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options
& self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (function_exists('opcache_invalidate')) {
// Silence error in case if `opcache.restrict_api`
directive is set.
@opcache_invalidate($key, true);
} elseif (function_exists('apc_compile_file')) {
@apc_compile_file($key);
}
}
return;
}
throw new \RuntimeException(sprintf('Failed to write cache
file "%s".', $key));
}
/**
* {@inheritdoc}
*/
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}
PK&d�[K�
k�Q�Q/classes/Gantry/Component/Twig/TwigExtension.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig;
use Gantry\Component\Content\Document\HtmlDocument;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Translator\TranslatorInterface;
use Gantry\Component\Twig\TokenParser\TokenParserPageblock;
use Gantry\Component\Twig\TokenParser\TokenParserAssets;
use Gantry\Component\Twig\TokenParser\TokenParserScripts;
use Gantry\Component\Twig\TokenParser\TokenParserStyles;
use Gantry\Component\Twig\TokenParser\TokenParserTryCatch;
use Gantry\Component\Twig\TokenParser\TokenParserMarkdown;
use Gantry\Component\Twig\TokenParser\TokenParserSwitch;
use Gantry\Component\Twig\TokenParser\TokenParserThrow;
use Gantry\Framework\Gantry;
use Gantry\Framework\Markdown\Parsedown;
use Gantry\Framework\Markdown\ParsedownExtra;
use Gantry\Framework\Request;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess;
class TwigExtension extends \Twig_Extension implements
\Twig_Extension_GlobalsInterface
{
use GantryTrait;
/**
* Register some standard globals
*
* @return array
*/
public function getGlobals()
{
return [
'gantry' => static::gantry(),
];
}
/**
* Return a list of all filters.
*
* @return array
*/
public function getFilters()
{
$filters = [
new \Twig_SimpleFilter('html', [$this,
'htmlFilter']),
new \Twig_SimpleFilter('url', [$this,
'urlFunc']),
new \Twig_SimpleFilter('trans_key', [$this,
'transKeyFilter']),
new \Twig_SimpleFilter('trans', [$this,
'transFilter']),
new \Twig_SimpleFilter('repeat', [$this,
'repeatFilter']),
new \Twig_SimpleFilter('values', [$this,
'valuesFilter']),
new \Twig_SimpleFilter('base64',
'base64_encode'),
new \Twig_SimpleFilter('imagesize', [$this,
'imageSize']),
new \Twig_SimpleFilter('truncate_text', [$this,
'truncateText']),
new \Twig_SimpleFilter('attribute_array', [$this,
'attributeArrayFilter'], ['is_safe' =>
['html']]),
];
if (1 || GANTRY5_PLATFORM !== 'grav') {
$filters = array_merge($filters, [
new \Twig_SimpleFilter('fieldName', [$this,
'fieldNameFilter']),
new \Twig_SimpleFilter('json_decode', [$this,
'jsonDecodeFilter']),
new \Twig_SimpleFilter('truncate_html', [$this,
'truncateHtml']),
new \Twig_SimpleFilter('markdown', [$this,
'markdownFunction'], ['is_safe' =>
['html']]),
new \Twig_SimpleFilter('nicetime', [$this,
'nicetimeFilter']),
// Casting values
new \Twig_SimpleFilter('string', [$this,
'stringFilter']),
new \Twig_SimpleFilter('int', [$this,
'intFilter'], ['is_safe' => ['all']]),
new \Twig_SimpleFilter('bool', [$this,
'boolFilter']),
new \Twig_SimpleFilter('float', [$this,
'floatFilter'], ['is_safe' => ['all']]),
new \Twig_SimpleFilter('array', [$this,
'arrayFilter']),
]);
}
return $filters;
}
/**
* Return a list of all functions.
*
* @return array
*/
public function getFunctions()
{
$functions = [
new \Twig_SimpleFunction('nested', [$this,
'nestedFunc']),
new \Twig_SimpleFunction('parse_assets', [$this,
'parseAssetsFunc']),
new \Twig_SimpleFunction('colorContrast', [$this,
'colorContrastFunc']),
new \Twig_SimpleFunction('get_cookie', [$this,
'getCookie']),
new \Twig_SimpleFunction('preg_match', [$this,
'pregMatch']),
new \Twig_SimpleFunction('imagesize', [$this,
'imageSize']),
new \Twig_SimpleFunction('is_selected', [$this,
'is_selectedFunc']),
new \Twig_SimpleFunction('url', [$this,
'urlFunc']),
];
if (1 || GANTRY5_PLATFORM !== 'grav') {
$functions = array_merge($functions, [
new \Twig_SimpleFunction('array', [$this,
'arrayFilter']),
new \Twig_SimpleFunction('json_decode', [$this,
'jsonDecodeFilter']),
]);
}
return $functions;
}
/**
* @return array
*/
public function getTokenParsers()
{
return [
new TokenParserPageblock(),
new TokenParserAssets(),
new TokenParserScripts(),
new TokenParserStyles(),
new TokenParserThrow(),
new TokenParserTryCatch(),
new TokenParserMarkdown(),
new TokenParserSwitch()
];
}
/**
* Filters field name by changing dot notation into array notation.
*
* @param string $str
* @return string
*/
public function fieldNameFilter($str)
{
$path = explode('.', $str);
return array_shift($path) . ($path ? '[' .
implode('][', $path) . ']' : '');
}
/**
* Translate by using key, default on original string.
*
* @param $str
* @return string
*/
public function transKeyFilter($str)
{
$params = \func_get_args();
array_shift($params);
$key = preg_replace('|[^A-Z0-9]+|', '_',
strtoupper(implode('_', $params)));
$translation = $this->transFilter($key);
return $translation === $key ? $str : $translation;
}
/**
* Translate string.
*
* @param string $str
* @return string
*/
public function transFilter($str)
{
/** @var TranslatorInterface $translator */
static $translator;
$params = \func_get_args();
if (!$translator) {
$translator = self::gantry()['translator'];
}
return \call_user_func_array([$translator, 'translate'],
$params);
}
/**
* Repeat string x times.
*
* @param string $str
* @param int $count
* @return string
*/
public function repeatFilter($str, $count)
{
return str_repeat($str, max(0, (int) $count));
}
/**
* Decodes string from JSON.
*
* @param string $str
* @param bool $assoc
* @param int $depth
* @param int $options
* @return array
*/
public function jsonDecodeFilter($str, $assoc = false, $depth = 512,
$options = 0)
{
return json_decode(html_entity_decode($str), $assoc, $depth,
$options);
}
public function imageSize($src, $attrib = true, $remote = false)
{
// TODO: need to better handle absolute and relative paths
//$url =
Gantry::instance()['document']->url(trim((string) $src),
false, false);
$width = $height = null;
$sizes = ['width' => $width, 'height' =>
$height];
$attr = '';
if (@is_file($src) || $remote) {
try {
list($width, $height,, $attr) = @getimagesize($src);
} catch (\Exception $e) {}
$sizes['width'] = $width;
$sizes['height'] = $height;
}
return $attrib ? $attr : $sizes;
}
/**
* Reindexes values in array.
*
* @param array $array
* @return array
*/
public function valuesFilter(array $array)
{
return array_values($array);
}
/**
* Casts input to string.
*
* @param mixed $input
* @return string
*/
public function stringFilter($input)
{
return (string) $input;
}
/**
* Casts input to int.
*
* @param mixed $input
* @return int
*/
public function intFilter($input)
{
return (int) $input;
}
/**
* Casts input to bool.
*
* @param mixed $input
* @return bool
*/
public function boolFilter($input)
{
return (bool) $input;
}
/**
* Casts input to float.
*
* @param mixed $input
* @return float
*/
public function floatFilter($input)
{
return (float) $input;
}
/**
* Casts input to array.
*
* @param mixed $input
* @return array
*/
public function arrayFilter($input)
{
return (array) $input;
}
/**
* Takes array of attribute keys and values and converts it to properly
escaped HTML attributes.
*
* @example ['data-id' => 'id',
'data-key' => 'key'] => '
data-id="id" data-key="key"'
* @example [['data-id' => 'id'],
['data-key' => 'key']] => '
data-id="id" data-key="key"'
*
* @param string|string[] $input
* @return string
*/
public function attributeArrayFilter($input)
{
if (\is_string($input)) {
return $input;
}
$array = [];
foreach ((array) $input as $key => $value) {
if (\is_array($value)) {
foreach ((array) $value as $key2 => $value2) {
$array[] = HtmlDocument::escape($key2) .
'="' . HtmlDocument::escape($value2, 'html_attr')
. '"';
}
} elseif ($key) {
$array[] = HtmlDocument::escape($key) . '="'
. HtmlDocument::escape($value, 'html_attr') . '"';
}
}
return $array ? ' ' . implode(' ', $array) :
'';
}
public function is_selectedFunc($a, $b)
{
$b = (array) $b;
array_walk(
$b,
function (&$item) {
if (\is_bool($item)) {
$item = (int) $item;
}
$item = (string) $item;
}
);
return \in_array((string) $a, $b, true);
}
/**
* Truncate text by number of characters but can cut off words. Removes
html tags.
*
* @param string $string
* @param int $limit Max number of characters.
*
* @return string
*/
public function truncateText($string, $limit = 150)
{
$platform = Gantry::instance()['platform'];
return $platform->truncate($string, (int) $limit, false);
}
/**
* Truncate text by number of characters but can cut off words.
*
* @param string $string
* @param int $limit Max number of characters.
*
* @return string
*/
public function truncateHtml($string, $limit = 150)
{
$platform = Gantry::instance()['platform'];
return $platform->truncate($string, (int) $limit, true);
}
/**
* @param string $string
* @param bool $block Block or Line processing
* @param array $settings
* @return mixed|string
*/
public function markdownFunction($string, $block = true, array
$settings = null)
{
// Initialize the preferred variant of Parsedown
if (!empty($settings['extra'])) {
$parsedown = new ParsedownExtra($settings);
} else {
$parsedown = new Parsedown($settings);
}
if ($block) {
$string = $parsedown->text($string);
} else {
$string = $parsedown->line($string);
}
return $string;
}
/**
* Get value by using dot notation for nested arrays/objects.
*
* @example {{ nested(array,
'this.is.my.nested.variable')|json_encode }}
*
* @param array $items Array of items.
* @param string $name Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return mixed Value.
*/
public function nestedFunc($items, $name, $default = null, $separator =
'.')
{
if ($items instanceof NestedArrayAccess) {
return $items->get($name, $default, $separator);
}
$path = explode($separator, $name);
$current = $items;
foreach ($path as $field) {
if (\is_object($current) &&
isset($current->{$field})) {
$current = $current->{$field};
} elseif (\is_array($current) &&
isset($current[$field])) {
$current = $current[$field];
} else {
return $default;
}
}
return $current;
}
/**
* Return URL to the resource.
*
* @example {{
url('theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4')
}}
*
* @param string $input Resource to be located.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @return string|null Returns url to the resource or null if
resource was not found.
*/
public function urlFunc($input, $domain = false, $timestamp_age = null)
{
$gantry = Gantry::instance();
return $gantry['document']->url(trim((string) $input),
$domain, $timestamp_age);
}
/**
* Filter stream URLs from HTML input.
*
* @param string $str HTML input to be filtered.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @return string Returns modified HTML.
*/
public function htmlFilter($str, $domain = false, $timestamp_age =
null)
{
$gantry = Gantry::instance();
return $gantry['document']->urlFilter($str, $domain,
$timestamp_age);
}
/**
* @param \libXMLError $error
* @param string $input
* @throws \RuntimeException
*/
protected function dealXmlError(\libXMLError $error, $input)
{
switch ($error->level) {
case LIBXML_ERR_WARNING:
$level = 1;
$message = "DOM Warning {$error->code}: ";
break;
case LIBXML_ERR_ERROR:
$level = 2;
$message = "DOM Error {$error->code}: ";
break;
case LIBXML_ERR_FATAL:
$level = 3;
$message = "Fatal DOM Error {$error->code}: ";
break;
default:
$level = 3;
$message = "Unknown DOM Error {$error->code}:
";
}
$message .= "{$error->message} while
parsing:\n{$input}\n";
if ($level <= 2 && !Gantry::instance()->debug()) {
return;
}
throw new \RuntimeException($message, 500);
}
/**
* Move supported document head elements into platform document object,
return all
* unsupported tags in a string.
*
* @param string $input
* @param string $location
* @param int $priority
* @return string
*/
public function parseAssetsFunc($input, $location = 'head',
$priority = 0)
{
if ($location === 'head') {
$scope = 'head';
$html = "<!doctype
html>\n<html><head>{$input}</head><body></body></html>";
} else {
$scope = 'body';
$html = "<!doctype
html>\n<html><head></head><body>{$input}</body></html>";
}
libxml_clear_errors();
$internal = libxml_use_internal_errors(true);
$doc = new \DOMDocument();
$doc->loadHTML($html);
foreach (libxml_get_errors() as $error) {
$this->dealXmlError($error, $html);
}
libxml_clear_errors();
libxml_use_internal_errors($internal);
$raw = [];
/** @var \DomElement $element */
foreach
($doc->getElementsByTagName($scope)->item(0)->childNodes as
$element) {
if (empty($element->tagName)) {
continue;
}
$result = ['tag' => $element->tagName,
'content' => $element->textContent];
foreach ($element->attributes as $attribute) {
$result[$attribute->name] = $attribute->value;
}
$success =
Gantry::instance()['document']->addHeaderTag($result,
$location, (int) $priority);
if (!$success) {
$raw[] = $doc->saveHTML($element);
}
}
return implode("\n", $raw);
}
public function colorContrastFunc($value)
{
$value = str_replace(' ', '', $value);
$rgb = new \stdClass;
$opacity = 1;
if (0 !== strpos($value, 'rgb')) {
$value = str_replace('#', '', $value);
if (\strlen($value) === 3) {
$h0 = str_repeat(substr($value, 0, 1), 2);
$h1 = str_repeat(substr($value, 1, 1), 2);
$h2 = str_repeat(substr($value, 2, 1), 2);
$value = $h0 . $h1 . $h2;
}
$rgb->r = hexdec(substr($value, 0, 2));
$rgb->g = hexdec(substr($value, 2, 2));
$rgb->b = hexdec(substr($value, 4, 2));
} else {
preg_match("/(\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(1\\.|0?\\.?[0-9]?+))?/uim",
$value, $matches);
$rgb->r = $matches[1];
$rgb->g = $matches[2];
$rgb->b = $matches[3];
$opacity = isset($matches[4]) ? $matches[4] : 1;
$opacity = substr($opacity, 0, 1) === '.' ?
'0' . $opacity : $opacity;
}
$yiq = ((($rgb->r * 299) + ($rgb->g * 587) + ($rgb->b *
114)) / 1000) >= 128;
$contrast = $yiq || (!$opacity || (float) $opacity < 0.35);
return $contrast;
}
/**
* Displays a facebook style 'time ago' formatted date/time.
*
* @param string|int $date
* @param bool $long_strings
*
* @return string
*/
public function nicetimeFilter($date, $long_strings = true)
{
static $lengths = [60, 60, 24, 7, 4.35, 12, 10];
static $periods_long = [
'GANTRY5_ENGINE_NICETIME_SECOND',
'GANTRY5_ENGINE_NICETIME_MINUTE',
'GANTRY5_ENGINE_NICETIME_HOUR',
'GANTRY5_ENGINE_NICETIME_DAY',
'GANTRY5_ENGINE_NICETIME_WEEK',
'GANTRY5_ENGINE_NICETIME_MONTH',
'GANTRY5_ENGINE_NICETIME_YEAR',
'GANTRY5_ENGINE_NICETIME_DECADE'
];
static $periods_short = [
'GANTRY5_ENGINE_NICETIME_SEC',
'GANTRY5_ENGINE_NICETIME_MIN',
'GANTRY5_ENGINE_NICETIME_HR',
'GANTRY5_ENGINE_NICETIME_DAY',
'GANTRY5_ENGINE_NICETIME_WK',
'GANTRY5_ENGINE_NICETIME_MO',
'GANTRY5_ENGINE_NICETIME_YR',
'GANTRY5_ENGINE_NICETIME_DEC'
];
if (empty($date)) {
return
$this->transFilter('GANTRY5_ENGINE_NICETIME_NO_DATE_PROVIDED');
}
$periods = $long_strings ? $periods_long : $periods_short;
$now = time();
// check if unix timestamp
if ((string)(int)$date === (string)$date) {
$unix_date = (int)$date;
} else {
$unix_date = strtotime($date);
}
// check validity of date
if (!$unix_date) {
return
$this->transFilter('GANTRY5_ENGINE_NICETIME_BAD_DATE');
}
// is it future date or past date
if ($now > $unix_date) {
$difference = $now - $unix_date;
$tense =
$this->transFilter('GANTRY5_ENGINE_NICETIME_AGO');
} else if ($now === $unix_date) {
$difference = $now - $unix_date;
$tense =
$this->transFilter('GANTRY5_ENGINE_NICETIME_JUST_NOW');
} else {
$difference = $unix_date - $now;
$tense =
$this->transFilter('GANTRY5_ENGINE_NICETIME_FROM_NOW');
}
for ($j = 0; $difference >= $lengths[$j] && $j <
\count($lengths) - 1; $j++) {
$difference /= $lengths[$j];
}
$period = $periods[$j];
$difference = round($difference);
if ($difference !== 1) {
$period .= '_PLURAL';
}
$period = $this->transFilter($period);
if ($now === $unix_date) {
return $tense;
}
return "{$difference} {$period} {$tense}";
}
public function getCookie($name)
{
$gantry = Gantry::instance();
/** @var Request $request */
$request = $gantry['request'];
return $request->cookie[$name];
}
public function pregMatch($pattern, $subject, &$matches = [])
{
preg_match($pattern, $subject, $matches);
return $matches ?: false;
}
}
PK&d�[��6���$classes/Gantry/Component/Url/Url.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Url;
class Url
{
/**
* UTF8 aware parse_url().
*
* @param string $url
* @param bool $queryArray
* @return array|bool
*/
public static function parse($url, $queryArray = false)
{
$encodedUrl = preg_replace_callback(
'%[^:/@?&=#]+%usD',
function ($matches) { return rawurlencode($matches[0]); },
$url
);
// PHP versions below 5.4.7 have troubles with URLs without scheme,
so lets help by fixing that.
// TODO: This is not needed in PHP >= 5.4.7, but for now we need
to test if the function works.
if ('/' === $encodedUrl[0] && false !==
strpos($encodedUrl, '://')) {
$schemeless = true;
// Fix the path so that parse_url() will not return false.
$parts = parse_url('fake://fake.com' . $encodedUrl);
// Remove the fake values.
unset($parts['scheme'], $parts['host']);
} else {
$parts = parse_url($encodedUrl);
}
if (!$parts) {
return false;
}
// PHP versions below 5.4.7 do not understand schemeless URLs
starting with // either.
if (isset($schemeless) && !isset($parts['host'])
&& 0 === strpos($encodedUrl, '//')) {
// Path is stored in format: //[host]/[path], so let's fix
it.
list($parts['host'], $path) = explode('/',
substr($parts['path'], 2), 2);
$parts['path'] = "/{$path}";
}
foreach($parts as $name => $value) {
$parts[$name] = rawurldecode($value);
}
// Return query string also as an array if requested.
if ($queryArray) {
$parts['vars'] = isset($parts['query']) ?
static::parseQuery($parts['query']) : [];
}
return $parts;
}
/**
* Parse query string and return array.
*
* @param $query
* @return mixed
*/
public static function parseQuery($query)
{
parse_str($query, $vars);
return $vars;
}
/**
* Build parsed URL array.
*
* @param array $parsed_url
* @return string
*/
public static function build(array $parsed_url)
{
// Build query string from variables if they are set.
if (isset($parsed_url['vars'])) {
$parsed_url['query'] =
static::buildQuery($parsed_url['vars']);
}
// Build individual parts of the url.
$scheme = isset($parsed_url['scheme']) ?
$parsed_url['scheme'] . '://' : '';
$host = isset($parsed_url['host']) ?
$parsed_url['host'] : '';
$port = isset($parsed_url['port']) ? ':' .
$parsed_url['port'] : '';
$user = isset($parsed_url['user']) ?
$parsed_url['user'] : '';
$pass = isset($parsed_url['pass']) ? ':' .
$parsed_url['pass'] : '';
$pass = ($user || $pass) ? "{$pass}@" : '';
$path = isset($parsed_url['path']) ?
$parsed_url['path'] : '';
$query = isset($parsed_url['query']) ? '?' .
$parsed_url['query'] : '';
$fragment = isset($parsed_url['fragment']) ?
'#' . $parsed_url['fragment'] : '';
$scheme = $host && !$scheme ? '//' : $scheme;
return
"{$scheme}{$user}{$pass}{$host}{$port}{$path}{$query}{$fragment}";
}
/**
* Build query string from variables.
*
* @param array $vars
* @return null|string
*/
public static function buildQuery(array $vars)
{
$list = [];
foreach ($vars as $key => $var) {
$list[] = $key . '=' . rawurlencode($var);
}
return $list ? implode('&', $list) : null;
}
}
PK&d�[�H��AA0classes/Gantry/Component/Whoops/SystemFacade.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Whoops;
class SystemFacade extends \Whoops\Util\SystemFacade
{
protected $registeredPatterns;
protected $whoopsErrorHandler;
protected $whoopsExceptionHandler;
protected $whoopsShutdownHandler;
protected $platformExceptionHandler;
/**
* @param array|string $patterns List or a single regex pattern to
match for silencing errors in particular files.
*/
public function __construct($patterns = [])
{
$this->registeredPatterns = array_map(
function ($pattern) {
return["pattern" => $pattern];
},
(array) $patterns
);
}
/**
* @param callable $handler
* @param int|string $types
*
* @return callable|null
*/
public function setErrorHandler(callable $handler, $types =
'use-php-defaults')
{
// Workaround for PHP 5.5
if ($types === 'use-php-defaults') {
$types = E_ALL | E_STRICT;
}
$this->whoopsErrorHandler = $handler;
return parent::setErrorHandler([$this, 'handleError'],
$types);
}
/**
* @param callable $function
*
* @return void
*/
public function registerShutdownFunction(callable $function)
{
$this->whoopsShutdownHandler = $function;
register_shutdown_function([$this, 'handleShutdown']);
}
/**
* @param callable $handler
*
* @return callable|null
*/
public function setExceptionHandler(callable $handler)
{
$this->whoopsExceptionHandler = $handler;
$this->platformExceptionHandler =
parent::setExceptionHandler([$this, 'handleException']);
return $this->platformExceptionHandler;
}
/**
* Converts generic PHP errors to \ErrorException instances, before
passing them off to be handled.
*
* This method MUST be compatible with set_error_handler.
*
* @param int $level
* @param string $message
* @param string $file
* @param int $line
*
* @return bool
* @throws \ErrorException
*/
public function handleError($level, $message, $file = null, $line =
null)
{
$handler = $this->whoopsErrorHandler;
if (!$this->registeredPatterns) {
// Just forward to parent function is there aren't no
registered patterns.
return $handler($level, $message, $file, $line);
}
// If there are registered patterns, only handle errors if error
matches one of the patterns.
if ($level & error_reporting()) {
foreach ($this->registeredPatterns as $entry) {
$pathMatches = $file &&
preg_match($entry["pattern"], $file);
if ($pathMatches) {
return $handler($level, $message, $file, $line);
}
}
}
// Propagate error to the next handler, allows error_get_last() to
work on silenced errors.
return false;
}
/**
* Handles an exception, ultimately generating a Whoops error page.
*
* @param \Throwable $exception
* @return void
*/
public function handleException($exception)
{
$handler = $this->whoopsExceptionHandler;
// If there are registered patterns, only handle errors if error
matches one of the patterns.
if ($this->registeredPatterns) {
foreach ($this->registeredPatterns as $entry) {
$file = $exception->getFile();
$pathMatches = $file &&
preg_match($entry["pattern"], $file);
if ($pathMatches) {
$handler($exception);
return;
}
}
}
// Propagate error to the next handler.
if ($this->platformExceptionHandler) {
call_user_func_array($this->platformExceptionHandler,
[&$exception]);
}
}
/**
* Special case to deal with Fatal errors and the like.
*/
public function handleShutdown()
{
$handler = $this->whoopsShutdownHandler;
$error = $this->getLastError();
// Ignore core warnings and errors.
if ($error && !($error['type'] &
(E_CORE_WARNING | E_CORE_ERROR))) {
$handler();
}
}
}
PK&d�[JH��CC(classes/Gantry/Framework/Assignments.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Component\Assignments\AbstractAssignments;
use Gantry\Joomla\CacheHelper;
use Gantry\Joomla\StyleHelper;
use Joomla\Utilities\ArrayHelper;
class Assignments extends AbstractAssignments
{
protected $platform = 'Joomla';
/**
* Load all assignments.
*
* @return array
*/
public function loadAssignments()
{
$app = \JFactory::getApplication();
if (!$app->isSite()) {
return [];
}
// Get current template, style id and rules.
$template = $app->getTemplate();
$active = $app->getMenu()->getActive();
if ($active) {
$style = (int) $active->template_style_id;
$rules = [$active->menutype => [$active->id =>
true]];
} else {
$style = 0;
$rules = [];
}
// Load saved assignments.
$assignments = parent::loadAssignments();
// Add missing template styles from Joomla.
$styles = StyleHelper::loadStyles($template);
$assignments += array_fill_keys(array_keys($styles), []);
foreach ($assignments as $id => &$assignment) {
// Add current menu item if it has been assigned to the style.
$assignment['menu'] = $style === $id ? $rules : [];
// Always add the current template style.
$assignment['style'] = ['id' => [$id
=> true]];
}
return $assignments;
}
/**
* Save assignments for the configuration.
*
* @param array $data
*/
public function save(array $data)
{
$data += ['assignment' => 0, 'menu' =>
[]];
// Joomla stores language and menu assignments by its own.
$this->saveAssignment($data['assignment']);
$this->saveMenu($data['menu']);
unset($data['assignment'], $data['menu'],
$data['style']);
// Continue saving rest of the assignments.
parent::save($data);
}
public function types()
{
return ['menu', 'style'];
}
public function saveMenu($data)
{
$active = [];
foreach ($data as $menutype => $items) {
$active += array_filter($items, function($value) {return $value
> 0; });
}
$active = array_keys($active);
// Detect disabled template.
$extension = \JTable::getInstance('Extension');
$template = Gantry::instance()['theme.name'];
if ($extension->load(array('enabled' => 0,
'type' => 'template', 'element' =>
$template, 'client_id' => 0))) {
throw new
\RuntimeException(\JText::_('COM_TEMPLATES_ERROR_SAVE_DISABLED_TEMPLATE'));
}
\JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_templates/tables');
$style = \JTable::getInstance('Style',
'TemplatesTable');
if (!$style->load($this->configuration) ||
$style->client_id != 0) {
throw new \RuntimeException('Template style does not
exist');
}
$user = \JFactory::getUser();
$n = 0;
if ($user->authorise('core.edit',
'com_menus')) {
$db = \JFactory::getDbo();
$user = \JFactory::getUser();
if (!empty($active)) {
ArrayHelper::toInteger($active);
// Update the mapping for menu items that this style IS
assigned to.
$query = $db->getQuery(true)
->update('#__menu')
->set('template_style_id = ' . (int)
$style->id)
->where('id IN (' . implode(',',
$active) . ')')
->where('template_style_id != ' . (int)
$style->id)
->where('checked_out IN (0,' . (int)
$user->id . ')');
$db->setQuery($query);
$db->execute();
$n += $db->getAffectedRows();
}
// Remove style mappings for menu items this style is NOT
assigned to.
// If unassigned then all existing maps will be removed.
$query = $db->getQuery(true)
->update('#__menu')
->set('template_style_id = 0');
if (!empty($active)) {
$query->where('id NOT IN (' .
implode(',', $active) . ')');
}
$query->where('template_style_id = ' . (int)
$style->id)
->where('checked_out IN (0,' . (int)
$user->id . ')');
$db->setQuery($query);
$db->execute();
$n += $db->getAffectedRows();
}
// Clean the cache.
CacheHelper::cleanTemplates();
return ($n > 0);
}
public function getAssignment()
{
$style = StyleHelper::getStyle($this->configuration);
return $style->home;
}
public function saveAssignment($value)
{
$options = $this->assignmentOptions();
if (!isset($options[$value])) {
throw new \RuntimeException('Invalid value for default
assignment!', 400);
}
$style = StyleHelper::getStyle($this->configuration);
$style->home = $value;
if (!$style->check() || !$style->store()) {
throw new \RuntimeException($style->getError());
}
// Clean the cache.
CacheHelper::cleanTemplates();
}
public function assignmentOptions()
{
if ((string)(int) $this->configuration !== (string)
$this->configuration) {
return [];
}
$languages = \JHtml::_('contentlanguage.existing');
$options = ['- Make Default -', 'All
Languages'];
foreach ($languages as $language) {
$options[$language->value] = $language->text;
}
return $options;
}
}
PK&d�[�����$�$"classes/Gantry/Framework/Atoms.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework;
use Gantry\Component\Config\BlueprintForm;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Atoms implements \ArrayAccess, \Iterator, ExportInterface
{
use ArrayAccess, Iterator, Export;
/**
* @var string
*/
protected $name;
/**
* @var array
*/
protected $items;
/**
* @var array
*/
protected $ids;
/**
* @var array|static[]
*/
protected static $instances;
protected $inherit = false;
/**
* @param string $outline
* @return static
*/
public static function instance($outline)
{
if (!isset(static::$instances[$outline])) {
$file =
CompiledYamlFile::instance("gantry-theme://config/{$outline}/page/head.yaml");
$head = $file->content();
static::$instances[$outline] = new
static(isset($head['atoms']) ? $head['atoms'] : [],
$outline);
$file->free();
static::$instances[$outline]->init();
}
return static::$instances[$outline];
}
/**
* Atoms constructor.
* @param array $atoms
* @param string $name
*/
public function __construct(array $atoms = [], $name = null)
{
$this->name = $name;
$this->items = array_filter($atoms);
$this->inherit =
file_exists('gantry-admin://blueprints/layout/inheritance/atom.yaml');
foreach ($this->items as &$item) {
if (!empty($item['id'])) {
$this->ids[$item['id']] = $item;
}
}
}
public function init()
{
foreach ($this->items as &$item) {
if (!empty($item['inherit']['outline'])
&& !empty($item['inherit']['atom'])) {
$inherited =
static::instance($item['inherit']['outline']);
$test =
$inherited->id($item['inherit']['atom']);
if (isset($test['attributes'])) {
$item['attributes'] =
$test['attributes'];
} else {
unset($item['inherit']);
}
}
}
return $this;
}
/**
* @return $this
*/
public function update()
{
foreach ($this->items as &$item) {
if (empty($item['id'])) {
$item['id'] = $this->createId($item);
}
if (!empty($item['inherit']['outline'])
&& !empty($item['inherit']['atom'])) {
unset($item['attributes']);
} else {
unset($item['inherit']);
}
}
return $this;
}
/**
* @param string $outline
* @return $this
*/
public function inheritAll($outline)
{
foreach ($this->items as &$item) {
if (!empty($item['id'])) {
$item['inherit'] = [
'outline' => $outline,
'atom' => $item['id'],
'include' => ['attributes']
];
}
}
return $this;
}
/**
* @param string $old
* @param string $new
* @param array $ids
* @return $this
*/
public function updateInheritance($old, $new = null, $ids = null)
{
$this->init();
foreach ($this->items as &$item) {
if (!empty($item['inherit']['outline'])
&& $item['inherit']['outline'] == $old
&& isset($item['inherit']['atom'])) {
if ($new && ($ids === null ||
isset($ids[$item['inherit']['atom']]))) {
$item['inherit']['outline'] = $new;
} else {
unset($item['inherit']);
}
}
}
return $this;
}
public function save()
{
if ($this->name) {
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
$loadPath =
$locator->findResource("gantry-theme://config/{$this->name}/page/head.yaml");
$savePath =
$locator->findResource("gantry-theme://config/{$this->name}/page/head.yaml",
true, true);
if ($loadPath && $savePath) {
$file = CompiledYamlFile::instance($loadPath);
$head = $file->content();
$head['atoms'] =
$this->update()->toArray();
$file->free();
$file = CompiledYamlFile::instance($savePath);
$file->save($head);
$file->free();
}
}
}
/**
* @param string $id
* @return array
*/
public function id($id)
{
return isset($this->ids[$id]) ? $this->ids[$id] : [];
}
/**
* @param string $type
* @return array
*/
public function type($type)
{
$list = [];
foreach ($this->items as $item) {
if ($item['type'] === $type) {
$list[] = $item;
}
}
return $list;
}
/**
* @param string $type
* @param array $data
* @return Config
*/
public function createAtom($type, array $data = [])
{
$self = $this;
$callable = function () use ($self, $type) {
return $self->getBlueprint($type);
};
// Create configuration from the data.
$item = new Config($data, $callable);
$item->def('id', null);
$item->def('type', $type);
if (!isset($item['title'])) {
$item->def('title',
$item->blueprint()->get('name'));
}
$item->def('attributes', []);
$item->def('inherit', []);
return $item;
}
/**
* @param string $type
* @return BlueprintForm
*/
public function getBlueprint($type)
{
$blueprint = BlueprintForm::instance($type,
'gantry-blueprints://particles');
if ($this->inherit) {
$blueprint->set('form/fields/_inherit',
['type' => 'gantry.inherit']);
}
return $blueprint;
}
/**
* @param string $type
* @param string $id
* @param bool $force
* @return BlueprintForm|null
*/
public function getInheritanceBlueprint($type, $id = null, $force =
false)
{
if (!$this->inherit) {
return null;
}
$inheriting = $id ? $this->getInheritingOutlines($id) : [];
$list = $this->getOutlines($type, false);
if ($force || (empty($inheriting) && $list)) {
$inheritance =
BlueprintForm::instance('layout/inheritance/atom.yaml',
'gantry-admin://blueprints');
$inheritance->set('form/fields/outline/filter',
array_keys($list));
$inheritance->set('form/fields/atom/atom', $type);
} elseif (!empty($inheriting)) {
// Already inherited by other outlines.
$inheritance =
BlueprintForm::instance('layout/inheritance/messages/inherited.yaml',
'gantry-admin://blueprints');
$inheritance->set(
'form/fields/_note/content',
sprintf($inheritance->get('form/fields/_note/content'),
'atom', ' <ul><li>' .
implode('</li> <li>', $inheriting) .
'</li></ul>')
);
} elseif ($this->name === 'default') {
// Base outline.
$inheritance =
BlueprintForm::instance('layout/inheritance/messages/default.yaml',
'gantry-admin://blueprints');
} else {
// Nothing to inherit from.
$inheritance =
BlueprintForm::instance('layout/inheritance/messages/empty.yaml',
'gantry-admin://blueprints');
}
return $inheritance;
}
/**
* @param string $id
* @return array
*/
public function getInheritingOutlines($id = null)
{
/** @var Outlines $outlines */
$outlines = Gantry::instance()['outlines'];
return $outlines->getInheritingOutlinesWithAtom($this->name,
$id);
}
/**
* @param string $type
* @param bool $includeInherited
* @return array
*/
public function getOutlines($type, $includeInherited = true)
{
if ($this->name !== 'default') {
/** @var Outlines $outlines */
$outlines = Gantry::instance()['outlines'];
$list = $outlines->getOutlinesWithAtom($type,
$includeInherited);
unset($list[$this->name]);
} else {
$list = [];
}
return $list;
}
/**
* @param array $item
* @return string
*/
protected function createId(array &$item)
{
$type = $item['type'];
while ($num = rand(1000, 9999)) {
if (!isset($this->ids["{$type}-{$num}"])) {
break;
}
}
$id = "{$type}-{$num}";
$this->ids[$id] = $item;
return $id;
}
}
PK&d�["��{�$�$(classes/Gantry/Framework/Base/Gantry.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Base;
use Gantry\Component\Config\Config;
use Gantry\Component\System\Messages;
use Gantry\Framework\Document;
use Gantry\Framework\Menu;
use Gantry\Framework\Outlines;
use Gantry\Framework\Page;
use Gantry\Framework\Platform;
use Gantry\Framework\Positions;
use Gantry\Framework\Request;
use Gantry\Framework\Services\ConfigServiceProvider;
use Gantry\Framework\Services\StreamsServiceProvider;
use Gantry\Framework\Site;
use Gantry\Framework\Translator;
use RocketTheme\Toolbox\DI\Container;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\Event\EventDispatcher;
abstract class Gantry extends Container
{
/**
* @var static
*/
protected static $instance;
protected $wrapper;
public static function instance()
{
if (!self::$instance) {
self::$instance = static::init();
if (!defined('GANTRY5_DEBUG')) {
define('GANTRY5_DEBUG',
self::$instance->debug());
}
}
return self::$instance;
}
public static function restart()
{
self::$instance = null;
return static::instance();
}
/**
* Returns true if debug mode has been enabled.
*
* @return boolean
*/
public function debug()
{
return $this['global']->get('debug', false);
}
/**
* Returns true if we are in administration.
*
* @return boolean
*/
public function admin()
{
return defined('GANTRYADMIN_PATH');
}
/**
* @return string
*/
public function siteUrl()
{
$gantry = Gantry::instance();
return $gantry['document']->siteUrl();
}
/**
* @param string $location
* @return array
*/
public function styles($location = 'head')
{
return $this['document']->getStyles($location);
}
/**
* @param string $location
* @return array
*/
public function scripts($location = 'head')
{
return $this['document']->getScripts($location);
}
/**
* Load Javascript framework / extension in platform independent way.
*
* @param string $framework
* @return bool
*/
public function load($framework)
{
return $this['document']->addFramework($framework);
}
/**
* Lock the variable against modification and return the value.
*
* @param string $id
* @return mixed
*/
public function lock($id)
{
$value = $this[$id];
try {
// Create a dummy service.
$this[$id] = function () use ($value) {
return $value;
};
} catch (\RuntimeException $e) {
// Services are already locked, so ignore the error.
}
// Lock the service and return value.
return $this[$id];
}
/**
* Fires an event with optional parameters.
*
* @param string $eventName
* @param Event $event
* @return Event
*/
public function fireEvent($eventName, Event $event = null)
{
/** @var EventDispatcher $events */
$events = $this['events'];
return $events->dispatch($eventName, $event);
}
public function route($path)
{
$routes = $this->offsetGet('routes');
$route = isset($routes[$path]) ? $routes[$path] : $routes[1];
if (!$route) {
// TODO: need to implement back to root in Prime..
return $this->offsetGet('base_url');
}
$path = implode('/', array_filter(func_get_args(),
function($var) { return isset($var) && $var !== ''; }));
// rawurlencode() the whole path, but keep the slashes.
$path = preg_replace(['|%2F|', '|%25|'],
['/', '%'], rawurlencode($path));
return preg_replace('|/+|', '/', '/'
. $this->offsetGet('base_url') . sprintf($route, $path));
}
public function authorize($action, $id = null)
{
return $this['platform']->authorize($action, $id);
}
public function wrapper($value = null)
{
if ($value !== null ) {
$this->wrapper = $value;
}
return $this->wrapper;
}
protected static function init()
{
/** @var Gantry $instance */
$instance = new static();
if (GANTRY_DEBUGGER) {
$instance['debugger'] = \Gantry\Debugger::instance();
}
$instance['loader'] = \Gantry5\Loader::get();
$instance->register(new ConfigServiceProvider);
$instance->register(new StreamsServiceProvider);
$instance['request'] = function () {
return new Request;
};
$instance['events'] = function () {
return new EventDispatcher;
};
$instance['platform'] = function ($c) {
return new Platform($c);
};
$instance['translator'] = function () {
return new Translator;
};
$instance['site'] = function () {
return new Site;
};
$instance['menu'] = function () {
return new Menu;
};
$instance['messages'] = function () {
return new Messages;
};
$instance['page'] = function ($c) {
return new Page($c);
};
$instance['document'] = function () {
return new Document;
};
// Make sure that nobody modifies the original collection by making
it a factory.
$instance['outlines'] = $instance->factory(function
($c) {
static $collection;
if (!$collection) {
$collection = (new Outlines($c))->load();
}
return $collection->copy();
});
// @deprecated 5.3
$instance['configurations'] =
$instance->factory(function ($c) {
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Depredated call:
gantry.configurations");
static $collection;
if (!$collection) {
$collection = (new Outlines($c))->load();
}
return $collection->copy();
});
$instance['positions'] = $instance->factory(function
($c) {
static $collection;
if (!$collection) {
$collection = (new Positions($c))->load();
}
return $collection->copy();
});
$instance['global'] = function ($c) {
$data = $c->loadGlobal() + [
'debug' => false,
'production' => true,
'use_media_folder' => false,
'asset_timestamps' => true,
'asset_timestamps_period' => 7,
'compile_yaml' => true,
'compile_twig' => true,
'offline_message' => ''
];
return new Config($data);
};
return $instance;
}
/**
* Check if Gantry is compatible with your theme / extension.
*
* This function can be used to make sure that user has installed
Gantry version
* that has been tested to work with your extension. All existing
functions should
* be backwards compatible, but each release can add some new
functionality, which
* you may want to use.
*
* <code>
* if ($gantry->isCompatible('5.0.1')) {
* // You can do it in the new way.
* } else {
* // Revert to the old way to display an error message.
* }
* </code>
*
* @param string $version Minimum required version.
*
* @return boolean Yes, if it is safe to use Gantry Framework.
*/
public function isCompatible($version)
{
// If requested version is smaller than 5.0-rc, it's not
compatible.
if (version_compare($version, '5.0-rc',
'<')) {
return false;
}
// Development version support.
if ($version === '5.3' || static::isDev()) {
return true;
}
// Check if future version is needed.
if (version_compare($version, GANTRY5_VERSION, '>')) {
return false;
}
return true;
}
/**
* Check if Gantry is running from a Git repository or is a CI build.
*
* Developers tend to do their work directly in the Git repositories
instead of
* creating and installing new builds after every change. This function
can be
* used to check the condition and make sure we do not break users
repository
* by replacing files during upgrade.
*
* @return boolean True if Git repository or CI build is detected.
*/
public function isDev()
{
if ('@version@' == GANTRY5_VERSION) {
return true;
}
if ('dev-' === substr(GANTRY5_VERSION, 0, 4)) {
return true;
}
return false;
}
/**
* @return array
*/
protected function loadGlobal()
{
return [];
}
}
PK&d�[B�s�MM&classes/Gantry/Framework/Base/Page.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Base;
abstract class Page
{
protected $container;
protected $config;
public function __construct($container)
{
$this->container = $container;
$this->config = $container['config'];
}
public function doctype()
{
return $this->config->get('page.doctype',
'html');
}
abstract public function url(array $args = []);
public function preset()
{
/** @var Theme $theme */
$theme = $this->container['theme'];
return 'g-' . preg_replace('/[^a-z0-9-]/',
'', $theme->type());
}
public function htmlAttributes()
{
return
$this->getAttributes($this->config->get('page.html'));
}
public function bodyAttributes($attributes = [])
{
return
$this->getAttributes($this->config->get('page.body.attribs'),
$attributes);
}
protected function getAttributes($params, $extra = [])
{
$params = array_merge_recursive($params, $extra);
$list = [];
foreach ($params as $param => $value) {
if (!$value) { continue; }
if (!is_array($value) || !count(array_filter($value,
'is_array'))) {
$value = array_filter(array_unique((array) $value));
$list[] = $param . '="' . implode('
', $value) . '"';
} else {
$values = new \RecursiveIteratorIterator(new
\RecursiveArrayIterator($value));
foreach ($values as $iparam => $ivalue) {
$ivalue = array_filter(array_unique((array) $ivalue));
$list[] = $iparam . '="' .
implode(' ', $ivalue) . '"';
}
}
}
return $list ? ' ' . implode(' ', $list) :
'';
}
}
PK&d�[qyX~��*classes/Gantry/Framework/Base/Platform.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Base;
use Gantry\Component\Filesystem\Folder;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess;
use RocketTheme\Toolbox\DI\Container;
/**
* The Platform Configuration class contains configuration information.
*
* @author RocketTheme
* @license MIT
*/
abstract class Platform
{
use NestedArrayAccess, Export;
protected $name;
protected $features = [];
protected $settings_key;
protected $items;
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
//Make sure that cache folder exists, otherwise it will be removed
from the lookup.
$cachePath = $this->getCachePath();
Folder::create($cachePath);
$this->items = [
'streams' => [
// Cached files.
'gantry-cache' => [
'type' => 'Stream',
'force' => true,
'prefixes' => ['' =>
[$cachePath]]
],
// Container for all frontend themes.
'gantry-themes' => [
'type' => 'ReadOnlyStream',
'prefixes' => $this->getThemesPaths()
],
// Selected frontend theme.
'gantry-theme' => [
'type' => 'ReadOnlyStream',
'prefixes' => $this->getThemePaths()
],
// System defined media files.
'gantry-assets' => [
'type' => 'ReadOnlyStream',
'prefixes' => $this->getAssetsPaths()
],
// User defined media files.
'gantry-media' => [
'type' => 'ReadOnlyStream',
'prefixes' => $this->getMediaPaths()
],
// Container for all Gantry engines.
'gantry-engines' => [
'type' => 'ReadOnlyStream',
'prefixes' => $this->getEnginesPaths()
],
// Gantry engine used to render the selected theme.
'gantry-engine' => [
'type' => 'ReadOnlyStream',
'prefixes' => $this->getEnginePaths()
],
// Layout definitions for the blueprints.
'gantry-layouts' => [
'type' => 'ReadOnlyStream',
'prefixes' => ['' =>
['gantry-theme://layouts', 'gantry-engine://layouts']]
],
// Gantry particles.
'gantry-particles' => [
'type' => 'ReadOnlyStream',
'prefixes' => ['' =>
['gantry-theme://particles',
'gantry-engine://particles']]
],
// Gantry administration.
'gantry-admin' => [
'type' => 'ReadOnlyStream',
'prefixes' => []
],
// Blueprints for the configuration.
'gantry-blueprints' => [
'type' => 'ReadOnlyStream',
'prefixes' => [
'' =>
['gantry-theme://blueprints',
'gantry-engine://blueprints'],
'particles' =>
['gantry-particles://']
]
],
// Configuration from the selected theme.
'gantry-config' => [
'type' => 'ReadOnlyStream',
'prefixes' => ['' =>
['gantry-theme://config']]
]
]
];
}
abstract public function getCachePath();
abstract public function getThemesPaths();
abstract public function getAssetsPaths();
abstract public function getMediaPaths();
public function init()
{
return $this;
}
public function has($feature)
{
return !empty($this->features[$feature]);
}
public function getThemePaths()
{
return ['' => []];
}
public function getEnginePaths($name = 'nucleus')
{
return ['' => ['gantry-theme://engine',
"gantry-engines://{$name}"]];
}
public function getEnginesPaths()
{
return ['' => []];
}
public function errorHandlerPaths()
{
return [];
}
/**
* Get preview url for individual theme.
*
* @param string $theme
* @return string|null
*/
abstract public function getThemePreviewUrl($theme);
/**
* Get administrator url for individual theme.
*
* @param string $theme
* @return string|null
*/
abstract public function getThemeAdminUrl($theme);
public function settings()
{
return null;
}
public function settings_key()
{
return $this->settings_key;
}
public function listModules()
{
return false;
}
public function getName()
{
return $this->name;
}
public function getEditor($name, $content = '', $width =
null, $height = null)
{
return null;
}
public function filter($text)
{
return $text;
}
public function finalize()
{
$gantry = Gantry::instance();
$gantry['document']->registerAssets();
}
public function call()
{
$args = func_get_args();
$callable = array_shift($args);
return is_callable($callable) ? call_user_func_array($callable,
$args) : null;
}
public function authorize($action)
{
return true;
}
/**
* @param array|string $dependencies
* @return bool|null
* @since 5.4.3
*/
public function checkDependencies($dependencies)
{
if (is_string($dependencies) && $dependencies !==
$this->name) {
return false;
}
if (isset($dependencies['platform'])) {
if (is_string($dependencies['platform']) &&
$dependencies['platform'] !== $this->name) {
return false;
}
if
(!isset($dependencies['platform'][$this->name])) {
return false;
}
}
return true;
}
}
PK&d�[3�S��&classes/Gantry/Framework/Base/Site.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Base;
class Site
{
}
PK&d�[�1L�GG'classes/Gantry/Framework/Base/Theme.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Base;
use Gantry\Component\Theme\AbstractTheme;
use Gantry\Component\Theme\ThemeTrait;
/**
* @deprecated 5.1.5
*/
abstract class Theme extends AbstractTheme
{
use ThemeTrait;
}
PK&d�[�.��+classes/Gantry/Framework/Configurations.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework;
/**
* @deprecated 5.1.1
*/
class Configurations extends Outlines
{
}
PK&d�[4y,cc%classes/Gantry/Framework/Document.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Component\Content\Document\HtmlDocument;
class Document extends HtmlDocument
{
protected static $availableFrameworks = [
'jquery' => 'registerJquery',
'jquery.framework' => 'registerJquery',
'jquery.ui.core' => 'registerJqueryUiCore',
'jquery.ui.sortable' =>
'registerJqueryUiSortable',
'bootstrap.2' => 'registerBootstrap2',
'mootools' => 'registerMootools',
'mootools.framework' => 'registerMootools',
'mootools.core' => 'registerMootools',
'mootools.more' => 'registerMootoolsMore',
'lightcase' => 'registerLightcase',
'lightcase.init' => 'registerLightcaseInit',
];
public static function registerAssets()
{
static::registerFrameworks();
static::registerStyles();
static::registerScripts();
}
/**
* NOTE: In PHP this function can be called either from Gantry DI
container or statically.
*
* @param bool $addDomain
* @return string
*/
public static function domain($addDomain = false)
{
if (!$addDomain) {
return '';
}
$absolute = \JUri::root(false);
$relative = \JUri::root(true);
return substr($absolute, 0, -strlen($relative));
}
public static function rootUri()
{
return rtrim(\JUri::root(true), '/') ?: '/';
}
public static function errorPage($new = null)
{
static $error = false;
if (isset($new)) {
$error = (bool) $new;
}
return $error;
}
protected static function registerStyles()
{
if (static::errorPage()) {
return;
}
$doc = \JFactory::getDocument();
$styles = static::$stack[0]->getStyles();
foreach ($styles as $style) {
switch ($style[':type']) {
case 'file':
$doc->addStyleSheet($style['href'],
$style['type'], $style['media'],
$style['element']);
break;
case 'inline':
$doc->addStyleDeclaration($style['content'],
$style['type']);
break;
}
}
}
protected static function registerScripts()
{
if (static::errorPage()) {
return;
}
$doc = \JFactory::getDocument();
$scripts = static::$stack[0]->getScripts();
foreach ($scripts as $script) {
switch ($script[':type']) {
case 'file':
$doc->addScript($script['src'],
$script['type'], $script['defer'],
$script['async']);
break;
case 'inline':
$doc->addScriptDeclaration($script['content'],
$script['type']);
break;
}
}
}
protected static function registerJquery()
{
if (!static::errorPage()) {
\JHtml::_('jquery.framework');
return;
}
// Workaround for error document type.
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/jui/js/jquery.min.js'
],
'head',
100
);
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/jui/js/jquery-noconflict.js'
],
'head',
100
);
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/jui/js/jquery-migrate.min.js'
],
'head',
100
);
}
protected static function registerJqueryUiCore()
{
if (!static::errorPage()) {
\JHtml::_('jquery.ui', ['core']);
return;
}
// Workaround for error document type.
static::registerJquery();
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/jui/js/jquery.ui.core.min.js'
],
'head',
100
);
}
protected static function registerJqueryUiSortable()
{
if (!static::errorPage()) {
\JHtml::_('jquery.ui', ['sortable']);
return;
}
// Workaround for error document type.
static::registerJqueryUiCore();
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/jui/js/jquery.ui.sortable.min.js'
],
'head',
100
);
}
protected static function registerBootstrap2()
{
Gantry::instance()['theme']->joomla(true);
if (!static::errorPage()) {
\JHtml::_('bootstrap.framework');
return;
}
// Workaround for error document type.
static::registerJquery();
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/jui/js/bootstrap.min.js'
],
'head',
100
);
}
protected static function registerMootools()
{
if (!static::errorPage()) {
\JHtml::_('behavior.framework');
return;
}
// Workaround for error document type.
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/system/js/mootools-core.js'
],
'head',
99
);
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/system/js/core.js'
],
'head',
99
);
}
protected static function registerMootoolsMore()
{
if (!static::errorPage()) {
\JHtml::_('behavior.framework', true);
return;
}
// Workaround for error document type.
static::registerMootools();
static::addHeaderTag(
[
'tag' => 'script',
'src' => \JUri::getInstance()->base(true) .
'/media/system/js/mootools-more.js'
],
'head',
99
);
}
/**
* Override to support index.php?Itemid=xxx.
*
* @param array $matches
* @return string
* @internal
*/
public static function linkHandler(array $matches)
{
$url = trim($matches[3]);
if (strpos($url, 'index.php?') !== 0) {
list($domain, $timestamp_age) = static::$urlFilterParams;
$url = static::url(trim($matches[3]), $domain, $timestamp_age);
}
return "{$matches[1]}{$matches[2]}=\"{$url}\"";
}
}
PK&d�[�NE&classes/Gantry/Framework/Exception.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework;
class Exception extends \RuntimeException
{
protected $responseCodes = [
200 => '200 OK',
400 => '400 Bad Request',
401 => '401 Unauthorized',
403 => '403 Forbidden',
404 => '404 Not Found',
410 => '410 Gone',
500 => '500 Internal Server Error',
501 => '501 Not Implemented',
503 => '503 Service Temporarily Unavailable'
];
public function getResponseCode() {
return isset($this->responseCodes[$this->code]) ? (int)
$this->code : 500;
}
public function getResponseStatus() {
return $this->responseCodes[$this->getResponseCode()];
}
}
PK&d�[��(�+�+%classes/Gantry/Framework/Exporter.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Component\Layout\Layout;
use Gantry\Framework\Services\ConfigServiceProvider;
use Gantry\Joomla\Category\CategoryFinder;
use Gantry\Joomla\Content\ContentFinder;
use Gantry\Joomla\Module\ModuleFinder;
use Gantry\Joomla\StyleHelper;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Exporter
{
protected $files = [];
public function all()
{
$theme = Gantry::instance()['theme']->details();
return [
'export' => [
'gantry' => [
'version' => GANTRY5_VERSION !==
'@version@' ? GANTRY5_VERSION : 'GIT',
'format' => 1
],
'platform' => [
'name' => 'joomla',
'version' => JVERSION
],
'theme' => [
'name' =>
$theme->get('name'),
'title' =>
$theme->get('details.name'),
'version' =>
$theme->get('details.version'),
'date' =>
$theme->get('details.date'),
'author' =>
$theme->get('details.author'),
'copyright' =>
$theme->get('details.copyright'),
'license' =>
$theme->get('details.license'),
]
],
'outlines' => $this->outlines(),
'positions' => $this->positions(),
'menus' => $this->menus(),
'content' => $this->articles(),
'categories' => $this->categories(),
'files' => $this->files,
];
}
public function outlines()
{
$gantry = Gantry::instance();
$styles = StyleHelper::loadStyles($gantry['theme.name']);
$list = [
'default' => ['title' =>
'Default'],
'_error' => ['title' =>
'Error'],
'_offline' => ['title' =>
'Offline'],
'_body_only' => ['title' =>
'Body Only'],
];
$inheritance = [];
foreach ($styles as $style) {
$name = $base =
strtolower(trim(preg_replace('|[^a-z\d_-]+|ui', '_',
$style->title), '_'));
$i = 0;
while (isset($list[$name])) {
$i++;
$name = "{$base}-{$i}";
};
$inheritance[$style->id] = $name;
$list[$name] = [
'id' => (int) $style->id,
'title' => $style->title,
'home' => $style->home,
];
if (!$style->home) {
unset($list[$name]['home']);
}
}
foreach ($list as $name => &$style) {
$id = isset($style['id']) ? $style['id'] :
$name;
$config = ConfigServiceProvider::load($gantry, $id, false,
false);
// Update layout inheritance.
$layout = Layout::instance($id);
$layout->name = $name;
foreach ($inheritance as $from => $to) {
$layout->updateInheritance($from, $to);
}
$style['preset'] =
$layout->preset['name'];
$config['index'] = $layout->buildIndex();
$config['layout'] = $layout->export();
// Update atom inheritance.
$atoms = $config->get('page.head.atoms');
if (is_array($atoms)) {
$atoms = new Atoms($atoms);
foreach ($inheritance as $from => $to) {
$atoms->updateInheritance($from, $to);
}
$config->set('page.head.atoms',
$atoms->update()->toArray());
}
// Add assignments.
if (is_numeric($id)) {
$assignments = $this->getOutlineAssignments($id);
if ($assignments) {
$config->set('assignments',
$this->getOutlineAssignments($id));
}
}
$style['config'] = $config->toArray();
}
return $list;
}
public function positions($all = true)
{
$gantry = Gantry::instance();
$positions = $gantry['outlines']->positions();
$positions['debug'] = 'Debug';
$finder = new ModuleFinder();
if (!$all) {
$finder->particle();
}
$modules = $finder->find()->export();
$list = [];
foreach ($modules as $position => &$items) {
if (!isset($positions[$position])) {
continue;
}
foreach ($items as &$item) {
$func = 'module' .
$item['options']['type'];
if (method_exists($this, $func)) {
$item = $this->{$func}($item);
}
}
$list[$position] = [
'title' => $positions[$position],
'items' => $items,
];
}
return $list;
}
public function menus()
{
$gantry = Gantry::instance();
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->select('id, menutype, title, description')
->from('#__menu_types');
$db->setQuery($query);
$menus = $db->loadObjectList('id');
$list = [];
foreach ($menus as $menu) {
$items =
$gantry['menu']->instance(['menu' =>
$menu->menutype])->items(false);
array_walk(
$items,
function (&$item) {
$item['id'] = (int) $item['id'];
if (in_array($item['type'],
['component', 'alias'])) {
$item['type'] =
"joomla.{$item['type']}";
}
unset($item['alias'],
$item['path'], $item['parent_id'],
$item['level']);
}
);
$list[$menu->menutype] = [
'id' => (int) $menu->id,
'title' => $menu->title,
'description' => $menu->description,
'items' => $items
];
}
return $list;
}
public function articles()
{
$finder = new ContentFinder();
$articles = $finder->limit(0)->find();
$list = [];
foreach ($articles as $article) {
$exported = $article->toArray();
// Convert images to use streams.
$exported['introtext'] =
$this->urlFilter($exported['introtext']);
$exported['fulltext'] =
$this->urlFilter($exported['fulltext']);
$list[$article->id . '-' . $article->alias] =
$exported;
}
return $list;
}
public function categories()
{
$finder = new CategoryFinder();
$categories = $finder->limit(0)->find();
$list = [];
foreach ($categories as $category) {
$list[$category->id] = $category->toArray();
}
return $list;
}
/**
* List all the rules available.
*
* @param string $configuration
* @return array
*/
public function getOutlineAssignments($configuration)
{
require_once JPATH_ADMINISTRATOR .
'/components/com_menus/helpers/menus.php';
$app = \JApplicationCms::getInstance('site');
$menu = $app->getMenu();
$data = \MenusHelper::getMenuLinks();
$items = [];
foreach ($data as $item) {
foreach ($item->links as $link) {
if ($link->template_style_id == $configuration) {
$items[$menu->getItem($link->value)->route] =
1;
}
}
}
if ($items) {
return ['page' => [$items]];
}
return [];
}
/**
* Filter stream URLs from HTML.
*
* @param string $html HTML input to be filtered.
* @return string Returns modified HTML.
*/
public function urlFilter($html)
{
// Tokenize all PRE and CODE tags to avoid modifying any
src|href|url in them
$tokens = [];
$html =
preg_replace_callback('#<(pre|code).*?>.*?<\\/\\1>#is',
function($matches) use (&$tokens) {
$token = uniqid('__g5_token');
$tokens['#' . $token . '#'] = $matches[0];
return $token;
}, $html);
$html =
preg_replace_callback('^(\s)(src|href)="(.*?)"^',
[$this, 'linkHandler'], $html);
$html = preg_replace_callback('^(\s)url\((.*?)\)^',
[$this, 'urlHandler'], $html);
$html = preg_replace(array_keys($tokens), array_values($tokens),
$html); // restore tokens
return $html;
}
public function url($url)
{
// Only process local urls.
if ($url === '' || $url[0] === '/' || $url[0]
=== '#') {
return $url;
}
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
// Handle URIs.
if (strpos($url, '://')) {
if ($locator->isStream($url)) {
// File is a stream, include it to files list.
list ($stream, $path) = explode('://', $url);
$this->files[$stream][$path] = $url;
}
return $url;
}
// Try to convert local paths to streams.
$paths = $locator->getPaths();
$found = false;
$stream = $path = '';
foreach ($paths as $stream => $prefixes) {
foreach ($prefixes as $prefix => $paths) {
foreach ($paths as $path) {
if (is_string($path) && strpos($url, $path) ===
0) {
$path = ($prefix ? "{$prefix}/" :
'') . substr($url, strlen($path) + 1);
$found = true;
break 3;
}
}
}
}
if ($found) {
$url = "{$stream}://{$path}";
$this->files[$stream][$path] = $url;
}
return $url;
}
/**
* @param array $matches
* @return string
* @internal
*/
public function linkHandler(array $matches)
{
$url = $this->url(trim($matches[3]));
return "{$matches[1]}{$matches[2]}=\"{$url}\"";
}
/**
* @param array $matches
* @return string
* @internal
*/
public function urlHandler(array $matches)
{
$url = $this->url(trim($matches[2], '"\''));
return "{$matches[1]}url({$url})";
}
protected function moduleMod_Custom(array $data)
{
// Convert to particle...
$data['type'] = 'particle';
$data['joomla'] = $data['options'];
$data['options'] = [
'type' => 'custom',
'attributes' => [
'enabled' =>
$data['joomla']['published'],
'html' =>
$this->urlFilter($data['joomla']['content']),
'filter' =>
$data['joomla']['params']['prepare_content']
]
];
unset($data['joomla']['content'],
$data['joomla']['params']['prepare_content']);
return $data;
}
}
PK&d�[��D���#classes/Gantry/Framework/Gantry.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
class Gantry extends Base\Gantry
{
/**
* @return boolean
*/
public function debug()
{
return JDEBUG;
}
/**
* @return boolean
*/
public function admin()
{
return \JFactory::getApplication()->isAdmin();
}
/**
* @param string $location
* @param bool $force
* @return array
*/
public function styles($location = 'head', $force = false)
{
// Do not display head, Joomla will take care of it (most of the
time).
return (!$force && $location == 'head') ? [] :
parent::styles($location);
}
/**
* @param string $location
* @param bool $force
* @return array
*/
public function scripts($location = 'head', $force = false)
{
// Do not display head, Joomla will take care of it (most of the
time).
return (!$force && $location == 'head') ? [] :
parent::scripts($location);
}
/**
* @return array
*/
protected function loadGlobal()
{
$global = null;
// Trigger the event.
$dispatcher = \JEventDispatcher::getInstance();
$dispatcher->trigger('onGantryGlobalConfig',
['global' => &$global]);
return $global;
}
}
PK&d�["�����/classes/Gantry/Framework/Markdown/Parsedown.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Markdown;
class Parsedown extends \Parsedown
{
use ParsedownTrait;
/**
* Parsedown constructor.
*
* @param array $defaults
*/
public function __construct(array $defaults = null)
{
$this->init($defaults ?: []);
}
}
PK&d�[S�kn��4classes/Gantry/Framework/Markdown/ParsedownExtra.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Markdown;
class ParsedownExtra extends \ParsedownExtra
{
use ParsedownTrait;
/**
* ParsedownExtra constructor.
*
* @param array $defaults
* @throws \Exception
*/
public function __construct(array $defaults = null)
{
parent::__construct();
$this->init($defaults ?: []);
}
}
PK&d�[TD���4classes/Gantry/Framework/Markdown/ParsedownTrait.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Markdown;
use Gantry\Framework\Gantry;
trait ParsedownTrait
{
protected $special_chars;
protected $twig_link_regex =
'/\!*\[(?:.*)\]\((\{([\{%#])\s*(.*?)\s*(?:\2|\})\})\)/';
/**
* Initialization function to setup key variables needed by the
MarkdownGravLinkTrait
*
* @param $defaults
*/
protected function init(array $defaults)
{
$defaults += [
'auto_line_breaks' => false,
'auto_url_links' => false,
'escape_markup' => false,
'special_chars' => false
];
$this->BlockTypes['{'][] = 'TwigTag';
$this->special_chars = ['>' => 'gt',
'<' => 'lt', '"' =>
'quot'];
$this->setBreaksEnabled($defaults['auto_line_breaks']);
$this->setUrlsLinked($defaults['auto_url_links']);
$this->setMarkupEscaped($defaults['escape_markup']);
$this->setSpecialChars($defaults['special_chars']);
}
/**
* Setter for special chars
*
* @param $special_chars
*
* @return $this
*/
public function setSpecialChars($special_chars)
{
$this->special_chars = $special_chars;
return $this;
}
/**
* Ensure Twig tags are treated as block level items with no
<p></p> tags
*
* @param array $line
* @return array|null
*/
protected function blockTwigTag($line)
{
if (preg_match('/(?:{{|{%|{#)(.*)(?:}}|%}|#})/',
$line['body'], $matches)) {
return ['markup' => $line['body']];
}
return null;
}
protected function inlineSpecialCharacter($excerpt)
{
if ($excerpt['text'][0] === '&' &&
!preg_match('/^&#?\w+;/', $excerpt['text'])) {
return [
'markup' => '&',
'extent' => 1,
];
}
if (isset($this->special_chars[$excerpt['text'][0]]))
{
return [
'markup' => '&' .
$this->special_chars[$excerpt['text'][0]] . ';',
'extent' => 1,
];
}
return null;
}
protected function inlineImage($excerpt)
{
if (preg_match($this->twig_link_regex,
$excerpt['text'], $matches)) {
$excerpt['text'] = str_replace($matches[1],
'/', $excerpt['text']);
$excerpt = parent::inlineImage($excerpt);
$excerpt['element']['attributes']['src'] =
$matches[1];
$excerpt['extent'] = $excerpt['extent'] +
\strlen($matches[1]) - 1;
return $excerpt;
}
$excerpt['type'] = 'image';
$excerpt = parent::inlineImage($excerpt);
// if this is an image process it
if
(isset($excerpt['element']['attributes']['src']))
{
$gantry = Gantry::instance();
$excerpt['element']['attributes']['src'] =
$gantry['document']->url($excerpt['element']['attributes']['src']);
}
return $excerpt;
}
protected function inlineLink($excerpt)
{
if (!isset($excerpt['type'])) {
$excerpt['type'] = 'link';
}
// do some trickery to get around Parsedown requirement for valid
URL if its Twig in there
if (preg_match($this->twig_link_regex,
$excerpt['text'], $matches)) {
$excerpt['text'] = str_replace($matches[1],
'/', $excerpt['text']);
$excerpt = parent::inlineLink($excerpt);
$excerpt['element']['attributes']['href'] =
$matches[1];
$excerpt['extent'] = $excerpt['extent'] +
\strlen($matches[1]) - 1;
return $excerpt;
}
$excerpt = parent::inlineLink($excerpt);
// if this is a link
if
(isset($excerpt['element']['attributes']['href']))
{
$gantry = Gantry::instance();
$excerpt['element']['attributes']['href'] =
$gantry['document']->url($excerpt['element']['attributes']['href']);
}
return $excerpt;
}
}
PK&d�[��.@2@2!classes/Gantry/Framework/Menu.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Component\Config\Config;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Menu\AbstractMenu;
use Gantry\Component\Menu\Item;
class Menu extends AbstractMenu
{
use GantryTrait;
/**
* @var \JApplicationCms
*/
protected $app;
/**
* @var \JMenu
*/
protected $menu;
public function __construct()
{
$this->app = \JApplicationCms::getInstance('site');
$lang = \JFactory::getLanguage();
$tag = \JLanguageMultilang::isEnabled() ? $lang->getTag() :
'*';
$this->menu = $this->app->getMenu();
$this->default = $this->menu->getDefault($tag);
$this->active = $this->menu->getActive();
}
public function init(&$params)
{
parent::init($params);
if (!empty($params['admin'])) {
/** @var \JTableMenuType $table */
$menuType = \JTable::getInstance('MenuType');
$menuType->load(['menutype' =>
$params['menu']]);
$config = $this->config();
$config->set('settings.title',
$menuType->title);
$config->set('settings.description',
$menuType->description);
}
}
/**
* Return list of menus.
*
* @return array
* @throws \RuntimeException
*/
public function getMenus()
{
static $items;
if ($items === null) {
require_once JPATH_ADMINISTRATOR .
'/components/com_menus/helpers/menus.php';
$items = (array) \MenusHelper::getMenuTypes();
}
return $items;
}
public function getGroupedItems()
{
$groups = array();
// Get the menu items.
$items = \MenusHelper::getMenuLinks();
// Build the groups arrays.
foreach ($items as $item) {
// Initialize the group.
$groups[$item->menutype] = [];
// Build the options array.
foreach ($item->links as $link) {
$groups[$item->menutype][$link->value] = [
'spacing' => str_repeat('
', max(0, $link->level-1)),
'label' => $link->text
];
}
}
return $groups;
}
/**
* Return default menu.
*
* @return string|null
*/
public function getDefaultMenuName()
{
return $this->default ? $this->default->menutype : null;
}
/**
* Returns true if the platform implements a Default menu.
*
* @return boolean
*/
public function hasDefaultMenu()
{
return true;
}
/**
* Return active menu.
*
* @return string|null
*/
public function getActiveMenuName()
{
return $this->active ? $this->active->menutype : null;
}
/**
* Returns true if the platform implements an Active menu.
*
* @return boolean
*/
public function hasActiveMenu()
{
return true;
}
/**
* @return string|null
*/
public function getCacheId()
{
if (!\JFactory::getUser()->guest) {
return null;
}
return $this->active ? $this->active->id : 0;
}
public function isActive($item)
{
$tree = $this->base->tree;
if (in_array($item->id, $tree)) {
return true;
} elseif ($item->type == 'alias') {
$aliasToId = $item->link_id;
if (count($tree) > 0 && $aliasToId ==
$tree[count($tree) - 1]) {
return (bool) $this->params['highlightAlias'];
} elseif (in_array($aliasToId, $tree)) {
return (bool)
$this->params['highlightParentAlias'];
}
}
return false;
}
public function isCurrent($item)
{
return $item->id == $this->active->id
|| ($item->type == 'alias' &&
$item->params->get('aliasoptions') ==
$this->active->id);
}
/**
* Get menu items from the platform.
*
* @param array $params
* @return array List of routes to the pages.
*/
protected function getItemsFromPlatform($params)
{
$attributes = ['menutype'];
$values = [$params['menu']];
// Items are already filtered by access and language, in admin we
need to work around that.
if (\JFactory::getApplication()->isAdmin()) {
$attributes[] = 'access';
$values[] = null;
$attributes[] = 'language';
$values[] = null;
}
return $this->menu->getItems($attributes, $values);
}
/**
* Get base menu item.
*
* If itemid is not specified or does not exist, return active menu
item.
* If there is no active menu item, fall back to home page for the
current language.
* If there is no home page, return null.
*
* @param int $itemid
*
* @return object|null
*/
protected function calcBase($itemid = null)
{
$menu = $this->app->getMenu();
// Get base menu item.
$base = $itemid ? $menu->getItem($itemid) : null;
if (!$base) {
// Use active menu item or fall back to default menu item.
$base = $this->active ?: $this->default;
}
// Return base menu item.
return $base;
}
/**
* Get a list of the menu items.
*
* Logic was originally copied from Joomla 3.4 mod_menu/helper.php
(joomla-cms/staging, 2014-11-12).
* We should keep the contents of the function similar to Joomla in
order to review it against any changes.
*
* @param array $params
* @param array $items
*/
public function getList(array $params, array $items)
{
// Get base menu item for this menu (defaults to active menu item).
$this->base = $this->calcBase($params['base']);
// Make sure that the menu item exists.
if (!$this->base &&
!\JFactory::getApplication()->isAdmin()) {
return;
}
$levels = \JFactory::getUser()->getAuthorisedViewLevels();
asort($levels);
// FIXME: need to create collection class to gather the sibling
data, otherwise caching cannot work.
//$key = 'gantry_menu_items.' . json_encode($params) .
'.' . json_encode($levels) . '.' .
$this->base->id;
//$cache = \JFactory::getCache('mod_menu', '');
//try {
// $this->items = $cache->get($key);
//} catch (\Exception $e) {
// $this->items = false;
//}
if (1) {
$tree = isset($this->base->tree) ?
$this->base->tree : [];
$start = $params['startLevel'];
$max = $params['maxLevels'];
$end = $max ? $start + $max - 1 : 0;
$menuItems = $this->getItemsFromPlatform($params);
$itemMap = [];
foreach ($items as $path => &$itemRef) {
if (isset($itemRef['id']) &&
is_numeric($itemRef['id'])) {
$itemRef['path'] = $path;
$itemMap[$itemRef['id']] = &$itemRef;
}
}
foreach ($menuItems as $menuItem) {
if (($start && $start > $menuItem->level)
|| ($end && $menuItem->level > $end)
|| ($start > 1 &&
!in_array($menuItem->tree[$start - 2], $tree))) {
continue;
}
// These params always come from Joomla and cannot be
overridden.
$itemParams = [
'id' => $menuItem->id,
'type' => $menuItem->type,
'alias' => $menuItem->alias,
'path' => $menuItem->route,
'link' => $menuItem->link,
'link_title' =>
$menuItem->params->get('menu-anchor_title', ''),
'rel' =>
$menuItem->params->get('menu-anchor_rel', ''),
'enabled' => (bool)
$menuItem->params->get('menu_show', 1),
];
// Rest of the items will come from saved configuration.
if (isset($itemMap[$menuItem->id])) {
// ID found, use it.
$itemParams += $itemMap[$menuItem->id];
// Store new path for the menu item into path map.
if ($itemParams['path'] !==
$itemMap[$menuItem->id]['path']) {
if (!$this->pathMap) {
$this->pathMap = new Config([]);
}
$this->pathMap->set(preg_replace('|/|u',
'/children/', $itemMap[$menuItem->id]['path']) .
'/path', $itemParams['path'], '/');
}
} elseif (isset($items[$menuItem->route])) {
// ID not found, try to use route.
$itemParams += $items[$menuItem->route];
}
// Get default target from Joomla.
switch ($menuItem->browserNav)
{
default:
case 0:
// Target window: Parent.
$target = '_self';
break;
case 1:
case 2:
// Target window: New with navigation.
$target = '_blank';
break;
}
// And if not available in configuration, default to
Joomla.
$itemParams += [
'title' => $menuItem->title,
'anchor_class' =>
$menuItem->params->get('menu-anchor_css', ''),
'image' =>
$menuItem->params->get('menu_image', ''),
'icon_only' =>
!$menuItem->params->get('menu_text', 1),
'target' => $target
];
$item = new Item($this, $menuItem->route, $itemParams);
$this->add($item);
$link = $item->link;
switch ($item->type) {
case 'separator':
case 'heading':
// These types have no link.
$link = null;
break;
case 'url':
if ((strpos($item->link, 'index.php?')
=== 0) && (strpos($item->link, 'Itemid=') === false))
{
// If this is an internal Joomla link, ensure
the Itemid is set.
$link = $item->link .
'&Itemid=' . $item->id;
}
break;
case 'alias':
// If this is an alias use the item id stored in
the parameters to make the link.
$link = 'index.php?Itemid=' .
$menuItem->params->get('aliasoptions', 0);
break;
default:
$app = $this->app;
$router = $app::getRouter();
if ($router->getMode() == JROUTER_MODE_SEF) {
$link = 'index.php?Itemid=' .
$item->id;
if
(isset($menuItem->query['format']) &&
$app->get('sef_suffix')) {
$link .= '&format=' .
$menuItem->query['format'];
}
} else {
$link .= '&Itemid=' .
$item->id;
}
break;
}
if (!$link) {
$item->url(false);
} elseif (strcasecmp(substr($link, 0, 4), 'http')
&& (strpos($link, 'index.php?') !== false)) {
$item->url(\JRoute::_($link, false,
$menuItem->params->get('secure')));
} else {
$item->url(\JRoute::_($link, false));
}
if ($item->type == 'url') {
// Moved from modules/mod_menu/tmpl/default_url.php,
not sure why Joomla had application logic in there.
// Keep compatibility to Joomla menu module, but we
need non-encoded version of the url.
$item->url(
htmlspecialchars_decode(\JFilterOutput::ampReplace(htmlspecialchars($item->link,
ENT_COMPAT|ENT_SUBSTITUTE, 'UTF-8')))
);
}
}
// FIXME: need to create collection class to gather the sibling
data, otherwise caching cannot work.
// $cache->store($this->items, $key);
}
}
}
PK&d�[�~���!�!%classes/Gantry/Framework/Outlines.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Admin\ThemeList;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Outline\OutlineCollection;
use Gantry\Joomla\StyleHelper;
use Gantry\Joomla\TemplateInstaller;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Outlines extends OutlineCollection
{
protected $createId;
public function preset($id)
{
if (is_numeric($id)) {
$style = StyleHelper::getStyle($id);
$params = json_decode($style->params, true);
$id = isset($params['preset']) ?
$params['preset'] : 'default';
}
return $id;
}
public function current($template = null)
{
if (!is_object($template)) {
// Get the template style.
$template = \JFactory::getApplication()->getTemplate(true);
}
$preset = $template->params->get('preset',
'default');
$outline = $template->params->get('configuration',
!empty($template->id) ? $template->id : null);
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage('Template Style:') &&
\Gantry\Debugger::addMessage($template);
if (JDEBUG && !$outline) {
static $shown = false;
if (!$shown) {
$shown = true;
\JFactory::getApplication()->enqueueMessage('[DEBUG]
JApplicationSite::getTemplate() was overridden with no specified Gantry 5
outline.', 'notice');
}
}
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
return ($outline &&
is_dir($locator("{$this->path}/{$outline}"))) ? $outline :
$preset;
}
/**
* @param string $path
* @return $this
*/
public function load($path = 'gantry-config://')
{
$this->path = $path;
$gantry = $this->container;
$theme = isset($gantry['theme.name']) ?
$gantry['theme.name'] : null;
$styles = ThemeList::getStyles($theme);
$installer = new
TemplateInstaller($this->container['theme.name']);
$title = $installer->getStyleName('%s - ');
$outlines = [];
foreach ($styles as $style) {
$preset = isset($style->params['preset']) ?
$style->params['preset'] : null;
$outline = isset($style->params['configuration'])
? $style->params['configuration'] : $preset;
if ($outline && $outline != $style->id) {
// New style generated by Joomla.
StyleHelper::copy($style, $outline, $style->id);
}
$outlines[$style->id] = preg_replace('|^' .
preg_quote($title) . '|', '', $style->style);
}
asort($outlines);
$this->items = $this->addDefaults($outlines);
return $this;
}
/**
* @param string|null $id
* @param string $title
* @param string|array $preset
* @return string
* @throws \RuntimeException
*/
public function create($id, $title = null, $preset = null)
{
if ($this->createId) {
// Workaround Joomla wanting to use different logic for style
duplication.
$new = parent::create($this->createId, $title, $preset);
$this->createId = null;
return $new;
}
$title = $title ? "%s - {$title}" : '%s -
Untitled';
$installer = new
TemplateInstaller($this->container['theme.name']);
$title = $installer->getStyleName($title);
$style = $installer->addStyle($title);
$error = $style->getError();
if ($error) {
throw new \RuntimeException($error, 400);
}
$presetId = (string)
(isset($preset['preset']['name']) ?
$preset['preset']['name'] : ($preset ?:
'default'));
StyleHelper::update($style->id, $presetId);
// Create configuration folder.
$id = parent::create($style->id, $title, $preset);
if ($id != $style->id) {
throw new \RuntimeException(sprintf("Creating outline:
folder '%s' already exists!", $style->id));
}
return $style->id;
}
public function duplicate($id, $title = null, $inherit = false)
{
if (!$this->canDuplicate($id)) {
throw new \RuntimeException("Outline '$id'
cannot be duplicated", 400);
}
// Handle special case of duplicating system outlines.
if ((string)(int) $id !== (string) $id) {
return parent::duplicate($id, $title, $inherit);
}
// Use Joomla logic to duplicate the style.
$model = StyleHelper::loadModel();
$pks = [$id];
if (!$model->duplicate($pks)) {
throw new \RuntimeException($model->getError(), 400);
}
// Seek the newly generated style ID since Joomla doesn't
return one on duplication.
$theme = $this->container['theme.name'];
$styles = ThemeList::getStyles($theme, true);
$style = end($styles);
if ($title) {
// Change the title.
$installer = new TemplateInstaller($theme);
$title = $installer->getStyleName("%s -
{$title}");
$this->rename($style->id, $title);
} else {
$title = $style->style;
}
$this->createId = $style->id;
return parent::duplicate($id, $title, $inherit);
}
public function rename($id, $title)
{
$model = StyleHelper::loadModel();
$item = $model->getTable();
$item->load($id);
if (!$item->id) {
throw new \RuntimeException('Outline not found',
404);
}
$theme = $this->container['theme.name'];
$installer = new TemplateInstaller($theme);
$title = $title ? "%s - {$title}" : '%s -
Untitled';
$title = $installer->getStyleName($title);
$item->title = $title;
if (!$item->check()) {
throw new \RuntimeException($item->getError(), 400);
}
if (!$item->store()) {
throw new \RuntimeException($item->getError(), 500);
}
if (isset($this->items[$id])) {
$this->items[$id] = $title;
}
return $id;
}
public function delete($id, $deleteModel = true)
{
if (!$this->canDelete($id)) {
throw new \RuntimeException("Outline '$id'
cannot be deleted", 400);
}
$model = StyleHelper::loadModel();
$item = $model->getTable();
$item->load($id);
try {
foreach ($this->getInheritingOutlines($id) as $outline =>
$title) {
$this->layout($outline)->updateInheritance($id)->save()->saveIndex();
}
foreach ($this->getInheritingOutlinesWithAtom($id) as
$outline => $title) {
Atoms::instance($outline)->updateInheritance($id)->save();
}
if ($deleteModel && !$model->delete($id)) {
$error = $model->getError();
// Well, Joomla can always send enqueue message instead!
if (!$error) {
$messages =
\JFactory::getApplication()->getMessageQueue();
$message = reset($messages);
$error = $message ? $message['message'] :
'Unknown error';
}
throw new \RuntimeException($error);
}
} catch (\Exception $e) {
throw new \RuntimeException('Deleting outline failed:
' . $e->getMessage(), 400, $e);
}
// Remove configuration directory.
$gantry = $this->container;
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path =
$locator->findResource("{$this->path}/{$item->id}",
true, true);
if ($path) {
if (file_exists($path)) {
Folder::delete($path);
}
}
unset($this->items[$item->id]);
}
/**
* @param string $id
* @return boolean
*/
public function canDelete($id)
{
$model = StyleHelper::loadModel();
$item = $model->getTable();
$item->load($id);
return !$item->id || $item->home ? false : true;
}
/**
* @param string $id
* @return boolean
*/
public function isDefault($id)
{
$model = StyleHelper::loadModel();
$item = $model->getTable();
$item->load($id);
return (bool) $item->home;
}
}
PK&d�[�%jȌ�!classes/Gantry/Framework/Page.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
class Page extends Base\Page
{
public $home;
public $outline;
public $language;
public $direction;
// Joomla specific properties.
public $theme;
public $baseUrl;
public $title;
public $description;
public function __construct($container)
{
parent::__construct($container);
$app = \JFactory::getApplication();
$document = \JFactory::getDocument();
$input = $app->input;
$this->tmpl = $input->getCmd('tmpl',
'');
$this->option = $input->getCmd('option',
'');
$this->view = $input->getCmd('view',
'');
$this->layout = $input->getCmd('layout',
'');
$this->task = $input->getCmd('task',
'');
$this->itemid = $input->getInt('Itemid', 0);
$this->printing = $input->getCmd('print',
'');
$this->class = '';
if ($this->itemid) {
$menuItem = $app->getMenu()->getActive();
if ($menuItem && $menuItem->id) {
$this->home = (bool) $menuItem->home;
$this->class =
$menuItem->params->get('pageclass_sfx', '');
}
}
$templateParams = $app->getTemplate(true);
$this->outline = Gantry::instance()['configuration'];
$this->sitename = $app->get('sitename');
$this->theme = $templateParams->template;
$this->baseUrl = \JUri::base(true);
$this->title = $document->title;
$this->description = $document->description;
// Document has lower case language code, which causes issues with
some JS scripts (Snipcart). Use tag instead.
$code = explode('-', $document->getLanguage(), 2);
$language = array_shift($code);
$country = strtoupper(array_shift($code));
$this->language = $language . ($country ? '-' .
$country : '');
$this->direction = $document->direction;
}
public function url(array $args = [])
{
$url = \JUri::getInstance();
foreach ($args as $key => $val) {
$url->setVar($key, $val);
}
return $url->toString();
}
public function htmlAttributes()
{
$attributes = [
'lang' => $this->language,
'dir' => $this->direction
]
+ (array) $this->config->get('page.html', []);
return $this->getAttributes($attributes);
}
public function bodyAttributes($attributes = [])
{
if ($this->tmpl == 'component') {
$classes = ['contentpane', 'modal'];
} else {
$classes = ['site', $this->option,
"view-{$this->view}"];
$classes[] = $this->layout ? 'layout-' .
$this->layout : 'no-layout';
$classes[] = $this->task ? 'task-' .
$this->task : 'no-task';
}
$classes[] = 'dir-' . $this->direction;
if ($this->class) $classes[] = $this->class;
if ($this->printing) $classes[] = 'print-mode';
if ($this->itemid) $classes[] = 'itemid-' .
$this->itemid;
if ($this->outline) $classes[] = 'outline-' .
$this->outline;
$baseAttributes = (array)
$this->config->get('page.body.attribs', []);
if (!empty($baseAttributes['class'])) {
$baseAttributes['class'] = array_merge((array)
$baseAttributes['class'], $classes);
} else {
$baseAttributes['class'] = $classes;
}
return $this->getAttributes($baseAttributes, $attributes);
}
}
PK&d�["��υB�B%classes/Gantry/Framework/Platform.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Admin\ThemeList;
use Gantry\Component\Filesystem\Folder;
use Gantry\Framework\Base\Platform as BasePlatform;
use Gantry\Joomla\Category\CategoryFinder;
use Gantry\Joomla\Content\Content;
use Gantry\Joomla\Content\ContentFinder;
/**
* The Platform Configuration class contains configuration information.
*
* @author RocketTheme
* @license MIT
*/
class Platform extends BasePlatform
{
public $no_base_layout = false;
public $module_wrapper = '<div
class="platform-content">%s</div>';
public $component_wrapper = '<div class="platform-content
row-fluid"><div
class="span12">%s</div></div>';
protected $name = 'joomla';
protected $features = ['modules' => true];
protected $settings_key = 'return';
protected $modules;
public function setModuleWrapper($html)
{
$this->module_wrapper = $html;
}
public function setComponentWrapper($html)
{
$this->component_wrapper = $html;
}
public function init()
{
// Support linked sample data.
$theme = isset($this->container['theme.name']) ?
$this->container['theme.name'] : null;
if ($theme && is_dir(JPATH_ROOT .
"/media/gantry5/themes/{$theme}/media-shared")) {
$custom = JPATH_ROOT .
"/media/gantry5/themes/{$theme}/custom";
if (!is_dir($custom)) {
// First run -- copy configuration into a single location.
$shared = JPATH_ROOT .
"/media/gantry5/themes/{$theme}/template-shared";
$demo = JPATH_ROOT .
"/media/gantry5/themes/{$theme}/template-demo";
try {
Folder::create($custom);
} catch (\Exception $e) {
throw new \RuntimeException(sprintf("Failed to
create folder '%s'.", $custom), 500, $e);
}
if (is_dir("{$shared}/custom/config")) {
Folder::copy("{$shared}/custom/config",
"{$custom}/config");
}
if (is_dir("{$demo}/custom/config")) {
Folder::copy("{$demo}/custom/config",
"{$custom}/config");
}
}
array_unshift($this->items['streams']['gantry-theme']['prefixes'][''],
"media/gantry5/themes/{$theme}/template-shared");
array_unshift($this->items['streams']['gantry-theme']['prefixes'][''],
"media/gantry5/themes/{$theme}/template-demo");
array_unshift($this->items['streams']['gantry-theme']['prefixes'][''],
"media/gantry5/themes/{$theme}/custom");
}
return parent::init();
}
public function getCachePath()
{
$path = \JFactory::getConfig()->get('cache_path',
JPATH_SITE . '/cache');
if (!is_dir($path)) {
throw new \RuntimeException('Joomla cache path does not
exist!');
}
return $path . '/gantry5';
}
public function getThemesPaths()
{
return ['' => ['templates']];
}
public function getMediaPaths()
{
$paths = ['images'];
// Support linked sample data.
$theme = isset($this->container['theme.name']) ?
$this->container['theme.name'] : null;
if ($theme && is_dir(JPATH_ROOT .
"/media/gantry5/themes/{$theme}/media-shared")) {
array_unshift($paths,
"media/gantry5/themes/{$theme}/media-shared");
array_unshift($paths,
"media/gantry5/themes/{$theme}/media-demo");
}
if
($this->container['global']->get('use_media_folder',
false)) {
array_push($paths, 'gantry-theme://images');
} else {
array_unshift($paths, 'gantry-theme://images');
}
return ['' => $paths];
}
public function getEnginesPaths()
{
if (is_link(GANTRY5_ROOT . '/media/gantry5/engines')) {
// Development environment.
return ['' =>
["media/gantry5/engines/{$this->name}",
'media/gantry5/engines/common']];
}
return ['' => ['media/gantry5/engines']];
}
public function getAssetsPaths()
{
if (is_link(GANTRY5_ROOT . '/media/gantry5/assets')) {
// Development environment.
return ['' => ['gantry-theme://',
"media/gantry5/assets/{$this->name}",
'media/gantry5/assets/common']];
}
return ['' => ['gantry-theme://',
'media/gantry5/assets']];
}
/**
* Get preview url for individual theme.
*
* @param string $theme
* @return string
*/
public function getThemePreviewUrl($theme)
{
return (string)(int) $theme === (string) $theme ?
\JUri::root(false) . 'index.php?templateStyle=' . $theme : null;
}
/**
* Get administrator url for individual theme.
*
* @param string $theme
* @return string
*/
public function getThemeAdminUrl($theme)
{
$token = \JSession::getFormToken();
return
\JRoute::_("index.php?option=com_gantry5&view=configurations/default/styles&theme={$theme}&{$token}=1"
, false);
}
public function filter($text)
{
\JPluginHelper::importPlugin('content');
return \JHtml::_('content.prepare', $text, '',
'mod_custom.content');
}
public function countModules($position)
{
$document = \JFactory::getDocument();
return ($document instanceof \JDocumentHTML) ?
$document->countModules($position) : 0;
}
public function getModules($position)
{
// TODO:
return [];
}
public function displayModule($id, $attribs = [])
{
$document = \JFactory::getDocument();
if (!$document instanceof \JDocumentHTML) {
return '';
}
$module = is_object($id) ? $id : $this->getModule($id);
// Make sure that module really exists.
if (!is_object($module)) {
return '';
}
$isGantry = \strpos($module->module, 'gantry5') !==
false;
$content = isset($module->content) ? $module->content : null;
$renderer = $document->loadRenderer('module');
$html = trim($renderer->render($module, $attribs));
// Add frontend editing feature as it has only been defined for
module positions.
$app = \JFactory::getApplication();
$user = \JFactory::getUser();
$frontEditing = ($app->isSite() &&
$app->get('frontediting', 1) && !$user->guest);
$menusEditing = ($app->get('frontediting', 1) == 2)
&& $user->authorise('core.edit',
'com_menus');
if (!$isGantry && $frontEditing && $html &&
$user->authorise('module.edit.frontend',
'com_modules.module.' . $module->id)) {
$displayData = [
'moduleHtml' => &$html,
'module' => $module,
'position' =>
isset($attribs['position']) ? $attribs['position'] :
$module->position,
'menusediting' => $menusEditing
];
\JLayoutHelper::render('joomla.edit.frontediting_modules',
$displayData);
}
// Work around Joomla "issue" which corrupts content of
custom html module (last checked J! 3.6.5).
$module->content = $content;
if ($html && !$isGantry) {
$this->container['theme']->joomla(true);
return sprintf($this->module_wrapper, $html);
}
return $html;
}
public function displayModules($position, $attribs = [])
{
$document = \JFactory::getDocument();
if (!$document instanceof \JDocumentHTML) {
return '';
}
$html = '';
foreach (\JModuleHelper::getModules($position) as $module) {
$html .= $this->displayModule($module, $attribs);
}
return $html;
}
public function displaySystemMessages($params = [])
{
// We cannot use JDocument renderer here as it fires too early to
display any messages.
return '<jdoc:include type="message" />';
}
public function displayContent($content, $params = [])
{
$document = \JFactory::getDocument();
if (!$document instanceof \JDocumentHTML) {
return $content;
}
$renderer = $document->loadRenderer('component');
$html = trim($renderer->render(null, $params, $content ?:
$document->getBuffer('component')));
$isGantry =
\strpos(\JFactory::getApplication()->input->getCmd('option'),
'gantry5') !== false;
if ($html && !$isGantry) {
$this->container['theme']->joomla(true);
return sprintf($this->component_wrapper, $html);
}
return $html;
}
public function getModule($id)
{
$modules = $this->getModuleList();
return $id && isset($modules[$id]) ? $modules[$id] : null;
}
protected function &getModuleList()
{
if ($this->modules === null) {
$modules = \JModuleHelper::getModuleList();
$this->modules = [];
foreach ($modules as $module) {
$this->modules[$module->id] = $module;
}
}
return $this->modules;
}
public function listModules()
{
$db = \JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('a.id, a.title, a.position, a.module,
a.published AS enabled')
->from('#__modules AS a');
// Join on the asset groups table.
$query->select('ag.title AS access')
->join('LEFT', '#__viewlevels AS ag ON ag.id
= a.access')
->where('a.published >= 0')
->where('a.client_id = 0')
->order('a.position, a.module, a.ordering');
$db->setQuery($query);
try {
$result = $db->loadObjectList();
} catch (\RuntimeException $e) {
return false;
}
return $result;
}
public function getEditor($name, $content = '', $width =
null, $height = null)
{
$conf = \JFactory::getConfig();
$editor = \JEditor::getInstance($conf->get('editor'));
if (!$height) {
$height = 250;
}
return $editor->display($name, $content, $width, $height, 50, 8,
false, null, null, null, ['html_height' => $height]);
}
public function errorHandlerPaths()
{
return ['|gantry5|'];
}
public function settings()
{
if (!$this->authorize('platform.settings.manage')) {
return '';
}
return
\JRoute::_('index.php?option=com_config&view=component&component=com_gantry5',
false);
}
public function update()
{
return
\JRoute::_('index.php?option=com_installer&view=update',
false);
}
public function updates()
{
if (!$this->authorize('updates.manage')) {
return [];
}
$styles = ThemeList::getThemes();
$extension_ids = array_unique(array_map(
function($item) {
return (int) $item->extension_id;
},
$styles));
$extension_ids = $extension_ids ? implode(',',
$extension_ids) : '-1';
$db = \JFactory::getDbo();
$query = $db->getQuery(true);
$query
->select('*')
->from('#__updates')
->where("element='pkg_gantry5' OR
extension_id IN ($extension_ids)");
$db->setQuery($query);
$updates = $db->loadObjectList();
$list = [];
foreach ($updates as $update) {
if ($update->element === 'pkg_gantry5') {
// Rename Gantry 5 package.
$update->name = 'Gantry';
// Ignore git and CI installs and if the Gantry version is
the same or higher than in the updates.
if (version_compare(GANTRY5_VERSION, 0) < 0 ||
version_compare($update->version, GANTRY5_VERSION) <= 0) {
continue;
}
} else {
// Check if templates need to be updated.
$version = isset($styles[$update->element]) ?
$styles[$update->element]->get('details.version') : null;
if (version_compare($version, 0) < 0 ||
version_compare($update->version, $version) <= 0) {
continue;
}
}
$list[] = $update->name . ' ' .
$update->version;
}
return $list;
}
public function factory()
{
$args = func_get_args();
$method = ['JFactory', 'get'. ucfirst((string)
array_shift($args))];
return method_exists($method[0], $method[1]) ?
call_user_func_array($method, $args) : null;
}
public function instance()
{
$args = func_get_args();
$class = ucfirst((string) array_shift($args));
if (!$class) {
return null;
}
if (class_exists('J'. $class)) {
$class = 'J'. $class;
}
$method = [$class, 'getInstance'];
return method_exists($method[0], $method[1]) ?
call_user_func_array($method, $args) : null;
}
public function route()
{
return call_user_func_array(['JRoute', '_'],
func_get_args());
}
public function html()
{
$args = func_get_args();
if (isset($args[0]) && method_exists('JHtml',
$args[0])) {
return call_user_func_array(['JHtml',
array_shift($args)], $args);
}
return call_user_func_array(['JHtml', '_'],
$args);
}
public function article($keys)
{
return Content::getInstance($keys);
}
public function finder($domain, $options = null)
{
$options = (array) $options;
switch ($domain) {
case 'article':
case 'articles':
case 'content':
$finder = new ContentFinder($options);
return \JFactory::getApplication()->isSite() ?
$finder->authorised() : $finder;
case 'category':
case 'categories':
$finder = (new
CategoryFinder($options))->extension('content');
return \JFactory::getApplication()->isSite() ?
$finder->authorised() : $finder;
}
return null;
}
public function truncate($text, $length, $html = false)
{
return \JHtml::_('string.truncate', $text, $length, true,
$html);
}
public function authorize($action, $id = null)
{
$user = \JFactory::getUser();
switch ($action) {
case 'platform.settings.manage':
return $user->authorise('core.admin',
'com_templates') || $user->authorise('core.admin',
'com_gantry5');
case 'menu.manage':
return $user->authorise('core.manage',
'com_menus') &&
$user->authorise('core.edit', 'com_menus');
case 'menu.edit':
if ($id) {
$db = \JFactory::getDbo();
$userId = \JFactory::getUser()->id;
// Verify that no items are checked out.
$query = $db->getQuery(true)
->select('id')
->from('#__menu')
->where('menutype=' .
$db->quote($id))
->where('checked_out !=' . (int)
$userId)
->where('checked_out !=0');
$db->setQuery($query);
if ($db->loadRowList()) {
return false;
}
// Verify that no module for this menu are checked out.
$query->clear()
->select('id')
->from('#__modules')
->where('module=' .
$db->quote('mod_menu'))
->where('params LIKE ' .
$db->quote('%"menutype":' . json_encode($id) .
'%'))
->where('checked_out !=' . (int)
$userId)
->where('checked_out !=0');
$db->setQuery($query);
if ($db->loadRowList()) {
return false;
}
}
return $user->authorise('core.edit',
'com_menus');
case 'updates.manage':
return $user->authorise('core.manage',
'com_installer');
case 'outline.create':
return $user->authorise('core.create',
'com_templates');
case 'outline.delete':
return $user->authorise('core.delete',
'com_templates');
case 'outline.rename':
return $user->authorise('core.edit',
'com_templates');
case 'outline.assign':
return $user->authorise('core.edit.state',
'com_templates') &&
$user->authorise('core.edit', 'com_menu');
case 'outline.edit':
return true;
}
return true;
}
}
PK&d�[�8��&classes/Gantry/Framework/Positions.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework;
use Gantry\Component\Position\Positions as BasePositions;
class Positions extends BasePositions
{
}
PK&d�[�l�$��$classes/Gantry/Framework/Request.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework;
use Gantry\Component\Request\Request as BaseRequest;
class Request extends BaseRequest {}
PK&d�[#Q�ii;classes/Gantry/Framework/Services/ConfigServiceProvider.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Services;
use Gantry\Component\Config\CompiledBlueprints;
use Gantry\Component\Config\CompiledConfig;
use Gantry\Component\Config\ConfigFileFinder;
use Gantry\Framework\Atoms;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class ConfigServiceProvider implements ServiceProviderInterface
{
public function register(Container $gantry)
{
$gantry['blueprints'] = function($c) {
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer('blueprints', 'Loading
blueprints');
$blueprints = static::blueprints($c);
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer('blueprints');
return $blueprints;
};
$gantry['config'] = function($c) {
// Make sure configuration has been set.
if (!isset($c['configuration'])) {
throw new \LogicException('Gantry: Please set current
configuration before using $gantry["config"]', 500);
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer('config', 'Loading
configuration');
// Get the current configuration and lock the value from
modification.
$outline = $c->lock('configuration');
$config = static::load($c, $outline);
GANTRY_DEBUGGER &&
\Gantry\Debugger::setConfig($config)->stopTimer('config');
return $config;
};
}
public static function blueprints(Container $container)
{
/** @var UniformResourceLocator $locator */
$locator = $container['locator'];
$cache =
$locator->findResource('gantry-cache://theme/compiled/blueprints',
true, true);
$files = [];
$paths =
$locator->findResources('gantry-particles://');
$files += (new
ConfigFileFinder)->setBase('particles')->locateFiles($paths);
$paths =
$locator->findResources('gantry-blueprints://');
$files += (new ConfigFileFinder)->locateFiles($paths);
$config = new CompiledBlueprints($cache, $files, GANTRY5_ROOT);
return $config->load();
}
public static function load(Container $container, $name =
'default', $combine = true, $withDefaults = true)
{
/** @var UniformResourceLocator $locator */
$locator = $container['locator'];
$combine = $combine && $name !== 'default';
// Merge current configuration with the default.
$uris = $combine ? ["gantry-config://{$name}",
'gantry-config://default'] :
["gantry-config://{$name}"];
$paths = [];
foreach ($uris as $uri) {
$paths = array_merge($paths, $locator->findResources($uri));
}
// Locate all configuration files to be compiled.
$files = (new ConfigFileFinder)->locateFiles($paths);
$cache =
$locator->findResource('gantry-cache://theme/compiled/config',
true, true);
if (!$cache) {
throw new \RuntimeException('Who just removed Gantry 5
cache folder? Try reloading the page if it fixes the issue');
}
$compiled = new CompiledConfig($cache, $files, GANTRY5_ROOT);
$compiled->setBlueprints(function() use ($container) {
return $container['blueprints'];
});
$config = $compiled->load($withDefaults);
// Set atom inheritance.
$atoms = $config->get('page.head.atoms');
if (is_array($atoms)) {
$config->set('page.head.atoms', (new
Atoms($atoms))->init()->toArray());
}
return $config;
}
}
PK&d�[��d��:classes/Gantry/Framework/Services/ErrorServiceProvider.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Services;
use Gantry\Component\Whoops\SystemFacade;
use Gantry\Framework\Platform;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Whoops\Handler\JsonResponseHandler;
use Whoops\Handler\PrettyPageHandler;
use Whoops\Run;
use Whoops\Util\Misc;
class ErrorServiceProvider implements ServiceProviderInterface
{
protected $format;
public function __construct($format = 'html')
{
$this->format = $format;
}
public function register(Container $container)
{
/** @var UniformResourceLocator $locator */
$locator = $container['locator'];
/** @var Platform $platform */
$platform = $container['platform'];
// Setup Whoops-based error handler
$system = new SystemFacade($platform->errorHandlerPaths());
$errors = new Run($system);
$error_page = new PrettyPageHandler;
$error_page->setPageTitle('Crikey! There was an
error...');
$error_page->setEditor('sublime');
foreach
($locator->findResources('gantry-assets://css/whoops.css') as
$path) {
$error_page->addResourcePath(dirname($path));
}
$error_page->addCustomCss('whoops.css');
$errors->pushHandler($error_page);
$jsonRequest = $this->format === 'json' || ($_SERVER
&& isset($_SERVER['HTTP_ACCEPT']) &&
$_SERVER['HTTP_ACCEPT'] == 'application/json');
if (Misc::isAjaxRequest() || $jsonRequest) {
$json_handler = new JsonResponseHandler;
//$json_handler->setJsonApi(true);
$errors->pushHandler($json_handler);
}
$errors->register();
$container['errors'] = $errors;
if (GANTRY_DEBUGGER &&
method_exists('Gantry\Debugger', 'setErrorHandler')) {
\Gantry\Debugger::setErrorHandler();
}
}
}
PK&d�[�I>44<classes/Gantry/Framework/Services/StreamsServiceProvider.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Framework\Services;
use Gantry\Component\Filesystem\Streams;
use Pimple\Container;
use RocketTheme\Toolbox\DI\ServiceProviderInterface;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class StreamsServiceProvider implements ServiceProviderInterface
{
public function register(Container $gantry)
{
$sp = $this;
$gantry['locator'] = function() use ($sp) {
return new UniformResourceLocator(GANTRY5_ROOT);
};
$gantry['streams'] = function($c) use ($sp) {
$schemes = (array)
$c['platform']->init()->get('streams');
/** @var UniformResourceLocator $locator */
$locator = $c['locator'];
$streams = new Streams($locator);
$streams->add($schemes);
GANTRY_DEBUGGER &&
method_exists('Gantry\Debugger', 'setLocator')
&& \Gantry\Debugger::setLocator($locator);
return $streams;
};
}
}
PK&d�[�ɿ�mm!classes/Gantry/Framework/Site.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
class Site
{
public function __construct()
{
$document = \JFactory::getDocument();
if ($document instanceof \JDocumentHTML) {
$this->theme = $document->template;
$this->url = $document->baseurl;
$this->title = $document->title;
$this->description = $document->description;
}
}
}
PK&d�[7*3���"classes/Gantry/Framework/Theme.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Component\Theme\AbstractTheme;
use Gantry\Component\Theme\ThemeTrait;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class Theme
* @package Gantry\Framework
*/
class Theme extends AbstractTheme
{
use ThemeTrait;
/**
* @var bool
*/
protected $joomla = false;
/**
* If parameter is set to true, loads bootstrap. Returns true if
bootstrap has been loaded.
*
* @param bool|null $enable
* @return bool
*/
public function joomla($enable = null)
{
if ($enable && !$this->joomla) {
$this->joomla = true;
// Workaround for Joomla! not loading bootstrap when it needs
it.
$this->gantry()->load('bootstrap.2');
}
return $this->joomla;
}
/**
* @see AbstractTheme::extendTwig()
*
* @param \Twig_Environment $twig
* @param \Twig_LoaderInterface $loader
* @return \Twig_Environment
*/
public function extendTwig(\Twig_Environment $twig,
\Twig_LoaderInterface $loader = null)
{
parent::extendTwig($twig, $loader);
/** @var \Twig_Extension_Core $core */
$core = $twig->getExtension('Twig_Extension_Core');
// Get user timezone and if not set, use Joomla default.
$timezone = \JFactory::getUser()->getParam('timezone',
\JFactory::getConfig()->get('offset', 'UTC'));
$core->setTimezone(new \DateTimeZone($timezone));
// Set locale for dates and numbers.
$core->setDateFormat(\JText::_('DATE_FORMAT_LC2'),
\JText::_('GANTRY5_X_DAYS'));
$core->setNumberFormat(0,
\JText::_('DECIMALS_SEPARATOR'),
\JText::_('THOUSANDS_SEPARATOR'));
$filter = new \Twig_SimpleFilter('date', [$this,
'twig_dateFilter'], array('needs_environment' =>
true));
$twig->addFilter($filter);
return $twig;
}
/**
* Converts a date to the given format.
*
* <pre>
* {{ post.published_at|date("m/d/Y") }}
* </pre>
*
* @param \Twig_Environment $env
* @param \DateTime|\DateTimeInterface|\DateInterval|string $date A
date
* @param string|null $format
The target format, null to use the default
* @param \DateTimeZone|string|null|false $timezone
The target timezone, null to use the default, false to leave unchanged
*
* @return string The formatted date
*/
public function twig_dateFilter(\Twig_Environment $env, $date, $format
= null, $timezone = null)
{
if (null === $format) {
$formats =
$env->getExtension('Twig_Extension_Core')->getDateFormat();
$format = $date instanceof \DateInterval ? $formats[1] :
$formats[0];
}
if ($date instanceof \DateInterval) {
return $date->format($format);
}
if (!($date instanceof \JDate)) {
// Create localized JDate object.
$twig_date = \twig_date_converter($env, $date, $timezone);
$date = new \JDate($twig_date->getTimestamp());
$date->setTimezone($twig_date->getTimezone());
} elseif ($timezone) {
$date->setTimezone($timezone);
}
return $date->format($format, true);
}
/**
* @see AbstractTheme::getContext()
*
* @param array $context
* @return array
*/
public function getContext(array $context)
{
$gantry = static::gantry();
$context = parent::getContext($context);
$context['site'] = $gantry['site'];
$context['joomla'] = $gantry['platform'];
return $context;
}
/**
* @see AbstractTheme::init()
*/
protected function init()
{
parent::init();
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$lang = \JFactory::getLanguage();
// FIXME: Do not hardcode this file.
$lang->load('files_gantry5_nucleus', JPATH_SITE);
if (\JFactory::getApplication()->isSite()) {
// Load our custom positions file as frontend requires the
strings to be there.
$filename =
$locator("gantry-theme://language/en-GB/en-GB.tpl_{$this->name}_positions.ini");
if ($filename) {
$lang->load("tpl_{$this->name}_positions",
\dirname(\dirname(\dirname($filename))), 'en-GB');
}
// Load template language files, including overrides.
$paths =
$locator->findResources('gantry-theme://language');
foreach (array_reverse($paths) as $path) {
$lang->load("tpl_{$this->name}",
\dirname($path));
}
}
$doc = \JFactory::getDocument();
if ($doc instanceof \JDocumentHtml) {
$doc->setHtml5(true);
}
$this->language = $doc->language;
$this->direction = $doc->direction;
$this->url = \JUri::root(true) . '/templates/' .
$this->name;
\JPluginHelper::importPlugin('gantry5');
// Trigger the onGantryThemeInit event.
$dispatcher = \JEventDispatcher::getInstance();
$dispatcher->trigger('onGantry5ThemeInit',
['theme' => $this]);
}
/**
* Get list of twig paths.
*
* @return array
*/
public static function getTwigPaths()
{
/** @var UniformResourceLocator $locator */
$locator = static::gantry()['locator'];
return
$locator->mergeResources(['gantry-theme://twig',
'gantry-engine://twig']);
}
/**
* @see AbstractTheme::setTwigLoaderPaths()
*
* @param \Twig_LoaderInterface $loader
* @return \Twig_Loader_Filesystem
*/
protected function setTwigLoaderPaths(\Twig_LoaderInterface $loader)
{
$loader = parent::setTwigLoaderPaths($loader);
if ($loader) {
$loader->setPaths($this->getTwigPaths());
}
return $loader;
}
}
PK&d�["ݲc�E�E+classes/Gantry/Framework/ThemeInstaller.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Component\Layout\Layout;
use Gantry\Component\Theme\ThemeInstaller as AbstractInstaller;
use Gantry\Joomla\Manifest;
use RocketTheme\Toolbox\File\YamlFile;
class ThemeInstaller extends AbstractInstaller
{
protected $extension;
protected $manifest;
public function __construct($extension = null)
{
parent::__construct();
jimport('joomla.filesystem.folder');
\JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_templates/tables');
if ($extension instanceof \JInstallerAdapterTemplate) {
$this->setInstaller($extension);
} elseif ($extension) {
$this->loadExtension($extension);
}
}
public function setInstaller(\JInstallerAdapterTemplate $install)
{
// We need access to a protected variable $install->extension.
$reflectionClass = new \ReflectionClass($install);
$property =
$reflectionClass->getProperty('extension');
$property->setAccessible(true);
$this->extension = $property->getValue($install);
$this->name = $this->extension->name;
$this->manifest = new Manifest($this->extension->name,
$install->getManifest());
return $this;
}
public function loadExtension($id)
{
if ((string) intval($id) !== (string) $id) {
$id = ['type' => 'template',
'element' => (string) $id, 'client_id' => 0];
}
$this->extension = \JTable::getInstance('extension');
$this->extension->load($id);
$this->name = $this->extension->name;
}
public function getPath()
{
return JPATH_SITE . '/templates/' .
$this->extension->name;
}
public function getStyleName($title)
{
return \JText::sprintf($title,
\JText::_($this->extension->name));
}
public function getStyle($name = null)
{
if (is_numeric($name)) {
$field = 'id';
} else {
$field = 'title';
$name = $this->getStyleName($name);
}
$style = $this->createStyle();
$style->load([
'template' => $this->extension->element,
'client_id' => $this->extension->client_id,
$field => $name
]);
return $style;
}
public function getDefaultStyle()
{
$style = \JTable::getInstance('Style',
'TemplatesTable');
$style->load(['home' => 1, 'client_id'
=> 0]);
return $style;
}
/**
* @param string $type
* @return \JTableMenu
*/
public function getMenu($type)
{
/** @var \JTableMenuType $table */
$table = \JTable::getInstance('MenuType');
$table->load(['menutype' => $type]);
return $table;
}
public function createSampleData()
{
$this->updateStyle('JLIB_INSTALLER_DEFAULT_STYLE', [],
1);
$this->installMenus();
}
public function render($template, $context = [])
{
$token = \JSession::getFormToken();
$manifest = $this->getManifest();
$context += [
'description' => $this->translate((string)
$manifest->get('description')),
'version' => (string)
$manifest->get('version'),
'date' => (string)
$manifest->get('creationDate'),
'author' => [
'name' => (string)
$manifest->get('author'),
'email' => (string)
$manifest->get('authorEmail'),
'url' => (string)
$manifest->get('authorUrl')
],
'copyright' => (string)
$manifest->get('copyright'),
'license' => (string)
$manifest->get('license'),
'install_url' =>
\JRoute::_("index.php?option=com_gantry5&view=install&theme={$this->name}&{$token}=1",
false),
'edit_url' =>
\JRoute::_("index.php?option=com_gantry5&view=configurations/default/styles&theme={$this->name}&{$token}=1",
false),
];
return parent::render($template, $context);
}
public function createStyle()
{
$style = \JTable::getInstance('Style',
'TemplatesTable');
$style->reset();
$style->template = $this->extension->element;
$style->client_id = $this->extension->client_id;
return $style;
}
public function addStyle($title, array $configuration = [], $home = 0)
{
// Make sure language debug is turned off.
$lang = \JFactory::getLanguage();
$debug = $lang->setDebug(false);
// Translate title.
$title = $this->getStyleName($title);
// Turn language debug back on.
$lang->setDebug($debug);
$data = [
'home' => (int) $home,
'title' => $title,
'params' => json_encode($configuration),
];
$style = $this->createStyle();
$style->save($data);
if ($home) {
$this->actions[] = ['action' =>
'default_style_assigned', 'text' =>
\JText::sprintf('GANTRY5_INSTALLER_ACTION_DEFAULT_STYLE_ASSIGNED',
$title)];
}
return $style;
}
public function updateStyle($name, array $configuration, $home = null)
{
$style = $this->getStyle($name);
if ($style->id) {
$home = ($home !== null ? $home : $style->home);
$params = (array) json_decode($style->params, true);
$data = [
'params' => json_encode($configuration +
$params),
'home' => $home
];
if ($home && !$style->home) {
$this->actions[] = ['action' =>
'default_style_assigned', 'text' =>
\JText::sprintf('GANTRY5_INSTALLER_ACTION_DEFAULT_STYLE_ASSIGNED',
$style->title)];
}
$style->save($data);
}
return $style;
}
public function assignHomeStyle($style)
{
// Update the mapping for menu items that this style IS assigned
to.
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->update('#__menu')
->set('template_style_id=' . (int) $style->id)
->where('home=1')
->where('client_id=0');
$db->setQuery($query);
$db->execute();
if ($db->getAffectedRows()) {
$this->actions[] = ['action' =>
'home_style_assigned', 'text' =>
\JText::sprintf('GANTRY5_INSTALLER_ACTION_HOME_STYLE_ASSIGNED',
$style->title)];
}
}
/**
* @param string $folder
* @param array $params
* @return string|bool
*/
public function createOutline($folder, array $params = [])
{
if (!$folder) {
throw new \RuntimeException('Cannot create outline without
folder name');
}
$this->initialize();
$created = false;
$params += [
'preset' => null,
'title' => null
];
$title = $params['title'] ?: ucwords(trim(strtr($folder,
['_' => ' '])));
$preset = $params['preset'] ?: 'default';
if ($folder[0] !== '_') {
$title = $this->getStyleName($title !== 'Default'
? "%s - {$title}" : 'JLIB_INSTALLER_DEFAULT_STYLE');
$style = $this->getStyle($title);
if (!$style->id) {
// Only add style if it doesn't exist.
$style = $this->addStyle($title, ['preset'
=> $preset]);
$created = true;
}
$id = $style->id;
} else {
$id = $folder;
}
$target = $folder !== 'default' ? $id : $folder;
// Copy configuration for the new layout.
if (($this->copyCustom($folder, $target) || $created) &&
isset($style)) {
// Update layout and save it.
$layout = Layout::load($target, $preset);
$layout->save()->saveIndex();
if ($id !== $target) {
// Default outline: Inherit everything from the base.
$layout->inheritAll()->name = $id;
$layout->save()->saveIndex();
$this->actions[] = ['action' =>
'base_outline_created', 'text' =>
$this->translate('GANTRY5_INSTALLER_ACTION_BASE_OUTLINE_CREATED',
$title)];
}
if ($created) {
$this->actions[] = ['action' =>
'outline_created', 'text' =>
$this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_CREATED',
$title)];
} else {
$this->actions[] = ['action' =>
'outline_updated', 'text' =>
$this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_UPDATED',
$title)];
}
// Update preset in Joomla table.
$this->updateStyle($title, ['preset' =>
$layout['preset']['name']]);
}
return $id;
}
/**
* @param array $item [menutype, title, alias, link,
template_style_id, params]
* @param int $parent_id Parent menu id.
* @param bool $load True if updating existing items.
* @return int
* @throws \Exception
*/
public function addMenuItem(array $item, $parent_id = 1, $load = false)
{
$component_id = $this->getComponent();
$table = \JTable::getInstance('menu');
$date = new \JDate();
$update = false;
// Defaults for the item.
$item += [
'menutype' => 'mainmenu',
'title' => 'Home',
'alias' => 'gantry5',
'note' => '',
'link' =>
'index.php?option=com_gantry5&view=custom',
'type' => 'component',
'published' => 1,
'parent_id' => $parent_id,
'component_id' => $component_id,
'checked_out' => 0,
'checked_out_time' => $date->toSql(),
'browserNav' => 0,
'access' => 1,
'img' => '',
'template_style_id' => 0,
'params' => '{}',
'home' => 0,
'language' => '*',
'client_id' => 0
];
if (in_array($item['type'], ['separator',
'heading'])) {
$item['link'] = '';
}
if ($item['type'] !== 'component') {
$item['component_id'] = 0;
}
if ($load) {
$update = $table->load([
'menutype' => $item['menutype'],
'alias' => $item['alias'],
'parent_id' => $item['parent_id']
]);
}
$table->setLocation($parent_id, 'last-child');
if (!$table->bind($item) || !$table->check() ||
!$table->store()) {
throw new \Exception($table->getError());
}
/** @var \JCache|\JCacheController $cache */
$cache = \JFactory::getCache();
$cache->clean('mod_menu');
$menu = \JTable::getInstance('menuType');
$menu->load(['menutype' =>
$item['menutype']]);
if
(!isset($this->actions["menu_{$item['menutype']}_created"]))
{
$postfix = $item['home'] ? '_HOME' :
'';
if ($update) {
$this->actions[] = ['action' =>
'menu_item_updated', 'text' =>
\JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_ITEM_UPDATED' .
$postfix, $table->title, $table->path, $menu->title)];
} else {
$this->actions[] = ['action' =>
'menu_item_created', 'text' =>
\JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_ITEM_CREATED' .
$postfix, $table->title, $table->path, $menu->title)];
}
} elseif ($item['home']) {
$this->actions[] = ['action' =>
'menu_item_updated', 'text' =>
\JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_ITEM_HOME',
$table->title, $table->path, $menu->title)];
}
return $table->id;
}
public function installMenus(array $menus = null, $parent = 1)
{
if ($menus === null) {
$path = $this->getPath();
$file = YamlFile::instance($path .
'/install/menus.yaml');
$menus = (array) $file->content();
$file->free();
}
foreach ($menus as $menutype => $menu) {
$title = !empty($menu['title']) ?
$menu['title'] : ucfirst($menutype);
$description = !empty($menu['description']) ?
$menu['description'] : '';
$exists = $this->getMenu($menutype)->id;
// If $parent = 0, do dry run.
if ((int) $parent && !$exists) {
$this->deleteMenu($menutype, true);
$this->createMenu($menutype, $title, $description);
}
if (!empty($menu['items'])) {
$this->addMenuItems($menutype, $menu['items'],
(int) $parent);
}
}
}
/**
* @param string $type
* @param string $title
* @param string $description
* @throws \Exception
*/
public function createMenu($type, $title, $description)
{
/** @var \JTableMenuType $table */
$table = \JTable::getInstance('MenuType');
$data = array(
'menutype' => $type,
'title' => $title,
'description' => $description
);
if (!$table->bind($data) || !$table->check()) {
// Menu already exists, do nothing
return;
}
if (!$table->store()) {
throw new \Exception($table->getError());
}
$this->actions["menu_{$type}_created"] =
['action' => 'menu_created', 'text' =>
\JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_CREATED',
$title)];
}
/**
* @param string $type
* @param bool $force
*/
public function deleteMenu($type, $force = false)
{
if ($force) {
$this->unsetHome($type);
}
$table = \JTable::getInstance('MenuType');
$table->load(array('menutype' => $type));
if ($table->id) {
$success = $table->delete();
if (!$success) {
\JFactory::getApplication()->enqueueMessage($table->getError(),
'error');
} else {
$this->actions["menu_{$type}_deleted"] =
['action' => 'menu_delete', 'text' =>
\JText::_('GANTRY5_INSTALLER_ACTION_MENU_DELETED',
$table->title)];
}
}
/** @var \JCache|\JCacheController $cache */
$cache = \JFactory::getCache();
$cache->clean('mod_menu');
}
public function unsetHome($type)
{
// Update the mapping for menu items that this style IS assigned
to.
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->update('#__menu')
->set('home=0')
->where('menutype=' . $db->quote($type))
->where('client_id=0');
$db->setQuery($query);
$db->execute();
}
/**
* @deprecated 5.3.2
*/
public function cleanup()
{
$this->initialize();
$this->finalize();
}
public function finalize()
{
parent::finalize();
$gantry = Gantry::instance();
/** @var Outlines $outlines */
$outlines = $gantry['outlines'];
$name = $this->extension->name;
// Update positions in manifest file.
$positions = $outlines->positions();
$manifest = new Manifest($name);
$manifest->setPositions(array_keys($positions));
$manifest->save();
}
protected function addMenuItems($menutype, array $items, $parent)
{
foreach ($items as $alias => $item) {
$item = (array) $item;
$item += [
'menutype' => $menutype,
'title' => ucfirst($alias),
'alias' => $alias
];
$outline = isset($item['outline']) ?
$item['outline'] : (isset($item['layout']) ?
$item['layout'] : null);
$params = $this->getOutline($outline);
if (!is_array($params)) {
$params = [
'preset' =>
isset($item['preset']) ? $item['preset'] :
(isset($item['layout']) ? $item['layout'] : null),
'title' => isset($item['style'])
? $item['style'] : null
];
}
$id = $outline ? $this->createOutline($outline, $params) :
0;
$item['template_style_id'] = (string)(int) $id ===
(string) $id ? $id : 0;
// If $parent = 0, do dry run.
$itemId = $parent ? $this->addMenuItem($item, $parent, true)
: 0;
if (!empty($item['items'])) {
$this->addMenuItems($menutype, $item['items'],
$itemId);
}
}
}
protected function getInstallerScript()
{
if (!$this->script) {
$className = $this->extension->name .
'InstallerScript';
if (!class_exists($className)) {
$manifest = new Manifest($this->extension->name);
$file = $manifest->getScriptFile();
$path = "{$this->getPath()}/{$file}";
if ($file && is_file($path)) {
require_once $path;
}
}
if (class_exists($className)) {
$this->script = new $className;
}
}
return $this->script;
}
protected function getManifest()
{
if (!$this->manifest) {
$this->manifest = new
Manifest($this->extension->name);
}
return $this->manifest;
}
protected function getComponent()
{
static $component_id;
if (!$component_id) {
// Get Gantry component id.
$component_id =
\JComponentHelper::getComponent('com_gantry5')->id;
}
return $component_id;
}
}
PK&d�[��g\\'classes/Gantry/Framework/Translator.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Framework;
use Gantry\Component\Translator\Translator as BaseTranslator;
class Translator extends BaseTranslator
{
public function translate($string)
{
if (\func_num_args() === 1) {
return \JText::_($string);
}
$args = \func_get_args();
return \call_user_func_array(['JText',
'sprintf'], $args);
}
}
PK&d�[J�s335classes/Gantry/Joomla/Assignments/AssignmentsMenu.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Assignments;
use Gantry\Component\Assignments\AssignmentsInterface;
class AssignmentsMenu implements AssignmentsInterface
{
public $type = 'menu';
public $priority = 1;
/**
* Returns list of rules which apply to the current page.
*
* @return array
*/
public function getRules()
{
$rules = [];
$app = \JFactory::getApplication();
if ($app->isSite()) {
$active = $app->getMenu()->getActive();
if ($active) {
$menutype = $active->menutype;
$id = $active->id;
$rules = [$menutype => [$id => $this->priority]];
}
}
return $rules;
}
/**
* List all the rules available.
*
* @param string $configuration
* @return array
*/
public function listRules($configuration)
{
require_once JPATH_ADMINISTRATOR .
'/components/com_menus/helpers/menus.php';
$data = \MenusHelper::getMenuLinks();
$userid = \JFactory::getUser()->id;
$list = [];
foreach ($data as $menu) {
$items = [];
foreach ($menu->links as $link) {
$items[] = [
'name' => $link->value,
'field' => ['id',
'link' . $link->value],
'value' => $link->template_style_id ==
$configuration,
'disabled' => $link->type !=
'component' || $link->checked_out &&
$link->checked_out != $userid,
'label' => str_repeat('—',
max(0, $link->level-1)) . ' ' . $link->text
];
}
$group = [
'label' => $menu->title ?:
$menu->menutype,
'items' => $items
];
$list[$menu->menutype] = $group;
}
return $list;
}
}
PK&d�[=�|���6classes/Gantry/Joomla/Assignments/AssignmentsStyle.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Assignments;
use Gantry\Component\Assignments\AssignmentsInterface;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class AssignmentsStyle implements AssignmentsInterface
{
public $type = 'style';
public $priority = 2;
/**
* Returns list of rules which apply to the current page.
*
* @return array
*/
public function getRules()
{
static $rules;
if (!isset($rules)) {
$rules = [];
$template = \JFactory::getApplication()->getTemplate(true);
$theme = $template->template;
$outline =
$template->params->get('configuration',
!empty($template->id) ? $template->id :
$template->params->get('preset', null));
if (JDEBUG) {
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage('Template Style:',
'debug') && \Gantry\Debugger::addMessage($template,
'debug');
if (!$outline) {
\JFactory::getApplication()->enqueueMessage('JApplicationSite::getTemplate()
was overridden with no specified Gantry 5 outline.',
'debug');
}
}
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
if ($outline &&
is_dir($locator("gantry-themes://{$theme}/custom/config/{$outline}")))
{
$rules = ['id' => [$outline =>
$this->priority]];
}
}
return $rules;
}
/**
* List all the rules available.
*
* @param string $configuration
* @return array
*/
public function listRules($configuration)
{
return [];
}
}
PK&d�[��%classes/Gantry/Joomla/CacheHelper.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla;
class CacheHelper
{
public static function cleanTemplates()
{
self::cleanByType('com_templates');
self::cleanByType('_system');
}
public static function cleanMenu()
{
self::cleanByType('mod_menu');
self::cleanByType('_system');
}
public static function cleanPlugin()
{
self::cleanByType('_system', 0);
self::cleanByType('_system', 1);
self::cleanByType('com_plugins', 0);
self::cleanByType('com_plugins', 1);
}
private static function cleanByType($group = null, $client_id = 0,
$event = 'onContentCleanCache')
{
$conf = \JFactory::getConfig();
$dispatcher = \JEventDispatcher::getInstance();
$options = array(
'defaultgroup' => $group,
'cachebase' => ($client_id) ? JPATH_ADMINISTRATOR
. '/cache' : $conf->get('cache_path', JPATH_SITE .
'/cache'),
'result' => true
);
try {
$cache = \JCache::getInstance('callback', $options);
$cache->clean();
} catch (\Exception $e) { // TODO: Joomla 3.7 uses JCacheException
$options['result'] = false;
}
// Trigger the onContentCleanCache event.
$dispatcher->trigger($event, $options);
}
}
PK&d�[*����+classes/Gantry/Joomla/Category/Category.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Category;
use Gantry\Framework\Gantry;
use Gantry\Joomla\Object\AbstractObject;
class Category extends AbstractObject
{
static protected $instances = [];
static protected $table = 'Category';
static protected $order = 'lft';
public function initialize()
{
if (!parent::initialize()) {
return false;
}
$this->params = json_decode($this->params);
$this->metadata = json_decode($this->metadata);
return true;
}
public function parent()
{
if ($this->alias != $this->path)
{
$parent = Category::getInstance($this->parent_id);
}
return isset($parent) && $parent->extension ==
$this->extension ? $parent : null;
}
public function parents()
{
$parent = $this->parent();
return $parent ? array_merge($parent->parents(), [$parent]) :
[];
}
public function route()
{
require_once JPATH_SITE .
'/components/com_content/helpers/route.php';
return
\JRoute::_(\ContentHelperRoute::getCategoryRoute($this->id .
':' . $this->alias), false);
}
public function render($file)
{
return Gantry::instance()['theme']->render($file,
['category' => $this]);
}
public function compile($string)
{
return Gantry::instance()['theme']->compile($string,
['category' => $this]);
}
public function toArray()
{
return $this->getProperties(true);
}
}
PK&d�[&��w;;1classes/Gantry/Joomla/Category/CategoryFinder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Category;
use Gantry\Joomla\Object\Finder;
class CategoryFinder extends Finder
{
protected $table = '#__categories';
protected $extension = 'com_content';
protected $readonly = true;
/**
* Makes all created objects as readonly.
*
* @return $this
*/
public function readonly($readonly = true)
{
$this->readonly = (bool)$readonly;
return $this;
}
public function find($object = true)
{
$ids = parent::find();
if (!$object) {
return $ids;
}
return Category::getInstances($ids, $this->readonly);
}
public function id($ids, $levels = 0)
{
if ($ids && $levels) {
$ids = (array) $ids;
$db = $this->db;
array_walk($ids, function (&$item) use ($db) { $item =
$db->quote($item); });
$idList = implode(',', $ids);
// Create a subquery for the subcategory list
$subQuery = $this->db->getQuery(true)
->select('sub.id')
->from('#__categories AS sub')
->join('INNER', '#__categories AS this ON
sub.lft > this.lft AND sub.rgt < this.rgt')
->where("this.id IN ({$idList})");
if (is_numeric($levels)) {
$subQuery->where('sub.level <= this.level +
' . (int) $levels);
}
// Add the subquery to the main query
$this->query->where("(a.id IN ({$idList}) OR a.id IN
({$subQuery->__toString()}))");
} else {
$this->where('a.id', 'IN', $ids);
}
return $this;
}
public function language($language = true)
{
if (!$language) {
return $this;
}
if ($language === true || is_numeric($language)) {
$language = \JFactory::getLanguage()->getTag();
}
return $this->where('a.language', 'IN',
[$language, '*']);
}
public function published($published = 1)
{
if (!is_array($published)) {
$published = (array) intval($published);
}
return $this->where('a.published', 'IN',
$published);
}
public function authorised($authorised = true)
{
if (!$authorised) {
return $this;
}
// Ignore unpublished categories.
$unpublished = $this->getUnpublished($this->extension);
if ($unpublished) {
$this->where('a.id', 'NOT IN',
$unpublished);
}
// Check authorization.
$user = \JFactory::getUser();
$groups = $user->getAuthorisedViewLevels();
return $this->where('a.access', 'IN',
$groups);
}
public function extension($extension)
{
$this->extension = static::getExtension($extension);
return $this->where('a.extension', '=',
$this->extension);
}
public static function getExtension($extension)
{
static $map = [
'article' => 'com_content',
'articles' => 'com_content',
'content' => 'com_content',
];
if (isset($map[$extension])) {
$extension = $map[$extension];
}
return $extension;
}
public static function getUnpublished($extension)
{
static $list;
if ($list === null) {
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->select('cat.id AS id')
->from('#__categories AS cat')
->join('LEFT', '#__categories AS parent
ON cat.lft BETWEEN parent.lft AND parent.rgt')
->where('parent.extension = ' .
$db->quote(static::getExtension($extension)))
->where('parent.published != 1 AND cat.published
< 1')
->group('cat.id');
$db->setQuery($query);
$list = $db->loadColumn();
}
return $list;
}
}
PK&d�[��-��)classes/Gantry/Joomla/Content/Content.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Content;
use Gantry\Framework\Gantry;
use Gantry\Joomla\Category\Category;
use Gantry\Joomla\Object\AbstractObject;
class Content extends AbstractObject
{
static protected $instances = [];
static protected $table = 'Content';
static protected $order = 'id';
public function initialize()
{
if (!parent::initialize()) {
return false;
}
$this->images = json_decode($this->images);
$this->urls = json_decode($this->urls);
$this->attribs = json_decode($this->attribs);
$this->metadata = json_decode($this->metadata);
$nullDate = \JFactory::getDbo()->getNullDate();
if ($this->modified === $nullDate) {
$this->modified = $this->created;
}
if ($this->publish_up === $nullDate) {
$this->publish_up = $this->created;
}
return true;
}
public function author()
{
return \JUser::getInstance($this->created_by);
}
public function category()
{
return Category::getInstance($this->catid);
}
public function categories()
{
$category = $this->category();
return array_merge($category->parents(), [$category]);
}
public function text()
{
return $this->introtext . ' ' . $this->fulltext;
}
public function preparedText()
{
return \JHtml::_('content.prepare', $this->text());
}
public function preparedIntroText()
{
return \JHtml::_('content.prepare', $this->introtext);
}
public function readmore()
{
return (bool)strlen($this->fulltext);
}
public function route()
{
require_once JPATH_SITE .
'/components/com_content/helpers/route.php';
$category = $this->category();
return \JRoute::_(\ContentHelperRoute::getArticleRoute($this->id
. ':' . $this->alias, $category->id . ':' .
$category->alias), false);
}
public function edit()
{
$user = \JFactory::getUser();
$asset = "com_content.article.{$this->id}";
if ($user->authorise('core.edit', $asset) ||
$user->authorise('core.edit.own', $asset)) {
return
"index.php?option=com_content&task=article.edit&a_id={$this->id}&tmpl=component";
}
return false;
}
public function render($file)
{
return Gantry::instance()['theme']->render($file,
['article' => $this]);
}
public function compile($string)
{
return Gantry::instance()['theme']->compile($string,
['article' => $this]);
}
public function toArray()
{
return $this->getProperties(true) + [
'category' => [
'alias' => $this->category()->alias,
'title' => $this->category()->title
],
'author' => [
'username' => $this->author()->username,
'fullname' => $this->author()->name
],
];
}
}
PK&d�[=3���/classes/Gantry/Joomla/Content/ContentFinder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Content;
use Gantry\Joomla\Category\Category;
use Gantry\Joomla\Category\CategoryFinder;
use Gantry\Joomla\Object\Collection;
use Gantry\Joomla\Object\Finder;
class ContentFinder extends Finder
{
protected $table = '#__content';
protected $readonly = true;
protected $state = [];
/**
* Makes all created objects as readonly.
*
* @return $this
*/
public function readonly($readonly = true)
{
$this->readonly = (bool)$readonly;
return $this;
}
public function find($object = true)
{
$ids = parent::find();
if (!$object) {
return $ids;
}
return Content::getInstances($ids, $this->readonly);
}
public function id($ids, $include = true)
{
return $this->addToGroup('a.id', $ids, $include);
}
public function author($ids, $include = true)
{
return $this->addToGroup('a.created_by', $ids,
$include);
}
public function category($ids, $include = true)
{
if ($ids instanceof Collection) {
$ids = $ids->toArray();
} else {
$ids = (array)$ids;
}
array_walk($ids, function (&$item) { $item = $item instanceof
Category ? $item->id : (int) $item; });
return $this->addToGroup('a.catid', $ids, $include);
}
public function featured($featured = true)
{
$featured = intval((bool)$featured);
$this->where('a.featured', '=', $featured);
return $this;
}
public function language($language = true)
{
if (!$language) {
return $this;
}
if ($language === true || is_numeric($language)) {
$language = \JFactory::getLanguage()->getTag();
}
return $this->where('a.language', 'IN',
[$language, '*']);
}
public function published($published = 1)
{
if (!is_array($published)) {
$published = (array) intval($published);
}
return $this->where('a.state', 'IN',
$published);
}
public function authorised($authorised = true)
{
if (!$authorised) {
return $this;
}
$unpublished = CategoryFinder::getUnpublished('content');
if ($unpublished) {
$this->where('a.catid', 'NOT IN',
$unpublished);
}
$user = \JFactory::getUser();
// Define null and now dates
$nullDate = $this->db->quote($this->db->getNullDate());
$nowDate =
$this->db->quote(\JFactory::getDate()->toSql());
// Filter by start and end dates.
if (!$user->authorise('core.edit.state',
'com_content') &&
!$user->authorise('core.edit', 'com_content')) {
$this->query
->where("(a.publish_up = {$nullDate} OR
a.publish_up <= {$nowDate})")
->where("(a.publish_down = {$nullDate} OR
a.publish_down >= {$nowDate})")
->where("a.state >= 1")
;
}
$groups = $user->getAuthorisedViewLevels();
$this->query->join('INNER', '#__categories AS
c ON c.id = a.catid');
return $this->where('a.access', 'IN',
$groups)->where('c.access', 'IN', $groups);
}
protected function addToGroup($key, $ids, $include = true)
{
$op = $include ? 'IN' : 'NOT IN';
if (isset($this->state[$key][$op])) {
$this->state[$key][$op] =
array_merge($this->state[$key][$op], $ids);
} else {
$this->state[$key][$op] = $ids;
}
return $this;
}
protected function prepare()
{
foreach ($this->state as $key => $list) {
foreach ($list as $op => $group) {
$this->where($key, $op, array_unique($group));
}
}
}
}
PK&d�[�v!��"classes/Gantry/Joomla/Manifest.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla;
/**
* Joomla manifest file modifier.
*/
class Manifest
{
protected $theme;
protected $path;
protected $xml;
/**
* @param string $theme
* @param \SimpleXMLElement $manifest
* @throws \RuntimeException
*/
public function __construct($theme, \SimpleXMLElement $manifest = null)
{
$this->theme = $theme;
$this->path = JPATH_SITE .
"/templates/{$theme}/templateDetails.xml";
if (!is_file($this->path)) {
throw new \RuntimeException(sprintf('Template %s does not
exist.', $theme));
}
$this->xml = $manifest ?: simplexml_load_file($this->path);
}
/**
* @param string $variable
* @return string
*/
public function get($variable)
{
return (string) $this->xml->{$variable};
}
/**
* @return \SimpleXMLElement
*/
public function getXml()
{
return $this->xml;
}
public function getScriptFile()
{
return (string) $this->xml->scriptfile;
}
public function setPositions(array $positions)
{
sort($positions);
// Get the positions.
$target =
current($this->xml->xpath('//positions'));
$xml = "<positions>\n <position>" .
implode("</position>\n <position>",
$positions) . "</position>\n </positions>";
$insert = new \SimpleXMLElement($xml);
// Replace all positions.
$targetDom = dom_import_simplexml($target);
$insertDom =
$targetDom->ownerDocument->importNode(dom_import_simplexml($insert),
true);
$targetDom->parentNode->replaceChild($insertDom, $targetDom);
}
public function save()
{
// Do not save manifest if template has been symbolically linked.
if (is_link(dirname($this->path))) {
return;
}
if (!$this->xml->asXML($this->path)) {
throw new \RuntimeException(sprintf('Saving manifest for
%s template failed', $this->theme));
}
}
}
PK&d�[�]k���'classes/Gantry/Joomla/Module/Module.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Module;
use Gantry\Framework\Gantry;
use Gantry\Joomla\Object\AbstractObject;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
\JTable::addIncludePath(JPATH_LIBRARIES . '/legacy/table/');
class Module extends AbstractObject implements ExportInterface
{
use Export;
static protected $instances = [];
static protected $table = 'Module';
static protected $order = 'id';
protected $_assignments;
public function assignments($assignments = null)
{
if (is_array($assignments)) {
$this->_assignments = array_map('intval',
array_values($assignments));
} elseif (!isset($this->_assignments)) {
$db = \JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('menuid')->from('#__modules_menu')->where('moduleid
= ' . $this->id);
$db->setQuery($query);
$this->_assignments = array_map('intval', (array)
$db->loadColumn());
}
return $this->_assignments;
}
public function initialize()
{
if (!parent::initialize()) {
return false;
}
$this->params = json_decode($this->params);
return true;
}
public function toArray()
{
$particle = $this->module === 'mod_gantry5_particle';
// Convert params to array.
$params = json_decode(json_encode($this->params), true);
$array = [
'id' => $this->id,
'position' => $this->position,
'ordering' => (int) $this->ordering,
'type' => $particle ? 'particle' :
'joomla',
'title' => $this->title,
'chrome' => [
'display_title' => (bool) $this->showtitle,
'class' =>
!empty($params['moduleclass_sfx']) ?
$params['moduleclass_sfx'] : ''
],
'options' => null,
'assignments' => $this->assignments()
];
$options = array_filter(
[
'type' => !$particle ? $this->module :
null,
'note' => $this->note ?: null,
'published' => (bool) $this->published,
'content' => $this->content ?: null,
'params' => &$params,
'language' => $this->language !==
'*' ? $this->language : null,
],
[$this, 'is_not_null']
);
if ($particle) {
$array['joomla'] = $options;
$options = !empty($params['particle']) ?
json_decode($params['particle'], true) : [];
$options['type'] =
isset($options['particle']) ? $options['particle'] :
null;
$options['attributes'] =
isset($options['options']['particle']) ?
$options['options']['particle'] : [];
unset($options['particle'],
$options['options']);
$array['options'] = $options;
unset($params['particle']);
} else {
$array['options'] = $options;
}
return array_filter($array, [$this, 'is_not_null']);
}
public function create(array $array)
{
$type = $array['type'];
if ($type === 'particle') {
$particle = isset($array['options']) ?
$array['options'] : [];
$array['options'] = isset($array['joomla'])
? $array['joomla'] : [];
$array['options']['type'] =
'mod_gantry5_particle';
$array['options']['params']['particle'] =
$particle;
} elseif ($type !== 'joomla') {
return null;
}
$options = $array['options'];
$properties = [
'title' => $array['title'],
'note' => isset($options['note']) ?
$options['note'] : '',
'content' => isset($options['content'])
? $options['content'] : '',
'position' => $array['position'],
'ordering' => (int) $array['ordering'],
'published' => (int)
!empty($options['published']),
'module' => $options['type'],
'showtitle' => (int)
!empty($array['chrome']['display_title']),
'params' => isset($options['params']) ?
json_decode(json_encode($options['params'])) : [],
'language' =>
isset($options['language']) ? $options['language'] :
'*',
'_assignments' =>
isset($array['assignments']) ? $array['assignments'] :
[],
];
$object = new static();
$object->bind($properties);
return $object;
}
public function render($file)
{
return Gantry::instance()['theme']->render($file,
['particle' => $this]);
}
public function compile($string)
{
return Gantry::instance()['theme']->compile($string,
['particle' => $this]);
}
// Internal functions
/**
* @param $val
* @return bool
* @internal
*/
public function is_not_null($val)
{
return !is_null($val);
}
static protected function collection($items)
{
return new ModuleCollection($items);
}
}
PK&d�[�Y����1classes/Gantry/Joomla/Module/ModuleCollection.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Module;
use Gantry\Joomla\Object\Collection;
class ModuleCollection extends Collection
{
public function toArray()
{
return $this->__call('toArray', []);
}
public function export()
{
$assignments = $this->assignments();
$paths =
$this->getAssignmentPath($this->values($assignments));
$items = $this->toArray();
$positions = [];
// Convert assignments to our format.
foreach ($items as $item) {
$position = $item['position'];
$name = $item['options']['type'] .
'-' . $item['id'];
if ($position === '') {
continue;
}
if (empty($item['assignments'])) {
$item['assignments'] = [];
} elseif (in_array(0, $item['assignments'])) {
$item['assignments'] = ['page' =>
true];
} else {
$list = [];
foreach ($item['assignments'] as $assignment) {
$key = abs($assignment);
if (isset($paths[$key])) {
$list[$paths[$key]] = $assignment > 0 ? 1 : -1;
}
}
$item['assignments'] = ['page' =>
[$list]];
}
unset($item['position'], $item['id'],
$item['ordering']);
$positions[$position][$name] = $item;
}
return $positions;
}
public function assignments()
{
$this->loadAssignments();
return $this->__call('assignments', []);
}
public function loadAssignments()
{
$ids = $this->defined('assignments', false);
$ids = array_filter($ids);
if (!$ids) {
return;
}
$idlist = implode(',', array_keys($ids));
$db = \JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('moduleid,
menuid')->from('#__modules_menu')->where("moduleid
IN ($idlist)");
$db->setQuery($query);
$assignments = $db->loadRowList();
$list = [];
foreach ($assignments as $value) {
$list[$value[0]][] = (int) $value[1];
}
foreach ($this as $module) {
$module->assignments(isset($list[$module->id]) ?
$list[$module->id] : []);
}
}
protected function getAssignmentPath(array $ids)
{
if (!$ids) {
return [];
}
$idlist = implode(',', array_map('intval',
$ids));
$db = \JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('id,
path')->from('#__menu')->where("id IN
($idlist)");
$db->setQuery($query);
$paths = $db->loadRowList();
$list = [];
foreach ($paths as $value) {
$list[$value[0]] = $value[1];
}
return $list;
}
protected function values($values)
{
$list = [];
foreach ($values as $array) {
$list = array_merge($list, (array) $array);
}
return array_unique($list);
}
}
PK&d�[�.�H
H
-classes/Gantry/Joomla/Module/ModuleFinder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Module;
use Gantry\Joomla\Object\Finder;
class ModuleFinder extends Finder
{
protected $table = '#__modules';
protected $readonly = true;
protected $state = [];
protected $published = [0, 1];
protected $limit = 0;
/**
* Makes all created objects as readonly.
*
* @return $this
*/
public function readonly($readonly = true)
{
$this->readonly = (bool)$readonly;
return $this;
}
public function find($object = true)
{
$ids = parent::find();
if (!$object) {
return $ids;
}
return Module::getInstances($ids, $this->readonly);
}
public function id($ids, $include = true)
{
return $this->addToGroup('a.id', $ids, $include);
}
public function language($language = true)
{
if (!$language) {
return $this;
}
if ($language === true || is_numeric($language)) {
$language = \JFactory::getLanguage()->getTag();
}
return $this->where('a.language', 'IN',
[$language, '*']);
}
public function published($published = 1)
{
if (!is_array($published)) {
$published = (array) intval($published);
}
$this->published = $published;
return $this;
}
public function particle()
{
return $this->where('a.module', '=',
'mod_gantry5_particle');
}
public function authorised($authorised = true)
{
if (!$authorised) {
return $this;
}
$groups = \JFactory::getUser()->getAuthorisedViewLevels();
return $this->where('a.access', 'IN',
$groups);
}
protected function addToGroup($key, $ids, $include = true)
{
$op = $include ? 'IN' : 'NOT IN';
if (isset($this->state[$key][$op])) {
$this->state[$key][$op] =
array_merge($this->state[$key][$op], $ids);
} else {
$this->state[$key][$op] = $ids;
}
return $this;
}
protected function prepare()
{
$this->where('client_id', '=',
0)->where('published', 'IN',
$this->published)->order('position')->order('ordering');
foreach ($this->state as $key => $list) {
foreach ($list as $op => $group) {
$this->where($key, $op, array_unique($group));
}
}
}
}
PK&d�[嶱�2�2/classes/Gantry/Joomla/Object/AbstractObject.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Object;
/**
* Abstract base class for database objects.
*
*
*/
abstract class AbstractObject extends \JObject
{
/**
* If you don't have global instance ids, override this in
extending class.
* @var array
*/
static protected $instances = [];
/**
* Override table class in your own class.
* @var string
*/
static protected $table;
/**
* JTable class prefix, override if needed.
* @var string
*/
static protected $tablePrefix = 'JTable';
/**
* Override table in your own class.
* @var string
*/
static protected $order;
/**
* @var int
*/
public $id;
/**
* Is object stored into database?
* @var boolean
*/
protected $_exists = false;
/**
* Readonly object.
* @var bool
*/
protected $_readonly = false;
/**
* @var bool
*/
protected $_initialized = false;
/**
* Class constructor, overridden in descendant classes.
*
* @param int $identifier Identifier.
*/
public function __construct($identifier = null)
{
parent::__construct();
if ($identifier) {
$this->load($identifier);
}
}
/**
* Override this function if you need to initialize object right after
creating it.
*
* Can be used for example if the database fields need to be converted
to array or JRegistry.
*
* @return bool True if initialization was done, false if object was
already initialized.
*/
public function initialize()
{
$initialized = $this->_initialized;
$this->_initialized = true;
return !$initialized;
}
/**
* Make instance as read only object.
*/
public function readonly()
{
$this->_readonly = true;
}
/**
* Returns the global instance to the object.
*
* Note that using array of fields will always make a query to the
database, but it's very useful feature if you want to search
* one item by using arbitrary set of matching fields. If there are
more than one matching object, first one gets returned.
*
* @param int|array $keys An optional primary key value to
load the object by, or an array of fields to match.
* @param boolean $reload Force object reload from the
database.
*
* @return Object
*/
static public function getInstance($keys = null, $reload = false)
{
// If we are creating or loading a new item or we load instance by
alternative keys,
// we need to create a new object.
if (!$keys || is_array($keys) || !isset(static::$instances[(int)
$keys])) {
$c = get_called_class();
$instance = new $c($keys);
/** @var Object $instance */
if (!$instance->exists()) return $instance;
// Instance exists: make sure that we return the global
instance.
$keys = $instance->id;
}
// Return global instance from the identifier, possibly reloading
it first.
$instance = static::$instances[(int) $keys];
if ($reload) $instance->load($keys);
return $instance;
}
/**
* Removes all or selected instances from the object cache.
*
* @param null|int|array $ids
*/
static public function freeInstances($ids = null)
{
if ($ids === null) {
$ids = array_keys(static::$instances);
}
$ids = (array) $ids;
foreach ($ids as $id) {
unset(static::$instances[$id]);
}
}
/**
* Returns true if the object exists in the database.
*
* @param boolean $exists Internal parameter to change state.
*
* @return boolean True if object exists in database.
*/
public function exists($exists = null)
{
$return = $this->_exists;
if ($exists !== null) $this->_exists = (bool) $exists;
return $return;
}
/**
* Tests if dynamically defined property has been defined.
*
* @param string $property
* @param bool $defined
* @return bool
*/
public function defined($property, $defined = true)
{
$property = '_' . $property;
return $defined ? isset($this->{$property}) :
!isset($this->{$property});
}
/**
* Returns an associative array of object properties.
*
* @param boolean $public If true, returns only the public
properties.
*
* @return array
*/
public function getProperties($public = true)
{
if ($public) {
$getProperties = function($obj) { return get_object_vars($obj);
};
return $getProperties($this);
}
return get_object_vars($this);
}
/**
* Method to bind an associative array to the instance.
*
* This method optionally takes an array of properties to ignore or
allow when binding.
*
* @param array $src An associative array or object to bind to
the JTable instance.
* @param array $fields An optional array list of properties to
ignore / include only while binding.
* @param boolean $include True to include only listed fields,
false to ignore listed fields.
*
* @return boolean True on success.
*/
public function bind(array $src = null, array $fields = null, $include
= false)
{
if (empty($src)) return false;
if (!empty($fields)) {
$src = $include ? array_intersect_key($src,
array_flip($fields)) : array_diff_key($src, array_flip($fields));
}
$this->setProperties ( $src );
return true;
}
/**
* Method to load object from the database.
*
* @param mixed $keys An optional primary key value to load the
object by, or an array of fields to match. If not
* set the instance key value is used.
*
* @return boolean True on success, false if the object doesn't
exist.
*/
public function load($keys = null)
{
if ($keys !== null && !is_array($keys)) {
$keys = array('id'=>(int) $keys);
}
// Create the table object.
$table = static::getTable ();
// Make sure we set the given keys to the object even if it is not
loaded.
$table->reset();
if ($keys !== null) $table->bind($keys);
// Load the object based on the keys.
$this->_exists = $table->load($keys, false);
// Work around Joomla 3.1.1 bug on load() returning true if keys
didn't exist.
if ($table->id == 0) $this->_exists = false;
// Assuming all is well at this point lets bind the data.
$this->setProperties($table->getProperties());
if ($this->id) {
if (!isset(static::$instances[$this->id])) {
static::$instances[$this->id] = $this;
}
}
$this->initialize();
return $this->_exists;
}
/**
* Method to save the object to the database.
*
* Before saving the object, this method checks if object can be safely
saved.
* It will also trigger onContentBeforeSave and onContentAfterSave
events.
*
* @return boolean True on success.
*/
public function save()
{
// Check the object.
if ($this->_readonly || !$this->check()) {
return false;
}
$isNew = !$this->_exists;
// Initialize table object.
$table = static::getTable ();
$table->bind($this->getProperties());
// Check the table object.
if (!$table->check()) {
$this->setError($table->getError());
return false;
}
// Include the content plugins for the on save events.
$dispatcher = \JEventDispatcher::getInstance();
\JPluginHelper::importPlugin('content');
// Trigger the onContentBeforeSave event.
$result = $dispatcher->trigger('onContentBeforeSave',
array("com_gantry5.".get_called_class(), $table, $isNew));
if (in_array(false, $result, true)) {
$this->setError($table->getError());
return false;
}
// Store the data.
if (!$table->store()) {
$this->setError($table->getError());
return false;
}
// If item was created, load the object.
if ($isNew) {
$this->load($table->id);
if (!isset(static::$instances[$this->id])) {
static::$instances[$this->id] = $this;
}
}
// Trigger the onContentAfterSave event.
$dispatcher->trigger('onContentAfterSave',
array("com_gantry5.".get_called_class(), $table, $isNew));
return true;
}
/**
* Method to delete the object from the database.
*
* @return boolean True on success.
*/
public function delete()
{
if ($this->_readonly) {
return false;
}
if (!$this->_exists) {
return true;
}
// Initialize table object.
$table = static::getTable();
$table->bind($this->getProperties());
// Include the content plugins for the on save events.
$dispatcher = \JEventDispatcher::getInstance();
\JPluginHelper::importPlugin('content');
// Trigger the onContentBeforeDelete event.
$result =
$dispatcher->trigger('onContentBeforeDelete',
array("com_gantry5.".get_called_class(), $table));
if (in_array(false, $result, true)) {
$this->setError($table->getError());
return false;
}
if (!$table->delete()) {
$this->setError($table->getError());
return false;
}
$this->_exists = false;
// Trigger the onContentAfterDelete event.
$dispatcher->trigger('onContentAfterDelete',
array("com_gantry5.".get_called_class(), $table));
return true;
}
/**
* Method to perform sanity checks on the instance properties to ensure
* they are safe to store in the database.
*
* Child classes should override this method to make sure the data they
are storing in
* the database is safe and as expected before storage.
*
* @return boolean True if the instance is sane and able to be stored
in the database.
*/
public function check()
{
return true;
}
static public function getAvailableInstances()
{
return static::collection(static::$instances);
}
static public function getInstances(array $ids, $readonly = true)
{
if (!$ids) {
return array();
}
$results = array();
$list = array();
foreach ($ids as $id) {
if (!isset(static::$instances[$id])) {
$list[] = $id;
}
}
if ($list) {
$query = static::getQuery();
$query->where('id IN (' . implode(',',
$list) . ')');
static::loadInstances($query);
}
foreach ($ids as $id) {
if (isset(static::$instances[$id])) {
if ($readonly) {
$results[$id] = clone static::$instances[$id];
} else {
$results[$id] = static::$instances[$id];
}
}
}
return static::collection($results);
}
// Internal functions
static protected function collection($items)
{
return new Collection($items);
}
/**
* Method to get the table object.
*
* @return \JTable The table object.
*/
static protected function getTable()
{
return \JTable::getInstance(static::$table, static::$tablePrefix);
}
/**
* @return \JDatabaseQuery
*/
static protected function getQuery()
{
$table = static::getTable();
$db = \JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('a.*')->from($table->getTableName().'
AS a')->order(static::$order);
return $query;
}
/**
* @param \JDatabaseQuery|string $query
*/
static protected function loadInstances($query = null)
{
if (!$query) {
$query = static::getQuery();
}
$db = \JFactory::getDbo();
$db->setQuery($query);
/** @var Object[] $items */
$items = (array) $db->loadObjectList('id',
get_called_class());
foreach ($items as $item) {
if (!isset(static::$instances[$item->id])) {
$item->exists(true);
$item->initialize();
}
}
static::$instances += $items;
}
}
PK&d�[�g����+classes/Gantry/Joomla/Object/Collection.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Object;
use \Gantry\Component\Collection\Collection as BaseCollection;
class Collection extends BaseCollection
{
public function __construct(array $items)
{
$this->items = $items;
}
public function get($property)
{
$list = [];
if ($property === 'id') {
return array_keys($this->items);
}
foreach ($this as $object) {
$list[$object->id] = $object->{$property};
}
return $list;
}
public function __call($name, $arguments)
{
$list = [];
foreach ($this as $object) {
$list[$object->id] = method_exists($object, $name) ?
call_user_func_array([$object, $name], $arguments) : null;
}
return $list;
}
}
PK&d�[T��BB'classes/Gantry/Joomla/Object/Finder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla\Object;
/**
* Class Finder
* @package Gantry\Joomla\Object
*/
abstract class Finder
{
/**
* Table associated with the model.
*
* @var string
*/
protected $table;
/**
* @var string
*/
protected $primaryKey = 'id';
/**
* @var \JDatabaseQuery
*/
protected $query;
/**
* @var \JDatabase
*/
protected $db;
protected $start = 0;
protected $limit = 20;
protected $skip = false;
/**
* Finder constructor.
*
* @param array $options
*/
public function __construct(array $options = [])
{
if (!$this->table) {
throw new \DomainException('Table name missing from '
. get_class($this));
}
$this->db = \JFactory::getDbo();
$this->query = $this->db->getQuery(true);
$this->query->from($this->table . ' AS a');
if ($options) {
$this->parse($options);
}
}
public function parse(array $options)
{
foreach ($options as $func => $params) {
if (method_exists($this, $func)) {
call_user_func_array([$this, $func], (array) $params);
}
}
return $this;
}
/**
* Set limitstart for the query.
*
* @param int $limitstart
*
* @return $this
*/
public function start($limitstart = 0)
{
$this->start = $limitstart;
return $this;
}
/**
* Set limit to the query.
*
* @param int $limit
*
* @return $this
*/
public function limit($limit = null)
{
if (!is_null($limit))
{
$this->limit = $limit;
}
return $this;
}
/**
* Set order by field and direction.
*
* This function can be used more than once to chain order by.
*
* @param string $by
* @param int $direction
* @param string $alias
*
* @return $this
*/
public function order($by, $direction = 1, $alias = 'a')
{
if (is_numeric($direction)) {
$direction = $direction > 0 ? 'ASC' :
'DESC';
} else {
$direction = strtolower((string)$direction) == 'desc'
? 'DESC' : 'ASC';
}
$by = (string)$alias . '.' .
$this->db->quoteName($by);
$this->query->order("{$by} {$direction}");
return $this;
}
/**
* Filter by field.
*
* @param string $field Field name.
* @param string $operation Operation
(>|>=|<|<=|=|IN|NOT IN)
* @param string|array $value Value.
*
* @return $this
*/
public function where($field, $operation, $value)
{
$db = $this->db;
$operation = strtoupper($operation);
switch ($operation)
{
case '>':
case '>=':
case '<':
case '<=':
case '=':
// Quote all non integer values.
$value = (string)(int)$value === (string)$value ?
(int)$value : $db->quote($value);
$this->query->where("{$this->db->quoteName($field)}
{$operation} {$value}");
break;
case 'BETWEEN':
case 'NOT BETWEEN':
list($a, $b) = (array) $value;
// Quote all non integer values.
$a = (string)(int)$a === (string)$a ? (int)$a :
$db->quote($a);
$b = (string)(int)$b === (string)$b ? (int)$b :
$db->quote($b);
$this->query->where("{$this->db->quoteName($field)}
{$operation} {$a} AND {$b}");
break;
case 'IN':
case 'NOT IN':
$value = (array) $value;
if (empty($value)) {
// WHERE field IN (nothing).
$this->query->where('0');
} else {
// Quote all non integer values.
array_walk($value, function (&$value) use ($db) {
$value = (string)(int)$value === (string)$value ? (int)$value :
$db->quote($value); });
$list = implode(',', $value);
$this->query->where("{$this->db->quoteName($field)}
{$operation} ({$list})");
}
break;
}
return $this;
}
/**
* Get items.
*
* Derived classes should generally override this function to return
correct objects.
*
* @return array
*/
public function find()
{
if ($this->skip)
{
return array();
}
$baseQuery = clone $this->query;
$this->prepare();
$query = $this->query;
$this->query = $baseQuery;
$query->select('a.' . $this->primaryKey);
$this->db->setQuery($query, $this->start,
$this->limit);
$results = (array) $this->db->loadColumn();
return $results;
}
/**
* Count items.
*
* @return int
*/
public function count()
{
$baseQuery = clone $this->query;
$this->prepare();
$query = $this->query;
$this->query = $baseQuery;
$query->select('COUNT(*)');
$this->db->setQuery($query);
$count = (int) $this->db->loadResult();
return $count;
}
/**
* Override to include common where rules.
*
* @return void
*/
protected function prepare()
{
}
}
PK&d�[�`�
�
%classes/Gantry/Joomla/StyleHelper.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla;
use Gantry\Component\Filesystem\Folder;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Joomla style helper.
*/
class StyleHelper
{
public static function getStyle($id)
{
\JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_templates/tables');
$style = \JTable::getInstance('Style',
'TemplatesTable');
$style->load($id);
return $style;
}
public static function loadStyles($template)
{
$db = \JFactory::getDbo();
$query = $db
->getQuery(true)
->select('s.id, s.template, s.home, s.title AS
long_title, s.params')
->from('#__template_styles AS s')
->where('s.client_id = 0')
->where("s.template = {$db->quote($template)}")
->order('s.id');
$db->setQuery($query);
$list = (array) $db->loadObjectList('id');
foreach ($list as $id => &$style) {
$style->title = preg_replace('/' .
preg_quote(\JText::_($style->template), '/') .
'\s*-\s*/u', '', $style->long_title);
$style->home = $style->home && $style->home
!== '1' ? $style->home : (bool)$style->home;
}
return $list;
}
public static function getDefaultStyle()
{
return static::getStyle(['home' => 1,
'client_id' => 0]);
}
public static function copy($style, $old, $new)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$oldPath = $locator->findResource('gantry-config://' .
$old, true, true);
$newPath = $locator->findResource('gantry-config://' .
$new, true, true);
if (file_exists($oldPath)) {
Folder::copy($oldPath, $newPath);
}
$extension = !empty($style->extension_id) ?
$style->extension_id : $style->template;
$installer = new TemplateInstaller($extension);
$installer->updateStyle($new, ['configuration' =>
$new]);
}
public static function update($id, $preset)
{
$style = static::getStyle($id);
$extension = !empty($style->extension_id) ?
$style->extension_id : $style->template;
$installer = new TemplateInstaller($extension);
$installer->updateStyle($id, ['configuration' =>
$id, 'preset' => $preset]);
}
public static function delete($id)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path = $locator->findResource('gantry-config://' .
$id, true, true);
if (is_dir($path)) {
Folder::delete($path, true);
}
}
/**
* @return \TemplatesModelStyle
*/
public static function loadModel()
{
static $model;
if (!$model) {
$path = JPATH_ADMINISTRATOR .
'/components/com_templates/';
\JTable::addIncludePath("{$path}/tables");
require_once "{$path}/models/style.php";
// Load language strings.
$lang = \JFactory::getLanguage();
$lang->load('com_templates');
$model = new \TemplatesModelStyle;
}
return $model;
}
}
PK&d�[h��+classes/Gantry/Joomla/TemplateInstaller.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Joomla;
use Gantry\Framework\ThemeInstaller;
/**
* Class TemplateInstaller
* @package Gantry\Joomla
* @deprecated 5.3.2
*/
class TemplateInstaller extends ThemeInstaller {}
PK&d�[%�|R��"classes/Leafo/ScssPhp/Compiler.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Base\Range;
use Leafo\ScssPhp\Block;
use Leafo\ScssPhp\Cache;
use Leafo\ScssPhp\Colors;
use Leafo\ScssPhp\Compiler\Environment;
use Leafo\ScssPhp\Exception\CompilerException;
use Leafo\ScssPhp\Formatter\OutputBlock;
use Leafo\ScssPhp\Node;
use Leafo\ScssPhp\SourceMap\SourceMapGenerator;
use Leafo\ScssPhp\Type;
use Leafo\ScssPhp\Parser;
use Leafo\ScssPhp\Util;
/**
* The scss compiler and parser.
*
* Converting SCSS to CSS is a three stage process. The incoming file is
parsed
* by `Parser` into a syntax tree, then it is compiled into another tree
* representing the CSS structure by `Compiler`. The CSS tree is fed into a
* formatter, like `Formatter` which then outputs CSS as a string.
*
* During the first compile, all values are *reduced*, which means that
their
* types are brought to the lowest form before being dump as strings. This
* handles math equations, variable dereferences, and the like.
*
* The `compile` function of `Compiler` is the entry point.
*
* In summary:
*
* The `Compiler` class creates an instance of the parser, feeds it SCSS
code,
* then transforms the resulting tree to a CSS tree. This class also holds
the
* evaluation context, such as all available mixins and variables at any
given
* time.
*
* The `Parser` class is only concerned with parsing its input.
*
* The `Formatter` takes a CSS tree, and dumps it to a formatted string,
* handling things like indentation.
*/
/**
* SCSS compiler
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Compiler
{
const LINE_COMMENTS = 1;
const DEBUG_INFO = 2;
const WITH_RULE = 1;
const WITH_MEDIA = 2;
const WITH_SUPPORTS = 4;
const WITH_ALL = 7;
const SOURCE_MAP_NONE = 0;
const SOURCE_MAP_INLINE = 1;
const SOURCE_MAP_FILE = 2;
/**
* @var array
*/
static protected $operatorNames = [
'+' => 'add',
'-' => 'sub',
'*' => 'mul',
'/' => 'div',
'%' => 'mod',
'==' => 'eq',
'!=' => 'neq',
'<' => 'lt',
'>' => 'gt',
'<=' => 'lte',
'>=' => 'gte',
'<=>' => 'cmp',
];
/**
* @var array
*/
static protected $namespaces = [
'special' => '%',
'mixin' => '@',
'function' => '^',
];
static public $true = [Type::T_KEYWORD, 'true'];
static public $false = [Type::T_KEYWORD, 'false'];
static public $null = [Type::T_NULL];
static public $nullString = [Type::T_STRING, '', []];
static public $defaultValue = [Type::T_KEYWORD, ''];
static public $selfSelector = [Type::T_SELF];
static public $emptyList = [Type::T_LIST, '', []];
static public $emptyMap = [Type::T_MAP, [], []];
static public $emptyString = [Type::T_STRING, '"', []];
static public $with = [Type::T_KEYWORD, 'with'];
static public $without = [Type::T_KEYWORD, 'without'];
protected $importPaths = [''];
protected $importCache = [];
protected $importedFiles = [];
protected $userFunctions = [];
protected $registeredVars = [];
protected $registeredFeatures = [
'extend-selector-pseudoclass' => false,
'at-error' => true,
'units-level-3' => false,
'global-variable-shadowing' => false,
];
protected $encoding = null;
protected $lineNumberStyle = null;
protected $sourceMap = self::SOURCE_MAP_NONE;
protected $sourceMapOptions = [];
/**
* @var string|\Leafo\ScssPhp\Formatter
*/
protected $formatter = 'Leafo\ScssPhp\Formatter\Nested';
protected $rootEnv;
protected $rootBlock;
/**
* @var \Leafo\ScssPhp\Compiler\Environment
*/
protected $env;
protected $scope;
protected $storeEnv;
protected $charsetSeen;
protected $sourceNames;
protected $cache;
protected $indentLevel;
protected $extends;
protected $extendsMap;
protected $parsedFiles;
protected $parser;
protected $sourceIndex;
protected $sourceLine;
protected $sourceColumn;
protected $stderr;
protected $shouldEvaluate;
protected $ignoreErrors;
protected $callStack = [];
/**
* Constructor
*/
public function __construct($cacheOptions = null)
{
$this->parsedFiles = [];
$this->sourceNames = [];
if ($cacheOptions) {
$this->cache = new Cache($cacheOptions);
}
}
public function getCompileOptions()
{
$options = [
'importPaths' => $this->importPaths,
'registeredVars' => $this->registeredVars,
'registeredFeatures' =>
$this->registeredFeatures,
'encoding' => $this->encoding,
'sourceMap' =>
serialize($this->sourceMap),
'sourceMapOptions' =>
$this->sourceMapOptions,
'formatter' => $this->formatter,
];
return $options;
}
/**
* Compile scss
*
* @api
*
* @param string $code
* @param string $path
*
* @return string
*/
public function compile($code, $path = null)
{
if ($this->cache) {
$cacheKey = ($path ? $path : "(stdin)") .
":" . md5($code);
$compileOptions = $this->getCompileOptions();
$cache = $this->cache->getCache("compile",
$cacheKey, $compileOptions);
if (is_array($cache)
&& isset($cache['dependencies'])
&& isset($cache['out'])
) {
// check if any dependency file changed before accepting
the cache
foreach ($cache['dependencies'] as $file =>
$mtime) {
if (! file_exists($file)
|| filemtime($file) !== $mtime
) {
unset($cache);
break;
}
}
if (isset($cache)) {
return $cache['out'];
}
}
}
$this->indentLevel = -1;
$this->extends = [];
$this->extendsMap = [];
$this->sourceIndex = null;
$this->sourceLine = null;
$this->sourceColumn = null;
$this->env = null;
$this->scope = null;
$this->storeEnv = null;
$this->charsetSeen = null;
$this->shouldEvaluate = null;
$this->stderr = fopen('php://stderr',
'w');
$this->parser = $this->parserFactory($path);
$tree = $this->parser->parse($code);
$this->parser = null;
$this->formatter = new $this->formatter();
$this->rootBlock = null;
$this->rootEnv = $this->pushEnv($tree);
$this->injectVariables($this->registeredVars);
$this->compileRoot($tree);
$this->popEnv();
$sourceMapGenerator = null;
if ($this->sourceMap) {
if (is_object($this->sourceMap) &&
$this->sourceMap instanceof SourceMapGenerator) {
$sourceMapGenerator = $this->sourceMap;
$this->sourceMap = self::SOURCE_MAP_FILE;
} elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) {
$sourceMapGenerator = new
SourceMapGenerator($this->sourceMapOptions);
}
}
$out = $this->formatter->format($this->scope,
$sourceMapGenerator);
if (! empty($out) && $this->sourceMap &&
$this->sourceMap !== self::SOURCE_MAP_NONE) {
$sourceMap = $sourceMapGenerator->generateJson();
$sourceMapUrl = null;
switch ($this->sourceMap) {
case self::SOURCE_MAP_INLINE:
$sourceMapUrl =
sprintf('data:application/json,%s',
Util::encodeURIComponent($sourceMap));
break;
case self::SOURCE_MAP_FILE:
$sourceMapUrl =
$sourceMapGenerator->saveMap($sourceMap);
break;
}
$out .= sprintf('/*# sourceMappingURL=%s */',
$sourceMapUrl);
}
if ($this->cache && isset($cacheKey) &&
isset($compileOptions)) {
$v = [
'dependencies' => $this->getParsedFiles(),
'out' => &$out,
];
$this->cache->setCache("compile", $cacheKey,
$v, $compileOptions);
}
return $out;
}
/**
* Instantiate parser
*
* @param string $path
*
* @return \Leafo\ScssPhp\Parser
*/
protected function parserFactory($path)
{
$parser = new Parser($path, count($this->sourceNames),
$this->encoding, $this->cache);
$this->sourceNames[] = $path;
$this->addParsedFile($path);
return $parser;
}
/**
* Is self extend?
*
* @param array $target
* @param array $origin
*
* @return boolean
*/
protected function isSelfExtend($target, $origin)
{
foreach ($origin as $sel) {
if (in_array($target, $sel)) {
return true;
}
}
return false;
}
/**
* Push extends
*
* @param array $target
* @param array $origin
* @param \stdClass $block
*/
protected function pushExtends($target, $origin, $block)
{
if ($this->isSelfExtend($target, $origin)) {
return;
}
$i = count($this->extends);
$this->extends[] = [$target, $origin, $block];
foreach ($target as $part) {
if (isset($this->extendsMap[$part])) {
$this->extendsMap[$part][] = $i;
} else {
$this->extendsMap[$part] = [$i];
}
}
}
/**
* Make output block
*
* @param string $type
* @param array $selectors
*
* @return \Leafo\ScssPhp\Formatter\OutputBlock
*/
protected function makeOutputBlock($type, $selectors = null)
{
$out = new OutputBlock;
$out->type = $type;
$out->lines = [];
$out->children = [];
$out->parent = $this->scope;
$out->selectors = $selectors;
$out->depth = $this->env->depth;
if ($this->env->block instanceof Block) {
$out->sourceName = $this->env->block->sourceName;
$out->sourceLine = $this->env->block->sourceLine;
$out->sourceColumn =
$this->env->block->sourceColumn;
} else {
$out->sourceName = null;
$out->sourceLine = null;
$out->sourceColumn = null;
}
return $out;
}
/**
* Compile root
*
* @param \Leafo\ScssPhp\Block $rootBlock
*/
protected function compileRoot(Block $rootBlock)
{
$this->rootBlock = $this->scope =
$this->makeOutputBlock(Type::T_ROOT);
$this->compileChildrenNoReturn($rootBlock->children,
$this->scope);
$this->flattenSelectors($this->scope);
$this->missingSelectors();
}
/**
* Report missing selectors
*/
protected function missingSelectors()
{
foreach ($this->extends as $extend) {
if (isset($extend[3])) {
continue;
}
list($target, $origin, $block) = $extend;
// ignore if !optional
if ($block[2]) {
continue;
}
$target = implode(' ', $target);
$origin = $this->collapseSelectors($origin);
$this->sourceLine = $block[Parser::SOURCE_LINE];
$this->throwError("\"$origin\" failed to
@extend \"$target\". The selector \"$target\" was not
found.");
}
}
/**
* Flatten selectors
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
* @param string $parentKey
*/
protected function flattenSelectors(OutputBlock $block, $parentKey =
null)
{
if ($block->selectors) {
$selectors = [];
foreach ($block->selectors as $s) {
$selectors[] = $s;
if (! is_array($s)) {
continue;
}
// check extends
if (! empty($this->extendsMap)) {
$this->matchExtends($s, $selectors);
// remove duplicates
array_walk($selectors, function (&$value) {
$value = serialize($value);
});
$selectors = array_unique($selectors);
array_walk($selectors, function (&$value) {
$value = unserialize($value);
});
}
}
$block->selectors = [];
$placeholderSelector = false;
foreach ($selectors as $selector) {
if ($this->hasSelectorPlaceholder($selector)) {
$placeholderSelector = true;
continue;
}
$block->selectors[] =
$this->compileSelector($selector);
}
if ($placeholderSelector && 0 ===
count($block->selectors) && null !== $parentKey) {
unset($block->parent->children[$parentKey]);
return;
}
}
foreach ($block->children as $key => $child) {
$this->flattenSelectors($child, $key);
}
}
/**
* Glue parts of :not( or :nth-child( ... that are in general splitted
in selectors parts
*
* @param array $parts
*
* @return array
*/
protected function glueFunctionSelectors($parts)
{
$new = [];
foreach ($parts as $part) {
if (is_array($part)) {
$part = $this->glueFunctionSelectors($part);
$new[] = $part;
} else {
// a selector part finishing with a ) is the last part of a
:not( or :nth-child(
// and need to be joined to this
if (count($new) && is_string($new[count($new) - 1])
&& strlen($part) && substr($part, -1)
=== ')' && strpos($part, '(') === false
) {
$new[count($new) - 1] .= $part;
} else {
$new[] = $part;
}
}
}
return $new;
}
/**
* Match extends
*
* @param array $selector
* @param array $out
* @param integer $from
* @param boolean $initial
*/
protected function matchExtends($selector, &$out, $from = 0,
$initial = true)
{
static $partsPile = [];
$selector = $this->glueFunctionSelectors($selector);
foreach ($selector as $i => $part) {
if ($i < $from) {
continue;
}
// check that we are not building an infinite loop of
extensions
// if the new part is just including a previous part don't
try to extend anymore
if (count($part) > 1) {
foreach ($partsPile as $previousPart) {
if (! count(array_diff($previousPart, $part))) {
continue 2;
}
}
}
if ($this->matchExtendsSingle($part, $origin)) {
$partsPile[] = $part;
$after = array_slice($selector, $i + 1);
$before = array_slice($selector, 0, $i);
list($before, $nonBreakableBefore) =
$this->extractRelationshipFromFragment($before);
foreach ($origin as $new) {
$k = 0;
// remove shared parts
if (count($new) > 1) {
while ($k < $i && isset($new[$k])
&& $selector[$k] === $new[$k]) {
$k++;
}
}
$replacement = [];
$tempReplacement = $k > 0 ? array_slice($new, $k) :
$new;
for ($l = count($tempReplacement) - 1; $l >= 0;
$l--) {
$slice = [];
foreach ($tempReplacement[$l] as $chunk) {
if (! in_array($chunk, $slice)) {
$slice[] = $chunk;
}
}
array_unshift($replacement, $slice);
if (!
$this->isImmediateRelationshipCombinator(end($slice))) {
break;
}
}
$afterBefore = $l != 0 ? array_slice($tempReplacement,
0, $l) : [];
// Merge shared direct relationships.
$mergedBefore =
$this->mergeDirectRelationships($afterBefore, $nonBreakableBefore);
$result = array_merge(
$before,
$mergedBefore,
$replacement,
$after
);
if ($result === $selector) {
continue;
}
$out[] = $result;
// recursively check for more matches
$startRecurseFrom = count($before) +
min(count($nonBreakableBefore), count($mergedBefore));
$this->matchExtends($result, $out,
$startRecurseFrom, false);
// selector sequence merging
if (! empty($before) && count($new) > 1) {
$preSharedParts = $k > 0 ? array_slice($before,
0, $k) : [];
$postSharedParts = $k > 0 ? array_slice($before,
$k) : $before;
list($betweenSharedParts, $nonBreakable2) =
$this->extractRelationshipFromFragment($afterBefore);
$result2 = array_merge(
$preSharedParts,
$betweenSharedParts,
$postSharedParts,
$nonBreakable2,
$nonBreakableBefore,
$replacement,
$after
);
$out[] = $result2;
}
}
array_pop($partsPile);
}
}
}
/**
* Match extends single
*
* @param array $rawSingle
* @param array $outOrigin
*
* @return boolean
*/
protected function matchExtendsSingle($rawSingle, &$outOrigin)
{
$counts = [];
$single = [];
// simple usual cases, no need to do the whole trick
if (in_array($rawSingle,
[['>'],['+'],['~']])) {
return false;
}
foreach ($rawSingle as $part) {
// matches Number
if (! is_string($part)) {
return false;
}
if (! preg_match('/^[\[.:#%]/', $part) &&
count($single)) {
$single[count($single) - 1] .= $part;
} else {
$single[] = $part;
}
}
$extendingDecoratedTag = false;
if (count($single) > 1) {
$matches = null;
$extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i',
$single[0], $matches) ? $matches[0] : false;
}
foreach ($single as $part) {
if (isset($this->extendsMap[$part])) {
foreach ($this->extendsMap[$part] as $idx) {
$counts[$idx] = isset($counts[$idx]) ? $counts[$idx] +
1 : 1;
}
}
}
$outOrigin = [];
$found = false;
foreach ($counts as $idx => $count) {
list($target, $origin, /* $block */) = $this->extends[$idx];
$origin = $this->glueFunctionSelectors($origin);
// check count
if ($count !== count($target)) {
continue;
}
$this->extends[$idx][3] = true;
$rem = array_diff($single, $target);
foreach ($origin as $j => $new) {
// prevent infinite loop when target extends itself
if ($this->isSelfExtend($single, $origin)) {
return false;
}
$replacement = end($new);
// Extending a decorated tag with another tag is not
possible.
if ($extendingDecoratedTag && $replacement[0] !=
$extendingDecoratedTag &&
preg_match('/^[a-z0-9]+$/i', $replacement[0])
) {
unset($origin[$j]);
continue;
}
$combined = $this->combineSelectorSingle($replacement,
$rem);
if (count(array_diff($combined,
$origin[$j][count($origin[$j]) - 1]))) {
$origin[$j][count($origin[$j]) - 1] = $combined;
}
}
$outOrigin = array_merge($outOrigin, $origin);
$found = true;
}
return $found;
}
/**
* Extract a relationship from the fragment.
*
* When extracting the last portion of a selector we will be left with
a
* fragment which may end with a direction relationship combinator.
This
* method will extract the relationship fragment and return it along
side
* the rest.
*
* @param array $fragment The selector fragment maybe ending with a
direction relationship combinator.
*
* @return array The selector without the relationship fragment if any,
the relationship fragment.
*/
protected function extractRelationshipFromFragment(array $fragment)
{
$parents = [];
$children = [];
$j = $i = count($fragment);
for (;;) {
$children = $j != $i ? array_slice($fragment, $j, $i - $j) :
[];
$parents = array_slice($fragment, 0, $j);
$slice = end($parents);
if (empty($slice) || !
$this->isImmediateRelationshipCombinator($slice[0])) {
break;
}
$j -= 2;
}
return [$parents, $children];
}
/**
* Combine selector single
*
* @param array $base
* @param array $other
*
* @return array
*/
protected function combineSelectorSingle($base, $other)
{
$tag = [];
$out = [];
$wasTag = true;
foreach ([$base, $other] as $single) {
foreach ($single as $part) {
if (preg_match('/^[\[.:#]/', $part)) {
$out[] = $part;
$wasTag = false;
} elseif (preg_match('/^[^_-]/', $part)) {
$tag[] = $part;
$wasTag = true;
} elseif ($wasTag) {
$tag[count($tag) - 1] .= $part;
} else {
$out[count($out) - 1] .= $part;
}
}
}
if (count($tag)) {
array_unshift($out, $tag[0]);
}
return $out;
}
/**
* Compile media
*
* @param \Leafo\ScssPhp\Block $media
*/
protected function compileMedia(Block $media)
{
$this->pushEnv($media);
$mediaQueries =
$this->compileMediaQuery($this->multiplyMedia($this->env));
if (! empty($mediaQueries) && $mediaQueries) {
$previousScope = $this->scope;
$parentScope = $this->mediaParent($this->scope);
foreach ($mediaQueries as $mediaQuery) {
$this->scope = $this->makeOutputBlock(Type::T_MEDIA,
[$mediaQuery]);
$parentScope->children[] = $this->scope;
$parentScope = $this->scope;
}
// top level properties in a media cause it to be wrapped
$needsWrap = false;
foreach ($media->children as $child) {
$type = $child[0];
if ($type !== Type::T_BLOCK &&
$type !== Type::T_MEDIA &&
$type !== Type::T_DIRECTIVE &&
$type !== Type::T_IMPORT
) {
$needsWrap = true;
break;
}
}
if ($needsWrap) {
$wrapped = new Block;
$wrapped->sourceName = $media->sourceName;
$wrapped->sourceIndex = $media->sourceIndex;
$wrapped->sourceLine = $media->sourceLine;
$wrapped->sourceColumn = $media->sourceColumn;
$wrapped->selectors = [];
$wrapped->comments = [];
$wrapped->parent = $media;
$wrapped->children = $media->children;
$media->children = [[Type::T_BLOCK, $wrapped]];
if (isset($this->lineNumberStyle)) {
$annotation =
$this->makeOutputBlock(Type::T_COMMENT);
$annotation->depth = 0;
$file = $this->sourceNames[$media->sourceIndex];
$line = $media->sourceLine;
switch ($this->lineNumberStyle) {
case static::LINE_COMMENTS:
$annotation->lines[] = '/* line '
. $line
. ($file ? ', '
. $file : '')
. ' */';
break;
case static::DEBUG_INFO:
$annotation->lines[] = '@media
-sass-debug-info{'
. ($file ?
'filename{font-family:"' . $file . '"}' :
'')
.
'line{font-family:' . $line . '}}';
break;
}
$this->scope->children[] = $annotation;
}
}
$this->compileChildrenNoReturn($media->children,
$this->scope);
$this->scope = $previousScope;
}
$this->popEnv();
}
/**
* Media parent
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
*
* @return \Leafo\ScssPhp\Formatter\OutputBlock
*/
protected function mediaParent(OutputBlock $scope)
{
while (! empty($scope->parent)) {
if (! empty($scope->type) && $scope->type !==
Type::T_MEDIA) {
break;
}
$scope = $scope->parent;
}
return $scope;
}
/**
* Compile directive
*
* @param \Leafo\ScssPhp\Block $block
*/
protected function compileDirective(Block $block)
{
$s = '@' . $block->name;
if (! empty($block->value)) {
$s .= ' ' . $this->compileValue($block->value);
}
if ($block->name === 'keyframes' ||
substr($block->name, -10) === '-keyframes') {
$this->compileKeyframeBlock($block, [$s]);
} else {
$this->compileNestedBlock($block, [$s]);
}
}
/**
* Compile at-root
*
* @param \Leafo\ScssPhp\Block $block
*/
protected function compileAtRoot(Block $block)
{
$env = $this->pushEnv($block);
$envs = $this->compactEnv($env);
$without = isset($block->with) ?
$this->compileWith($block->with) : static::WITH_RULE;
// wrap inline selector
if ($block->selector) {
$wrapped = new Block;
$wrapped->sourceName = $block->sourceName;
$wrapped->sourceIndex = $block->sourceIndex;
$wrapped->sourceLine = $block->sourceLine;
$wrapped->sourceColumn = $block->sourceColumn;
$wrapped->selectors = $block->selector;
$wrapped->comments = [];
$wrapped->parent = $block;
$wrapped->children = $block->children;
$wrapped->selfParent = $block->selfParent;
$block->children = [[Type::T_BLOCK, $wrapped]];
$block->selector = null;
}
$selfParent = $block->selfParent;
if (! $block->selfParent->selectors &&
isset($block->parent) && $block->parent &&
isset($block->parent->selectors) &&
$block->parent->selectors
) {
$selfParent = $block->parent;
}
$this->env = $this->filterWithout($envs, $without);
$saveScope = $this->scope;
$this->scope = $this->filterScopeWithout($saveScope,
$without);
// propagate selfParent to the children where they still can be
useful
$this->compileChildrenNoReturn($block->children,
$this->scope, $selfParent);
$this->scope = $this->completeScope($this->scope,
$saveScope);
$this->scope = $saveScope;
$this->env = $this->extractEnv($envs);
$this->popEnv();
}
/**
* Filter at-root scope depending of with/without option
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
* @param mixed $without
*
* @return mixed
*/
protected function filterScopeWithout($scope, $without)
{
$filteredScopes = [];
if ($scope->type === TYPE::T_ROOT) {
return $scope;
}
// start from the root
while ($scope->parent && $scope->parent->type !==
TYPE::T_ROOT) {
$scope = $scope->parent;
}
for (;;) {
if (! $scope) {
break;
}
if (! $this->isWithout($without, $scope)) {
$s = clone $scope;
$s->children = [];
$s->lines = [];
$s->parent = null;
if ($s->type !== Type::T_MEDIA && $s->type
!== Type::T_DIRECTIVE) {
$s->selectors = [];
}
$filteredScopes[] = $s;
}
if ($scope->children) {
$scope = end($scope->children);
} else {
$scope = null;
}
}
if (! count($filteredScopes)) {
return $this->rootBlock;
}
$newScope = array_shift($filteredScopes);
$newScope->parent = $this->rootBlock;
$this->rootBlock->children[] = $newScope;
$p = &$newScope;
while (count($filteredScopes)) {
$s = array_shift($filteredScopes);
$s->parent = $p;
$p->children[] = &$s;
$p = $s;
}
return $newScope;
}
/**
* found missing selector from a at-root compilation in the previous
scope
* (if at-root is just enclosing a property, the selector is in the
parent tree)
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
* @param \Leafo\ScssPhp\Formatter\OutputBlock $previousScope
*
* @return mixed
*/
protected function completeScope($scope, $previousScope)
{
if (! $scope->type && (! $scope->selectors || !
count($scope->selectors)) && count($scope->lines)) {
$scope->selectors =
$this->findScopeSelectors($previousScope, $scope->depth);
}
if ($scope->children) {
foreach ($scope->children as $k => $c) {
$scope->children[$k] = $this->completeScope($c,
$previousScope);
}
}
return $scope;
}
/**
* Find a selector by the depth node in the scope
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
* @param integer $depth
*
* @return array
*/
protected function findScopeSelectors($scope, $depth)
{
if ($scope->depth === $depth && $scope->selectors) {
return $scope->selectors;
}
if ($scope->children) {
foreach (array_reverse($scope->children) as $c) {
if ($s = $this->findScopeSelectors($c, $depth)) {
return $s;
}
}
}
return [];
}
/**
* Compile @at-root's with: inclusion / without: exclusion into
filter flags
*
* @param array $with
*
* @return integer
*/
protected function compileWith($with)
{
static $mapping = [
'rule' => self::WITH_RULE,
'media' => self::WITH_MEDIA,
'supports' => self::WITH_SUPPORTS,
'all' => self::WITH_ALL,
];
// exclude selectors by default
$without = static::WITH_RULE;
if ($this->libMapHasKey([$with, static::$with])) {
$without = static::WITH_ALL;
$list = $this->coerceList($this->libMapGet([$with,
static::$with]));
foreach ($list[2] as $item) {
$keyword =
$this->compileStringContent($this->coerceString($item));
if (array_key_exists($keyword, $mapping)) {
$without &= ~($mapping[$keyword]);
}
}
}
if ($this->libMapHasKey([$with, static::$without])) {
$without = 0;
$list = $this->coerceList($this->libMapGet([$with,
static::$without]));
foreach ($list[2] as $item) {
$keyword =
$this->compileStringContent($this->coerceString($item));
if (array_key_exists($keyword, $mapping)) {
$without |= $mapping[$keyword];
}
}
}
return $without;
}
/**
* Filter env stack
*
* @param array $envs
* @param integer $without
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function filterWithout($envs, $without)
{
$filtered = [];
foreach ($envs as $e) {
if ($e->block && $this->isWithout($without,
$e->block)) {
$ec = clone $e;
$ec->block = null;
$ec->selectors = [];
$filtered[] = $ec;
} else {
$filtered[] = $e;
}
}
return $this->extractEnv($filtered);
}
/**
* Filter WITH rules
*
* @param integer
$without
* @param \Leafo\ScssPhp\Block|\Leafo\ScssPhp\Formatter\OutputBlock
$block
*
* @return boolean
*/
protected function isWithout($without, $block)
{
if (isset($block->type)) {
if ($block->type === Type::T_MEDIA) {
return ($without & static::WITH_MEDIA) ? true : false;
}
if ($block->type === Type::T_DIRECTIVE) {
if (isset($block->name) && $block->name ===
'supports') {
return ($without & static::WITH_SUPPORTS) ? true :
false;
}
if (isset($block->selectors) &&
strpos(serialize($block->selectors), '@supports') !== false) {
return ($without & static::WITH_SUPPORTS) ? true :
false;
}
}
}
if ((($without & static::WITH_RULE) &&
isset($block->selectors))) {
return true;
}
return false;
}
/**
* Compile keyframe block
*
* @param \Leafo\ScssPhp\Block $block
* @param array $selectors
*/
protected function compileKeyframeBlock(Block $block, $selectors)
{
$env = $this->pushEnv($block);
$envs = $this->compactEnv($env);
$this->env = $this->extractEnv(array_filter($envs, function
(Environment $e) {
return ! isset($e->block->selectors);
}));
$this->scope = $this->makeOutputBlock($block->type,
$selectors);
$this->scope->depth = 1;
$this->scope->parent->children[] = $this->scope;
$this->compileChildrenNoReturn($block->children,
$this->scope);
$this->scope = $this->scope->parent;
$this->env = $this->extractEnv($envs);
$this->popEnv();
}
/**
* Compile nested block
*
* @param \Leafo\ScssPhp\Block $block
* @param array $selectors
*/
protected function compileNestedBlock(Block $block, $selectors)
{
$this->pushEnv($block);
$this->scope = $this->makeOutputBlock($block->type,
$selectors);
$this->scope->parent->children[] = $this->scope;
// wrap assign children in a block
// except for @font-face
if ($block->type !== Type::T_DIRECTIVE || $block->name !==
"font-face") {
// need wrapping?
$needWrapping = false;
foreach ($block->children as $child) {
if ($child[0] === Type::T_ASSIGN) {
$needWrapping = true;
break;
}
}
if ($needWrapping) {
$wrapped = new Block;
$wrapped->sourceName = $block->sourceName;
$wrapped->sourceIndex = $block->sourceIndex;
$wrapped->sourceLine = $block->sourceLine;
$wrapped->sourceColumn = $block->sourceColumn;
$wrapped->selectors = [];
$wrapped->comments = [];
$wrapped->parent = $block;
$wrapped->children = $block->children;
$wrapped->selfParent = $block->selfParent;
$block->children = [[Type::T_BLOCK, $wrapped]];
}
}
$this->compileChildrenNoReturn($block->children,
$this->scope);
$this->scope = $this->scope->parent;
$this->popEnv();
}
/**
* Recursively compiles a block.
*
* A block is analogous to a CSS block in most cases. A single SCSS
document
* is encapsulated in a block when parsed, but it does not have parent
tags
* so all of its children appear on the root level when compiled.
*
* Blocks are made up of selectors and children.
*
* The children of a block are just all the blocks that are defined
within.
*
* Compiling the block involves pushing a fresh environment on the
stack,
* and iterating through the props, compiling each one.
*
* @see Compiler::compileChild()
*
* @param \Leafo\ScssPhp\Block $block
*/
protected function compileBlock(Block $block)
{
$env = $this->pushEnv($block);
$env->selectors = $this->evalSelectors($block->selectors);
$out = $this->makeOutputBlock(null);
if (isset($this->lineNumberStyle) &&
count($env->selectors) && count($block->children)) {
$annotation = $this->makeOutputBlock(Type::T_COMMENT);
$annotation->depth = 0;
$file = $this->sourceNames[$block->sourceIndex];
$line = $block->sourceLine;
switch ($this->lineNumberStyle) {
case static::LINE_COMMENTS:
$annotation->lines[] = '/* line ' . $line
. ($file ? ', ' . $file
: '')
. ' */';
break;
case static::DEBUG_INFO:
$annotation->lines[] = '@media
-sass-debug-info{'
. ($file ?
'filename{font-family:"' . $file . '"}' :
'')
. 'line{font-family:' .
$line . '}}';
break;
}
$this->scope->children[] = $annotation;
}
$this->scope->children[] = $out;
if (count($block->children)) {
$out->selectors = $this->multiplySelectors($env,
$block->selfParent);
// propagate selfParent to the children where they still can be
useful
$selfParentSelectors = null;
if (isset($block->selfParent->selectors)) {
$selfParentSelectors = $block->selfParent->selectors;
$block->selfParent->selectors = $out->selectors;
}
$this->compileChildrenNoReturn($block->children, $out,
$block->selfParent);
// and revert for the following childs of the same block
if ($selfParentSelectors) {
$block->selfParent->selectors = $selfParentSelectors;
}
}
$this->formatter->stripSemicolon($out->lines);
$this->popEnv();
}
/**
* Compile root level comment
*
* @param array $block
*/
protected function compileComment($block)
{
$out = $this->makeOutputBlock(Type::T_COMMENT);
$out->lines[] = is_string($block[1]) ? $block[1] :
$this->compileValue($block[1]);
$this->scope->children[] = $out;
}
/**
* Evaluate selectors
*
* @param array $selectors
*
* @return array
*/
protected function evalSelectors($selectors)
{
$this->shouldEvaluate = false;
$selectors = array_map([$this, 'evalSelector'],
$selectors);
// after evaluating interpolates, we might need a second pass
if ($this->shouldEvaluate) {
$selectors = $this->revertSelfSelector($selectors);
$buffer = $this->collapseSelectors($selectors);
$parser = $this->parserFactory(__METHOD__);
if ($parser->parseSelector($buffer, $newSelectors)) {
$selectors = array_map([$this, 'evalSelector'],
$newSelectors);
}
}
return $selectors;
}
/**
* Evaluate selector
*
* @param array $selector
*
* @return array
*/
protected function evalSelector($selector)
{
return array_map([$this, 'evalSelectorPart'], $selector);
}
/**
* Evaluate selector part; replaces all the interpolates, stripping
quotes
*
* @param array $part
*
* @return array
*/
protected function evalSelectorPart($part)
{
foreach ($part as &$p) {
if (is_array($p) && ($p[0] === Type::T_INTERPOLATE ||
$p[0] === Type::T_STRING)) {
$p = $this->compileValue($p);
// force re-evaluation
if (strpos($p, '&') !== false || strpos($p,
',') !== false) {
$this->shouldEvaluate = true;
}
} elseif (is_string($p) && strlen($p) >= 2
&&
($first = $p[0]) && ($first === '"'
|| $first === "'") &&
substr($p, -1) === $first
) {
$p = substr($p, 1, -1);
}
}
return $this->flattenSelectorSingle($part);
}
/**
* Collapse selectors
*
* @param array $selectors
* @param boolean $selectorFormat
* if false return a collapsed string
* if true return an array description of a structured selector
*
* @return string
*/
protected function collapseSelectors($selectors, $selectorFormat =
false)
{
$parts = [];
foreach ($selectors as $selector) {
$output = [];
$glueNext = false;
foreach ($selector as $node) {
$compound = '';
array_walk_recursive(
$node,
function ($value, $key) use (&$compound) {
$compound .= $value;
}
);
if ($selectorFormat &&
$this->isImmediateRelationshipCombinator($compound)) {
if (count($output)) {
$output[count($output) - 1] .= ' ' .
$compound;
} else {
$output[] = $compound;
}
$glueNext = true;
} elseif ($glueNext) {
$output[count($output) - 1] .= ' ' .
$compound;
$glueNext = false;
} else {
$output[] = $compound;
}
}
if ($selectorFormat) {
foreach ($output as &$o) {
$o = [Type::T_STRING, '', [$o]];
}
$output = [Type::T_LIST, ' ', $output];
} else {
$output = implode(' ', $output);
}
$parts[] = $output;
}
if ($selectorFormat) {
$parts = [Type::T_LIST, ',', $parts];
} else {
$parts = implode(', ', $parts);
}
return $parts;
}
/**
* Parse down the selector and revert [self] to "&"
before a reparsing
*
* @param array $selectors
*
* @return array
*/
protected function revertSelfSelector($selectors)
{
foreach ($selectors as &$part) {
if (is_array($part)) {
if ($part === [Type::T_SELF]) {
$part = '&';
} else {
$part = $this->revertSelfSelector($part);
}
}
}
return $selectors;
}
/**
* Flatten selector single; joins together .classes and #ids
*
* @param array $single
*
* @return array
*/
protected function flattenSelectorSingle($single)
{
$joined = [];
foreach ($single as $part) {
if (empty($joined) ||
! is_string($part) ||
preg_match('/[\[.:#%]/', $part)
) {
$joined[] = $part;
continue;
}
if (is_array(end($joined))) {
$joined[] = $part;
} else {
$joined[count($joined) - 1] .= $part;
}
}
return $joined;
}
/**
* Compile selector to string; self(&) should have been replaced by
now
*
* @param string|array $selector
*
* @return string
*/
protected function compileSelector($selector)
{
if (! is_array($selector)) {
return $selector; // media and the like
}
return implode(
' ',
array_map(
[$this, 'compileSelectorPart'],
$selector
)
);
}
/**
* Compile selector part
*
* @param array $piece
*
* @return string
*/
protected function compileSelectorPart($piece)
{
foreach ($piece as &$p) {
if (! is_array($p)) {
continue;
}
switch ($p[0]) {
case Type::T_SELF:
$p = '&';
break;
default:
$p = $this->compileValue($p);
break;
}
}
return implode($piece);
}
/**
* Has selector placeholder?
*
* @param array $selector
*
* @return boolean
*/
protected function hasSelectorPlaceholder($selector)
{
if (! is_array($selector)) {
return false;
}
foreach ($selector as $parts) {
foreach ($parts as $part) {
if (strlen($part) && '%' === $part[0]) {
return true;
}
}
}
return false;
}
protected function pushCallStack($name = '')
{
$this->callStack[] = [
'n' => $name,
Parser::SOURCE_INDEX => $this->sourceIndex,
Parser::SOURCE_LINE => $this->sourceLine,
Parser::SOURCE_COLUMN => $this->sourceColumn
];
// infinite calling loop
if (count($this->callStack) > 25000) {
// not displayed but you can var_dump it to deep debug
$msg = $this->callStackMessage(true, 100);
$msg = "Infinite calling loop";
$this->throwError($msg);
}
}
protected function popCallStack()
{
array_pop($this->callStack);
}
/**
* Compile children and return result
*
* @param array $stms
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
* @param string $traceName
*
* @return array|null
*/
protected function compileChildren($stms, OutputBlock $out, $traceName
= '')
{
$this->pushCallStack($traceName);
foreach ($stms as $stm) {
$ret = $this->compileChild($stm, $out);
if (isset($ret)) {
return $ret;
}
}
$this->popCallStack();
return null;
}
/**
* Compile children and throw exception if unexpected @return
*
* @param array $stms
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
* @param \Leafo\ScssPhp\Block $selfParent
* @param string $traceName
*
* @throws \Exception
*/
protected function compileChildrenNoReturn($stms, OutputBlock $out,
$selfParent = null, $traceName = '')
{
$this->pushCallStack($traceName);
foreach ($stms as $stm) {
if ($selfParent && isset($stm[1]) &&
is_object($stm[1]) && $stm[1] instanceof Block) {
$stm[1]->selfParent = $selfParent;
$ret = $this->compileChild($stm, $out);
$stm[1]->selfParent = null;
} elseif ($selfParent && $stm[0] === TYPE::T_INCLUDE) {
$stm['selfParent'] = $selfParent;
$ret = $this->compileChild($stm, $out);
unset($stm['selfParent']);
} else {
$ret = $this->compileChild($stm, $out);
}
if (isset($ret)) {
$this->throwError('@return may only be used within
a function');
return;
}
}
$this->popCallStack();
}
/**
* evaluate media query : compile internal value keeping the structure
inchanged
*
* @param array $queryList
*
* @return array
*/
protected function evaluateMediaQuery($queryList)
{
foreach ($queryList as $kql => $query) {
foreach ($query as $kq => $q) {
for ($i = 1; $i < count($q); $i++) {
$value = $this->compileValue($q[$i]);
// the parser had no mean to know if media type or
expression if it was an interpolation
if ($q[0] == Type::T_MEDIA_TYPE &&
(strpos($value, '(') !== false ||
strpos($value, ')') !== false ||
strpos($value, ':') !== false)
) {
$queryList[$kql][$kq][0] =
Type::T_MEDIA_EXPRESSION;
if (strpos($value, 'and') !== false) {
$values = explode('and', $value);
$value = trim(array_pop($values));
while ($v = trim(array_pop($values))) {
$type = Type::T_MEDIA_EXPRESSION;
if (strpos($v, '(') === false
&&
strpos($v, ')') === false
&&
strpos($v, ':') === false
) {
$type = Type::T_MEDIA_TYPE;
}
if (substr($v, 0, 1) === '('
&& substr($v, -1) === ')') {
$v = substr($v, 1, -1);
}
$queryList[$kql][] =
[$type,[Type::T_KEYWORD, $v]];
}
}
if (substr($value, 0, 1) === '('
&& substr($value, -1) === ')') {
$value = substr($value, 1, -1);
}
}
$queryList[$kql][$kq][$i] = [Type::T_KEYWORD, $value];
}
}
}
return $queryList;
}
/**
* Compile media query
*
* @param array $queryList
*
* @return array
*/
protected function compileMediaQuery($queryList)
{
$start = '@media ';
$default = trim($start);
$out = [];
$current = "";
foreach ($queryList as $query) {
$type = null;
$parts = [];
$mediaTypeOnly = true;
foreach ($query as $q) {
if ($q[0] !== Type::T_MEDIA_TYPE) {
$mediaTypeOnly = false;
break;
}
}
foreach ($query as $q) {
switch ($q[0]) {
case Type::T_MEDIA_TYPE:
$newType = array_map([$this,
'compileValue'], array_slice($q, 1));
// combining not and anything else than media type
is too risky and should be avoided
if (! $mediaTypeOnly) {
if (in_array(Type::T_NOT, $newType) || ($type
&& in_array(Type::T_NOT, $type) )) {
if ($type) {
array_unshift($parts, implode('
', array_filter($type)));
}
if (! empty($parts)) {
if (strlen($current)) {
$current .=
$this->formatter->tagSeparator;
}
$current .= implode(' and ',
$parts);
}
if ($current) {
$out[] = $start . $current;
}
$current = "";
$type = null;
$parts = [];
}
}
if ($newType === ['all'] &&
$default) {
$default = $start . 'all';
}
// all can be safely ignored and mixed with
whatever else
if ($newType !== ['all']) {
if ($type) {
$type = $this->mergeMediaTypes($type,
$newType);
if (empty($type)) {
// merge failed : ignore this query
that is not valid, skip to the next one
$parts = [];
$default = ''; // if
everything fail, no @media at all
continue 3;
}
} else {
$type = $newType;
}
}
break;
case Type::T_MEDIA_EXPRESSION:
if (isset($q[2])) {
$parts[] = '('
. $this->compileValue($q[1])
. $this->formatter->assignSeparator
. $this->compileValue($q[2])
. ')';
} else {
$parts[] = '('
. $this->compileValue($q[1])
. ')';
}
break;
case Type::T_MEDIA_VALUE:
$parts[] = $this->compileValue($q[1]);
break;
}
}
if ($type) {
array_unshift($parts, implode(' ',
array_filter($type)));
}
if (! empty($parts)) {
if (strlen($current)) {
$current .= $this->formatter->tagSeparator;
}
$current .= implode(' and ', $parts);
}
}
if ($current) {
$out[] = $start . $current;
}
// no @media type except all, and no conflict?
if (! $out && $default) {
$out[] = $default;
}
return $out;
}
/**
* Merge direct relationships between selectors
*
* @param array $selectors1
* @param array $selectors2
*
* @return array
*/
protected function mergeDirectRelationships($selectors1, $selectors2)
{
if (empty($selectors1) || empty($selectors2)) {
return array_merge($selectors1, $selectors2);
}
$part1 = end($selectors1);
$part2 = end($selectors2);
if (! $this->isImmediateRelationshipCombinator($part1[0])
&& $part1 !== $part2) {
return array_merge($selectors1, $selectors2);
}
$merged = [];
do {
$part1 = array_pop($selectors1);
$part2 = array_pop($selectors2);
if (! $this->isImmediateRelationshipCombinator($part1[0])
&& $part1 !== $part2) {
if
($this->isImmediateRelationshipCombinator(reset($merged)[0])) {
array_unshift($merged, [$part1[0] . $part2[0]]);
$merged = array_merge($selectors1, $selectors2,
$merged);
} else {
$merged = array_merge($selectors1, [$part1],
$selectors2, [$part2], $merged);
}
break;
}
array_unshift($merged, $part1);
} while (! empty($selectors1) && ! empty($selectors2));
return $merged;
}
/**
* Merge media types
*
* @param array $type1
* @param array $type2
*
* @return array|null
*/
protected function mergeMediaTypes($type1, $type2)
{
if (empty($type1)) {
return $type2;
}
if (empty($type2)) {
return $type1;
}
$m1 = '';
$t1 = '';
if (count($type1) > 1) {
$m1= strtolower($type1[0]);
$t1= strtolower($type1[1]);
} else {
$t1 = strtolower($type1[0]);
}
$m2 = '';
$t2 = '';
if (count($type2) > 1) {
$m2 = strtolower($type2[0]);
$t2 = strtolower($type2[1]);
} else {
$t2 = strtolower($type2[0]);
}
if (($m1 === Type::T_NOT) ^ ($m2 === Type::T_NOT)) {
if ($t1 === $t2) {
return null;
}
return [
$m1 === Type::T_NOT ? $m2 : $m1,
$m1 === Type::T_NOT ? $t2 : $t1,
];
}
if ($m1 === Type::T_NOT && $m2 === Type::T_NOT) {
// CSS has no way of representing "neither screen nor
print"
if ($t1 !== $t2) {
return null;
}
return [Type::T_NOT, $t1];
}
if ($t1 !== $t2) {
return null;
}
// t1 == t2, neither m1 nor m2 are "not"
return [empty($m1)? $m2 : $m1, $t1];
}
/**
* Compile import; returns true if the value was something that could
be imported
*
* @param array $rawPath
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
* @param boolean $once
*
* @return boolean
*/
protected function compileImport($rawPath, OutputBlock $out, $once =
false)
{
if ($rawPath[0] === Type::T_STRING) {
$path = $this->compileStringContent($rawPath);
if ($path = $this->findImport($path)) {
if (! $once || ! in_array($path, $this->importedFiles))
{
$this->importFile($path, $out);
$this->importedFiles[] = $path;
}
return true;
}
return false;
}
if ($rawPath[0] === Type::T_LIST) {
// handle a list of strings
if (count($rawPath[2]) === 0) {
return false;
}
foreach ($rawPath[2] as $path) {
if ($path[0] !== Type::T_STRING) {
return false;
}
}
foreach ($rawPath[2] as $path) {
$this->compileImport($path, $out);
}
return true;
}
return false;
}
/**
* Compile child; returns a value to halt execution
*
* @param array $child
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
*
* @return array
*/
protected function compileChild($child, OutputBlock $out)
{
if (isset($child[Parser::SOURCE_LINE])) {
$this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ?
$child[Parser::SOURCE_INDEX] : null;
$this->sourceLine = isset($child[Parser::SOURCE_LINE]) ?
$child[Parser::SOURCE_LINE] : -1;
$this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ?
$child[Parser::SOURCE_COLUMN] : -1;
} elseif (is_array($child) &&
isset($child[1]->sourceLine)) {
$this->sourceIndex = $child[1]->sourceIndex;
$this->sourceLine = $child[1]->sourceLine;
$this->sourceColumn = $child[1]->sourceColumn;
} elseif (! empty($out->sourceLine) && !
empty($out->sourceName)) {
$this->sourceLine = $out->sourceLine;
$this->sourceIndex = array_search($out->sourceName,
$this->sourceNames);
if ($this->sourceIndex === false) {
$this->sourceIndex = null;
}
}
switch ($child[0]) {
case Type::T_SCSSPHP_IMPORT_ONCE:
$rawPath = $this->reduce($child[1]);
if (! $this->compileImport($rawPath, $out, true)) {
$out->lines[] = '@import ' .
$this->compileValue($rawPath) . ';';
}
break;
case Type::T_IMPORT:
$rawPath = $this->reduce($child[1]);
if (! $this->compileImport($rawPath, $out)) {
$out->lines[] = '@import ' .
$this->compileValue($rawPath) . ';';
}
break;
case Type::T_DIRECTIVE:
$this->compileDirective($child[1]);
break;
case Type::T_AT_ROOT:
$this->compileAtRoot($child[1]);
break;
case Type::T_MEDIA:
$this->compileMedia($child[1]);
break;
case Type::T_BLOCK:
$this->compileBlock($child[1]);
break;
case Type::T_CHARSET:
if (! $this->charsetSeen) {
$this->charsetSeen = true;
$out->lines[] = '@charset ' .
$this->compileValue($child[1]) . ';';
}
break;
case Type::T_ASSIGN:
list(, $name, $value) = $child;
if ($name[0] === Type::T_VARIABLE) {
$flags = isset($child[3]) ? $child[3] : [];
$isDefault = in_array('!default', $flags);
$isGlobal = in_array('!global', $flags);
if ($isGlobal) {
$this->set($name[1], $this->reduce($value),
false, $this->rootEnv, $value);
break;
}
$shouldSet = $isDefault &&
(($result = $this->get($name[1], false)) ===
null
|| $result === static::$null);
if (! $isDefault || $shouldSet) {
$this->set($name[1], $this->reduce($value),
true, null, $value);
}
break;
}
$compiledName = $this->compileValue($name);
// handle shorthand syntax: size / line-height
if ($compiledName === 'font' || $compiledName ===
'grid-row' || $compiledName === 'grid-column') {
if ($value[0] === Type::T_VARIABLE) {
// if the font value comes from variable, the
content is already reduced
// (i.e., formulas were already calculated), so we
need the original unreduced value
$value = $this->get($value[1], true, null,
true);
}
$fontValue=&$value;
if ($value[0] === Type::T_LIST &&
$value[1]==',') {
// this is the case if more than one font is given:
example: "font: 400 1em/1.3 arial,helvetica"
// we need to handle the first list element
$fontValue=&$value[2][0];
}
if ($fontValue[0] === Type::T_EXPRESSION &&
$fontValue[1] === '/') {
$fontValue = $this->expToString($fontValue);
} elseif ($fontValue[0] === Type::T_LIST) {
foreach ($fontValue[2] as &$item) {
if ($item[0] === Type::T_EXPRESSION &&
$item[1] === '/') {
$item = $this->expToString($item);
}
}
}
}
// if the value reduces to null from something else then
// the property should be discarded
if ($value[0] !== Type::T_NULL) {
$value = $this->reduce($value);
if ($value[0] === Type::T_NULL || $value ===
static::$nullString) {
break;
}
}
$compiledValue = $this->compileValue($value);
$out->lines[] = $this->formatter->property(
$compiledName,
$compiledValue
);
break;
case Type::T_COMMENT:
if ($out->type === Type::T_ROOT) {
$this->compileComment($child);
break;
}
$out->lines[] = $child[1];
break;
case Type::T_MIXIN:
case Type::T_FUNCTION:
list(, $block) = $child;
$this->set(static::$namespaces[$block->type] .
$block->name, $block);
break;
case Type::T_EXTEND:
foreach ($child[1] as $sel) {
$results = $this->evalSelectors([$sel]);
foreach ($results as $result) {
// only use the first one
$result = current($result);
$this->pushExtends($result, $out->selectors,
$child);
}
}
break;
case Type::T_IF:
list(, $if) = $child;
if ($this->isTruthy($this->reduce($if->cond,
true))) {
return $this->compileChildren($if->children,
$out);
}
foreach ($if->cases as $case) {
if ($case->type === Type::T_ELSE ||
$case->type === Type::T_ELSEIF &&
$this->isTruthy($this->reduce($case->cond))
) {
return
$this->compileChildren($case->children, $out);
}
}
break;
case Type::T_EACH:
list(, $each) = $child;
$list =
$this->coerceList($this->reduce($each->list));
$this->pushEnv();
foreach ($list[2] as $item) {
if (count($each->vars) === 1) {
$this->set($each->vars[0], $item, true);
} else {
list(,, $values) = $this->coerceList($item);
foreach ($each->vars as $i => $var) {
$this->set($var, isset($values[$i]) ?
$values[$i] : static::$null, true);
}
}
$ret = $this->compileChildren($each->children,
$out);
if ($ret) {
if ($ret[0] !== Type::T_CONTROL) {
$this->popEnv();
return $ret;
}
if ($ret[1]) {
break;
}
}
}
$this->popEnv();
break;
case Type::T_WHILE:
list(, $while) = $child;
while ($this->isTruthy($this->reduce($while->cond,
true))) {
$ret = $this->compileChildren($while->children,
$out);
if ($ret) {
if ($ret[0] !== Type::T_CONTROL) {
return $ret;
}
if ($ret[1]) {
break;
}
}
}
break;
case Type::T_FOR:
list(, $for) = $child;
$start = $this->reduce($for->start, true);
$end = $this->reduce($for->end, true);
if (! ($start[2] == $end[2] || $end->unitless())) {
$this->throwError('Incompatible units:
"%s" and "%s".', $start->unitStr(),
$end->unitStr());
break;
}
$unit = $start[2];
$start = $start[1];
$end = $end[1];
$d = $start < $end ? 1 : -1;
for (;;) {
if ((! $for->until && $start - $d == $end)
||
($for->until && $start == $end)
) {
break;
}
$this->set($for->var, new Node\Number($start,
$unit));
$start += $d;
$ret = $this->compileChildren($for->children,
$out);
if ($ret) {
if ($ret[0] !== Type::T_CONTROL) {
return $ret;
}
if ($ret[1]) {
break;
}
}
}
break;
case Type::T_BREAK:
return [Type::T_CONTROL, true];
case Type::T_CONTINUE:
return [Type::T_CONTROL, false];
case Type::T_RETURN:
return $this->reduce($child[1], true);
case Type::T_NESTED_PROPERTY:
list(, $prop) = $child;
$prefixed = [];
$prefix = $this->compileValue($prop->prefix) .
'-';
foreach ($prop->children as $child) {
switch ($child[0]) {
case Type::T_ASSIGN:
array_unshift($child[1][2], $prefix);
break;
case Type::T_NESTED_PROPERTY:
array_unshift($child[1]->prefix[2],
$prefix);
break;
}
$prefixed[] = $child;
}
$this->compileChildrenNoReturn($prefixed, $out);
break;
case Type::T_INCLUDE:
// including a mixin
list(, $name, $argValues, $content) = $child;
$mixin =
$this->get(static::$namespaces['mixin'] . $name, false);
if (! $mixin) {
$this->throwError("Undefined mixin
$name");
break;
}
$callingScope = $this->getStoreEnv();
// push scope, apply args
$this->pushEnv();
$this->env->depth--;
$storeEnv = $this->storeEnv;
$this->storeEnv = $this->env;
// Find the parent selectors in the env to be able to know
what '&' refers to in the mixin
// and assign this fake parent to childs
$selfParent = null;
if (isset($child['selfParent']) &&
isset($child['selfParent']->selectors)) {
$selfParent = $child['selfParent'];
} else {
$parentSelectors =
$this->multiplySelectors($this->env);
if ($parentSelectors) {
$parent = new Block();
$parent->selectors = $parentSelectors;
foreach ($mixin->children as $k => $child) {
if (isset($child[1]) &&
is_object($child[1]) && $child[1] instanceof Block) {
$mixin->children[$k][1]->parent =
$parent;
}
}
}
}
// clone the stored content to not have its scope spoiled
by a further call to the same mixin
// i.e., recursive @include of the same mixin
if (isset($content)) {
$copyContent = clone $content;
$copyContent->scope = $callingScope;
$this->setRaw(static::$namespaces['special'] .
'content', $copyContent, $this->env);
}
if (isset($mixin->args)) {
$this->applyArguments($mixin->args, $argValues);
}
$this->env->marker = 'mixin';
$this->compileChildrenNoReturn($mixin->children,
$out, $selfParent, $this->env->marker . " " . $name);
$this->storeEnv = $storeEnv;
$this->popEnv();
break;
case Type::T_MIXIN_CONTENT:
$env = isset($this->storeEnv) ? $this->storeEnv :
$this->env;
$content =
$this->get(static::$namespaces['special'] .
'content', false, $env);
if (! $content) {
$content = new \stdClass();
$content->scope = new \stdClass();
$content->children =
$this->storeEnv->parent->block->children;
break;
}
$storeEnv = $this->storeEnv;
$this->storeEnv = $content->scope;
$this->compileChildrenNoReturn($content->children,
$out);
$this->storeEnv = $storeEnv;
break;
case Type::T_DEBUG:
list(, $value) = $child;
$fname = $this->sourceNames[$this->sourceIndex];
$line = $this->sourceLine;
$value = $this->compileValue($this->reduce($value,
true));
fwrite($this->stderr, "File $fname on line $line
DEBUG: $value\n");
break;
case Type::T_WARN:
list(, $value) = $child;
$fname = $this->sourceNames[$this->sourceIndex];
$line = $this->sourceLine;
$value = $this->compileValue($this->reduce($value,
true));
fwrite($this->stderr, "File $fname on line $line
WARN: $value\n");
break;
case Type::T_ERROR:
list(, $value) = $child;
$fname = $this->sourceNames[$this->sourceIndex];
$line = $this->sourceLine;
$value = $this->compileValue($this->reduce($value,
true));
$this->throwError("File $fname on line $line ERROR:
$value\n");
break;
case Type::T_CONTROL:
$this->throwError('@break/@continue not permitted
in this scope');
break;
default:
$this->throwError("unknown child type:
$child[0]");
}
}
/**
* Reduce expression to string
*
* @param array $exp
*
* @return array
*/
protected function expToString($exp)
{
list(, $op, $left, $right, /* $inParens */, $whiteLeft,
$whiteRight) = $exp;
$content = [$this->reduce($left)];
if ($whiteLeft) {
$content[] = ' ';
}
$content[] = $op;
if ($whiteRight) {
$content[] = ' ';
}
$content[] = $this->reduce($right);
return [Type::T_STRING, '', $content];
}
/**
* Is truthy?
*
* @param array $value
*
* @return boolean
*/
protected function isTruthy($value)
{
return $value !== static::$false && $value !==
static::$null;
}
/**
* Is the value a direct relationship combinator?
*
* @param string $value
*
* @return boolean
*/
protected function isImmediateRelationshipCombinator($value)
{
return $value === '>' || $value === '+' ||
$value === '~';
}
/**
* Should $value cause its operand to eval
*
* @param array $value
*
* @return boolean
*/
protected function shouldEval($value)
{
switch ($value[0]) {
case Type::T_EXPRESSION:
if ($value[1] === '/') {
return $this->shouldEval($value[2]) ||
$this->shouldEval($value[3]);
}
// fall-thru
case Type::T_VARIABLE:
case Type::T_FUNCTION_CALL:
return true;
}
return false;
}
/**
* Reduce value
*
* @param array $value
* @param boolean $inExp
*
* @return array|\Leafo\ScssPhp\Node\Number
*/
protected function reduce($value, $inExp = false)
{
switch ($value[0]) {
case Type::T_EXPRESSION:
list(, $op, $left, $right, $inParens) = $value;
$opName = isset(static::$operatorNames[$op]) ?
static::$operatorNames[$op] : $op;
$inExp = $inExp || $this->shouldEval($left) ||
$this->shouldEval($right);
$left = $this->reduce($left, true);
if ($op !== 'and' && $op !==
'or') {
$right = $this->reduce($right, true);
}
// special case: looks like css shorthand
if ($opName == 'div' && ! $inParens
&& ! $inExp && isset($right[2])
&& (($right[0] !== Type::T_NUMBER &&
$right[2] != '')
|| ($right[0] === Type::T_NUMBER && !
$right->unitless()))
) {
return $this->expToString($value);
}
$left = $this->coerceForExpression($left);
$right = $this->coerceForExpression($right);
$ltype = $left[0];
$rtype = $right[0];
$ucOpName = ucfirst($opName);
$ucLType = ucfirst($ltype);
$ucRType = ucfirst($rtype);
// this tries:
// 1. op[op name][left type][right type]
// 2. op[left type][right type] (passing the op as first
arg
// 3. op[op name]
$fn = "op${ucOpName}${ucLType}${ucRType}";
if (is_callable([$this, $fn]) ||
(($fn = "op${ucLType}${ucRType}") &&
is_callable([$this, $fn]) &&
$passOp = true) ||
(($fn = "op${ucOpName}") &&
is_callable([$this, $fn]) &&
$genOp = true)
) {
$coerceUnit = false;
if (! isset($genOp) &&
$left[0] === Type::T_NUMBER && $right[0]
=== Type::T_NUMBER
) {
$coerceUnit = true;
switch ($opName) {
case 'mul':
$targetUnit = $left[2];
foreach ($right[2] as $unit => $exp) {
$targetUnit[$unit] =
(isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) + $exp;
}
break;
case 'div':
$targetUnit = $left[2];
foreach ($right[2] as $unit => $exp) {
$targetUnit[$unit] =
(isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) - $exp;
}
break;
case 'mod':
$targetUnit = $left[2];
break;
default:
$targetUnit = $left->unitless() ?
$right[2] : $left[2];
}
if (! $left->unitless() && !
$right->unitless()) {
$left = $left->normalize();
$right = $right->normalize();
}
}
$shouldEval = $inParens || $inExp;
if (isset($passOp)) {
$out = $this->$fn($op, $left, $right,
$shouldEval);
} else {
$out = $this->$fn($left, $right, $shouldEval);
}
if (isset($out)) {
if ($coerceUnit && $out[0] ===
Type::T_NUMBER) {
$out = $out->coerce($targetUnit);
}
return $out;
}
}
return $this->expToString($value);
case Type::T_UNARY:
list(, $op, $exp, $inParens) = $value;
$inExp = $inExp || $this->shouldEval($exp);
$exp = $this->reduce($exp);
if ($exp[0] === Type::T_NUMBER) {
switch ($op) {
case '+':
return new Node\Number($exp[1], $exp[2]);
case '-':
return new Node\Number(-$exp[1], $exp[2]);
}
}
if ($op === 'not') {
if ($inExp || $inParens) {
if ($exp === static::$false || $exp ===
static::$null) {
return static::$true;
}
return static::$false;
}
$op = $op . ' ';
}
return [Type::T_STRING, '', [$op, $exp]];
case Type::T_VARIABLE:
return $this->reduce($this->get($value[1]));
case Type::T_LIST:
foreach ($value[2] as &$item) {
$item = $this->reduce($item);
}
return $value;
case Type::T_MAP:
foreach ($value[1] as &$item) {
$item = $this->reduce($item);
}
foreach ($value[2] as &$item) {
$item = $this->reduce($item);
}
return $value;
case Type::T_STRING:
foreach ($value[2] as &$item) {
if (is_array($item) || $item instanceof \ArrayAccess) {
$item = $this->reduce($item);
}
}
return $value;
case Type::T_INTERPOLATE:
$value[1] = $this->reduce($value[1]);
if ($inExp) {
return $value[1];
}
return $value;
case Type::T_FUNCTION_CALL:
return $this->fncall($value[1], $value[2]);
case Type::T_SELF:
$selfSelector = $this->multiplySelectors($this->env);
$selfSelector = $this->collapseSelectors($selfSelector,
true);
return $selfSelector;
default:
return $value;
}
}
/**
* Function caller
*
* @param string $name
* @param array $argValues
*
* @return array|null
*/
protected function fncall($name, $argValues)
{
// SCSS @function
if ($this->callScssFunction($name, $argValues, $returnValue)) {
return $returnValue;
}
// native PHP functions
if ($this->callNativeFunction($name, $argValues, $returnValue))
{
return $returnValue;
}
// for CSS functions, simply flatten the arguments into a list
$listArgs = [];
foreach ((array) $argValues as $arg) {
if (empty($arg[0])) {
$listArgs[] = $this->reduce($arg[1]);
}
}
return [Type::T_FUNCTION, $name, [Type::T_LIST, ',',
$listArgs]];
}
/**
* Normalize name
*
* @param string $name
*
* @return string
*/
protected function normalizeName($name)
{
return str_replace('-', '_', $name);
}
/**
* Normalize value
*
* @param array $value
*
* @return array
*/
public function normalizeValue($value)
{
$value = $this->coerceForExpression($this->reduce($value));
switch ($value[0]) {
case Type::T_LIST:
$value = $this->extractInterpolation($value);
if ($value[0] !== Type::T_LIST) {
return [Type::T_KEYWORD,
$this->compileValue($value)];
}
foreach ($value[2] as $key => $item) {
$value[2][$key] = $this->normalizeValue($item);
}
return $value;
case Type::T_STRING:
return [$value[0], '"',
[$this->compileStringContent($value)]];
case Type::T_NUMBER:
return $value->normalize();
case Type::T_INTERPOLATE:
return [Type::T_KEYWORD, $this->compileValue($value)];
default:
return $value;
}
}
/**
* Add numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opAddNumberNumber($left, $right)
{
return new Node\Number($left[1] + $right[1], $left[2]);
}
/**
* Multiply numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opMulNumberNumber($left, $right)
{
return new Node\Number($left[1] * $right[1], $left[2]);
}
/**
* Subtract numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opSubNumberNumber($left, $right)
{
return new Node\Number($left[1] - $right[1], $left[2]);
}
/**
* Divide numbers
*
* @param array $left
* @param array $right
*
* @return array|\Leafo\ScssPhp\Node\Number
*/
protected function opDivNumberNumber($left, $right)
{
if ($right[1] == 0) {
return [Type::T_STRING, '', [$left[1] . $left[2] .
'/' . $right[1] . $right[2]]];
}
return new Node\Number($left[1] / $right[1], $left[2]);
}
/**
* Mod numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opModNumberNumber($left, $right)
{
return new Node\Number($left[1] % $right[1], $left[2]);
}
/**
* Add strings
*
* @param array $left
* @param array $right
*
* @return array|null
*/
protected function opAdd($left, $right)
{
if ($strLeft = $this->coerceString($left)) {
if ($right[0] === Type::T_STRING) {
$right[1] = '';
}
$strLeft[2][] = $right;
return $strLeft;
}
if ($strRight = $this->coerceString($right)) {
if ($left[0] === Type::T_STRING) {
$left[1] = '';
}
array_unshift($strRight[2], $left);
return $strRight;
}
return null;
}
/**
* Boolean and
*
* @param array $left
* @param array $right
* @param boolean $shouldEval
*
* @return array|null
*/
protected function opAnd($left, $right, $shouldEval)
{
$truthy = ($left === static::$null || $right === static::$null) ||
($left === static::$false || $left === static::$true)
&&
($right === static::$false || $right === static::$true);
if (! $shouldEval) {
if (! $truthy) {
return null;
}
}
if ($left !== static::$false && $left !== static::$null) {
return $this->reduce($right, true);
}
return $left;
}
/**
* Boolean or
*
* @param array $left
* @param array $right
* @param boolean $shouldEval
*
* @return array|null
*/
protected function opOr($left, $right, $shouldEval)
{
$truthy = ($left === static::$null || $right === static::$null) ||
($left === static::$false || $left === static::$true)
&&
($right === static::$false || $right === static::$true);
if (! $shouldEval) {
if (! $truthy) {
return null;
}
}
if ($left !== static::$false && $left !== static::$null) {
return $left;
}
return $this->reduce($right, true);
}
/**
* Compare colors
*
* @param string $op
* @param array $left
* @param array $right
*
* @return array
*/
protected function opColorColor($op, $left, $right)
{
$out = [Type::T_COLOR];
foreach ([1, 2, 3] as $i) {
$lval = isset($left[$i]) ? $left[$i] : 0;
$rval = isset($right[$i]) ? $right[$i] : 0;
switch ($op) {
case '+':
$out[] = $lval + $rval;
break;
case '-':
$out[] = $lval - $rval;
break;
case '*':
$out[] = $lval * $rval;
break;
case '%':
$out[] = $lval % $rval;
break;
case '/':
if ($rval == 0) {
$this->throwError("color: Can't divide
by zero");
break 2;
}
$out[] = (int) ($lval / $rval);
break;
case '==':
return $this->opEq($left, $right);
case '!=':
return $this->opNeq($left, $right);
default:
$this->throwError("color: unknown op
$op");
break 2;
}
}
if (isset($left[4])) {
$out[4] = $left[4];
} elseif (isset($right[4])) {
$out[4] = $right[4];
}
return $this->fixColor($out);
}
/**
* Compare color and number
*
* @param string $op
* @param array $left
* @param array $right
*
* @return array
*/
protected function opColorNumber($op, $left, $right)
{
$value = $right[1];
return $this->opColorColor(
$op,
$left,
[Type::T_COLOR, $value, $value, $value]
);
}
/**
* Compare number and color
*
* @param string $op
* @param array $left
* @param array $right
*
* @return array
*/
protected function opNumberColor($op, $left, $right)
{
$value = $left[1];
return $this->opColorColor(
$op,
[Type::T_COLOR, $value, $value, $value],
$right
);
}
/**
* Compare number1 == number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opEq($left, $right)
{
if (($lStr = $this->coerceString($left)) && ($rStr =
$this->coerceString($right))) {
$lStr[1] = '';
$rStr[1] = '';
$left = $this->compileValue($lStr);
$right = $this->compileValue($rStr);
}
return $this->toBool($left === $right);
}
/**
* Compare number1 != number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opNeq($left, $right)
{
if (($lStr = $this->coerceString($left)) && ($rStr =
$this->coerceString($right))) {
$lStr[1] = '';
$rStr[1] = '';
$left = $this->compileValue($lStr);
$right = $this->compileValue($rStr);
}
return $this->toBool($left !== $right);
}
/**
* Compare number1 >= number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opGteNumberNumber($left, $right)
{
return $this->toBool($left[1] >= $right[1]);
}
/**
* Compare number1 > number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opGtNumberNumber($left, $right)
{
return $this->toBool($left[1] > $right[1]);
}
/**
* Compare number1 <= number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opLteNumberNumber($left, $right)
{
return $this->toBool($left[1] <= $right[1]);
}
/**
* Compare number1 < number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opLtNumberNumber($left, $right)
{
return $this->toBool($left[1] < $right[1]);
}
/**
* Three-way comparison, aka spaceship operator
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opCmpNumberNumber($left, $right)
{
$n = $left[1] - $right[1];
return new Node\Number($n ? $n / abs($n) : 0, '');
}
/**
* Cast to boolean
*
* @api
*
* @param mixed $thing
*
* @return array
*/
public function toBool($thing)
{
return $thing ? static::$true : static::$false;
}
/**
* Compiles a primitive value into a CSS property value.
*
* Values in scssphp are typed by being wrapped in arrays, their format
is
* typically:
*
* array(type, contents [, additional_contents]*)
*
* The input is expected to be reduced. This function will not work on
* things like expressions and variables.
*
* @api
*
* @param array $value
*
* @return string
*/
public function compileValue($value)
{
$value = $this->reduce($value);
switch ($value[0]) {
case Type::T_KEYWORD:
return $value[1];
case Type::T_COLOR:
// [1] - red component (either number for a %)
// [2] - green component
// [3] - blue component
// [4] - optional alpha component
list(, $r, $g, $b) = $value;
$r = round($r);
$g = round($g);
$b = round($b);
if (count($value) === 5 && $value[4] !== 1) { //
rgba
$a = new Node\Number($value[4], '');
return 'rgba(' . $r . ', ' . $g .
', ' . $b . ', ' . $a . ')';
}
$h = sprintf('#%02x%02x%02x', $r, $g, $b);
// Converting hex color to short notation (e.g. #003399 to
#039)
if ($h[1] === $h[2] && $h[3] === $h[4] &&
$h[5] === $h[6]) {
$h = '#' . $h[1] . $h[3] . $h[5];
}
return $h;
case Type::T_NUMBER:
return $value->output($this);
case Type::T_STRING:
return $value[1] . $this->compileStringContent($value) .
$value[1];
case Type::T_FUNCTION:
$args = ! empty($value[2]) ?
$this->compileValue($value[2]) : '';
return "$value[1]($args)";
case Type::T_LIST:
$value = $this->extractInterpolation($value);
if ($value[0] !== Type::T_LIST) {
return $this->compileValue($value);
}
list(, $delim, $items) = $value;
if ($delim !== ' ') {
$delim .= ' ';
}
$filtered = [];
foreach ($items as $item) {
if ($item[0] === Type::T_NULL) {
continue;
}
$filtered[] = $this->compileValue($item);
}
return implode("$delim", $filtered);
case Type::T_MAP:
$keys = $value[1];
$values = $value[2];
$filtered = [];
for ($i = 0, $s = count($keys); $i < $s; $i++) {
$filtered[$this->compileValue($keys[$i])] =
$this->compileValue($values[$i]);
}
array_walk($filtered, function (&$value, $key) {
$value = $key . ': ' . $value;
});
return '(' . implode(', ', $filtered) .
')';
case Type::T_INTERPOLATED:
// node created by extractInterpolation
list(, $interpolate, $left, $right) = $value;
list(,, $whiteLeft, $whiteRight) = $interpolate;
$left = count($left[2]) > 0 ?
$this->compileValue($left) . $whiteLeft :
'';
$right = count($right[2]) > 0 ?
$whiteRight . $this->compileValue($right) :
'';
return $left . $this->compileValue($interpolate) .
$right;
case Type::T_INTERPOLATE:
// strip quotes if it's a string
$reduced = $this->reduce($value[1]);
switch ($reduced[0]) {
case Type::T_LIST:
$reduced =
$this->extractInterpolation($reduced);
if ($reduced[0] !== Type::T_LIST) {
break;
}
list(, $delim, $items) = $reduced;
if ($delim !== ' ') {
$delim .= ' ';
}
$filtered = [];
foreach ($items as $item) {
if ($item[0] === Type::T_NULL) {
continue;
}
$temp =
$this->compileValue([Type::T_KEYWORD, $item]);
if ($temp[0] === Type::T_STRING) {
$filtered[] =
$this->compileStringContent($temp);
} elseif ($temp[0] === Type::T_KEYWORD) {
$filtered[] = $temp[1];
} else {
$filtered[] =
$this->compileValue($temp);
}
}
$reduced = [Type::T_KEYWORD,
implode("$delim", $filtered)];
break;
case Type::T_STRING:
$reduced = [Type::T_KEYWORD,
$this->compileStringContent($reduced)];
break;
case Type::T_NULL:
$reduced = [Type::T_KEYWORD, ''];
}
return $this->compileValue($reduced);
case Type::T_NULL:
return 'null';
default:
$this->throwError("unknown value type:
$value[0]");
}
}
/**
* Flatten list
*
* @param array $list
*
* @return string
*/
protected function flattenList($list)
{
return $this->compileValue($list);
}
/**
* Compile string content
*
* @param array $string
*
* @return string
*/
protected function compileStringContent($string)
{
$parts = [];
foreach ($string[2] as $part) {
if (is_array($part) || $part instanceof \ArrayAccess) {
$parts[] = $this->compileValue($part);
} else {
$parts[] = $part;
}
}
return implode($parts);
}
/**
* Extract interpolation; it doesn't need to be recursive,
compileValue will handle that
*
* @param array $list
*
* @return array
*/
protected function extractInterpolation($list)
{
$items = $list[2];
foreach ($items as $i => $item) {
if ($item[0] === Type::T_INTERPOLATE) {
$before = [Type::T_LIST, $list[1], array_slice($items, 0,
$i)];
$after = [Type::T_LIST, $list[1], array_slice($items, $i +
1)];
return [Type::T_INTERPOLATED, $item, $before, $after];
}
}
return $list;
}
/**
* Find the final set of selectors
*
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param \Leafo\ScssPhp\Block $selfParent
*
* @return array
*/
protected function multiplySelectors(Environment $env, $selfParent =
null)
{
$envs = $this->compactEnv($env);
$selectors = [];
$parentSelectors = [[]];
$selfParentSelectors = null;
if (! is_null($selfParent) && $selfParent->selectors) {
$selfParentSelectors =
$this->evalSelectors($selfParent->selectors);
}
while ($env = array_pop($envs)) {
if (empty($env->selectors)) {
continue;
}
$selectors = $env->selectors;
do {
$stillHasSelf = false;
$prevSelectors = $selectors;
$selectors = [];
foreach ($prevSelectors as $selector) {
foreach ($parentSelectors as $parent) {
if ($selfParentSelectors) {
foreach ($selfParentSelectors as $selfParent) {
// if no '&' in the selector,
each call will give same result, only add once
$s = $this->joinSelectors($parent,
$selector, $stillHasSelf, $selfParent);
$selectors[serialize($s)] = $s;
}
} else {
$s = $this->joinSelectors($parent,
$selector, $stillHasSelf);
$selectors[serialize($s)] = $s;
}
}
}
} while ($stillHasSelf);
$parentSelectors = $selectors;
}
$selectors = array_values($selectors);
return $selectors;
}
/**
* Join selectors; looks for & to replace, or append parent before
child
*
* @param array $parent
* @param array $child
* @param boolean &$stillHasSelf
* @param array $selfParentSelectors
* @return array
*/
protected function joinSelectors($parent, $child, &$stillHasSelf,
$selfParentSelectors = null)
{
$setSelf = false;
$out = [];
foreach ($child as $part) {
$newPart = [];
foreach ($part as $p) {
// only replace & once and should be recalled to be
able to make combinations
if ($p === static::$selfSelector && $setSelf) {
$stillHasSelf = true;
}
if ($p === static::$selfSelector && ! $setSelf) {
$setSelf = true;
if (is_null($selfParentSelectors)) {
$selfParentSelectors = $parent;
}
foreach ($selfParentSelectors as $i => $parentPart)
{
if ($i > 0) {
$out[] = $newPart;
$newPart = [];
}
foreach ($parentPart as $pp) {
if (is_array($pp)) {
$flatten = [];
array_walk_recursive($pp, function ($a) use
(&$flatten) {
$flatten[] = $a;
});
$pp = implode($flatten);
}
$newPart[] = $pp;
}
}
} else {
$newPart[] = $p;
}
}
$out[] = $newPart;
}
return $setSelf ? $out : array_merge($parent, $child);
}
/**
* Multiply media
*
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param array $childQueries
*
* @return array
*/
protected function multiplyMedia(Environment $env = null, $childQueries
= null)
{
if (! isset($env) ||
! empty($env->block->type) &&
$env->block->type !== Type::T_MEDIA
) {
return $childQueries;
}
// plain old block, skip
if (empty($env->block->type)) {
return $this->multiplyMedia($env->parent, $childQueries);
}
$parentQueries = isset($env->block->queryList)
? $env->block->queryList
: [[[Type::T_MEDIA_VALUE, $env->block->value]]];
$store = [$this->env, $this->storeEnv];
$this->env = $env;
$this->storeEnv = null;
$parentQueries = $this->evaluateMediaQuery($parentQueries);
list($this->env, $this->storeEnv) = $store;
if ($childQueries === null) {
$childQueries = $parentQueries;
} else {
$originalQueries = $childQueries;
$childQueries = [];
foreach ($parentQueries as $parentQuery) {
foreach ($originalQueries as $childQuery) {
$childQueries[] = array_merge(
$parentQuery,
[[Type::T_MEDIA_TYPE, [Type::T_KEYWORD,
'all']]],
$childQuery
);
}
}
}
return $this->multiplyMedia($env->parent, $childQueries);
}
/**
* Convert env linked list to stack
*
* @param \Leafo\ScssPhp\Compiler\Environment $env
*
* @return array
*/
protected function compactEnv(Environment $env)
{
for ($envs = []; $env; $env = $env->parent) {
$envs[] = $env;
}
return $envs;
}
/**
* Convert env stack to singly linked list
*
* @param array $envs
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function extractEnv($envs)
{
for ($env = null; $e = array_pop($envs);) {
$e->parent = $env;
$env = $e;
}
return $env;
}
/**
* Push environment
*
* @param \Leafo\ScssPhp\Block $block
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function pushEnv(Block $block = null)
{
$env = new Environment;
$env->parent = $this->env;
$env->store = [];
$env->block = $block;
$env->depth = isset($this->env->depth) ?
$this->env->depth + 1 : 0;
$this->env = $env;
return $env;
}
/**
* Pop environment
*/
protected function popEnv()
{
$this->env = $this->env->parent;
}
/**
* Get store environment
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function getStoreEnv()
{
return isset($this->storeEnv) ? $this->storeEnv :
$this->env;
}
/**
* Set variable
*
* @param string $name
* @param mixed $value
* @param boolean $shadow
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param mixed $valueUnreduced
*/
protected function set($name, $value, $shadow = false, Environment $env
= null, $valueUnreduced = null)
{
$name = $this->normalizeName($name);
if (! isset($env)) {
$env = $this->getStoreEnv();
}
if ($shadow) {
$this->setRaw($name, $value, $env, $valueUnreduced);
} else {
$this->setExisting($name, $value, $env, $valueUnreduced);
}
}
/**
* Set existing variable
*
* @param string $name
* @param mixed $value
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param mixed $valueUnreduced
*/
protected function setExisting($name, $value, Environment $env,
$valueUnreduced = null)
{
$storeEnv = $env;
$hasNamespace = $name[0] === '^' || $name[0] ===
'@' || $name[0] === '%';
for (;;) {
if (array_key_exists($name, $env->store)) {
break;
}
if (! $hasNamespace && isset($env->marker)) {
$env = $storeEnv;
break;
}
if (! isset($env->parent)) {
$env = $storeEnv;
break;
}
$env = $env->parent;
}
$env->store[$name] = $value;
if ($valueUnreduced) {
$env->storeUnreduced[$name] = $valueUnreduced;
}
}
/**
* Set raw variable
*
* @param string $name
* @param mixed $value
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param mixed $valueUnreduced
*/
protected function setRaw($name, $value, Environment $env,
$valueUnreduced = null)
{
$env->store[$name] = $value;
if ($valueUnreduced) {
$env->storeUnreduced[$name] = $valueUnreduced;
}
}
/**
* Get variable
*
* @api
*
* @param string $name
* @param boolean $shouldThrow
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param boolean $unreduced
*
* @return mixed|null
*/
public function get($name, $shouldThrow = true, Environment $env =
null, $unreduced = false)
{
$normalizedName = $this->normalizeName($name);
$specialContentKey = static::$namespaces['special'] .
'content';
if (! isset($env)) {
$env = $this->getStoreEnv();
}
$nextIsRoot = false;
$hasNamespace = $normalizedName[0] === '^' ||
$normalizedName[0] === '@' || $normalizedName[0] ===
'%';
$maxDepth = 10000;
for (;;) {
if ($maxDepth-- <= 0) {
break;
}
if (array_key_exists($normalizedName, $env->store)) {
if ($unreduced &&
isset($env->storeUnreduced[$normalizedName])) {
return $env->storeUnreduced[$normalizedName];
}
return $env->store[$normalizedName];
}
if (! $hasNamespace && isset($env->marker)) {
if (! $nextIsRoot && !
empty($env->store[$specialContentKey])) {
$env = $env->store[$specialContentKey]->scope;
continue;
}
$env = $this->rootEnv;
continue;
}
if (! isset($env->parent)) {
break;
}
$env = $env->parent;
}
if ($shouldThrow) {
$this->throwError("Undefined variable \$$name" .
($maxDepth<=0 ? " (infinite recursion)" : ""));
}
// found nothing
return null;
}
/**
* Has variable?
*
* @param string $name
* @param \Leafo\ScssPhp\Compiler\Environment $env
*
* @return boolean
*/
protected function has($name, Environment $env = null)
{
return $this->get($name, false, $env) !== null;
}
/**
* Inject variables
*
* @param array $args
*/
protected function injectVariables(array $args)
{
if (empty($args)) {
return;
}
$parser = $this->parserFactory(__METHOD__);
foreach ($args as $name => $strValue) {
if ($name[0] === '$') {
$name = substr($name, 1);
}
if (! $parser->parseValue($strValue, $value)) {
$value = $this->coerceValue($strValue);
}
$this->set($name, $value);
}
}
/**
* Set variables
*
* @api
*
* @param array $variables
*/
public function setVariables(array $variables)
{
$this->registeredVars = array_merge($this->registeredVars,
$variables);
}
/**
* Unset variable
*
* @api
*
* @param string $name
*/
public function unsetVariable($name)
{
unset($this->registeredVars[$name]);
}
/**
* Returns list of variables
*
* @api
*
* @return array
*/
public function getVariables()
{
return $this->registeredVars;
}
/**
* Adds to list of parsed files
*
* @api
*
* @param string $path
*/
public function addParsedFile($path)
{
if (isset($path) && file_exists($path)) {
$this->parsedFiles[realpath($path)] = filemtime($path);
}
}
/**
* Returns list of parsed files
*
* @api
*
* @return array
*/
public function getParsedFiles()
{
return $this->parsedFiles;
}
/**
* Add import path
*
* @api
*
* @param string|callable $path
*/
public function addImportPath($path)
{
if (! in_array($path, $this->importPaths)) {
$this->importPaths[] = $path;
}
}
/**
* Set import paths
*
* @api
*
* @param string|array $path
*/
public function setImportPaths($path)
{
$this->importPaths = (array) $path;
}
/**
* Set number precision
*
* @api
*
* @param integer $numberPrecision
*/
public function setNumberPrecision($numberPrecision)
{
Node\Number::$precision = $numberPrecision;
}
/**
* Set formatter
*
* @api
*
* @param string $formatterName
*/
public function setFormatter($formatterName)
{
$this->formatter = $formatterName;
}
/**
* Set line number style
*
* @api
*
* @param string $lineNumberStyle
*/
public function setLineNumberStyle($lineNumberStyle)
{
$this->lineNumberStyle = $lineNumberStyle;
}
/**
* Enable/disable source maps
*
* @api
*
* @param integer $sourceMap
*/
public function setSourceMap($sourceMap)
{
$this->sourceMap = $sourceMap;
}
/**
* Set source map options
*
* @api
*
* @param array $sourceMapOptions
*/
public function setSourceMapOptions($sourceMapOptions)
{
$this->sourceMapOptions = $sourceMapOptions;
}
/**
* Register function
*
* @api
*
* @param string $name
* @param callable $func
* @param array $prototype
*/
public function registerFunction($name, $func, $prototype = null)
{
$this->userFunctions[$this->normalizeName($name)] = [$func,
$prototype];
}
/**
* Unregister function
*
* @api
*
* @param string $name
*/
public function unregisterFunction($name)
{
unset($this->userFunctions[$this->normalizeName($name)]);
}
/**
* Add feature
*
* @api
*
* @param string $name
*/
public function addFeature($name)
{
$this->registeredFeatures[$name] = true;
}
/**
* Import file
*
* @param string $path
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
*/
protected function importFile($path, OutputBlock $out)
{
// see if tree is cached
$realPath = realpath($path);
if (isset($this->importCache[$realPath])) {
$this->handleImportLoop($realPath);
$tree = $this->importCache[$realPath];
} else {
$code = file_get_contents($path);
$parser = $this->parserFactory($path);
$tree = $parser->parse($code);
$this->importCache[$realPath] = $tree;
}
$pi = pathinfo($path);
array_unshift($this->importPaths, $pi['dirname']);
$this->compileChildrenNoReturn($tree->children, $out);
array_shift($this->importPaths);
}
/**
* Return the file path for an import url if it exists
*
* @api
*
* @param string $url
*
* @return string|null
*/
public function findImport($url)
{
$urls = [];
// for "normal" scss imports (ignore vanilla css and
external requests)
if (! preg_match('/\.css$|^https?:\/\//', $url)) {
// try both normal and the _partial filename
$urls = [$url, preg_replace('/[^\/]+$/',
'_\0', $url)];
}
$hasExtension = preg_match('/[.]s?css$/', $url);
foreach ($this->importPaths as $dir) {
if (is_string($dir)) {
// check urls for normal import paths
foreach ($urls as $full) {
$separator = (
! empty($dir) &&
substr($dir, -1) !== '/' &&
substr($full, 0, 1) !== '/'
) ? '/' : '';
$full = $dir . $separator . $full;
if ($this->fileExists($file = $full .
'.scss') ||
($hasExtension &&
$this->fileExists($file = $full))
) {
return $file;
}
}
} elseif (is_callable($dir)) {
// check custom callback for import path
$file = call_user_func($dir, $url);
if ($file !== null) {
return $file;
}
}
}
return null;
}
/**
* Set encoding
*
* @api
*
* @param string $encoding
*/
public function setEncoding($encoding)
{
$this->encoding = $encoding;
}
/**
* Ignore errors?
*
* @api
*
* @param boolean $ignoreErrors
*
* @return \Leafo\ScssPhp\Compiler
*/
public function setIgnoreErrors($ignoreErrors)
{
$this->ignoreErrors = $ignoreErrors;
return $this;
}
/**
* Throw error (exception)
*
* @api
*
* @param string $msg Message with optional sprintf()-style vararg
parameters
*
* @throws \Leafo\ScssPhp\Exception\CompilerException
*/
public function throwError($msg)
{
if ($this->ignoreErrors) {
return;
}
$line = $this->sourceLine;
$column = $this->sourceColumn;
$loc = isset($this->sourceNames[$this->sourceIndex])
? $this->sourceNames[$this->sourceIndex] . " on
line $line, at column $column"
: "line: $line, column: $column";
if (func_num_args() > 1) {
$msg = call_user_func_array('sprintf',
func_get_args());
}
$msg = "$msg: $loc";
$callStackMsg = $this->callStackMessage();
if ($callStackMsg) {
$msg .= "\nCall Stack:\n" . $callStackMsg;
}
throw new CompilerException($msg);
}
/**
* Beautify call stack for output
*
* @param boolean $all
* @param null $limit
*
* @return string
*/
protected function callStackMessage($all = false, $limit = null)
{
$callStackMsg = [];
$ncall = 0;
if ($this->callStack) {
foreach (array_reverse($this->callStack) as $call) {
if ($all || (isset($call['n']) &&
$call['n'])) {
$msg = "#" . $ncall++ . " " .
$call['n'] . " ";
$msg .=
(isset($this->sourceNames[$call[Parser::SOURCE_INDEX]])
?
$this->sourceNames[$call[Parser::SOURCE_INDEX]]
: '(unknown file)');
$msg .= " on line " .
$call[Parser::SOURCE_LINE];
$callStackMsg[] = $msg;
if (! is_null($limit) && $ncall>$limit) {
break;
}
}
}
}
return implode("\n", $callStackMsg);
}
/**
* Handle import loop
*
* @param string $name
*
* @throws \Exception
*/
protected function handleImportLoop($name)
{
for ($env = $this->env; $env; $env = $env->parent) {
$file = $this->sourceNames[$env->block->sourceIndex];
if (realpath($file) === $name) {
$this->throwError('An @import loop has been found:
%s imports %s', $file, basename($file));
break;
}
}
}
/**
* Does file exist?
*
* @param string $name
*
* @return boolean
*/
protected function fileExists($name)
{
return file_exists($name) && is_file($name);
}
/**
* Call SCSS @function
*
* @param string $name
* @param array $argValues
* @param array $returnValue
*
* @return boolean Returns true if returnValue is set; otherwise, false
*/
protected function callScssFunction($name, $argValues,
&$returnValue)
{
$func = $this->get(static::$namespaces['function'] .
$name, false);
if (! $func) {
return false;
}
$this->pushEnv();
$storeEnv = $this->storeEnv;
$this->storeEnv = $this->env;
// set the args
if (isset($func->args)) {
$this->applyArguments($func->args, $argValues);
}
// throw away lines and children
$tmp = new OutputBlock;
$tmp->lines = [];
$tmp->children = [];
$this->env->marker = 'function';
$ret = $this->compileChildren($func->children, $tmp,
$this->env->marker . " " . $name);
$this->storeEnv = $storeEnv;
$this->popEnv();
$returnValue = ! isset($ret) ? static::$defaultValue : $ret;
return true;
}
/**
* Call built-in and registered (PHP) functions
*
* @param string $name
* @param array $args
* @param array $returnValue
*
* @return boolean Returns true if returnValue is set; otherwise, false
*/
protected function callNativeFunction($name, $args, &$returnValue)
{
// try a lib function
$name = $this->normalizeName($name);
if (isset($this->userFunctions[$name])) {
// see if we can find a user function
list($f, $prototype) = $this->userFunctions[$name];
} elseif (($f = $this->getBuiltinFunction($name)) &&
is_callable($f)) {
$libName = $f[1];
$prototype = isset(static::$$libName) ? static::$$libName :
null;
} else {
return false;
}
@list($sorted, $kwargs) = $this->sortArgs($prototype, $args);
if ($name !== 'if' && $name !== 'call')
{
foreach ($sorted as &$val) {
// @todo fix root cause for this php 7.4 hack
if ($val === null) continue;
$val = $this->reduce($val, true);
}
}
$returnValue = call_user_func($f, $sorted, $kwargs);
if (! isset($returnValue)) {
return false;
}
$returnValue = $this->coerceValue($returnValue);
return true;
}
/**
* Get built-in function
*
* @param string $name Normalized name
*
* @return array
*/
protected function getBuiltinFunction($name)
{
$libName = 'lib' . preg_replace_callback(
'/_(.)/',
function ($m) {
return ucfirst($m[1]);
},
ucfirst($name)
);
return [$this, $libName];
}
/**
* Sorts keyword arguments
*
* @param array $prototype
* @param array $args
*
* @return array
*/
protected function sortArgs($prototype, $args)
{
$keyArgs = [];
$posArgs = [];
// separate positional and keyword arguments
foreach ($args as $arg) {
list($key, $value) = $arg;
$key = $key[1];
if (empty($key)) {
$posArgs[] = empty($arg[2]) ? $value : $arg;
} else {
$keyArgs[$key] = $value;
}
}
if (! isset($prototype)) {
return [$posArgs, $keyArgs];
}
// copy positional args
$finalArgs = array_pad($posArgs, count($prototype), null);
// overwrite positional args with keyword args
foreach ($prototype as $i => $names) {
foreach ((array) $names as $name) {
if (isset($keyArgs[$name])) {
$finalArgs[$i] = $keyArgs[$name];
}
}
}
return [$finalArgs, $keyArgs];
}
/**
* Apply argument values per definition
*
* @param array $argDef
* @param array $argValues
*
* @throws \Exception
*/
protected function applyArguments($argDef, $argValues)
{
$storeEnv = $this->getStoreEnv();
$env = new Environment;
$env->store = $storeEnv->store;
$hasVariable = false;
$args = [];
foreach ($argDef as $i => $arg) {
list($name, $default, $isVariable) = $argDef[$i];
$args[$name] = [$i, $name, $default, $isVariable];
$hasVariable |= $isVariable;
}
$keywordArgs = [];
$deferredKeywordArgs = [];
$remaining = [];
// assign the keyword args
foreach ((array) $argValues as $arg) {
if (! empty($arg[0])) {
if (! isset($args[$arg[0][1]])) {
if ($hasVariable) {
$deferredKeywordArgs[$arg[0][1]] = $arg[1];
} else {
$this->throwError("Mixin or function
doesn't have an argument named $%s.", $arg[0][1]);
break;
}
} elseif ($args[$arg[0][1]][0] < count($remaining)) {
$this->throwError("The argument $%s was passed
both by position and by name.", $arg[0][1]);
break;
} else {
$keywordArgs[$arg[0][1]] = $arg[1];
}
} elseif (count($keywordArgs)) {
$this->throwError('Positional arguments must come
before keyword arguments.');
break;
} elseif ($arg[2] === true) {
$val = $this->reduce($arg[1], true);
if ($val[0] === Type::T_LIST) {
foreach ($val[2] as $name => $item) {
if (! is_numeric($name)) {
$keywordArgs[$name] = $item;
} else {
$remaining[] = $item;
}
}
} elseif ($val[0] === Type::T_MAP) {
foreach ($val[1] as $i => $name) {
$name =
$this->compileStringContent($this->coerceString($name));
$item = $val[2][$i];
if (! is_numeric($name)) {
$keywordArgs[$name] = $item;
} else {
$remaining[] = $item;
}
}
} else {
$remaining[] = $val;
}
} else {
$remaining[] = $arg[1];
}
}
foreach ($args as $arg) {
list($i, $name, $default, $isVariable) = $arg;
if ($isVariable) {
$val = [Type::T_LIST, ',', [], $isVariable];
for ($count = count($remaining); $i < $count; $i++) {
$val[2][] = $remaining[$i];
}
foreach ($deferredKeywordArgs as $itemName => $item) {
$val[2][$itemName] = $item;
}
} elseif (isset($remaining[$i])) {
$val = $remaining[$i];
} elseif (isset($keywordArgs[$name])) {
$val = $keywordArgs[$name];
} elseif (! empty($default)) {
continue;
} else {
$this->throwError("Missing argument $name");
break;
}
$this->set($name, $this->reduce($val, true), true, $env);
}
$storeEnv->store = $env->store;
foreach ($args as $arg) {
list($i, $name, $default, $isVariable) = $arg;
if ($isVariable || isset($remaining[$i]) ||
isset($keywordArgs[$name]) || empty($default)) {
continue;
}
$this->set($name, $this->reduce($default, true), true);
}
}
/**
* Coerce a php value into a scss one
*
* @param mixed $value
*
* @return array|\Leafo\ScssPhp\Node\Number
*/
protected function coerceValue($value)
{
if (is_array($value) || $value instanceof \ArrayAccess) {
return $value;
}
if (is_bool($value)) {
return $this->toBool($value);
}
if ($value === null) {
return static::$null;
}
if (is_numeric($value)) {
return new Node\Number($value, '');
}
if ($value === '') {
return static::$emptyString;
}
if (preg_match('/^(#([0-9a-f]{6})|#([0-9a-f]{3}))$/i',
$value, $m)) {
$color = [Type::T_COLOR];
if (isset($m[3])) {
$num = hexdec($m[3]);
foreach ([3, 2, 1] as $i) {
$t = $num & 0xf;
$color[$i] = $t << 4 | $t;
$num >>= 4;
}
} else {
$num = hexdec($m[2]);
foreach ([3, 2, 1] as $i) {
$color[$i] = $num & 0xff;
$num >>= 8;
}
}
return $color;
}
return [Type::T_KEYWORD, $value];
}
/**
* Coerce something to map
*
* @param array $item
*
* @return array
*/
protected function coerceMap($item)
{
if ($item[0] === Type::T_MAP) {
return $item;
}
if ($item === static::$emptyList) {
return static::$emptyMap;
}
return [Type::T_MAP, [$item], [static::$null]];
}
/**
* Coerce something to list
*
* @param array $item
* @param string $delim
*
* @return array
*/
protected function coerceList($item, $delim = ',')
{
if (isset($item) && $item[0] === Type::T_LIST) {
return $item;
}
if (isset($item) && $item[0] === Type::T_MAP) {
$keys = $item[1];
$values = $item[2];
$list = [];
for ($i = 0, $s = count($keys); $i < $s; $i++) {
$key = $keys[$i];
$value = $values[$i];
$list[] = [
Type::T_LIST,
'',
[[Type::T_KEYWORD,
$this->compileStringContent($this->coerceString($key))], $value]
];
}
return [Type::T_LIST, ',', $list];
}
return [Type::T_LIST, $delim, ! isset($item) ? []: [$item]];
}
/**
* Coerce color for expression
*
* @param array $value
*
* @return array|null
*/
protected function coerceForExpression($value)
{
if ($color = $this->coerceColor($value)) {
return $color;
}
return $value;
}
/**
* Coerce value to color
*
* @param array $value
*
* @return array|null
*/
protected function coerceColor($value)
{
switch ($value[0]) {
case Type::T_COLOR:
return $value;
case Type::T_KEYWORD:
$name = strtolower($value[1]);
if (isset(Colors::$cssColors[$name])) {
$rgba = explode(',',
Colors::$cssColors[$name]);
return isset($rgba[3])
? [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1],
(int) $rgba[2], (int) $rgba[3]]
: [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1],
(int) $rgba[2]];
}
return null;
}
return null;
}
/**
* Coerce value to string
*
* @param array $value
*
* @return array|null
*/
protected function coerceString($value)
{
if ($value[0] === Type::T_STRING) {
return $value;
}
return [Type::T_STRING, '',
[$this->compileValue($value)]];
}
/**
* Coerce value to a percentage
*
* @param array $value
*
* @return integer|float
*/
protected function coercePercent($value)
{
if ($value[0] === Type::T_NUMBER) {
if (! empty($value[2]['%'])) {
return $value[1] / 100;
}
return $value[1];
}
return 0;
}
/**
* Assert value is a map
*
* @api
*
* @param array $value
*
* @return array
*
* @throws \Exception
*/
public function assertMap($value)
{
$value = $this->coerceMap($value);
if ($value[0] !== Type::T_MAP) {
$this->throwError('expecting map, %s received',
$value[0]);
}
return $value;
}
/**
* Assert value is a list
*
* @api
*
* @param array $value
*
* @return array
*
* @throws \Exception
*/
public function assertList($value)
{
if ($value[0] !== Type::T_LIST) {
$this->throwError('expecting list, %s received',
$value[0]);
}
return $value;
}
/**
* Assert value is a color
*
* @api
*
* @param array $value
*
* @return array
*
* @throws \Exception
*/
public function assertColor($value)
{
if ($color = $this->coerceColor($value)) {
return $color;
}
$this->throwError('expecting color, %s received',
$value[0]);
}
/**
* Assert value is a number
*
* @api
*
* @param array $value
*
* @return integer|float
*
* @throws \Exception
*/
public function assertNumber($value)
{
if ($value[0] !== Type::T_NUMBER) {
$this->throwError('expecting number, %s received',
$value[0]);
}
return $value[1];
}
/**
* Make sure a color's components don't go out of bounds
*
* @param array $c
*
* @return array
*/
protected function fixColor($c)
{
foreach ([1, 2, 3] as $i) {
if ($c[$i] < 0) {
$c[$i] = 0;
}
if ($c[$i] > 255) {
$c[$i] = 255;
}
}
return $c;
}
/**
* Convert RGB to HSL
*
* @api
*
* @param integer $red
* @param integer $green
* @param integer $blue
*
* @return array
*/
public function toHSL($red, $green, $blue)
{
$min = min($red, $green, $blue);
$max = max($red, $green, $blue);
$l = $min + $max;
$d = $max - $min;
if ((int) $d === 0) {
$h = $s = 0;
} else {
if ($l < 255) {
$s = $d / $l;
} else {
$s = $d / (510 - $l);
}
if ($red == $max) {
$h = 60 * ($green - $blue) / $d;
} elseif ($green == $max) {
$h = 60 * ($blue - $red) / $d + 120;
} elseif ($blue == $max) {
$h = 60 * ($red - $green) / $d + 240;
}
}
return [Type::T_HSL, fmod($h, 360), $s * 100, $l / 5.1];
}
/**
* Hue to RGB helper
*
* @param float $m1
* @param float $m2
* @param float $h
*
* @return float
*/
protected function hueToRGB($m1, $m2, $h)
{
if ($h < 0) {
$h += 1;
} elseif ($h > 1) {
$h -= 1;
}
if ($h * 6 < 1) {
return $m1 + ($m2 - $m1) * $h * 6;
}
if ($h * 2 < 1) {
return $m2;
}
if ($h * 3 < 2) {
return $m1 + ($m2 - $m1) * (2/3 - $h) * 6;
}
return $m1;
}
/**
* Convert HSL to RGB
*
* @api
*
* @param integer $hue H from 0 to 360
* @param integer $saturation S from 0 to 100
* @param integer $lightness L from 0 to 100
*
* @return array
*/
public function toRGB($hue, $saturation, $lightness)
{
if ($hue < 0) {
$hue += 360;
}
$h = $hue / 360;
$s = min(100, max(0, $saturation)) / 100;
$l = min(100, max(0, $lightness)) / 100;
$m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;
$m1 = $l * 2 - $m2;
$r = $this->hueToRGB($m1, $m2, $h + 1/3) * 255;
$g = $this->hueToRGB($m1, $m2, $h) * 255;
$b = $this->hueToRGB($m1, $m2, $h - 1/3) * 255;
$out = [Type::T_COLOR, $r, $g, $b];
return $out;
}
// Built in functions
//protected static $libCall = ['name', 'args...'];
protected function libCall($args, $kwargs)
{
$name =
$this->compileStringContent($this->coerceString($this->reduce(array_shift($args),
true)));
$posArgs = [];
foreach ($args as $arg) {
if (empty($arg[0])) {
if ($arg[2] === true) {
$tmp = $this->reduce($arg[1]);
if ($tmp[0] === Type::T_LIST) {
foreach ($tmp[2] as $item) {
$posArgs[] = [null, $item, false];
}
} else {
$posArgs[] = [null, $tmp, true];
}
continue;
}
$posArgs[] = [null, $this->reduce($arg), false];
continue;
}
$posArgs[] = [null, $arg, false];
}
if (count($kwargs)) {
foreach ($kwargs as $key => $value) {
$posArgs[] = [[Type::T_VARIABLE, $key], $value, false];
}
}
return $this->reduce([Type::T_FUNCTION_CALL, $name, $posArgs]);
}
protected static $libIf = ['condition', 'if-true',
'if-false'];
protected function libIf($args)
{
list($cond, $t, $f) = $args;
if (! $this->isTruthy($this->reduce($cond, true))) {
return $this->reduce($f, true);
}
return $this->reduce($t, true);
}
protected static $libIndex = ['list', 'value'];
protected function libIndex($args)
{
list($list, $value) = $args;
if ($value[0] === Type::T_MAP) {
return static::$null;
}
if ($list[0] === Type::T_MAP ||
$list[0] === Type::T_STRING ||
$list[0] === Type::T_KEYWORD ||
$list[0] === Type::T_INTERPOLATE
) {
$list = $this->coerceList($list, ' ');
}
if ($list[0] !== Type::T_LIST) {
return static::$null;
}
$values = [];
foreach ($list[2] as $item) {
$values[] = $this->normalizeValue($item);
}
$key = array_search($this->normalizeValue($value), $values);
return false === $key ? static::$null : $key + 1;
}
protected static $libRgb = ['red', 'green',
'blue'];
protected function libRgb($args)
{
list($r, $g, $b) = $args;
return [Type::T_COLOR, $r[1], $g[1], $b[1]];
}
protected static $libRgba = [
['red', 'color'],
'green', 'blue', 'alpha'];
protected function libRgba($args)
{
if ($color = $this->coerceColor($args[0])) {
$num = isset($args[3]) ? $args[3] : $args[1];
$alpha = $this->assertNumber($num);
$color[4] = $alpha;
return $color;
}
list($r, $g, $b, $a) = $args;
return [Type::T_COLOR, $r[1], $g[1], $b[1], $a[1]];
}
// helper function for adjust_color, change_color, and scale_color
protected function alterColor($args, $fn)
{
$color = $this->assertColor($args[0]);
foreach ([1, 2, 3, 7] as $i) {
if (isset($args[$i])) {
$val = $this->assertNumber($args[$i]);
$ii = $i === 7 ? 4 : $i; // alpha
$color[$ii] = call_user_func($fn, isset($color[$ii]) ?
$color[$ii] : 0, $val, $i);
}
}
if (isset($args[4]) || isset($args[5]) || isset($args[6])) {
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
foreach ([4, 5, 6] as $i) {
if (isset($args[$i])) {
$val = $this->assertNumber($args[$i]);
$hsl[$i - 3] = call_user_func($fn, $hsl[$i - 3], $val,
$i);
}
}
$rgb = $this->toRGB($hsl[1], $hsl[2], $hsl[3]);
if (isset($color[4])) {
$rgb[4] = $color[4];
}
$color = $rgb;
}
return $color;
}
protected static $libAdjustColor = [
'color', 'red', 'green',
'blue',
'hue', 'saturation', 'lightness',
'alpha'
];
protected function libAdjustColor($args)
{
return $this->alterColor($args, function ($base, $alter, $i) {
return $base + $alter;
});
}
protected static $libChangeColor = [
'color', 'red', 'green',
'blue',
'hue', 'saturation', 'lightness',
'alpha'
];
protected function libChangeColor($args)
{
return $this->alterColor($args, function ($base, $alter, $i) {
return $alter;
});
}
protected static $libScaleColor = [
'color', 'red', 'green',
'blue',
'hue', 'saturation', 'lightness',
'alpha'
];
protected function libScaleColor($args)
{
return $this->alterColor($args, function ($base, $scale, $i) {
// 1, 2, 3 - rgb
// 4, 5, 6 - hsl
// 7 - a
switch ($i) {
case 1:
case 2:
case 3:
$max = 255;
break;
case 4:
$max = 360;
break;
case 7:
$max = 1;
break;
default:
$max = 100;
}
$scale = $scale / 100;
if ($scale < 0) {
return $base * $scale + $base;
}
return ($max - $base) * $scale + $base;
});
}
protected static $libIeHexStr = ['color'];
protected function libIeHexStr($args)
{
$color = $this->coerceColor($args[0]);
$color[4] = isset($color[4]) ? round(255 * $color[4]) : 255;
return sprintf('#%02X%02X%02X%02X', $color[4], $color[1],
$color[2], $color[3]);
}
protected static $libRed = ['color'];
protected function libRed($args)
{
$color = $this->coerceColor($args[0]);
return $color[1];
}
protected static $libGreen = ['color'];
protected function libGreen($args)
{
$color = $this->coerceColor($args[0]);
return $color[2];
}
protected static $libBlue = ['color'];
protected function libBlue($args)
{
$color = $this->coerceColor($args[0]);
return $color[3];
}
protected static $libAlpha = ['color'];
protected function libAlpha($args)
{
if ($color = $this->coerceColor($args[0])) {
return isset($color[4]) ? $color[4] : 1;
}
// this might be the IE function, so return value unchanged
return null;
}
protected static $libOpacity = ['color'];
protected function libOpacity($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
return $this->libAlpha($args);
}
// mix two colors
protected static $libMix = ['color-1', 'color-2',
'weight'];
protected function libMix($args)
{
list($first, $second, $weight) = $args;
$first = $this->assertColor($first);
$second = $this->assertColor($second);
if (! isset($weight)) {
$weight = 0.5;
} else {
$weight = $this->coercePercent($weight);
}
$firstAlpha = isset($first[4]) ? $first[4] : 1;
$secondAlpha = isset($second[4]) ? $second[4] : 1;
$w = $weight * 2 - 1;
$a = $firstAlpha - $secondAlpha;
$w1 = (($w * $a === -1 ? $w : ($w + $a) / (1 + $w * $a)) + 1) /
2.0;
$w2 = 1.0 - $w1;
$new = [Type::T_COLOR,
$w1 * $first[1] + $w2 * $second[1],
$w1 * $first[2] + $w2 * $second[2],
$w1 * $first[3] + $w2 * $second[3],
];
if ($firstAlpha != 1.0 || $secondAlpha != 1.0) {
$new[] = $firstAlpha * $weight + $secondAlpha * (1 - $weight);
}
return $this->fixColor($new);
}
protected static $libHsl = ['hue', 'saturation',
'lightness'];
protected function libHsl($args)
{
list($h, $s, $l) = $args;
return $this->toRGB($h[1], $s[1], $l[1]);
}
protected static $libHsla = ['hue', 'saturation',
'lightness', 'alpha'];
protected function libHsla($args)
{
list($h, $s, $l, $a) = $args;
$color = $this->toRGB($h[1], $s[1], $l[1]);
$color[4] = $a[1];
return $color;
}
protected static $libHue = ['color'];
protected function libHue($args)
{
$color = $this->assertColor($args[0]);
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
return new Node\Number($hsl[1], 'deg');
}
protected static $libSaturation = ['color'];
protected function libSaturation($args)
{
$color = $this->assertColor($args[0]);
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
return new Node\Number($hsl[2], '%');
}
protected static $libLightness = ['color'];
protected function libLightness($args)
{
$color = $this->assertColor($args[0]);
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
return new Node\Number($hsl[3], '%');
}
protected function adjustHsl($color, $idx, $amount)
{
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
$hsl[$idx] += $amount;
$out = $this->toRGB($hsl[1], $hsl[2], $hsl[3]);
if (isset($color[4])) {
$out[4] = $color[4];
}
return $out;
}
protected static $libAdjustHue = ['color',
'degrees'];
protected function libAdjustHue($args)
{
$color = $this->assertColor($args[0]);
$degrees = $this->assertNumber($args[1]);
return $this->adjustHsl($color, 1, $degrees);
}
protected static $libLighten = ['color', 'amount'];
protected function libLighten($args)
{
$color = $this->assertColor($args[0]);
$amount = Util::checkRange('amount', new Range(0, 100),
$args[1], '%');
return $this->adjustHsl($color, 3, $amount);
}
protected static $libDarken = ['color', 'amount'];
protected function libDarken($args)
{
$color = $this->assertColor($args[0]);
$amount = Util::checkRange('amount', new Range(0, 100),
$args[1], '%');
return $this->adjustHsl($color, 3, -$amount);
}
protected static $libSaturate = ['color',
'amount'];
protected function libSaturate($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
$color = $this->assertColor($value);
$amount = 100 * $this->coercePercent($args[1]);
return $this->adjustHsl($color, 2, $amount);
}
protected static $libDesaturate = ['color',
'amount'];
protected function libDesaturate($args)
{
$color = $this->assertColor($args[0]);
$amount = 100 * $this->coercePercent($args[1]);
return $this->adjustHsl($color, 2, -$amount);
}
protected static $libGrayscale = ['color'];
protected function libGrayscale($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
return $this->adjustHsl($this->assertColor($value), 2, -100);
}
protected static $libComplement = ['color'];
protected function libComplement($args)
{
return $this->adjustHsl($this->assertColor($args[0]), 1,
180);
}
protected static $libInvert = ['color'];
protected function libInvert($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
$color = $this->assertColor($value);
$color[1] = 255 - $color[1];
$color[2] = 255 - $color[2];
$color[3] = 255 - $color[3];
return $color;
}
// increases opacity by amount
protected static $libOpacify = ['color', 'amount'];
protected function libOpacify($args)
{
$color = $this->assertColor($args[0]);
$amount = $this->coercePercent($args[1]);
$color[4] = (isset($color[4]) ? $color[4] : 1) + $amount;
$color[4] = min(1, max(0, $color[4]));
return $color;
}
protected static $libFadeIn = ['color', 'amount'];
protected function libFadeIn($args)
{
return $this->libOpacify($args);
}
// decreases opacity by amount
protected static $libTransparentize = ['color',
'amount'];
protected function libTransparentize($args)
{
$color = $this->assertColor($args[0]);
$amount = $this->coercePercent($args[1]);
$color[4] = (isset($color[4]) ? $color[4] : 1) - $amount;
$color[4] = min(1, max(0, $color[4]));
return $color;
}
protected static $libFadeOut = ['color', 'amount'];
protected function libFadeOut($args)
{
return $this->libTransparentize($args);
}
protected static $libUnquote = ['string'];
protected function libUnquote($args)
{
$str = $args[0];
if ($str[0] === Type::T_STRING) {
$str[1] = '';
}
return $str;
}
protected static $libQuote = ['string'];
protected function libQuote($args)
{
$value = $args[0];
if ($value[0] === Type::T_STRING && ! empty($value[1])) {
return $value;
}
return [Type::T_STRING, '"', [$value]];
}
protected static $libPercentage = ['value'];
protected function libPercentage($args)
{
return new Node\Number($this->coercePercent($args[0]) * 100,
'%');
}
protected static $libRound = ['value'];
protected function libRound($args)
{
$num = $args[0];
return new Node\Number(round($num[1]), $num[2]);
}
protected static $libFloor = ['value'];
protected function libFloor($args)
{
$num = $args[0];
return new Node\Number(floor($num[1]), $num[2]);
}
protected static $libCeil = ['value'];
protected function libCeil($args)
{
$num = $args[0];
return new Node\Number(ceil($num[1]), $num[2]);
}
protected static $libAbs = ['value'];
protected function libAbs($args)
{
$num = $args[0];
return new Node\Number(abs($num[1]), $num[2]);
}
protected function libMin($args)
{
$numbers = $this->getNormalizedNumbers($args);
$min = null;
foreach ($numbers as $key => $number) {
if (null === $min || $number[1] <= $min[1]) {
$min = [$key, $number[1]];
}
}
return $args[$min[0]];
}
protected function libMax($args)
{
$numbers = $this->getNormalizedNumbers($args);
$max = null;
foreach ($numbers as $key => $number) {
if (null === $max || $number[1] >= $max[1]) {
$max = [$key, $number[1]];
}
}
return $args[$max[0]];
}
/**
* Helper to normalize args containing numbers
*
* @param array $args
*
* @return array
*/
protected function getNormalizedNumbers($args)
{
$unit = null;
$originalUnit = null;
$numbers = [];
foreach ($args as $key => $item) {
if ($item[0] !== Type::T_NUMBER) {
$this->throwError('%s is not a number',
$item[0]);
break;
}
$number = $item->normalize();
if (null === $unit) {
$unit = $number[2];
$originalUnit = $item->unitStr();
} elseif ($number[1] && $unit !== $number[2]) {
$this->throwError('Incompatible units:
"%s" and "%s".', $originalUnit,
$item->unitStr());
break;
}
$numbers[$key] = $number;
}
return $numbers;
}
protected static $libLength = ['list'];
protected function libLength($args)
{
$list = $this->coerceList($args[0]);
return count($list[2]);
}
//protected static $libListSeparator = ['list...'];
protected function libListSeparator($args)
{
if (count($args) > 1) {
return 'comma';
}
$list = $this->coerceList($args[0]);
if (count($list[2]) <= 1) {
return 'space';
}
if ($list[1] === ',') {
return 'comma';
}
return 'space';
}
protected static $libNth = ['list', 'n'];
protected function libNth($args)
{
$list = $this->coerceList($args[0]);
$n = $this->assertNumber($args[1]);
if ($n > 0) {
$n--;
} elseif ($n < 0) {
$n += count($list[2]);
}
return isset($list[2][$n]) ? $list[2][$n] : static::$defaultValue;
}
protected static $libSetNth = ['list', 'n',
'value'];
protected function libSetNth($args)
{
$list = $this->coerceList($args[0]);
$n = $this->assertNumber($args[1]);
if ($n > 0) {
$n--;
} elseif ($n < 0) {
$n += count($list[2]);
}
if (! isset($list[2][$n])) {
$this->throwError('Invalid argument for
"n"');
return null;
}
$list[2][$n] = $args[2];
return $list;
}
protected static $libMapGet = ['map', 'key'];
protected function libMapGet($args)
{
$map = $this->assertMap($args[0]);
$key =
$this->compileStringContent($this->coerceString($args[1]));
for ($i = count($map[1]) - 1; $i >= 0; $i--) {
if ($key ===
$this->compileStringContent($this->coerceString($map[1][$i]))) {
return $map[2][$i];
}
}
return static::$null;
}
protected static $libMapKeys = ['map'];
protected function libMapKeys($args)
{
$map = $this->assertMap($args[0]);
$keys = $map[1];
return [Type::T_LIST, ',', $keys];
}
protected static $libMapValues = ['map'];
protected function libMapValues($args)
{
$map = $this->assertMap($args[0]);
$values = $map[2];
return [Type::T_LIST, ',', $values];
}
protected static $libMapRemove = ['map', 'key'];
protected function libMapRemove($args)
{
$map = $this->assertMap($args[0]);
$key =
$this->compileStringContent($this->coerceString($args[1]));
for ($i = count($map[1]) - 1; $i >= 0; $i--) {
if ($key ===
$this->compileStringContent($this->coerceString($map[1][$i]))) {
array_splice($map[1], $i, 1);
array_splice($map[2], $i, 1);
}
}
return $map;
}
protected static $libMapHasKey = ['map', 'key'];
protected function libMapHasKey($args)
{
$map = $this->assertMap($args[0]);
$key =
$this->compileStringContent($this->coerceString($args[1]));
for ($i = count($map[1]) - 1; $i >= 0; $i--) {
if ($key ===
$this->compileStringContent($this->coerceString($map[1][$i]))) {
return true;
}
}
return false;
}
protected static $libMapMerge = ['map-1', 'map-2'];
protected function libMapMerge($args)
{
$map1 = $this->assertMap($args[0]);
$map2 = $this->assertMap($args[1]);
foreach ($map2[1] as $i2 => $key2) {
$key =
$this->compileStringContent($this->coerceString($key2));
foreach ($map1[1] as $i1 => $key1) {
if ($key ===
$this->compileStringContent($this->coerceString($key1))) {
$map1[2][$i1] = $map2[2][$i2];
continue 2;
}
}
$map1[1][] = $map2[1][$i2];
$map1[2][] = $map2[2][$i2];
}
return $map1;
}
protected static $libKeywords = ['args'];
protected function libKeywords($args)
{
$this->assertList($args[0]);
$keys = [];
$values = [];
foreach ($args[0][2] as $name => $arg) {
$keys[] = [Type::T_KEYWORD, $name];
$values[] = $arg;
}
return [Type::T_MAP, $keys, $values];
}
protected function listSeparatorForJoin($list1, $sep)
{
if (! isset($sep)) {
return $list1[1];
}
switch ($this->compileValue($sep)) {
case 'comma':
return ',';
case 'space':
return '';
default:
return $list1[1];
}
}
protected static $libJoin = ['list1', 'list2',
'separator'];
protected function libJoin($args)
{
list($list1, $list2, $sep) = $args;
$list1 = $this->coerceList($list1, ' ');
$list2 = $this->coerceList($list2, ' ');
$sep = $this->listSeparatorForJoin($list1, $sep);
return [Type::T_LIST, $sep, array_merge($list1[2], $list2[2])];
}
protected static $libAppend = ['list', 'val',
'separator'];
protected function libAppend($args)
{
list($list1, $value, $sep) = $args;
$list1 = $this->coerceList($list1, ' ');
$sep = $this->listSeparatorForJoin($list1, $sep);
return [Type::T_LIST, $sep, array_merge($list1[2], [$value])];
}
protected function libZip($args)
{
foreach ($args as $arg) {
$this->assertList($arg);
}
$lists = [];
$firstList = array_shift($args);
foreach ($firstList[2] as $key => $item) {
$list = [Type::T_LIST, '', [$item]];
foreach ($args as $arg) {
if (isset($arg[2][$key])) {
$list[2][] = $arg[2][$key];
} else {
break 2;
}
}
$lists[] = $list;
}
return [Type::T_LIST, ',', $lists];
}
protected static $libTypeOf = ['value'];
protected function libTypeOf($args)
{
$value = $args[0];
switch ($value[0]) {
case Type::T_KEYWORD:
if ($value === static::$true || $value === static::$false)
{
return 'bool';
}
if ($this->coerceColor($value)) {
return 'color';
}
// fall-thru
case Type::T_FUNCTION:
return 'string';
case Type::T_LIST:
if (isset($value[3]) && $value[3]) {
return 'arglist';
}
// fall-thru
default:
return $value[0];
}
}
protected static $libUnit = ['number'];
protected function libUnit($args)
{
$num = $args[0];
if ($num[0] === Type::T_NUMBER) {
return [Type::T_STRING, '"',
[$num->unitStr()]];
}
return '';
}
protected static $libUnitless = ['number'];
protected function libUnitless($args)
{
$value = $args[0];
return $value[0] === Type::T_NUMBER &&
$value->unitless();
}
protected static $libComparable = ['number-1',
'number-2'];
protected function libComparable($args)
{
list($number1, $number2) = $args;
if (! isset($number1[0]) || $number1[0] !== Type::T_NUMBER ||
! isset($number2[0]) || $number2[0] !== Type::T_NUMBER
) {
$this->throwError('Invalid argument(s) for
"comparable"');
return null;
}
$number1 = $number1->normalize();
$number2 = $number2->normalize();
return $number1[2] === $number2[2] || $number1->unitless() ||
$number2->unitless();
}
protected static $libStrIndex = ['string',
'substring'];
protected function libStrIndex($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$substring = $this->coerceString($args[1]);
$substringContent = $this->compileStringContent($substring);
$result = strpos($stringContent, $substringContent);
return $result === false ? static::$null : new Node\Number($result
+ 1, '');
}
protected static $libStrInsert = ['string',
'insert', 'index'];
protected function libStrInsert($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$insert = $this->coerceString($args[1]);
$insertContent = $this->compileStringContent($insert);
list(, $index) = $args[2];
$string[2] = [substr_replace($stringContent, $insertContent, $index
- 1, 0)];
return $string;
}
protected static $libStrLength = ['string'];
protected function libStrLength($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
return new Node\Number(strlen($stringContent), '');
}
protected static $libStrSlice = ['string',
'start-at', 'end-at:-1'];
protected function libStrSlice($args)
{
if (isset($args[2]) && ! $args[2][1]) {
return static::$nullString;
}
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$start = (int) $args[1][1];
if ($start > 0) {
$start--;
}
$end = isset($args[2]) ? (int) $args[2][1] : -1;
$length = $end < 0 ? $end + 1 : ($end > 0 ? $end - $start :
$end);
$string[2] = $length
? [substr($stringContent, $start, $length)]
: [substr($stringContent, $start)];
return $string;
}
protected static $libToLowerCase = ['string'];
protected function libToLowerCase($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$string[2] = [function_exists('mb_strtolower') ?
mb_strtolower($stringContent) : strtolower($stringContent)];
return $string;
}
protected static $libToUpperCase = ['string'];
protected function libToUpperCase($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$string[2] = [function_exists('mb_strtoupper') ?
mb_strtoupper($stringContent) : strtoupper($stringContent)];
return $string;
}
protected static $libFeatureExists = ['feature'];
protected function libFeatureExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->toBool(
array_key_exists($name, $this->registeredFeatures) ?
$this->registeredFeatures[$name] : false
);
}
protected static $libFunctionExists = ['name'];
protected function libFunctionExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
// user defined functions
if ($this->has(static::$namespaces['function'] .
$name)) {
return true;
}
$name = $this->normalizeName($name);
if (isset($this->userFunctions[$name])) {
return true;
}
// built-in functions
$f = $this->getBuiltinFunction($name);
return $this->toBool(is_callable($f));
}
protected static $libGlobalVariableExists = ['name'];
protected function libGlobalVariableExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->has($name, $this->rootEnv);
}
protected static $libMixinExists = ['name'];
protected function libMixinExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->has(static::$namespaces['mixin'] .
$name);
}
protected static $libVariableExists = ['name'];
protected function libVariableExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->has($name);
}
/**
* Workaround IE7's content counter bug.
*
* @param array $args
*
* @return array
*/
protected function libCounter($args)
{
$list = array_map([$this, 'compileValue'], $args);
return [Type::T_STRING, '', ['counter(' .
implode(',', $list) . ')']];
}
protected static $libRandom = ['limit'];
protected function libRandom($args)
{
if (isset($args[0])) {
$n = $this->assertNumber($args[0]);
if ($n < 1) {
$this->throwError("limit must be greater than or
equal to 1");
return null;
}
return new Node\Number(mt_rand(1, $n), '');
}
return new Node\Number(mt_rand(1, mt_getrandmax()), '');
}
protected function libUniqueId()
{
static $id;
if (! isset($id)) {
$id = mt_rand(0, pow(36, 8));
}
$id += mt_rand(0, 10) + 1;
return [Type::T_STRING, '', ['u' .
str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT)]];
}
protected static $libInspect = ['value'];
protected function libInspect($args)
{
if ($args[0] === static::$null) {
return [Type::T_KEYWORD, 'null'];
}
return $args[0];
}
/**
* Preprocess selector args
*
* @param array $arg
*
* @return array|boolean
*/
protected function getSelectorArg($arg)
{
static $parser = null;
if (is_null($parser)) {
$parser = $this->parserFactory(__METHOD__);
}
$arg = $this->libUnquote([$arg]);
$arg = $this->compileValue($arg);
$parsedSelector = [];
if ($parser->parseSelector($arg, $parsedSelector)) {
$selector = $this->evalSelectors($parsedSelector);
$gluedSelector = $this->glueFunctionSelectors($selector);
return $gluedSelector;
}
return false;
}
/**
* Postprocess selector to output in right format
*
* @param array $selectors
*
* @return string
*/
protected function formatOutputSelector($selectors)
{
$selectors = $this->collapseSelectors($selectors, true);
return $selectors;
}
protected static $libIsSuperselector = ['super',
'sub'];
protected function libIsSuperselector($args)
{
list($super, $sub) = $args;
$super = $this->getSelectorArg($super);
$sub = $this->getSelectorArg($sub);
return $this->isSuperSelector($super, $sub);
}
/**
* Test a $super selector again $sub
*
* @param array $super
* @param array $sub
*
* @return boolean
*/
protected function isSuperSelector($super, $sub)
{
// one and only one selector for each arg
if (! $super || count($super) !== 1) {
$this->throwError("Invalid super selector for
isSuperSelector()");
}
if (! $sub || count($sub) !== 1) {
$this->throwError("Invalid sub selector for
isSuperSelector()");
}
$super = reset($super);
$sub = reset($sub);
$i = 0;
$nextMustMatch = false;
foreach ($super as $node) {
$compound = '';
array_walk_recursive(
$node,
function ($value, $key) use (&$compound) {
$compound .= $value;
}
);
if ($this->isImmediateRelationshipCombinator($compound)) {
if ($node !== $sub[$i]) {
return false;
}
$nextMustMatch = true;
$i++;
} else {
while ($i < count($sub) && !
$this->isSuperPart($node, $sub[$i])) {
if ($nextMustMatch) {
return false;
}
$i++;
}
if ($i >= count($sub)) {
return false;
}
$nextMustMatch = false;
$i++;
}
}
return true;
}
/**
* Test a part of super selector again a part of sub selector
*
* @param array $superParts
* @param array $subParts
*
* @return boolean
*/
protected function isSuperPart($superParts, $subParts)
{
$i = 0;
foreach ($superParts as $superPart) {
while ($i < count($subParts) && $subParts[$i] !==
$superPart) {
$i++;
}
if ($i >= count($subParts)) {
return false;
}
$i++;
}
return true;
}
//protected static $libSelectorAppend = ['selector...'];
protected function libSelectorAppend($args)
{
if (count($args) < 1) {
$this->throwError("selector-append() needs at least 1
argument");
}
$selectors = array_map([$this, 'getSelectorArg'], $args);
return
$this->formatOutputSelector($this->selectorAppend($selectors));
}
/**
* Append parts of the last selector in the list to the previous,
recursively
*
* @param array $selectors
*
* @return array
*
* @throws \Leafo\ScssPhp\Exception\CompilerException
*/
protected function selectorAppend($selectors)
{
$lastSelectors = array_pop($selectors);
if (! $lastSelectors) {
$this->throwError("Invalid selector list in
selector-append()");
}
while (count($selectors)) {
$previousSelectors = array_pop($selectors);
if (! $previousSelectors) {
$this->throwError("Invalid selector list in
selector-append()");
}
// do the trick, happening $lastSelector to $previousSelector
$appended = [];
foreach ($lastSelectors as $lastSelector) {
$previous = $previousSelectors;
foreach ($lastSelector as $lastSelectorParts) {
foreach ($lastSelectorParts as $lastSelectorPart) {
foreach ($previous as $i => $previousSelector) {
foreach ($previousSelector as $j =>
$previousSelectorParts) {
$previous[$i][$j][] = $lastSelectorPart;
}
}
}
}
foreach ($previous as $ps) {
$appended[] = $ps;
}
}
$lastSelectors = $appended;
}
return $lastSelectors;
}
protected static $libSelectorExtend = ['selectors',
'extendee', 'extender'];
protected function libSelectorExtend($args)
{
list($selectors, $extendee, $extender) = $args;
$selectors = $this->getSelectorArg($selectors);
$extendee = $this->getSelectorArg($extendee);
$extender = $this->getSelectorArg($extender);
if (! $selectors || ! $extendee || ! $extender) {
$this->throwError("selector-extend() invalid
arguments");
}
$extended = $this->extendOrReplaceSelectors($selectors,
$extendee, $extender);
return $this->formatOutputSelector($extended);
}
protected static $libSelectorReplace = ['selectors',
'original', 'replacement'];
protected function libSelectorReplace($args)
{
list($selectors, $original, $replacement) = $args;
$selectors = $this->getSelectorArg($selectors);
$original = $this->getSelectorArg($original);
$replacement = $this->getSelectorArg($replacement);
if (! $selectors || ! $original || ! $replacement) {
$this->throwError("selector-replace() invalid
arguments");
}
$replaced = $this->extendOrReplaceSelectors($selectors,
$original, $replacement, true);
return $this->formatOutputSelector($replaced);
}
/**
* Extend/replace in selectors
* used by selector-extend and selector-replace that use the same logic
*
* @param array $selectors
* @param array $extendee
* @param array $extender
* @param boolean $replace
*
* @return array
*/
protected function extendOrReplaceSelectors($selectors, $extendee,
$extender, $replace = false)
{
$saveExtends = $this->extends;
$saveExtendsMap = $this->extendsMap;
$this->extends = [];
$this->extendsMap = [];
foreach ($extendee as $es) {
// only use the first one
$this->pushExtends(reset($es), $extender, null);
}
$extended = [];
foreach ($selectors as $selector) {
if (! $replace) {
$extended[] = $selector;
}
$n = count($extended);
$this->matchExtends($selector, $extended);
// if didnt match, keep the original selector if we are in a
replace operation
if ($replace and count($extended) === $n) {
$extended[] = $selector;
}
}
$this->extends = $saveExtends;
$this->extendsMap = $saveExtendsMap;
return $extended;
}
//protected static $libSelectorNest = ['selector...'];
protected function libSelectorNest($args)
{
if (count($args) < 1) {
$this->throwError("selector-nest() needs at least 1
argument");
}
$selectorsMap = array_map([$this, 'getSelectorArg'],
$args);
$envs = [];
foreach ($selectorsMap as $selectors) {
$env = new Environment();
$env->selectors = $selectors;
$envs[] = $env;
}
$envs = array_reverse($envs);
$env = $this->extractEnv($envs);
$outputSelectors = $this->multiplySelectors($env);
return $this->formatOutputSelector($outputSelectors);
}
protected static $libSelectorParse = ['selectors'];
protected function libSelectorParse($args)
{
$selectors = reset($args);
$selectors = $this->getSelectorArg($selectors);
return $this->formatOutputSelector($selectors);
}
protected static $libSelectorUnify = ['selectors1',
'selectors2'];
protected function libSelectorUnify($args)
{
list($selectors1, $selectors2) = $args;
$selectors1 = $this->getSelectorArg($selectors1);
$selectors2 = $this->getSelectorArg($selectors2);
if (! $selectors1 || ! $selectors2) {
$this->throwError("selector-unify() invalid
arguments");
}
// only consider the first compound of each
$compound1 = reset($selectors1);
$compound2 = reset($selectors2);
// unify them and that's it
$unified = $this->unifyCompoundSelectors($compound1,
$compound2);
return $this->formatOutputSelector($unified);
}
/**
* The selector-unify magic as its best
* (at least works as expected on test cases)
*
* @param array $compound1
* @param array $compound2
* @return array|mixed
*/
protected function unifyCompoundSelectors($compound1, $compound2)
{
if (! count($compound1)) {
return $compound2;
}
if (! count($compound2)) {
return $compound1;
}
// check that last part are compatible
$lastPart1 = array_pop($compound1);
$lastPart2 = array_pop($compound2);
$last = $this->mergeParts($lastPart1, $lastPart2);
if (! $last) {
return [[]];
}
$unifiedCompound = [$last];
$unifiedSelectors = [$unifiedCompound];
// do the rest
while (count($compound1) || count($compound2)) {
$part1 = end($compound1);
$part2 = end($compound2);
if ($part1 && ($match2 =
$this->matchPartInCompound($part1, $compound2))) {
list($compound2, $part2, $after2) = $match2;
if ($after2) {
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, $after2);
}
$c = $this->mergeParts($part1, $part2);
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, [$c]);
$part1 = $part2 = null;
array_pop($compound1);
}
if ($part2 && ($match1 =
$this->matchPartInCompound($part2, $compound1))) {
list($compound1, $part1, $after1) = $match1;
if ($after1) {
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, $after1);
}
$c = $this->mergeParts($part2, $part1);
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, [$c]);
$part1 = $part2 = null;
array_pop($compound2);
}
$new = [];
if ($part1 && $part2) {
array_pop($compound1);
array_pop($compound2);
$s = $this->prependSelectors($unifiedSelectors,
[$part2]);
$new = array_merge($new, $this->prependSelectors($s,
[$part1]));
$s = $this->prependSelectors($unifiedSelectors,
[$part1]);
$new = array_merge($new, $this->prependSelectors($s,
[$part2]));
} elseif ($part1) {
array_pop($compound1);
$new = array_merge($new,
$this->prependSelectors($unifiedSelectors, [$part1]));
} elseif ($part2) {
array_pop($compound2);
$new = array_merge($new,
$this->prependSelectors($unifiedSelectors, [$part2]));
}
if ($new) {
$unifiedSelectors = $new;
}
}
return $unifiedSelectors;
}
/**
* Prepend each selector from $selectors with $parts
*
* @param array $selectors
* @param array $parts
*
* @return array
*/
protected function prependSelectors($selectors, $parts)
{
$new = [];
foreach ($selectors as $compoundSelector) {
array_unshift($compoundSelector, $parts);
$new[] = $compoundSelector;
}
return $new;
}
/**
* Try to find a matching part in a compound:
* - with same html tag name
* - with some class or id or something in common
*
* @param array $part
* @param array $compound
*
* @return array|boolean
*/
protected function matchPartInCompound($part, $compound)
{
$partTag = $this->findTagName($part);
$before = $compound;
$after = [];
// try to find a match by tag name first
while (count($before)) {
$p = array_pop($before);
if ($partTag && $partTag !== '*' &&
$partTag == $this->findTagName($p)) {
return [$before, $p, $after];
}
$after[] = $p;
}
// try again matching a non empty intersection and a compatible
tagname
$before = $compound;
$after = [];
while (count($before)) {
$p = array_pop($before);
if ($this->checkCompatibleTags($partTag,
$this->findTagName($p))) {
if (count(array_intersect($part, $p))) {
return [$before, $p, $after];
}
}
$after[] = $p;
}
return false;
}
/**
* Merge two part list taking care that
* - the html tag is coming first - if any
* - the :something are coming last
*
* @param array $parts1
* @param array $parts2
*
* @return array
*/
protected function mergeParts($parts1, $parts2)
{
$tag1 = $this->findTagName($parts1);
$tag2 = $this->findTagName($parts2);
$tag = $this->checkCompatibleTags($tag1, $tag2);
// not compatible tags
if ($tag === false) {
return [];
}
if ($tag) {
if ($tag1) {
$parts1 = array_diff($parts1, [$tag1]);
}
if ($tag2) {
$parts2 = array_diff($parts2, [$tag2]);
}
}
$mergedParts = array_merge($parts1, $parts2);
$mergedOrderedParts = [];
foreach ($mergedParts as $part) {
if (strpos($part, ':') === 0) {
$mergedOrderedParts[] = $part;
}
}
$mergedParts = array_diff($mergedParts, $mergedOrderedParts);
$mergedParts = array_merge($mergedParts, $mergedOrderedParts);
if ($tag) {
array_unshift($mergedParts, $tag);
}
return $mergedParts;
}
/**
* Check the compatibility between two tag names:
* if both are defined they should be identical or one has to be
'*'
*
* @param string $tag1
* @param string $tag2
*
* @return array|boolean
*/
protected function checkCompatibleTags($tag1, $tag2)
{
$tags = [$tag1, $tag2];
$tags = array_unique($tags);
$tags = array_filter($tags);
if (count($tags)>1) {
$tags = array_diff($tags, ['*']);
}
// not compatible nodes
if (count($tags)>1) {
return false;
}
return $tags;
}
/**
* Find the html tag name in a selector parts list
*
* @param array $parts
*
* @return mixed|string
*/
protected function findTagName($parts)
{
foreach ($parts as $part) {
if (! preg_match('/^[\[.:#%_-]/', $part)) {
return $part;
}
}
return '';
}
protected static $libSimpleSelectors = ['selector'];
protected function libSimpleSelectors($args)
{
$selector = reset($args);
$selector = $this->getSelectorArg($selector);
// remove selectors list layer, keeping the first one
$selector = reset($selector);
// remove parts list layer, keeping the first part
$part = reset($selector);
$listParts = [];
foreach ($part as $p) {
$listParts[] = [Type::T_STRING, '', [$p]];
}
return [Type::T_LIST, ',', $listParts];
}
}
PK&d�[�[����
composer.jsonnu�[���{
"name": "gantry/joomla",
"description": "Gantry Framework Library",
"license": "GPLv2",
"require": {
"php": ">=5.5.9",
"symfony/event-dispatcher": "~2.8",
"symfony/yaml": "~2.8",
"twig/twig": "~1.41",
"pimple/pimple": "~3.0",
"filp/whoops": "~2.5.0",
"rockettheme/toolbox": "~1.3",
"leafo/scssphp": "~0.8",
"erusev/parsedown-extra": "~0.7.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"autoload": {
"psr-4": {
"Gantry\\": "classes/Gantry",
"Leafo\\ScssPhp\\": "classes/Leafo/ScssPhp"
}
},
"config": {
"platform": {
"php": "5.5.9"
}
}
}
PK&d�[_?�s����
composer.locknu�[���{
"_readme": [
"This file locks the dependencies of your project to a known
state",
"Read more about it at
https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f03f176a8d30aa23c9c08489789a8c68",
"packages": [
{
"name": "erusev/parsedown",
"version": "1.7.4",
"source": {
"type": "git",
"url":
"https://github.com/erusev/parsedown.git",
"reference":
"cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"reference":
"cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
],
"support": {
"issues":
"https://github.com/erusev/parsedown/issues",
"source":
"https://github.com/erusev/parsedown/tree/1.7.x"
},
"time": "2019-12-30T22:54:17+00:00"
},
{
"name": "erusev/parsedown-extra",
"version": "0.7.1",
"source": {
"type": "git",
"url":
"https://github.com/erusev/parsedown-extra.git",
"reference":
"0db5cce7354e4b76f155d092ab5eb3981c21258c"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/erusev/parsedown-extra/zipball/0db5cce7354e4b76f155d092ab5eb3981c21258c",
"reference":
"0db5cce7354e4b76f155d092ab5eb3981c21258c",
"shasum": ""
},
"require": {
"erusev/parsedown": "~1.4"
},
"type": "library",
"autoload": {
"psr-0": {
"ParsedownExtra": ""
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "An extension of Parsedown that
adds support for Markdown Extra.",
"homepage":
"https://github.com/erusev/parsedown-extra",
"keywords": [
"markdown",
"markdown extra",
"parsedown",
"parser"
],
"support": {
"issues":
"https://github.com/erusev/parsedown-extra/issues",
"source":
"https://github.com/erusev/parsedown-extra/tree/master"
},
"time": "2015-11-01T10:19:22+00:00"
},
{
"name": "filp/whoops",
"version": "2.5.1",
"source": {
"type": "git",
"url":
"https://github.com/filp/whoops.git",
"reference":
"ee9699e79d8fcdd15c107e035d7b965e4fa854ac"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/filp/whoops/zipball/ee9699e79d8fcdd15c107e035d7b965e4fa854ac",
"reference":
"ee9699e79d8fcdd15c107e035d7b965e4fa854ac",
"shasum": ""
},
"require": {
"php": "^5.5.9 || ^7.0",
"psr/log": "^1.0.1"
},
"require-dev": {
"mockery/mockery": "^0.9 || ^1.0",
"phpunit/phpunit": "^4.8.35 || ^5.7",
"symfony/var-dumper": "^2.6 || ^3.0 ||
^4.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex
values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP
responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Filipe Dobreira",
"homepage":
"https://github.com/filp",
"role": "Developer"
}
],
"description": "php error handling for cool
kids",
"homepage":
"https://filp.github.io/whoops/",
"keywords": [
"error",
"exception",
"handling",
"library",
"throwable",
"whoops"
],
"support": {
"issues":
"https://github.com/filp/whoops/issues",
"source":
"https://github.com/filp/whoops/tree/2.5.1"
},
"time": "2019-12-21T10:00:00+00:00"
},
{
"name": "leafo/scssphp",
"version": "v0.8.4",
"source": {
"type": "git",
"url":
"https://github.com/leafo/scssphp.git",
"reference":
"b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/leafo/scssphp/zipball/b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9",
"reference":
"b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9",
"shasum": ""
},
"require": {
"php": "^5.4.0 || ^7"
},
"require-dev": {
"phpunit/phpunit": "~4.6",
"squizlabs/php_codesniffer": "~2.5",
"twbs/bootstrap": "~4.3",
"zurb/foundation": "~6.5"
},
"bin": [
"bin/pscss"
],
"type": "library",
"autoload": {
"psr-4": {
"Leafo\\ScssPhp\\": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Leaf Corcoran",
"email": "leafot@gmail.com",
"homepage": "http://leafo.net"
}
],
"description": "scssphp is a compiler for SCSS
written in PHP.",
"homepage":
"http://leafo.github.io/scssphp/",
"keywords": [
"css",
"less",
"sass",
"scss",
"stylesheet"
],
"support": {
"issues":
"https://github.com/leafo/scssphp/issues",
"source":
"https://github.com/leafo/scssphp/tree/v0.8.4"
},
"abandoned": "scssphp/scssphp",
"time": "2019-06-18T21:15:44+00:00"
},
{
"name": "pimple/pimple",
"version": "v3.2.3",
"source": {
"type": "git",
"url":
"https://github.com/silexphp/Pimple.git",
"reference":
"9e403941ef9d65d20cba7d54e29fe906db42cf32"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32",
"reference":
"9e403941ef9d65d20cba7d54e29fe906db42cf32",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"psr/container": "^1.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2.x-dev"
}
},
"autoload": {
"psr-0": {
"Pimple": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Pimple, a simple Dependency
Injection Container",
"homepage": "http://pimple.sensiolabs.org",
"keywords": [
"container",
"dependency injection"
],
"support": {
"issues":
"https://github.com/silexphp/Pimple/issues",
"source":
"https://github.com/silexphp/Pimple/tree/master"
},
"time": "2018-01-21T07:42:36+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"source": {
"type": "git",
"url":
"https://github.com/php-fig/container.git",
"reference":
"b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference":
"b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage":
"http://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP
FIG PSR-11)",
"homepage":
"https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"support": {
"issues":
"https://github.com/php-fig/container/issues",
"source":
"https://github.com/php-fig/container/tree/master"
},
"time": "2017-02-14T16:28:37+00:00"
},
{
"name": "psr/log",
"version": "1.1.3",
"source": {
"type": "git",
"url":
"https://github.com/php-fig/log.git",
"reference":
"0f73288fd15629204f9d42b7055f72dacbe811fc"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
"reference":
"0f73288fd15629204f9d42b7055f72dacbe811fc",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage":
"http://www.php-fig.org/"
}
],
"description": "Common interface for logging
libraries",
"homepage":
"https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source":
"https://github.com/php-fig/log/tree/1.1.3"
},
"time": "2020-03-23T09:12:05+00:00"
},
{
"name": "rockettheme/toolbox",
"version": "1.4.7",
"source": {
"type": "git",
"url":
"https://github.com/rockettheme/toolbox.git",
"reference":
"6a86bc0607884d2194260b6b72d67333e0141585"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/rockettheme/toolbox/zipball/6a86bc0607884d2194260b6b72d67333e0141585",
"reference":
"6a86bc0607884d2194260b6b72d67333e0141585",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=5.4.0",
"pimple/pimple": "~3.0",
"symfony/event-dispatcher": ">2.5",
"symfony/yaml": ">2.5"
},
"require-dev": {
"phpunit/phpunit": "~6"
},
"type": "library",
"autoload": {
"psr-4": {
"RocketTheme\\Toolbox\\ArrayTraits\\":
"ArrayTraits/src",
"RocketTheme\\Toolbox\\Blueprints\\":
"Blueprints/src",
"RocketTheme\\Toolbox\\Compat\\":
"Compat/src",
"RocketTheme\\Toolbox\\DI\\":
"DI/src",
"RocketTheme\\Toolbox\\Event\\":
"Event/src",
"RocketTheme\\Toolbox\\File\\":
"File/src",
"RocketTheme\\Toolbox\\ResourceLocator\\":
"ResourceLocator/src",
"RocketTheme\\Toolbox\\Session\\":
"Session/src",
"RocketTheme\\Toolbox\\StreamWrapper\\":
"StreamWrapper/src"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "RocketTheme Toolbox
Library",
"homepage": "http://www.rockettheme.com",
"keywords": [
"php",
"rockettheme"
],
"support": {
"issues":
"https://github.com/rockettheme/toolbox/issues",
"source":
"https://github.com/rockettheme/toolbox/tree/1.4.7"
},
"time": "2020-03-19T18:24:40+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.8.52",
"source": {
"type": "git",
"url":
"https://github.com/symfony/event-dispatcher.git",
"reference":
"a77e974a5fecb4398833b0709210e3d5e334ffb0"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0",
"reference":
"a77e974a5fecb4398833b0709210e3d5e334ffb0",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "^2.0.5|~3.0.0",
"symfony/dependency-injection":
"~2.6|~3.0.0",
"symfony/expression-language":
"~2.6|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\":
""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher
Component",
"homepage": "https://symfony.com",
"support": {
"source":
"https://github.com/symfony/event-dispatcher/tree/v2.8.50"
},
"time": "2018-11-21T14:20:20+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.19.0",
"source": {
"type": "git",
"url":
"https://github.com/symfony/polyfill-ctype.git",
"reference":
"aed596913b70fae57be53d86faa2e9ef85a2297b"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b",
"reference":
"aed596913b70fae57be53d86faa2e9ef85a2297b",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.19-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url":
"https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype
functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source":
"https://github.com/symfony/polyfill-ctype/tree/v1.19.0"
},
"funding": [
{
"url":
"https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url":
"https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-23T09:01:57+00:00"
},
{
"name": "symfony/yaml",
"version": "v2.8.52",
"source": {
"type": "git",
"url":
"https://github.com/symfony/yaml.git",
"reference":
"02c1859112aa779d9ab394ae4f3381911d84052b"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b",
"reference":
"02c1859112aa779d9ab394ae4f3381911d84052b",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"support": {
"source":
"https://github.com/symfony/yaml/tree/v2.8.52"
},
"time": "2018-11-11T11:18:13+00:00"
},
{
"name": "twig/twig",
"version": "v1.42.5",
"source": {
"type": "git",
"url":
"https://github.com/twigphp/Twig.git",
"reference":
"87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/twigphp/Twig/zipball/87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e",
"reference":
"87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e",
"shasum": ""
},
"require": {
"php": ">=5.5.0",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"psr/container": "^1.0",
"symfony/phpunit-bridge": "^4.4|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.42-dev"
}
},
"autoload": {
"psr-0": {
"Twig_": "lib/"
},
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage":
"http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email":
"armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and
secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues":
"https://github.com/twigphp/Twig/issues",
"source":
"https://github.com/twigphp/Twig/tree/1.x"
},
"time": "2020-02-11T05:59:23+00:00"
}
],
"packages-dev": [
{
"name": "phpunit/php-code-coverage",
"version": "1.2.18",
"source": {
"type": "git",
"url":
"https://github.com/sebastianbergmann/php-code-coverage.git",
"reference":
"fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b",
"reference":
"fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator":
">=1.3.0@stable",
"phpunit/php-text-template":
">=1.2.0@stable",
"phpunit/php-token-stream":
">=1.1.3,<1.3.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*@dev"
},
"suggest": {
"ext-dom": "*",
"ext-xdebug": ">=2.0.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"classmap": [
"PHP/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email":
"sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Library that provides
collection, processing, and rendering functionality for PHP code coverage
information.",
"homepage":
"https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"support": {
"irc":
"irc://irc.freenode.net/phpunit",
"issues":
"https://github.com/sebastianbergmann/php-code-coverage/issues",
"source":
"https://github.com/sebastianbergmann/php-code-coverage/tree/1.2.18"
},
"time": "2014-09-02T10:13:14+00:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "1.4.5",
"source": {
"type": "git",
"url":
"https://github.com/sebastianbergmann/php-file-iterator.git",
"reference":
"730b01bc3e867237eaac355e06a36b85dd93a8b4"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
"reference":
"730b01bc3e867237eaac355e06a36b85dd93a8b4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email":
"sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "FilterIterator implementation
that filters files based on a list of suffixes.",
"homepage":
"https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"support": {
"irc":
"irc://irc.freenode.net/phpunit",
"issues":
"https://github.com/sebastianbergmann/php-file-iterator/issues",
"source":
"https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
},
"time": "2017-11-27T13:52:08+00:00"
},
{
"name": "phpunit/php-text-template",
"version": "1.2.1",
"source": {
"type": "git",
"url":
"https://github.com/sebastianbergmann/php-text-template.git",
"reference":
"31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
"reference":
"31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Simple template engine.",
"homepage":
"https://github.com/sebastianbergmann/php-text-template/",
"keywords": [
"template"
],
"support": {
"issues":
"https://github.com/sebastianbergmann/php-text-template/issues",
"source":
"https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
},
"time": "2015-06-21T13:50:34+00:00"
},
{
"name": "phpunit/php-timer",
"version": "1.0.9",
"source": {
"type": "git",
"url":
"https://github.com/sebastianbergmann/php-timer.git",
"reference":
"3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
"reference":
"3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 ||
^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email":
"sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Utility class for timing",
"homepage":
"https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"support": {
"issues":
"https://github.com/sebastianbergmann/php-timer/issues",
"source":
"https://github.com/sebastianbergmann/php-timer/tree/master"
},
"time": "2017-02-26T11:10:40+00:00"
},
{
"name": "phpunit/php-token-stream",
"version": "1.2.2",
"source": {
"type": "git",
"url":
"https://github.com/sebastianbergmann/php-token-stream.git",
"reference":
"ad4e1e23ae01b483c16f600ff1bebec184588e32"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32",
"reference":
"ad4e1e23ae01b483c16f600ff1bebec184588e32",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"classmap": [
"PHP/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email":
"sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Wrapper around PHP's
tokenizer extension.",
"homepage":
"https://github.com/sebastianbergmann/php-token-stream/",
"keywords": [
"tokenizer"
],
"support": {
"irc":
"irc://irc.freenode.net/phpunit",
"issues":
"https://github.com/sebastianbergmann/php-token-stream/issues",
"source":
"https://github.com/sebastianbergmann/php-token-stream/tree/1.2.2"
},
"abandoned": true,
"time": "2014-03-03T05:10:30+00:00"
},
{
"name": "phpunit/phpunit",
"version": "3.7.38",
"source": {
"type": "git",
"url":
"https://github.com/sebastianbergmann/phpunit.git",
"reference":
"38709dc22d519a3d1be46849868aa2ddf822bcf6"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6",
"reference":
"38709dc22d519a3d1be46849868aa2ddf822bcf6",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-dom": "*",
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
"phpunit/php-code-coverage": "~1.2",
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.1",
"phpunit/php-timer": "~1.0",
"phpunit/phpunit-mock-objects": "~1.2",
"symfony/yaml": "~2.0"
},
"require-dev": {
"pear-pear.php.net/pear": "1.9.4"
},
"suggest": {
"phpunit/php-invoker": "~1.1"
},
"bin": [
"composer/bin/phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.7.x-dev"
}
},
"autoload": {
"classmap": [
"PHPUnit/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"include-path": [
"",
"../../symfony/yaml/"
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing
framework.",
"homepage": "http://www.phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
"support": {
"irc":
"irc://irc.freenode.net/phpunit",
"issues":
"https://github.com/sebastianbergmann/phpunit/issues",
"source":
"https://github.com/sebastianbergmann/phpunit/tree/3.7"
},
"time": "2014-10-17T09:04:17+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "1.2.3",
"source": {
"type": "git",
"url":
"https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference":
"5794e3c5c5ba0fb037b11d8151add2a07fa82875"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875",
"reference":
"5794e3c5c5ba0fb037b11d8151add2a07fa82875",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-text-template":
">=1.1.1@stable"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"autoload": {
"classmap": [
"PHPUnit/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email":
"sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Mock Object library for
PHPUnit",
"homepage":
"https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"support": {
"irc":
"irc://irc.freenode.net/phpunit",
"issues":
"https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
"source":
"https://github.com/sebastianbergmann/phpunit-mock-objects/tree/1.2.3"
},
"abandoned": true,
"time": "2013-01-13T10:24:48+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.5.9"
},
"platform-dev": [],
"platform-overrides": {
"php": "5.5.9"
},
"plugin-api-version": "2.0.0"
}
PK&d�[9�&���
Loader.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry5;
abstract class Loader
{
public static function setup()
{
self::get();
}
/**
* @return mixed
*/
public static function get()
{
static $loader;
if (!$loader) {
require_once __DIR__ . '/RealLoader.php';
$loader = RealLoader::getClassLoader();
}
return $loader;
}
}
PK&d�[[ކ��MD5SUMSnu�[���language/en-GB/en-GB.plg_quickicon_gantry5.sys.ini 6c74971e95e095ea9511c25336dcd19a
gantry5.xml 4e7f62f0fbfddefb16d773510ac0f391
MD5SUMS d41d8cd98f00b204e9800998ecf8427e
gantry5.php ce06d8c4f4eaadec5a31bcd300d30f00
PK&d�[��Gɮ�RealLoader.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry5;
/**
* Use \Gantry5\Loader::setup() or \Gantry5\Loader::get() instead.
*
* This class separates Loader logic from the \Gantry5\Loader class. By
adding this extra class we are able to upgrade
* Gantry5 and initializing the new version during a single request -- as
long as Gantry5 has not been initialized.
*
* @internal
*/
abstract class RealLoader
{
protected static $errorMessagePhpMin = 'You are running PHP %s,
but Gantry 5 Framework needs at least PHP %s to run.';
protected static $errorMessageGantryLoaded = 'Attempting to load
Gantry 5 Framework multiple times.';
/**
* Initializes Gantry5 and returns Composer ClassLoader.
*
* @return \Composer\Autoload\ClassLoader
* @throws \RuntimeException
* @throws \LogicException
*/
public static function getClassLoader()
{
// Fail safe version check for PHP <5.5.9.
if (version_compare($phpVersion = PHP_VERSION, '5.5.9',
'<')) {
throw new \RuntimeException(sprintf(self::$errorMessagePhpMin,
$phpVersion, '5.5.9'));
}
if (defined('GANTRY5_VERSION')) {
throw new \LogicException(self::$errorMessageGantryLoaded);
}
define('GANTRY5_VERSION', '5.4.37');
define('GANTRY5_VERSION_DATE', 'January 25,
2021');
if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
define('GANTRY_DEBUGGER',
class_exists('Gantry\\Debugger'));
return self::autoload();
}
/**
* @return \Composer\Autoload\ClassLoader
* @throws \LogicException
* @internal
*/
protected static function autoload()
{
// Register platform specific overrides.
if (defined('JVERSION') &&
defined('JPATH_ROOT')) {
define('GANTRY5_PLATFORM', 'joomla');
define('GANTRY5_ROOT', JPATH_ROOT);
} elseif (defined('WP_DEBUG') &&
defined('ABSPATH')) {
define('GANTRY5_PLATFORM', 'wordpress');
if (class_exists('Env') &&
defined('CONTENT_DIR')) {
// Bedrock support.
define('GANTRY5_ROOT', preg_replace('|'
. preg_quote(CONTENT_DIR). '$|', '', WP_CONTENT_DIR));
} else {
// Plain WP support.
define('GANTRY5_ROOT', dirname(WP_CONTENT_DIR));
}
} elseif (defined('GRAV_VERSION') &&
defined('ROOT_DIR')) {
define('GANTRY5_PLATFORM', 'grav');
define('GANTRY5_ROOT', rtrim(ROOT_DIR,
'/'));
} elseif (defined('PRIME_ROOT')) {
define('GANTRY5_PLATFORM', 'prime');
define('GANTRY5_ROOT', PRIME_ROOT);
} else {
throw new \RuntimeException('Gantry: CMS not
detected!');
}
$base = __DIR__;
$vendor = "{$base}/platforms/" . GANTRY5_PLATFORM;
$dev = is_dir($vendor);
if (!$dev) {
$vendor = $base;
}
$autoload = "{$vendor}/vendor/autoload.php";
// Initialize auto-loading.
if (!file_exists($autoload)) {
throw new \LogicException('Please run composer in Gantry 5
Library!');
}
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require_once $autoload;
if ($dev) {
$loader->addPsr4('Gantry\\',
"{$base}/classes/Gantry");
}
return $loader;
}
}
PK&d�[=+d��vendor/autoload.phpnu�[���<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit7bfda60b2ff69dc96fe4a1f15c2e6d42::getLoader();
PK&d�[��@���%vendor/composer/autoload_classmap.phpnu�[���<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir .
'/composer/InstalledVersions.php',
);
PK&d�[�ɿ@��"vendor/composer/autoload_files.phpnu�[���<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir .
'/symfony/polyfill-ctype/bootstrap.php',
);
PK&d�[LlP���'vendor/composer/autoload_namespaces.phpnu�[���<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Twig_' => array($vendorDir . '/twig/twig/lib'),
'Pimple' => array($vendorDir .
'/pimple/pimple/src'),
'ParsedownExtra' => array($vendorDir .
'/erusev/parsedown-extra'),
'Parsedown' => array($vendorDir .
'/erusev/parsedown'),
);
PK&d�[$$۳��!vendor/composer/autoload_psr4.phpnu�[���<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Whoops\\' => array($vendorDir .
'/filp/whoops/src/Whoops'),
'Twig\\' => array($vendorDir .
'/twig/twig/src'),
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir .
'/symfony/polyfill-ctype'),
'Symfony\\Component\\Yaml\\' => array($vendorDir .
'/symfony/yaml'),
'Symfony\\Component\\EventDispatcher\\' =>
array($vendorDir . '/symfony/event-dispatcher'),
'RocketTheme\\Toolbox\\StreamWrapper\\' =>
array($vendorDir . '/rockettheme/toolbox/StreamWrapper/src'),
'RocketTheme\\Toolbox\\Session\\' => array($vendorDir .
'/rockettheme/toolbox/Session/src'),
'RocketTheme\\Toolbox\\ResourceLocator\\' =>
array($vendorDir . '/rockettheme/toolbox/ResourceLocator/src'),
'RocketTheme\\Toolbox\\File\\' => array($vendorDir .
'/rockettheme/toolbox/File/src'),
'RocketTheme\\Toolbox\\Event\\' => array($vendorDir .
'/rockettheme/toolbox/Event/src'),
'RocketTheme\\Toolbox\\DI\\' => array($vendorDir .
'/rockettheme/toolbox/DI/src'),
'RocketTheme\\Toolbox\\Compat\\' => array($vendorDir .
'/rockettheme/toolbox/Compat/src'),
'RocketTheme\\Toolbox\\Blueprints\\' => array($vendorDir .
'/rockettheme/toolbox/Blueprints/src'),
'RocketTheme\\Toolbox\\ArrayTraits\\' => array($vendorDir
. '/rockettheme/toolbox/ArrayTraits/src'),
'Psr\\Log\\' => array($vendorDir .
'/psr/log/Psr/Log'),
'Psr\\Container\\' => array($vendorDir .
'/psr/container/src'),
'Leafo\\ScssPhp\\' => array($baseDir .
'/classes/Leafo/ScssPhp', $vendorDir .
'/leafo/scssphp/src'),
'Gantry\\' => array($baseDir .
'/classes/Gantry'),
);
PK&d�[��na� � !vendor/composer/autoload_real.phpnu�[���<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit7bfda60b2ff69dc96fe4a1f15c2e6d42
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit7bfda60b2ff69dc96fe4a1f15c2e6d42',
'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit7bfda60b2ff69dc96fe4a1f15c2e6d42',
'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 &&
!defined('HHVM_VERSION') &&
(!function_exists('zend_loader_file_encoded') ||
!zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit7bfda60b2ff69dc96fe4a1f15c2e6d42::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ .
'/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles =
Composer\Autoload\ComposerStaticInit7bfda60b2ff69dc96fe4a1f15c2e6d42::$files;
} else {
$includeFiles = require __DIR__ .
'/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire7bfda60b2ff69dc96fe4a1f15c2e6d42($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire7bfda60b2ff69dc96fe4a1f15c2e6d42($fileIdentifier,
$file)
{
if
(empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] =
true;
}
}
PK&d�[��@F��#vendor/composer/autoload_static.phpnu�[���<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit7bfda60b2ff69dc96fe4a1f15c2e6d42
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ .
'/..' . '/symfony/polyfill-ctype/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'W' =>
array (
'Whoops\\' => 7,
),
'T' =>
array (
'Twig\\' => 5,
),
'S' =>
array (
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Component\\Yaml\\' => 23,
'Symfony\\Component\\EventDispatcher\\' => 34,
),
'R' =>
array (
'RocketTheme\\Toolbox\\StreamWrapper\\' => 34,
'RocketTheme\\Toolbox\\Session\\' => 28,
'RocketTheme\\Toolbox\\ResourceLocator\\' => 36,
'RocketTheme\\Toolbox\\File\\' => 25,
'RocketTheme\\Toolbox\\Event\\' => 26,
'RocketTheme\\Toolbox\\DI\\' => 23,
'RocketTheme\\Toolbox\\Compat\\' => 27,
'RocketTheme\\Toolbox\\Blueprints\\' => 31,
'RocketTheme\\Toolbox\\ArrayTraits\\' => 32,
),
'P' =>
array (
'Psr\\Log\\' => 8,
'Psr\\Container\\' => 14,
),
'L' =>
array (
'Leafo\\ScssPhp\\' => 14,
),
'G' =>
array (
'Gantry\\' => 7,
),
);
public static $prefixDirsPsr4 = array (
'Whoops\\' =>
array (
0 => __DIR__ . '/..' .
'/filp/whoops/src/Whoops',
),
'Twig\\' =>
array (
0 => __DIR__ . '/..' . '/twig/twig/src',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' .
'/symfony/polyfill-ctype',
),
'Symfony\\Component\\Yaml\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/yaml',
),
'Symfony\\Component\\EventDispatcher\\' =>
array (
0 => __DIR__ . '/..' .
'/symfony/event-dispatcher',
),
'RocketTheme\\Toolbox\\StreamWrapper\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/StreamWrapper/src',
),
'RocketTheme\\Toolbox\\Session\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/Session/src',
),
'RocketTheme\\Toolbox\\ResourceLocator\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/ResourceLocator/src',
),
'RocketTheme\\Toolbox\\File\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/File/src',
),
'RocketTheme\\Toolbox\\Event\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/Event/src',
),
'RocketTheme\\Toolbox\\DI\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/DI/src',
),
'RocketTheme\\Toolbox\\Compat\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/Compat/src',
),
'RocketTheme\\Toolbox\\Blueprints\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/Blueprints/src',
),
'RocketTheme\\Toolbox\\ArrayTraits\\' =>
array (
0 => __DIR__ . '/..' .
'/rockettheme/toolbox/ArrayTraits/src',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' .
'/psr/log/Psr/Log',
),
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' .
'/psr/container/src',
),
'Leafo\\ScssPhp\\' =>
array (
0 => __DIR__ . '/../..' .
'/classes/Leafo/ScssPhp',
1 => __DIR__ . '/..' .
'/leafo/scssphp/src',
),
'Gantry\\' =>
array (
0 => __DIR__ . '/../..' .
'/classes/Gantry',
),
);
public static $prefixesPsr0 = array (
'T' =>
array (
'Twig_' =>
array (
0 => __DIR__ . '/..' .
'/twig/twig/lib',
),
),
'P' =>
array (
'Pimple' =>
array (
0 => __DIR__ . '/..' .
'/pimple/pimple/src',
),
'ParsedownExtra' =>
array (
0 => __DIR__ . '/..' .
'/erusev/parsedown-extra',
),
'Parsedown' =>
array (
0 => __DIR__ . '/..' .
'/erusev/parsedown',
),
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ .
'/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 =
ComposerStaticInit7bfda60b2ff69dc96fe4a1f15c2e6d42::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 =
ComposerStaticInit7bfda60b2ff69dc96fe4a1f15c2e6d42::$prefixDirsPsr4;
$loader->prefixesPsr0 =
ComposerStaticInit7bfda60b2ff69dc96fe4a1f15c2e6d42::$prefixesPsr0;
$loader->classMap =
ComposerStaticInit7bfda60b2ff69dc96fe4a1f15c2e6d42::$classMap;
}, null, ClassLoader::class);
}
}
PK&d�[?�T��4�4vendor/composer/ClassLoader.phpnu�[���<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component',
__DIR__.'/component');
* $loader->add('Symfony',
__DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for
instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge',
array_values($this->prefixesPsr0));
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap,
$classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this
namespace.
*
* @param string $prefix The prefix/namespace, with trailing
'\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4
prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing
'\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4
prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to
check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the
extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch')
&& filter_var(ini_get('apc.enabled'),
FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true,
$prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative ||
isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class,
'.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\',
DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\'))
{
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR .
substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR .
$logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_',
DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_',
DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs)
{
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR
. $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR .
$logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file =
stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}
PK&d�[����f�fvendor/composer/installed.jsonnu�[���{
"packages": [
{
"name": "erusev/parsedown",
"version": "1.7.4",
"version_normalized": "1.7.4.0",
"source": {
"type": "git",
"url":
"https://github.com/erusev/parsedown.git",
"reference":
"cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"reference":
"cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"time": "2019-12-30T22:54:17+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
],
"support": {
"issues":
"https://github.com/erusev/parsedown/issues",
"source":
"https://github.com/erusev/parsedown/tree/1.7.x"
},
"install-path": "../erusev/parsedown"
},
{
"name": "erusev/parsedown-extra",
"version": "0.7.1",
"version_normalized": "0.7.1.0",
"source": {
"type": "git",
"url":
"https://github.com/erusev/parsedown-extra.git",
"reference":
"0db5cce7354e4b76f155d092ab5eb3981c21258c"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/erusev/parsedown-extra/zipball/0db5cce7354e4b76f155d092ab5eb3981c21258c",
"reference":
"0db5cce7354e4b76f155d092ab5eb3981c21258c",
"shasum": ""
},
"require": {
"erusev/parsedown": "~1.4"
},
"time": "2015-11-01T10:19:22+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"ParsedownExtra": ""
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "An extension of Parsedown that
adds support for Markdown Extra.",
"homepage":
"https://github.com/erusev/parsedown-extra",
"keywords": [
"markdown",
"markdown extra",
"parsedown",
"parser"
],
"support": {
"issues":
"https://github.com/erusev/parsedown-extra/issues",
"source":
"https://github.com/erusev/parsedown-extra/tree/master"
},
"install-path": "../erusev/parsedown-extra"
},
{
"name": "filp/whoops",
"version": "2.5.1",
"version_normalized": "2.5.1.0",
"source": {
"type": "git",
"url":
"https://github.com/filp/whoops.git",
"reference":
"ee9699e79d8fcdd15c107e035d7b965e4fa854ac"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/filp/whoops/zipball/ee9699e79d8fcdd15c107e035d7b965e4fa854ac",
"reference":
"ee9699e79d8fcdd15c107e035d7b965e4fa854ac",
"shasum": ""
},
"require": {
"php": "^5.5.9 || ^7.0",
"psr/log": "^1.0.1"
},
"require-dev": {
"mockery/mockery": "^0.9 || ^1.0",
"phpunit/phpunit": "^4.8.35 || ^5.7",
"symfony/var-dumper": "^2.6 || ^3.0 ||
^4.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex
values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP
responses"
},
"time": "2019-12-21T10:00:00+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Filipe Dobreira",
"homepage":
"https://github.com/filp",
"role": "Developer"
}
],
"description": "php error handling for cool
kids",
"homepage":
"https://filp.github.io/whoops/",
"keywords": [
"error",
"exception",
"handling",
"library",
"throwable",
"whoops"
],
"support": {
"issues":
"https://github.com/filp/whoops/issues",
"source":
"https://github.com/filp/whoops/tree/2.5.1"
},
"install-path": "../filp/whoops"
},
{
"name": "leafo/scssphp",
"version": "v0.8.4",
"version_normalized": "0.8.4.0",
"source": {
"type": "git",
"url":
"https://github.com/leafo/scssphp.git",
"reference":
"b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/leafo/scssphp/zipball/b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9",
"reference":
"b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9",
"shasum": ""
},
"require": {
"php": "^5.4.0 || ^7"
},
"require-dev": {
"phpunit/phpunit": "~4.6",
"squizlabs/php_codesniffer": "~2.5",
"twbs/bootstrap": "~4.3",
"zurb/foundation": "~6.5"
},
"time": "2019-06-18T21:15:44+00:00",
"bin": [
"bin/pscss"
],
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Leafo\\ScssPhp\\": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Leaf Corcoran",
"email": "leafot@gmail.com",
"homepage": "http://leafo.net"
}
],
"description": "scssphp is a compiler for SCSS
written in PHP.",
"homepage":
"http://leafo.github.io/scssphp/",
"keywords": [
"css",
"less",
"sass",
"scss",
"stylesheet"
],
"support": {
"issues":
"https://github.com/leafo/scssphp/issues",
"source":
"https://github.com/leafo/scssphp/tree/v0.8.4"
},
"abandoned": "scssphp/scssphp",
"install-path": "../leafo/scssphp"
},
{
"name": "pimple/pimple",
"version": "v3.2.3",
"version_normalized": "3.2.3.0",
"source": {
"type": "git",
"url":
"https://github.com/silexphp/Pimple.git",
"reference":
"9e403941ef9d65d20cba7d54e29fe906db42cf32"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32",
"reference":
"9e403941ef9d65d20cba7d54e29fe906db42cf32",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"psr/container": "^1.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^3.2"
},
"time": "2018-01-21T07:42:36+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Pimple": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Pimple, a simple Dependency
Injection Container",
"homepage": "http://pimple.sensiolabs.org",
"keywords": [
"container",
"dependency injection"
],
"support": {
"issues":
"https://github.com/silexphp/Pimple/issues",
"source":
"https://github.com/silexphp/Pimple/tree/master"
},
"install-path": "../pimple/pimple"
},
{
"name": "psr/container",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url":
"https://github.com/php-fig/container.git",
"reference":
"b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference":
"b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2017-02-14T16:28:37+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage":
"http://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP
FIG PSR-11)",
"homepage":
"https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"support": {
"issues":
"https://github.com/php-fig/container/issues",
"source":
"https://github.com/php-fig/container/tree/master"
},
"install-path": "../psr/container"
},
{
"name": "psr/log",
"version": "1.1.3",
"version_normalized": "1.1.3.0",
"source": {
"type": "git",
"url":
"https://github.com/php-fig/log.git",
"reference":
"0f73288fd15629204f9d42b7055f72dacbe811fc"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
"reference":
"0f73288fd15629204f9d42b7055f72dacbe811fc",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2020-03-23T09:12:05+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage":
"http://www.php-fig.org/"
}
],
"description": "Common interface for logging
libraries",
"homepage":
"https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source":
"https://github.com/php-fig/log/tree/1.1.3"
},
"install-path": "../psr/log"
},
{
"name": "rockettheme/toolbox",
"version": "1.4.7",
"version_normalized": "1.4.7.0",
"source": {
"type": "git",
"url":
"https://github.com/rockettheme/toolbox.git",
"reference":
"6a86bc0607884d2194260b6b72d67333e0141585"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/rockettheme/toolbox/zipball/6a86bc0607884d2194260b6b72d67333e0141585",
"reference":
"6a86bc0607884d2194260b6b72d67333e0141585",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=5.4.0",
"pimple/pimple": "~3.0",
"symfony/event-dispatcher": ">2.5",
"symfony/yaml": ">2.5"
},
"require-dev": {
"phpunit/phpunit": "~6"
},
"time": "2020-03-19T18:24:40+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"RocketTheme\\Toolbox\\ArrayTraits\\":
"ArrayTraits/src",
"RocketTheme\\Toolbox\\Blueprints\\":
"Blueprints/src",
"RocketTheme\\Toolbox\\Compat\\":
"Compat/src",
"RocketTheme\\Toolbox\\DI\\":
"DI/src",
"RocketTheme\\Toolbox\\Event\\":
"Event/src",
"RocketTheme\\Toolbox\\File\\":
"File/src",
"RocketTheme\\Toolbox\\ResourceLocator\\":
"ResourceLocator/src",
"RocketTheme\\Toolbox\\Session\\":
"Session/src",
"RocketTheme\\Toolbox\\StreamWrapper\\":
"StreamWrapper/src"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "RocketTheme Toolbox
Library",
"homepage": "http://www.rockettheme.com",
"keywords": [
"php",
"rockettheme"
],
"support": {
"issues":
"https://github.com/rockettheme/toolbox/issues",
"source":
"https://github.com/rockettheme/toolbox/tree/1.4.7"
},
"install-path": "../rockettheme/toolbox"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.8.52",
"version_normalized": "2.8.52.0",
"source": {
"type": "git",
"url":
"https://github.com/symfony/event-dispatcher.git",
"reference":
"a77e974a5fecb4398833b0709210e3d5e334ffb0"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0",
"reference":
"a77e974a5fecb4398833b0709210e3d5e334ffb0",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "^2.0.5|~3.0.0",
"symfony/dependency-injection":
"~2.6|~3.0.0",
"symfony/expression-language":
"~2.6|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"time": "2018-11-21T14:20:20+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\":
""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher
Component",
"homepage": "https://symfony.com",
"support": {
"source":
"https://github.com/symfony/event-dispatcher/tree/v2.8.50"
},
"install-path":
"../symfony/event-dispatcher"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.19.0",
"version_normalized": "1.19.0.0",
"source": {
"type": "git",
"url":
"https://github.com/symfony/polyfill-ctype.git",
"reference":
"aed596913b70fae57be53d86faa2e9ef85a2297b"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b",
"reference":
"aed596913b70fae57be53d86faa2e9ef85a2297b",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2020-10-23T09:01:57+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.19-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url":
"https://github.com/symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype
functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source":
"https://github.com/symfony/polyfill-ctype/tree/v1.19.0"
},
"funding": [
{
"url":
"https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url":
"https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-ctype"
},
{
"name": "symfony/yaml",
"version": "v2.8.52",
"version_normalized": "2.8.52.0",
"source": {
"type": "git",
"url":
"https://github.com/symfony/yaml.git",
"reference":
"02c1859112aa779d9ab394ae4f3381911d84052b"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b",
"reference":
"02c1859112aa779d9ab394ae4f3381911d84052b",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/polyfill-ctype": "~1.8"
},
"time": "2018-11-11T11:18:13+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"support": {
"source":
"https://github.com/symfony/yaml/tree/v2.8.52"
},
"install-path": "../symfony/yaml"
},
{
"name": "twig/twig",
"version": "v1.42.5",
"version_normalized": "1.42.5.0",
"source": {
"type": "git",
"url":
"https://github.com/twigphp/Twig.git",
"reference":
"87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e"
},
"dist": {
"type": "zip",
"url":
"https://api.github.com/repos/twigphp/Twig/zipball/87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e",
"reference":
"87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e",
"shasum": ""
},
"require": {
"php": ">=5.5.0",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"psr/container": "^1.0",
"symfony/phpunit-bridge": "^4.4|^5.0"
},
"time": "2020-02-11T05:59:23+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.42-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Twig_": "lib/"
},
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url":
"https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage":
"http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email":
"armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and
secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues":
"https://github.com/twigphp/Twig/issues",
"source":
"https://github.com/twigphp/Twig/tree/1.x"
},
"install-path": "../twig/twig"
}
],
"dev": false,
"dev-package-names": []
}
PK&d�[�+E�77vendor/composer/installed.phpnu�[���<?php
return array (
'root' =>
array (
'pretty_version' => '5.4.37',
'version' => '5.4.37.0',
'aliases' =>
array (
),
'reference' =>
'a701c1159e7a000861a1b2094ed392f752343e72',
'name' => 'gantry/joomla',
),
'versions' =>
array (
'erusev/parsedown' =>
array (
'pretty_version' => '1.7.4',
'version' => '1.7.4.0',
'aliases' =>
array (
),
'reference' =>
'cb17b6477dfff935958ba01325f2e8a2bfa6dab3',
),
'erusev/parsedown-extra' =>
array (
'pretty_version' => '0.7.1',
'version' => '0.7.1.0',
'aliases' =>
array (
),
'reference' =>
'0db5cce7354e4b76f155d092ab5eb3981c21258c',
),
'filp/whoops' =>
array (
'pretty_version' => '2.5.1',
'version' => '2.5.1.0',
'aliases' =>
array (
),
'reference' =>
'ee9699e79d8fcdd15c107e035d7b965e4fa854ac',
),
'gantry/joomla' =>
array (
'pretty_version' => '5.4.37',
'version' => '5.4.37.0',
'aliases' =>
array (
),
'reference' =>
'a701c1159e7a000861a1b2094ed392f752343e72',
),
'leafo/scssphp' =>
array (
'pretty_version' => 'v0.8.4',
'version' => '0.8.4.0',
'aliases' =>
array (
),
'reference' =>
'b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9',
),
'pimple/pimple' =>
array (
'pretty_version' => 'v3.2.3',
'version' => '3.2.3.0',
'aliases' =>
array (
),
'reference' =>
'9e403941ef9d65d20cba7d54e29fe906db42cf32',
),
'psr/container' =>
array (
'pretty_version' => '1.0.0',
'version' => '1.0.0.0',
'aliases' =>
array (
),
'reference' =>
'b7ce3b176482dbbc1245ebf52b181af44c2cf55f',
),
'psr/log' =>
array (
'pretty_version' => '1.1.3',
'version' => '1.1.3.0',
'aliases' =>
array (
),
'reference' =>
'0f73288fd15629204f9d42b7055f72dacbe811fc',
),
'rockettheme/toolbox' =>
array (
'pretty_version' => '1.4.7',
'version' => '1.4.7.0',
'aliases' =>
array (
),
'reference' =>
'6a86bc0607884d2194260b6b72d67333e0141585',
),
'symfony/event-dispatcher' =>
array (
'pretty_version' => 'v2.8.52',
'version' => '2.8.52.0',
'aliases' =>
array (
),
'reference' =>
'a77e974a5fecb4398833b0709210e3d5e334ffb0',
),
'symfony/polyfill-ctype' =>
array (
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'aliases' =>
array (
),
'reference' =>
'aed596913b70fae57be53d86faa2e9ef85a2297b',
),
'symfony/yaml' =>
array (
'pretty_version' => 'v2.8.52',
'version' => '2.8.52.0',
'aliases' =>
array (
),
'reference' =>
'02c1859112aa779d9ab394ae4f3381911d84052b',
),
'twig/twig' =>
array (
'pretty_version' => 'v1.42.5',
'version' => '1.42.5.0',
'aliases' =>
array (
),
'reference' =>
'87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e',
),
),
);
PK&d�[v@��bb%vendor/composer/InstalledVersions.phpnu�[���<?php
namespace Composer;
use Composer\Semver\VersionParser;
class InstalledVersions
{
private static $installed = array (
'root' =>
array (
'pretty_version' => '5.4.37',
'version' => '5.4.37.0',
'aliases' =>
array (
),
'reference' =>
'a701c1159e7a000861a1b2094ed392f752343e72',
'name' => 'gantry/joomla',
),
'versions' =>
array (
'erusev/parsedown' =>
array (
'pretty_version' => '1.7.4',
'version' => '1.7.4.0',
'aliases' =>
array (
),
'reference' =>
'cb17b6477dfff935958ba01325f2e8a2bfa6dab3',
),
'erusev/parsedown-extra' =>
array (
'pretty_version' => '0.7.1',
'version' => '0.7.1.0',
'aliases' =>
array (
),
'reference' =>
'0db5cce7354e4b76f155d092ab5eb3981c21258c',
),
'filp/whoops' =>
array (
'pretty_version' => '2.5.1',
'version' => '2.5.1.0',
'aliases' =>
array (
),
'reference' =>
'ee9699e79d8fcdd15c107e035d7b965e4fa854ac',
),
'gantry/joomla' =>
array (
'pretty_version' => '5.4.37',
'version' => '5.4.37.0',
'aliases' =>
array (
),
'reference' =>
'a701c1159e7a000861a1b2094ed392f752343e72',
),
'leafo/scssphp' =>
array (
'pretty_version' => 'v0.8.4',
'version' => '0.8.4.0',
'aliases' =>
array (
),
'reference' =>
'b9cdea3e42c3bcb1a9faafd04ccce4e8ec860ad9',
),
'pimple/pimple' =>
array (
'pretty_version' => 'v3.2.3',
'version' => '3.2.3.0',
'aliases' =>
array (
),
'reference' =>
'9e403941ef9d65d20cba7d54e29fe906db42cf32',
),
'psr/container' =>
array (
'pretty_version' => '1.0.0',
'version' => '1.0.0.0',
'aliases' =>
array (
),
'reference' =>
'b7ce3b176482dbbc1245ebf52b181af44c2cf55f',
),
'psr/log' =>
array (
'pretty_version' => '1.1.3',
'version' => '1.1.3.0',
'aliases' =>
array (
),
'reference' =>
'0f73288fd15629204f9d42b7055f72dacbe811fc',
),
'rockettheme/toolbox' =>
array (
'pretty_version' => '1.4.7',
'version' => '1.4.7.0',
'aliases' =>
array (
),
'reference' =>
'6a86bc0607884d2194260b6b72d67333e0141585',
),
'symfony/event-dispatcher' =>
array (
'pretty_version' => 'v2.8.52',
'version' => '2.8.52.0',
'aliases' =>
array (
),
'reference' =>
'a77e974a5fecb4398833b0709210e3d5e334ffb0',
),
'symfony/polyfill-ctype' =>
array (
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'aliases' =>
array (
),
'reference' =>
'aed596913b70fae57be53d86faa2e9ef85a2297b',
),
'symfony/yaml' =>
array (
'pretty_version' => 'v2.8.52',
'version' => '2.8.52.0',
'aliases' =>
array (
),
'reference' =>
'02c1859112aa779d9ab394ae4f3381911d84052b',
),
'twig/twig' =>
array (
'pretty_version' => 'v1.42.5',
'version' => '1.42.5.0',
'aliases' =>
array (
),
'reference' =>
'87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e',
),
),
);
public static function getInstalledPackages()
{
return array_keys(self::$installed['versions']);
}
public static function isInstalled($packageName)
{
return isset(self::$installed['versions'][$packageName]);
}
public static function satisfies(VersionParser $parser, $packageName,
$constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided =
$parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
public static function getVersionRanges($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName .
'" is not installed');
}
$ranges = array();
if
(isset(self::$installed['versions'][$packageName]['pretty_version']))
{
$ranges[] =
self::$installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases',
self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges,
self::$installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced',
self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges,
self::$installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided',
self::$installed['versions'][$packageName])) {
$ranges = array_merge($ranges,
self::$installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
public static function getVersion($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName .
'" is not installed');
}
if
(!isset(self::$installed['versions'][$packageName]['version']))
{
return null;
}
return
self::$installed['versions'][$packageName]['version'];
}
public static function getPrettyVersion($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName .
'" is not installed');
}
if
(!isset(self::$installed['versions'][$packageName]['pretty_version']))
{
return null;
}
return
self::$installed['versions'][$packageName]['pretty_version'];
}
public static function getReference($packageName)
{
if (!isset(self::$installed['versions'][$packageName])) {
throw new \OutOfBoundsException('Package "' . $packageName .
'" is not installed');
}
if
(!isset(self::$installed['versions'][$packageName]['reference']))
{
return null;
}
return
self::$installed['versions'][$packageName]['reference'];
}
public static function getRootPackage()
{
return self::$installed['root'];
}
public static function getRawData()
{
return self::$installed;
}
public static function reload($data)
{
self::$installed = $data;
}
}
PK&d�[i�
O��"vendor/composer/platform_check.phpnu�[���<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 50509)) {
$issues[] = 'Your Composer dependencies require a PHP version
">= 5.5.9". You are running ' . PHP_VERSION .
'.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI ===
'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your
platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) .
PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' .
PHP_EOL.PHP_EOL . str_replace('You are running
'.PHP_VERSION.'.', '', implode(PHP_EOL, $issues))
. PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' .
implode(' ', $issues),
E_USER_ERROR
);
}
PK&d�[�4�%vendor/erusev/parsedown/composer.jsonnu�[���{
"name": "erusev/parsedown",
"description": "Parser for Markdown.",
"keywords": ["markdown", "parser"],
"homepage": "http://parsedown.org",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"require": {
"php": ">=5.3.0",
"ext-mbstring": "*"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"autoload": {
"psr-0": {"Parsedown": ""}
},
"autoload-dev": {
"psr-0": {
"TestParsedown": "test/",
"ParsedownTest": "test/",
"CommonMarkTest": "test/",
"CommonMarkTestWeak": "test/"
}
}
}
PK&d�[7�~�����%vendor/erusev/parsedown/Parsedown.phpnu�[���<?php
#
#
# Parsedown
# http://parsedown.org
#
# (c) Emanuil Rusev
# http://erusev.com
#
# For the full license information, view the LICENSE file that was
distributed
# with this source code.
#
#
class Parsedown
{
# ~
const version = '1.7.4';
# ~
function text($text)
{
# make sure no definitions are set
$this->DefinitionData = array();
# standardize line breaks
$text = str_replace(array("\r\n", "\r"),
"\n", $text);
# remove surrounding line breaks
$text = trim($text, "\n");
# split text into lines
$lines = explode("\n", $text);
# iterate through lines to identify blocks
$markup = $this->lines($lines);
# trim line breaks
$markup = trim($markup, "\n");
return $markup;
}
#
# Setters
#
function setBreaksEnabled($breaksEnabled)
{
$this->breaksEnabled = $breaksEnabled;
return $this;
}
protected $breaksEnabled;
function setMarkupEscaped($markupEscaped)
{
$this->markupEscaped = $markupEscaped;
return $this;
}
protected $markupEscaped;
function setUrlsLinked($urlsLinked)
{
$this->urlsLinked = $urlsLinked;
return $this;
}
protected $urlsLinked = true;
function setSafeMode($safeMode)
{
$this->safeMode = (bool) $safeMode;
return $this;
}
protected $safeMode;
protected $safeLinksWhitelist = array(
'http://',
'https://',
'ftp://',
'ftps://',
'mailto:',
'data:image/png;base64,',
'data:image/gif;base64,',
'data:image/jpeg;base64,',
'irc:',
'ircs:',
'git:',
'ssh:',
'news:',
'steam:',
);
#
# Lines
#
protected $BlockTypes = array(
'#' => array('Header'),
'*' => array('Rule', 'List'),
'+' => array('List'),
'-' => array('SetextHeader',
'Table', 'Rule', 'List'),
'0' => array('List'),
'1' => array('List'),
'2' => array('List'),
'3' => array('List'),
'4' => array('List'),
'5' => array('List'),
'6' => array('List'),
'7' => array('List'),
'8' => array('List'),
'9' => array('List'),
':' => array('Table'),
'<' => array('Comment',
'Markup'),
'=' => array('SetextHeader'),
'>' => array('Quote'),
'[' => array('Reference'),
'_' => array('Rule'),
'`' => array('FencedCode'),
'|' => array('Table'),
'~' => array('FencedCode'),
);
# ~
protected $unmarkedBlockTypes = array(
'Code',
);
#
# Blocks
#
protected function lines(array $lines)
{
$CurrentBlock = null;
foreach ($lines as $line)
{
if (chop($line) === '')
{
if (isset($CurrentBlock))
{
$CurrentBlock['interrupted'] = true;
}
continue;
}
if (strpos($line, "\t") !== false)
{
$parts = explode("\t", $line);
$line = $parts[0];
unset($parts[0]);
foreach ($parts as $part)
{
$shortage = 4 - mb_strlen($line, 'utf-8') %
4;
$line .= str_repeat(' ', $shortage);
$line .= $part;
}
}
$indent = 0;
while (isset($line[$indent]) and $line[$indent] === '
')
{
$indent ++;
}
$text = $indent > 0 ? substr($line, $indent) : $line;
# ~
$Line = array('body' => $line, 'indent'
=> $indent, 'text' => $text);
# ~
if (isset($CurrentBlock['continuable']))
{
$Block =
$this->{'block'.$CurrentBlock['type'].'Continue'}($Line,
$CurrentBlock);
if (isset($Block))
{
$CurrentBlock = $Block;
continue;
}
else
{
if
($this->isBlockCompletable($CurrentBlock['type']))
{
$CurrentBlock =
$this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
}
}
}
# ~
$marker = $text[0];
# ~
$blockTypes = $this->unmarkedBlockTypes;
if (isset($this->BlockTypes[$marker]))
{
foreach ($this->BlockTypes[$marker] as $blockType)
{
$blockTypes []= $blockType;
}
}
#
# ~
foreach ($blockTypes as $blockType)
{
$Block = $this->{'block'.$blockType}($Line,
$CurrentBlock);
if (isset($Block))
{
$Block['type'] = $blockType;
if ( ! isset($Block['identified']))
{
$Blocks []= $CurrentBlock;
$Block['identified'] = true;
}
if ($this->isBlockContinuable($blockType))
{
$Block['continuable'] = true;
}
$CurrentBlock = $Block;
continue 2;
}
}
# ~
if (isset($CurrentBlock) and !
isset($CurrentBlock['type']) and !
isset($CurrentBlock['interrupted']))
{
$CurrentBlock['element']['text'] .=
"\n".$text;
}
else
{
$Blocks []= $CurrentBlock;
$CurrentBlock = $this->paragraph($Line);
$CurrentBlock['identified'] = true;
}
}
# ~
if (isset($CurrentBlock['continuable']) and
$this->isBlockCompletable($CurrentBlock['type']))
{
$CurrentBlock =
$this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);
}
# ~
$Blocks []= $CurrentBlock;
unset($Blocks[0]);
# ~
$markup = '';
foreach ($Blocks as $Block)
{
if (isset($Block['hidden']))
{
continue;
}
$markup .= "\n";
$markup .= isset($Block['markup']) ?
$Block['markup'] :
$this->element($Block['element']);
}
$markup .= "\n";
# ~
return $markup;
}
protected function isBlockContinuable($Type)
{
return method_exists($this,
'block'.$Type.'Continue');
}
protected function isBlockCompletable($Type)
{
return method_exists($this,
'block'.$Type.'Complete');
}
#
# Code
protected function blockCode($Line, $Block = null)
{
if (isset($Block) and ! isset($Block['type']) and !
isset($Block['interrupted']))
{
return;
}
if ($Line['indent'] >= 4)
{
$text = substr($Line['body'], 4);
$Block = array(
'element' => array(
'name' => 'pre',
'handler' => 'element',
'text' => array(
'name' => 'code',
'text' => $text,
),
),
);
return $Block;
}
}
protected function blockCodeContinue($Line, $Block)
{
if ($Line['indent'] >= 4)
{
if (isset($Block['interrupted']))
{
$Block['element']['text']['text'] .=
"\n";
unset($Block['interrupted']);
}
$Block['element']['text']['text']
.= "\n";
$text = substr($Line['body'], 4);
$Block['element']['text']['text']
.= $text;
return $Block;
}
}
protected function blockCodeComplete($Block)
{
$text =
$Block['element']['text']['text'];
$Block['element']['text']['text'] =
$text;
return $Block;
}
#
# Comment
protected function blockComment($Line)
{
if ($this->markupEscaped or $this->safeMode)
{
return;
}
if (isset($Line['text'][3]) and
$Line['text'][3] === '-' and $Line['text'][2]
=== '-' and $Line['text'][1] === '!')
{
$Block = array(
'markup' => $Line['body'],
);
if (preg_match('/-->$/', $Line['text']))
{
$Block['closed'] = true;
}
return $Block;
}
}
protected function blockCommentContinue($Line, array $Block)
{
if (isset($Block['closed']))
{
return;
}
$Block['markup'] .= "\n" .
$Line['body'];
if (preg_match('/-->$/', $Line['text']))
{
$Block['closed'] = true;
}
return $Block;
}
#
# Fenced Code
protected function blockFencedCode($Line)
{
if
(preg_match('/^['.$Line['text'][0].']{3,}[
]*([^`]+)?[ ]*$/', $Line['text'], $matches))
{
$Element = array(
'name' => 'code',
'text' => '',
);
if (isset($matches[1]))
{
/**
*
https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes
* Every HTML element may have a class attribute specified.
* The attribute, if specified, must have a value that is a
set
* of space-separated tokens representing the various
classes
* that the element belongs to.
* [...]
* The space characters, for the purposes of this
specification,
* are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab),
* U+000A LINE FEED (LF), U+000C FORM FEED (FF), and
* U+000D CARRIAGE RETURN (CR).
*/
$language = substr($matches[1], 0, strcspn($matches[1],
" \t\n\f\r"));
$class = 'language-'.$language;
$Element['attributes'] = array(
'class' => $class,
);
}
$Block = array(
'char' => $Line['text'][0],
'element' => array(
'name' => 'pre',
'handler' => 'element',
'text' => $Element,
),
);
return $Block;
}
}
protected function blockFencedCodeContinue($Line, $Block)
{
if (isset($Block['complete']))
{
return;
}
if (isset($Block['interrupted']))
{
$Block['element']['text']['text']
.= "\n";
unset($Block['interrupted']);
}
if (preg_match('/^'.$Block['char'].'{3,}[
]*$/', $Line['text']))
{
$Block['element']['text']['text']
= substr($Block['element']['text']['text'],
1);
$Block['complete'] = true;
return $Block;
}
$Block['element']['text']['text'] .=
"\n".$Line['body'];
return $Block;
}
protected function blockFencedCodeComplete($Block)
{
$text =
$Block['element']['text']['text'];
$Block['element']['text']['text'] =
$text;
return $Block;
}
#
# Header
protected function blockHeader($Line)
{
if (isset($Line['text'][1]))
{
$level = 1;
while (isset($Line['text'][$level]) and
$Line['text'][$level] === '#')
{
$level ++;
}
if ($level > 6)
{
return;
}
$text = trim($Line['text'], '# ');
$Block = array(
'element' => array(
'name' => 'h' . min(6, $level),
'text' => $text,
'handler' => 'line',
),
);
return $Block;
}
}
#
# List
protected function blockList($Line)
{
list($name, $pattern) = $Line['text'][0] <=
'-' ? array('ul', '[*+-]') :
array('ol', '[0-9]+[.]');
if (preg_match('/^('.$pattern.'[ ]+)(.*)/',
$Line['text'], $matches))
{
$Block = array(
'indent' => $Line['indent'],
'pattern' => $pattern,
'element' => array(
'name' => $name,
'handler' => 'elements',
),
);
if($name === 'ol')
{
$listStart = stristr($matches[0], '.', true);
if($listStart !== '1')
{
$Block['element']['attributes'] =
array('start' => $listStart);
}
}
$Block['li'] = array(
'name' => 'li',
'handler' => 'li',
'text' => array(
$matches[2],
),
);
$Block['element']['text'] []= &
$Block['li'];
return $Block;
}
}
protected function blockListContinue($Line, array $Block)
{
if ($Block['indent'] === $Line['indent'] and
preg_match('/^'.$Block['pattern'].'(?:[
]+(.*)|$)/', $Line['text'], $matches))
{
if (isset($Block['interrupted']))
{
$Block['li']['text'] []= '';
$Block['loose'] = true;
unset($Block['interrupted']);
}
unset($Block['li']);
$text = isset($matches[1]) ? $matches[1] : '';
$Block['li'] = array(
'name' => 'li',
'handler' => 'li',
'text' => array(
$text,
),
);
$Block['element']['text'] []= &
$Block['li'];
return $Block;
}
if ($Line['text'][0] === '[' and
$this->blockReference($Line))
{
return $Block;
}
if ( ! isset($Block['interrupted']))
{
$text = preg_replace('/^[ ]{0,4}/', '',
$Line['body']);
$Block['li']['text'] []= $text;
return $Block;
}
if ($Line['indent'] > 0)
{
$Block['li']['text'] []= '';
$text = preg_replace('/^[ ]{0,4}/', '',
$Line['body']);
$Block['li']['text'] []= $text;
unset($Block['interrupted']);
return $Block;
}
}
protected function blockListComplete(array $Block)
{
if (isset($Block['loose']))
{
foreach ($Block['element']['text'] as
&$li)
{
if (end($li['text']) !== '')
{
$li['text'] []= '';
}
}
}
return $Block;
}
#
# Quote
protected function blockQuote($Line)
{
if (preg_match('/^>[ ]?(.*)/',
$Line['text'], $matches))
{
$Block = array(
'element' => array(
'name' => 'blockquote',
'handler' => 'lines',
'text' => (array) $matches[1],
),
);
return $Block;
}
}
protected function blockQuoteContinue($Line, array $Block)
{
if ($Line['text'][0] === '>' and
preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))
{
if (isset($Block['interrupted']))
{
$Block['element']['text'] []=
'';
unset($Block['interrupted']);
}
$Block['element']['text'] []= $matches[1];
return $Block;
}
if ( ! isset($Block['interrupted']))
{
$Block['element']['text'] []=
$Line['text'];
return $Block;
}
}
#
# Rule
protected function blockRule($Line)
{
if
(preg_match('/^(['.$Line['text'][0].'])([
]*\1){2,}[ ]*$/', $Line['text']))
{
$Block = array(
'element' => array(
'name' => 'hr'
),
);
return $Block;
}
}
#
# Setext
protected function blockSetextHeader($Line, array $Block = null)
{
if ( ! isset($Block) or isset($Block['type']) or
isset($Block['interrupted']))
{
return;
}
if (chop($Line['text'], $Line['text'][0]) ===
'')
{
$Block['element']['name'] =
$Line['text'][0] === '=' ? 'h1' :
'h2';
return $Block;
}
}
#
# Markup
protected function blockMarkup($Line)
{
if ($this->markupEscaped or $this->safeMode)
{
return;
}
if (preg_match('/^<(\w[\w-]*)(?:[
]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/',
$Line['text'], $matches))
{
$element = strtolower($matches[1]);
if (in_array($element, $this->textLevelElements))
{
return;
}
$Block = array(
'name' => $matches[1],
'depth' => 0,
'markup' => $Line['text'],
);
$length = strlen($matches[0]);
$remainder = substr($Line['text'], $length);
if (trim($remainder) === '')
{
if (isset($matches[2]) or in_array($matches[1],
$this->voidElements))
{
$Block['closed'] = true;
$Block['void'] = true;
}
}
else
{
if (isset($matches[2]) or in_array($matches[1],
$this->voidElements))
{
return;
}
if (preg_match('/<\/'.$matches[1].'>[
]*$/i', $remainder))
{
$Block['closed'] = true;
}
}
return $Block;
}
}
protected function blockMarkupContinue($Line, array $Block)
{
if (isset($Block['closed']))
{
return;
}
if
(preg_match('/^<'.$Block['name'].'(?:[
]*'.$this->regexHtmlAttribute.')*[ ]*>/i',
$Line['text'])) # open
{
$Block['depth'] ++;
}
if
(preg_match('/(.*?)<\/'.$Block['name'].'>[
]*$/i', $Line['text'], $matches)) # close
{
if ($Block['depth'] > 0)
{
$Block['depth'] --;
}
else
{
$Block['closed'] = true;
}
}
if (isset($Block['interrupted']))
{
$Block['markup'] .= "\n";
unset($Block['interrupted']);
}
$Block['markup'] .=
"\n".$Line['body'];
return $Block;
}
#
# Reference
protected function blockReference($Line)
{
if (preg_match('/^\[(.+?)\]:[ ]*<?(\S+?)>?(?:[
]+["\'(](.+)["\')])?[ ]*$/',
$Line['text'], $matches))
{
$id = strtolower($matches[1]);
$Data = array(
'url' => $matches[2],
'title' => null,
);
if (isset($matches[3]))
{
$Data['title'] = $matches[3];
}
$this->DefinitionData['Reference'][$id] = $Data;
$Block = array(
'hidden' => true,
);
return $Block;
}
}
#
# Table
protected function blockTable($Line, array $Block = null)
{
if ( ! isset($Block) or isset($Block['type']) or
isset($Block['interrupted']))
{
return;
}
if (strpos($Block['element']['text'],
'|') !== false and chop($Line['text'], '
-:|') === '')
{
$alignments = array();
$divider = $Line['text'];
$divider = trim($divider);
$divider = trim($divider, '|');
$dividerCells = explode('|', $divider);
foreach ($dividerCells as $dividerCell)
{
$dividerCell = trim($dividerCell);
if ($dividerCell === '')
{
continue;
}
$alignment = null;
if ($dividerCell[0] === ':')
{
$alignment = 'left';
}
if (substr($dividerCell, - 1) === ':')
{
$alignment = $alignment === 'left' ?
'center' : 'right';
}
$alignments []= $alignment;
}
# ~
$HeaderElements = array();
$header = $Block['element']['text'];
$header = trim($header);
$header = trim($header, '|');
$headerCells = explode('|', $header);
foreach ($headerCells as $index => $headerCell)
{
$headerCell = trim($headerCell);
$HeaderElement = array(
'name' => 'th',
'text' => $headerCell,
'handler' => 'line',
);
if (isset($alignments[$index]))
{
$alignment = $alignments[$index];
$HeaderElement['attributes'] = array(
'style' => 'text-align:
'.$alignment.';',
);
}
$HeaderElements []= $HeaderElement;
}
# ~
$Block = array(
'alignments' => $alignments,
'identified' => true,
'element' => array(
'name' => 'table',
'handler' => 'elements',
),
);
$Block['element']['text'] []= array(
'name' => 'thead',
'handler' => 'elements',
);
$Block['element']['text'] []= array(
'name' => 'tbody',
'handler' => 'elements',
'text' => array(),
);
$Block['element']['text'][0]['text'] []=
array(
'name' => 'tr',
'handler' => 'elements',
'text' => $HeaderElements,
);
return $Block;
}
}
protected function blockTableContinue($Line, array $Block)
{
if (isset($Block['interrupted']))
{
return;
}
if ($Line['text'][0] === '|' or
strpos($Line['text'], '|'))
{
$Elements = array();
$row = $Line['text'];
$row = trim($row);
$row = trim($row, '|');
preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/',
$row, $matches);
foreach ($matches[0] as $index => $cell)
{
$cell = trim($cell);
$Element = array(
'name' => 'td',
'handler' => 'line',
'text' => $cell,
);
if (isset($Block['alignments'][$index]))
{
$Element['attributes'] = array(
'style' => 'text-align:
'.$Block['alignments'][$index].';',
);
}
$Elements []= $Element;
}
$Element = array(
'name' => 'tr',
'handler' => 'elements',
'text' => $Elements,
);
$Block['element']['text'][1]['text'] []=
$Element;
return $Block;
}
}
#
# ~
#
protected function paragraph($Line)
{
$Block = array(
'element' => array(
'name' => 'p',
'text' => $Line['text'],
'handler' => 'line',
),
);
return $Block;
}
#
# Inline Elements
#
protected $InlineTypes = array(
'"' => array('SpecialCharacter'),
'!' => array('Image'),
'&' => array('SpecialCharacter'),
'*' => array('Emphasis'),
':' => array('Url'),
'<' => array('UrlTag',
'EmailTag', 'Markup', 'SpecialCharacter'),
'>' => array('SpecialCharacter'),
'[' => array('Link'),
'_' => array('Emphasis'),
'`' => array('Code'),
'~' => array('Strikethrough'),
'\\' => array('EscapeSequence'),
);
# ~
protected $inlineMarkerList = '!"*_&[:<>`~\\';
#
# ~
#
public function line($text, $nonNestables=array())
{
$markup = '';
# $excerpt is based on the first occurrence of a marker
while ($excerpt = strpbrk($text, $this->inlineMarkerList))
{
$marker = $excerpt[0];
$markerPosition = strpos($text, $marker);
$Excerpt = array('text' => $excerpt,
'context' => $text);
foreach ($this->InlineTypes[$marker] as $inlineType)
{
# check to see if the current inline type is nestable in
the current context
if ( ! empty($nonNestables) and in_array($inlineType,
$nonNestables))
{
continue;
}
$Inline =
$this->{'inline'.$inlineType}($Excerpt);
if ( ! isset($Inline))
{
continue;
}
# makes sure that the inline belongs to "our"
marker
if (isset($Inline['position']) and
$Inline['position'] > $markerPosition)
{
continue;
}
# sets a default inline position
if ( ! isset($Inline['position']))
{
$Inline['position'] = $markerPosition;
}
# cause the new element to 'inherit' our non
nestables
foreach ($nonNestables as $non_nestable)
{
$Inline['element']['nonNestables'][] = $non_nestable;
}
# the text that comes before the inline
$unmarkedText = substr($text, 0,
$Inline['position']);
# compile the unmarked text
$markup .= $this->unmarkedText($unmarkedText);
# compile the inline
$markup .= isset($Inline['markup']) ?
$Inline['markup'] :
$this->element($Inline['element']);
# remove the examined text
$text = substr($text, $Inline['position'] +
$Inline['extent']);
continue 2;
}
# the marker does not belong to an inline
$unmarkedText = substr($text, 0, $markerPosition + 1);
$markup .= $this->unmarkedText($unmarkedText);
$text = substr($text, $markerPosition + 1);
}
$markup .= $this->unmarkedText($text);
return $markup;
}
#
# ~
#
protected function inlineCode($Excerpt)
{
$marker = $Excerpt['text'][0];
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[
]*(?<!'.$marker.')\1(?!'.$marker.')/s',
$Excerpt['text'], $matches))
{
$text = $matches[2];
$text = preg_replace("/[ ]*\n/", ' ',
$text);
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'code',
'text' => $text,
),
);
}
}
protected function inlineEmailTag($Excerpt)
{
if (strpos($Excerpt['text'], '>') !== false
and preg_match('/^<((mailto:)?\S+?@\S+?)>/i',
$Excerpt['text'], $matches))
{
$url = $matches[1];
if ( ! isset($matches[2]))
{
$url = 'mailto:' . $url;
}
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'a',
'text' => $matches[1],
'attributes' => array(
'href' => $url,
),
),
);
}
}
protected function inlineEmphasis($Excerpt)
{
if ( ! isset($Excerpt['text'][1]))
{
return;
}
$marker = $Excerpt['text'][0];
if ($Excerpt['text'][1] === $marker and
preg_match($this->StrongRegex[$marker], $Excerpt['text'],
$matches))
{
$emphasis = 'strong';
}
elseif (preg_match($this->EmRegex[$marker],
$Excerpt['text'], $matches))
{
$emphasis = 'em';
}
else
{
return;
}
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => $emphasis,
'handler' => 'line',
'text' => $matches[1],
),
);
}
protected function inlineEscapeSequence($Excerpt)
{
if (isset($Excerpt['text'][1]) and
in_array($Excerpt['text'][1], $this->specialCharacters))
{
return array(
'markup' => $Excerpt['text'][1],
'extent' => 2,
);
}
}
protected function inlineImage($Excerpt)
{
if ( ! isset($Excerpt['text'][1]) or
$Excerpt['text'][1] !== '[')
{
return;
}
$Excerpt['text']= substr($Excerpt['text'], 1);
$Link = $this->inlineLink($Excerpt);
if ($Link === null)
{
return;
}
$Inline = array(
'extent' => $Link['extent'] + 1,
'element' => array(
'name' => 'img',
'attributes' => array(
'src' =>
$Link['element']['attributes']['href'],
'alt' =>
$Link['element']['text'],
),
),
);
$Inline['element']['attributes'] +=
$Link['element']['attributes'];
unset($Inline['element']['attributes']['href']);
return $Inline;
}
protected function inlineLink($Excerpt)
{
$Element = array(
'name' => 'a',
'handler' => 'line',
'nonNestables' => array('Url',
'Link'),
'text' => null,
'attributes' => array(
'href' => null,
'title' => null,
),
);
$extent = 0;
$remainder = $Excerpt['text'];
if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder,
$matches))
{
$Element['text'] = $matches[1];
$extent += strlen($matches[0]);
$remainder = substr($remainder, $extent);
}
else
{
return;
}
if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[
]+("[^"]*"|\'[^\']*\'))?\s*[)]/',
$remainder, $matches))
{
$Element['attributes']['href'] =
$matches[1];
if (isset($matches[2]))
{
$Element['attributes']['title'] =
substr($matches[2], 1, - 1);
}
$extent += strlen($matches[0]);
}
else
{
if (preg_match('/^\s*\[(.*?)\]/', $remainder,
$matches))
{
$definition = strlen($matches[1]) ? $matches[1] :
$Element['text'];
$definition = strtolower($definition);
$extent += strlen($matches[0]);
}
else
{
$definition = strtolower($Element['text']);
}
if ( !
isset($this->DefinitionData['Reference'][$definition]))
{
return;
}
$Definition =
$this->DefinitionData['Reference'][$definition];
$Element['attributes']['href'] =
$Definition['url'];
$Element['attributes']['title'] =
$Definition['title'];
}
return array(
'extent' => $extent,
'element' => $Element,
);
}
protected function inlineMarkup($Excerpt)
{
if ($this->markupEscaped or $this->safeMode or
strpos($Excerpt['text'], '>') === false)
{
return;
}
if ($Excerpt['text'][1] === '/' and
preg_match('/^<\/\w[\w-]*[ ]*>/s',
$Excerpt['text'], $matches))
{
return array(
'markup' => $matches[0],
'extent' => strlen($matches[0]),
);
}
if ($Excerpt['text'][1] === '!' and
preg_match('/^<!---?[^>-](?:-?[^-])*-->/s',
$Excerpt['text'], $matches))
{
return array(
'markup' => $matches[0],
'extent' => strlen($matches[0]),
);
}
if ($Excerpt['text'][1] !== ' ' and
preg_match('/^<\w[\w-]*(?:[
]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s',
$Excerpt['text'], $matches))
{
return array(
'markup' => $matches[0],
'extent' => strlen($matches[0]),
);
}
}
protected function inlineSpecialCharacter($Excerpt)
{
if ($Excerpt['text'][0] === '&' and !
preg_match('/^&#?\w+;/', $Excerpt['text']))
{
return array(
'markup' => '&',
'extent' => 1,
);
}
$SpecialCharacter = array('>' => 'gt',
'<' => 'lt', '"' =>
'quot');
if (isset($SpecialCharacter[$Excerpt['text'][0]]))
{
return array(
'markup' =>
'&'.$SpecialCharacter[$Excerpt['text'][0]].';',
'extent' => 1,
);
}
}
protected function inlineStrikethrough($Excerpt)
{
if ( ! isset($Excerpt['text'][1]))
{
return;
}
if ($Excerpt['text'][1] === '~' and
preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/',
$Excerpt['text'], $matches))
{
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'del',
'text' => $matches[1],
'handler' => 'line',
),
);
}
}
protected function inlineUrl($Excerpt)
{
if ($this->urlsLinked !== true or !
isset($Excerpt['text'][2]) or $Excerpt['text'][2] !==
'/')
{
return;
}
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui',
$Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))
{
$url = $matches[0][0];
$Inline = array(
'extent' => strlen($matches[0][0]),
'position' => $matches[0][1],
'element' => array(
'name' => 'a',
'text' => $url,
'attributes' => array(
'href' => $url,
),
),
);
return $Inline;
}
}
protected function inlineUrlTag($Excerpt)
{
if (strpos($Excerpt['text'], '>') !== false
and preg_match('/^<(\w+:\/{2}[^ >]+)>/i',
$Excerpt['text'], $matches))
{
$url = $matches[1];
return array(
'extent' => strlen($matches[0]),
'element' => array(
'name' => 'a',
'text' => $url,
'attributes' => array(
'href' => $url,
),
),
);
}
}
# ~
protected function unmarkedText($text)
{
if ($this->breaksEnabled)
{
$text = preg_replace('/[ ]*\n/', "<br
/>\n", $text);
}
else
{
$text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/',
"<br />\n", $text);
$text = str_replace(" \n", "\n", $text);
}
return $text;
}
#
# Handlers
#
protected function element(array $Element)
{
if ($this->safeMode)
{
$Element = $this->sanitiseElement($Element);
}
$markup = '<'.$Element['name'];
if (isset($Element['attributes']))
{
foreach ($Element['attributes'] as $name =>
$value)
{
if ($value === null)
{
continue;
}
$markup .= '
'.$name.'="'.self::escape($value).'"';
}
}
$permitRawHtml = false;
if (isset($Element['text']))
{
$text = $Element['text'];
}
// very strongly consider an alternative if you're writing an
// extension
elseif (isset($Element['rawHtml']))
{
$text = $Element['rawHtml'];
$allowRawHtmlInSafeMode =
isset($Element['allowRawHtmlInSafeMode']) &&
$Element['allowRawHtmlInSafeMode'];
$permitRawHtml = !$this->safeMode ||
$allowRawHtmlInSafeMode;
}
if (isset($text))
{
$markup .= '>';
if (!isset($Element['nonNestables']))
{
$Element['nonNestables'] = array();
}
if (isset($Element['handler']))
{
$markup .= $this->{$Element['handler']}($text,
$Element['nonNestables']);
}
elseif (!$permitRawHtml)
{
$markup .= self::escape($text, true);
}
else
{
$markup .= $text;
}
$markup .=
'</'.$Element['name'].'>';
}
else
{
$markup .= ' />';
}
return $markup;
}
protected function elements(array $Elements)
{
$markup = '';
foreach ($Elements as $Element)
{
$markup .= "\n" . $this->element($Element);
}
$markup .= "\n";
return $markup;
}
# ~
protected function li($lines)
{
$markup = $this->lines($lines);
$trimmedMarkup = trim($markup);
if ( ! in_array('', $lines) and substr($trimmedMarkup, 0,
3) === '<p>')
{
$markup = $trimmedMarkup;
$markup = substr($markup, 3);
$position = strpos($markup, "</p>");
$markup = substr_replace($markup, '', $position, 4);
}
return $markup;
}
#
# Deprecated Methods
#
function parse($text)
{
$markup = $this->text($text);
return $markup;
}
protected function sanitiseElement(array $Element)
{
static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/';
static $safeUrlNameToAtt = array(
'a' => 'href',
'img' => 'src',
);
if (isset($safeUrlNameToAtt[$Element['name']]))
{
$Element = $this->filterUnsafeUrlInAttribute($Element,
$safeUrlNameToAtt[$Element['name']]);
}
if ( ! empty($Element['attributes']))
{
foreach ($Element['attributes'] as $att => $val)
{
# filter out badly parsed attribute
if ( ! preg_match($goodAttribute, $att))
{
unset($Element['attributes'][$att]);
}
# dump onevent attribute
elseif (self::striAtStart($att, 'on'))
{
unset($Element['attributes'][$att]);
}
}
}
return $Element;
}
protected function filterUnsafeUrlInAttribute(array $Element,
$attribute)
{
foreach ($this->safeLinksWhitelist as $scheme)
{
if
(self::striAtStart($Element['attributes'][$attribute], $scheme))
{
return $Element;
}
}
$Element['attributes'][$attribute] =
str_replace(':', '%3A',
$Element['attributes'][$attribute]);
return $Element;
}
#
# Static Methods
#
protected static function escape($text, $allowQuotes = false)
{
return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES :
ENT_QUOTES, 'UTF-8');
}
protected static function striAtStart($string, $needle)
{
$len = strlen($needle);
if ($len > strlen($string))
{
return false;
}
else
{
return strtolower(substr($string, 0, $len)) ===
strtolower($needle);
}
}
static function instance($name = 'default')
{
if (isset(self::$instances[$name]))
{
return self::$instances[$name];
}
$instance = new static();
self::$instances[$name] = $instance;
return $instance;
}
private static $instances = array();
#
# Fields
#
protected $DefinitionData;
#
# Read-Only
protected $specialCharacters = array(
'\\', '`', '*', '_',
'{', '}', '[', ']', '(',
')', '>', '#', '+',
'-', '.', '!', '|',
);
protected $StrongRegex = array(
'*' =>
'/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',
'_' =>
'/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us',
);
protected $EmRegex = array(
'*' =>
'/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
'_' =>
'/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us',
);
protected $regexHtmlAttribute =
'[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?';
protected $voidElements = array(
'area', 'base', 'br',
'col', 'command', 'embed', 'hr',
'img', 'input', 'link', 'meta',
'param', 'source',
);
protected $textLevelElements = array(
'a', 'br', 'bdo', 'abbr',
'blink', 'nextid', 'acronym',
'basefont',
'b', 'em', 'big', 'cite',
'small', 'spacer', 'listing',
'i', 'rp', 'del', 'code',
'strike', 'marquee',
'q', 'rt', 'ins', 'font',
'strong',
's', 'tt', 'kbd', 'mark',
'u', 'xm', 'sub', 'nobr',
'sup', 'ruby',
'var', 'span',
'wbr', 'time',
);
}
PK&d�["D_QQ+vendor/erusev/parsedown-extra/composer.jsonnu�[���{
"name": "erusev/parsedown-extra",
"description": "An extension of Parsedown that adds
support for Markdown Extra.",
"keywords": ["markdown", "markdown
extra", "parser", "parsedown"],
"homepage":
"https://github.com/erusev/parsedown-extra",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"require": {
"erusev/parsedown": "~1.4"
},
"autoload": {
"psr-0": {"ParsedownExtra": ""}
}
}PK&d�[�����2�20vendor/erusev/parsedown-extra/ParsedownExtra.phpnu�[���<?php
#
#
# Parsedown Extra
# https://github.com/erusev/parsedown-extra
#
# (c) Emanuil Rusev
# http://erusev.com
#
# For the full license information, view the LICENSE file that was
distributed
# with this source code.
#
#
class ParsedownExtra extends Parsedown
{
# ~
const version = '0.7.0';
# ~
function __construct()
{
if (parent::version < '1.5.0')
{
throw new Exception('ParsedownExtra requires a later
version of Parsedown');
}
$this->BlockTypes[':'] []= 'DefinitionList';
$this->BlockTypes['*'] []= 'Abbreviation';
# identify footnote definitions before reference definitions
array_unshift($this->BlockTypes['['],
'Footnote');
# identify footnote markers before before links
array_unshift($this->InlineTypes['['],
'FootnoteMarker');
}
#
# ~
function text($text)
{
$markup = parent::text($text);
# merge consecutive dl elements
$markup = preg_replace('/<\/dl>\s+<dl>\s+/',
'', $markup);
# add footnotes
if (isset($this->DefinitionData['Footnote']))
{
$Element = $this->buildFootnoteElement();
$markup .= "\n" . $this->element($Element);
}
return $markup;
}
#
# Blocks
#
#
# Abbreviation
protected function blockAbbreviation($Line)
{
if (preg_match('/^\*\[(.+?)\]:[ ]*(.+?)[ ]*$/',
$Line['text'], $matches))
{
$this->DefinitionData['Abbreviation'][$matches[1]]
= $matches[2];
$Block = array(
'hidden' => true,
);
return $Block;
}
}
#
# Footnote
protected function blockFootnote($Line)
{
if (preg_match('/^\[\^(.+?)\]:[ ]?(.*)$/',
$Line['text'], $matches))
{
$Block = array(
'label' => $matches[1],
'text' => $matches[2],
'hidden' => true,
);
return $Block;
}
}
protected function blockFootnoteContinue($Line, $Block)
{
if ($Line['text'][0] === '[' and
preg_match('/^\[\^(.+?)\]:/', $Line['text']))
{
return;
}
if (isset($Block['interrupted']))
{
if ($Line['indent'] >= 4)
{
$Block['text'] .= "\n\n" .
$Line['text'];
return $Block;
}
}
else
{
$Block['text'] .= "\n" .
$Line['text'];
return $Block;
}
}
protected function blockFootnoteComplete($Block)
{
$this->DefinitionData['Footnote'][$Block['label']] =
array(
'text' => $Block['text'],
'count' => null,
'number' => null,
);
return $Block;
}
#
# Definition List
protected function blockDefinitionList($Line, $Block)
{
if ( ! isset($Block) or isset($Block['type']))
{
return;
}
$Element = array(
'name' => 'dl',
'handler' => 'elements',
'text' => array(),
);
$terms = explode("\n",
$Block['element']['text']);
foreach ($terms as $term)
{
$Element['text'] []= array(
'name' => 'dt',
'handler' => 'line',
'text' => $term,
);
}
$Block['element'] = $Element;
$Block = $this->addDdElement($Line, $Block);
return $Block;
}
protected function blockDefinitionListContinue($Line, array $Block)
{
if ($Line['text'][0] === ':')
{
$Block = $this->addDdElement($Line, $Block);
return $Block;
}
else
{
if (isset($Block['interrupted']) and
$Line['indent'] === 0)
{
return;
}
if (isset($Block['interrupted']))
{
$Block['dd']['handler'] =
'text';
$Block['dd']['text'] .=
"\n\n";
unset($Block['interrupted']);
}
$text = substr($Line['body'],
min($Line['indent'], 4));
$Block['dd']['text'] .= "\n" .
$text;
return $Block;
}
}
#
# Header
protected function blockHeader($Line)
{
$Block = parent::blockHeader($Line);
if (preg_match('/[
#]*{('.$this->regexAttribute.'+)}[ ]*$/',
$Block['element']['text'], $matches,
PREG_OFFSET_CAPTURE))
{
$attributeString = $matches[1][0];
$Block['element']['attributes'] =
$this->parseAttributeData($attributeString);
$Block['element']['text'] =
substr($Block['element']['text'], 0, $matches[0][1]);
}
return $Block;
}
#
# Markup
protected function blockMarkupComplete($Block)
{
if ( ! isset($Block['void']))
{
$Block['markup'] =
$this->processTag($Block['markup']);
}
return $Block;
}
#
# Setext
protected function blockSetextHeader($Line, array $Block = null)
{
$Block = parent::blockSetextHeader($Line, $Block);
if (preg_match('/[
]*{('.$this->regexAttribute.'+)}[ ]*$/',
$Block['element']['text'], $matches,
PREG_OFFSET_CAPTURE))
{
$attributeString = $matches[1][0];
$Block['element']['attributes'] =
$this->parseAttributeData($attributeString);
$Block['element']['text'] =
substr($Block['element']['text'], 0, $matches[0][1]);
}
return $Block;
}
#
# Inline Elements
#
#
# Footnote Marker
protected function inlineFootnoteMarker($Excerpt)
{
if (preg_match('/^\[\^(.+?)\]/',
$Excerpt['text'], $matches))
{
$name = $matches[1];
if ( !
isset($this->DefinitionData['Footnote'][$name]))
{
return;
}
$this->DefinitionData['Footnote'][$name]['count']
++;
if ( !
isset($this->DefinitionData['Footnote'][$name]['number']))
{
$this->DefinitionData['Footnote'][$name]['number'] =
++ $this->footnoteCount; # » &
}
$Element = array(
'name' => 'sup',
'attributes' => array('id' =>
'fnref'.$this->DefinitionData['Footnote'][$name]['count'].':'.$name),
'handler' => 'element',
'text' => array(
'name' => 'a',
'attributes' => array('href'
=> '#fn:'.$name, 'class' =>
'footnote-ref'),
'text' =>
$this->DefinitionData['Footnote'][$name]['number'],
),
);
return array(
'extent' => strlen($matches[0]),
'element' => $Element,
);
}
}
private $footnoteCount = 0;
#
# Link
protected function inlineLink($Excerpt)
{
$Link = parent::inlineLink($Excerpt);
$remainder = substr($Excerpt['text'],
$Link['extent']);
if (preg_match('/^[
]*{('.$this->regexAttribute.'+)}/', $remainder,
$matches))
{
$Link['element']['attributes'] +=
$this->parseAttributeData($matches[1]);
$Link['extent'] += strlen($matches[0]);
}
return $Link;
}
#
# ~
#
protected function unmarkedText($text)
{
$text = parent::unmarkedText($text);
if (isset($this->DefinitionData['Abbreviation']))
{
foreach ($this->DefinitionData['Abbreviation'] as
$abbreviation => $meaning)
{
$pattern = '/\b'.preg_quote($abbreviation,
'/').'\b/';
$text = preg_replace($pattern, '<abbr
title="'.$meaning.'">'.$abbreviation.'</abbr>',
$text);
}
}
return $text;
}
#
# Util Methods
#
protected function addDdElement(array $Line, array $Block)
{
$text = substr($Line['text'], 1);
$text = trim($text);
unset($Block['dd']);
$Block['dd'] = array(
'name' => 'dd',
'handler' => 'line',
'text' => $text,
);
if (isset($Block['interrupted']))
{
$Block['dd']['handler'] = 'text';
unset($Block['interrupted']);
}
$Block['element']['text'] []= &
$Block['dd'];
return $Block;
}
protected function buildFootnoteElement()
{
$Element = array(
'name' => 'div',
'attributes' => array('class' =>
'footnotes'),
'handler' => 'elements',
'text' => array(
array(
'name' => 'hr',
),
array(
'name' => 'ol',
'handler' => 'elements',
'text' => array(),
),
),
);
uasort($this->DefinitionData['Footnote'],
'self::sortFootnotes');
foreach ($this->DefinitionData['Footnote'] as
$definitionId => $DefinitionData)
{
if ( ! isset($DefinitionData['number']))
{
continue;
}
$text = $DefinitionData['text'];
$text = parent::text($text);
$numbers = range(1, $DefinitionData['count']);
$backLinksMarkup = '';
foreach ($numbers as $number)
{
$backLinksMarkup .= ' <a
href="#fnref'.$number.':'.$definitionId.'"
rev="footnote"
class="footnote-backref">↩</a>';
}
$backLinksMarkup = substr($backLinksMarkup, 1);
if (substr($text, - 4) === '</p>')
{
$backLinksMarkup = ' '.$backLinksMarkup;
$text = substr_replace($text,
$backLinksMarkup.'</p>', - 4);
}
else
{
$text .=
"\n".'<p>'.$backLinksMarkup.'</p>';
}
$Element['text'][1]['text'] []= array(
'name' => 'li',
'attributes' => array('id' =>
'fn:'.$definitionId),
'text' => "\n".$text."\n",
);
}
return $Element;
}
# ~
protected function parseAttributeData($attributeString)
{
$Data = array();
$attributes = preg_split('/[ ]+/', $attributeString, - 1,
PREG_SPLIT_NO_EMPTY);
foreach ($attributes as $attribute)
{
if ($attribute[0] === '#')
{
$Data['id'] = substr($attribute, 1);
}
else # "."
{
$classes []= substr($attribute, 1);
}
}
if (isset($classes))
{
$Data['class'] = implode(' ', $classes);
}
return $Data;
}
# ~
protected function processTag($elementMarkup) # recursive
{
# http://stackoverflow.com/q/1148928/200145
libxml_use_internal_errors(true);
$DOMDocument = new DOMDocument;
# http://stackoverflow.com/q/11309194/200145
$elementMarkup = mb_convert_encoding($elementMarkup,
'HTML-ENTITIES', 'UTF-8');
# http://stackoverflow.com/q/4879946/200145
$DOMDocument->loadHTML($elementMarkup);
$DOMDocument->removeChild($DOMDocument->doctype);
$DOMDocument->replaceChild($DOMDocument->firstChild->firstChild->firstChild,
$DOMDocument->firstChild);
$elementText = '';
if
($DOMDocument->documentElement->getAttribute('markdown')
=== '1')
{
foreach ($DOMDocument->documentElement->childNodes as
$Node)
{
$elementText .= $DOMDocument->saveHTML($Node);
}
$DOMDocument->documentElement->removeAttribute('markdown');
$elementText =
"\n".$this->text($elementText)."\n";
}
else
{
foreach ($DOMDocument->documentElement->childNodes as
$Node)
{
$nodeMarkup = $DOMDocument->saveHTML($Node);
if ($Node instanceof DOMElement and !
in_array($Node->nodeName, $this->textLevelElements))
{
$elementText .= $this->processTag($nodeMarkup);
}
else
{
$elementText .= $nodeMarkup;
}
}
}
# because we don't want for markup to get encoded
$DOMDocument->documentElement->nodeValue =
'placeholder\x1A';
$markup =
$DOMDocument->saveHTML($DOMDocument->documentElement);
$markup = str_replace('placeholder\x1A', $elementText,
$markup);
return $markup;
}
# ~
protected function sortFootnotes($A, $B) # callback
{
return $A['number'] - $B['number'];
}
#
# Fields
#
protected $regexAttribute = '(?:[#.][-\w]+[ ]*)';
}
PK&d�[PQ(Fll vendor/filp/whoops/composer.jsonnu�[���{
"name": "filp/whoops",
"license": "MIT",
"description": "php error handling for cool kids",
"keywords": ["library", "error",
"handling", "exception", "whoops",
"throwable"],
"homepage": "https://filp.github.io/whoops/",
"authors": [
{
"name": "Filipe Dobreira",
"homepage": "https://github.com/filp",
"role": "Developer"
}
],
"require": {
"php": "^5.5.9 || ^7.0",
"psr/log": "^1.0.1"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7",
"mockery/mockery": "^0.9 || ^1.0",
"symfony/var-dumper": "^2.6 || ^3.0 || ^4.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex values
better with var-dumper available",
"whoops/soap": "Formats errors as SOAP
responses"
},
"autoload": {
"psr-4": {
"Whoops\\": "src/Whoops/"
}
},
"autoload-dev": {
"psr-4": {
"Whoops\\": "tests/Whoops/"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
}
}
PK&d�["�sCcc:vendor/filp/whoops/src/Whoops/Exception/ErrorException.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Exception;
use ErrorException as BaseErrorException;
/**
* Wraps ErrorException; mostly used for typing (at least now)
* to easily cleanup the stack trace of redundant info.
*/
class ErrorException extends BaseErrorException
{
}
PK&d�[�)
���5vendor/filp/whoops/src/Whoops/Exception/Formatter.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Exception;
class Formatter
{
/**
* Returns all basic information about the exception in a simple array
* for further convertion to other languages
* @param Inspector $inspector
* @param bool $shouldAddTrace
* @return array
*/
public static function formatExceptionAsDataArray(Inspector $inspector,
$shouldAddTrace)
{
$exception = $inspector->getException();
$response = [
'type' => get_class($exception),
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
];
if ($shouldAddTrace) {
$frames = $inspector->getFrames();
$frameData = [];
foreach ($frames as $frame) {
/** @var Frame $frame */
$frameData[] = [
'file' => $frame->getFile(),
'line' => $frame->getLine(),
'function' => $frame->getFunction(),
'class' => $frame->getClass(),
'args' => $frame->getArgs(),
];
}
$response['trace'] = $frameData;
}
return $response;
}
public static function formatExceptionPlain(Inspector $inspector)
{
$message = $inspector->getException()->getMessage();
$frames = $inspector->getFrames();
$plain = $inspector->getExceptionName();
$plain .= ' thrown with message "';
$plain .= $message;
$plain .= '"'."\n\n";
$plain .= "Stacktrace:\n";
foreach ($frames as $i => $frame) {
$plain .= "#". (count($frames) - $i - 1). "
";
$plain .= $frame->getClass() ?: '';
$plain .= $frame->getClass() &&
$frame->getFunction() ? ":" : "";
$plain .= $frame->getFunction() ?: '';
$plain .= ' in ';
$plain .= ($frame->getFile() ?:
'<#unknown>');
$plain .= ':';
$plain .= (int) $frame->getLine(). "\n";
}
return $plain;
}
}
PK&d�[/�/tt1vendor/filp/whoops/src/Whoops/Exception/Frame.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Exception;
use InvalidArgumentException;
use Serializable;
class Frame implements Serializable
{
/**
* @var array
*/
protected $frame;
/**
* @var string
*/
protected $fileContentsCache;
/**
* @var array[]
*/
protected $comments = [];
/**
* @var bool
*/
protected $application;
/**
* @param array[]
*/
public function __construct(array $frame)
{
$this->frame = $frame;
}
/**
* @param bool $shortened
* @return string|null
*/
public function getFile($shortened = false)
{
if (empty($this->frame['file'])) {
return null;
}
$file = $this->frame['file'];
// Check if this frame occurred within an eval().
// @todo: This can be made more reliable by checking if we've
entered
// eval() in a previous trace, but will need some more work on the
upper
// trace collector(s).
if (preg_match('/^(.*)\((\d+)\) : (?:eval\(\)\'d|assert)
code$/', $file, $matches)) {
$file = $this->frame['file'] = $matches[1];
$this->frame['line'] = (int) $matches[2];
}
if ($shortened && is_string($file)) {
// Replace the part of the path that all frames have in common,
and add 'soft hyphens' for smoother line-breaks.
$dirname =
dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))));
if ($dirname !== '/') {
$file = str_replace($dirname, "…",
$file);
}
$file = str_replace("/", "/­",
$file);
}
return $file;
}
/**
* @return int|null
*/
public function getLine()
{
return isset($this->frame['line']) ?
$this->frame['line'] : null;
}
/**
* @return string|null
*/
public function getClass()
{
return isset($this->frame['class']) ?
$this->frame['class'] : null;
}
/**
* @return string|null
*/
public function getFunction()
{
return isset($this->frame['function']) ?
$this->frame['function'] : null;
}
/**
* @return array
*/
public function getArgs()
{
return isset($this->frame['args']) ? (array)
$this->frame['args'] : [];
}
/**
* Returns the full contents of the file for this frame,
* if it's known.
* @return string|null
*/
public function getFileContents()
{
if ($this->fileContentsCache === null && $filePath =
$this->getFile()) {
// Leave the stage early when 'Unknown' or
'[internal]' is passed
// this would otherwise raise an exception when
// open_basedir is enabled.
if ($filePath === "Unknown" || $filePath ===
'[internal]') {
return null;
}
try {
$this->fileContentsCache = file_get_contents($filePath);
} catch (ErrorException $exception) {
// Internal file paths of PHP extensions cannot be opened
}
}
return $this->fileContentsCache;
}
/**
* Adds a comment to this frame, that can be received and
* used by other handlers. For example, the PrettyPage handler
* can attach these comments under the code for each frame.
*
* An interesting use for this would be, for example, code analysis
* & annotations.
*
* @param string $comment
* @param string $context Optional string identifying the origin of the
comment
*/
public function addComment($comment, $context = 'global')
{
$this->comments[] = [
'comment' => $comment,
'context' => $context,
];
}
/**
* Returns all comments for this frame. Optionally allows
* a filter to only retrieve comments from a specific
* context.
*
* @param string $filter
* @return array[]
*/
public function getComments($filter = null)
{
$comments = $this->comments;
if ($filter !== null) {
$comments = array_filter($comments, function ($c) use ($filter)
{
return $c['context'] == $filter;
});
}
return $comments;
}
/**
* Returns the array containing the raw frame data from which
* this Frame object was built
*
* @return array
*/
public function getRawFrame()
{
return $this->frame;
}
/**
* Returns the contents of the file for this frame as an
* array of lines, and optionally as a clamped range of lines.
*
* NOTE: lines are 0-indexed
*
* @example
* Get all lines for this file
* $frame->getFileLines(); // => array( 0 =>
'<?php', 1 => '...', ...)
* @example
* Get one line for this file, starting at line 10 (zero-indexed,
remember!)
* $frame->getFileLines(9, 1); // array( 10 =>
'...', 11 => '...')
*
* @throws InvalidArgumentException if $length is less than or equal to
0
* @param int $start
* @param int $length
* @return string[]|null
*/
public function getFileLines($start = 0, $length = null)
{
if (null !== ($contents = $this->getFileContents())) {
$lines = explode("\n", $contents);
// Get a subset of lines from $start to $end
if ($length !== null) {
$start = (int) $start;
$length = (int) $length;
if ($start < 0) {
$start = 0;
}
if ($length <= 0) {
throw new InvalidArgumentException(
"\$length($length) cannot be lower or equal to
0"
);
}
$lines = array_slice($lines, $start, $length, true);
}
return $lines;
}
}
/**
* Implements the Serializable interface, with special
* steps to also save the existing comments.
*
* @see Serializable::serialize
* @return string
*/
public function serialize()
{
$frame = $this->frame;
if (!empty($this->comments)) {
$frame['_comments'] = $this->comments;
}
return serialize($frame);
}
/**
* Unserializes the frame data, while also preserving
* any existing comment data.
*
* @see Serializable::unserialize
* @param string $serializedFrame
*/
public function unserialize($serializedFrame)
{
$frame = unserialize($serializedFrame);
if (!empty($frame['_comments'])) {
$this->comments = $frame['_comments'];
unset($frame['_comments']);
}
$this->frame = $frame;
}
/**
* Compares Frame against one another
* @param Frame $frame
* @return bool
*/
public function equals(Frame $frame)
{
if (!$this->getFile() || $this->getFile() ===
'Unknown' || !$this->getLine()) {
return false;
}
return $frame->getFile() === $this->getFile() &&
$frame->getLine() === $this->getLine();
}
/**
* Returns whether this frame belongs to the application or not.
*
* @return boolean
*/
public function isApplication()
{
return $this->application;
}
/**
* Mark as an frame belonging to the application.
*
* @param boolean $application
*/
public function setApplication($application)
{
$this->application = $application;
}
}
PK&d�[l1�ț�;vendor/filp/whoops/src/Whoops/Exception/FrameCollection.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Exception;
use ArrayAccess;
use ArrayIterator;
use Countable;
use IteratorAggregate;
use Serializable;
use UnexpectedValueException;
/**
* Exposes a fluent interface for dealing with an ordered list
* of stack-trace frames.
*/
class FrameCollection implements ArrayAccess, IteratorAggregate,
Serializable, Countable
{
/**
* @var array[]
*/
private $frames;
/**
* @param array $frames
*/
public function __construct(array $frames)
{
$this->frames = array_map(function ($frame) {
return new Frame($frame);
}, $frames);
}
/**
* Filters frames using a callable, returns the same FrameCollection
*
* @param callable $callable
* @return FrameCollection
*/
public function filter($callable)
{
$this->frames = array_values(array_filter($this->frames,
$callable));
return $this;
}
/**
* Map the collection of frames
*
* @param callable $callable
* @return FrameCollection
*/
public function map($callable)
{
// Contain the map within a higher-order callable
// that enforces type-correctness for the $callable
$this->frames = array_map(function ($frame) use ($callable) {
$frame = call_user_func($callable, $frame);
if (!$frame instanceof Frame) {
throw new UnexpectedValueException(
"Callable to " . __CLASS__ . "::map must
return a Frame object"
);
}
return $frame;
}, $this->frames);
return $this;
}
/**
* Returns an array with all frames, does not affect
* the internal array.
*
* @todo If this gets any more complex than this,
* have getIterator use this method.
* @see FrameCollection::getIterator
* @return array
*/
public function getArray()
{
return $this->frames;
}
/**
* @see IteratorAggregate::getIterator
* @return ArrayIterator
*/
public function getIterator()
{
return new ArrayIterator($this->frames);
}
/**
* @see ArrayAccess::offsetExists
* @param int $offset
*/
public function offsetExists($offset)
{
return isset($this->frames[$offset]);
}
/**
* @see ArrayAccess::offsetGet
* @param int $offset
*/
public function offsetGet($offset)
{
return $this->frames[$offset];
}
/**
* @see ArrayAccess::offsetSet
* @param int $offset
*/
public function offsetSet($offset, $value)
{
throw new \Exception(__CLASS__ . ' is read only');
}
/**
* @see ArrayAccess::offsetUnset
* @param int $offset
*/
public function offsetUnset($offset)
{
throw new \Exception(__CLASS__ . ' is read only');
}
/**
* @see Countable::count
* @return int
*/
public function count()
{
return count($this->frames);
}
/**
* Count the frames that belongs to the application.
*
* @return int
*/
public function countIsApplication()
{
return count(array_filter($this->frames, function (Frame $f) {
return $f->isApplication();
}));
}
/**
* @see Serializable::serialize
* @return string
*/
public function serialize()
{
return serialize($this->frames);
}
/**
* @see Serializable::unserialize
* @param string $serializedFrames
*/
public function unserialize($serializedFrames)
{
$this->frames = unserialize($serializedFrames);
}
/**
* @param Frame[] $frames Array of Frame instances, usually from
$e->getPrevious()
*/
public function prependFrames(array $frames)
{
$this->frames = array_merge($frames, $this->frames);
}
/**
* Gets the innermost part of stack trace that is not the same as that
of outer exception
*
* @param FrameCollection $parentFrames Outer exception frames to
compare tail against
* @return Frame[]
*/
public function topDiff(FrameCollection $parentFrames)
{
$diff = $this->frames;
$parentFrames = $parentFrames->getArray();
$p = count($parentFrames)-1;
for ($i = count($diff)-1; $i >= 0 && $p >= 0; $i--) {
/** @var Frame $tailFrame */
$tailFrame = $diff[$i];
if ($tailFrame->equals($parentFrames[$p])) {
unset($diff[$i]);
}
$p--;
}
return $diff;
}
}
PK&d�[�'mB�"�"5vendor/filp/whoops/src/Whoops/Exception/Inspector.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Exception;
use Whoops\Util\Misc;
class Inspector
{
/**
* @var \Throwable
*/
private $exception;
/**
* @var \Whoops\Exception\FrameCollection
*/
private $frames;
/**
* @var \Whoops\Exception\Inspector
*/
private $previousExceptionInspector;
/**
* @var \Throwable[]
*/
private $previousExceptions;
/**
* @param \Throwable $exception The exception to inspect
*/
public function __construct($exception)
{
$this->exception = $exception;
}
/**
* @return \Throwable
*/
public function getException()
{
return $this->exception;
}
/**
* @return string
*/
public function getExceptionName()
{
return get_class($this->exception);
}
/**
* @return string
*/
public function getExceptionMessage()
{
return
$this->extractDocrefUrl($this->exception->getMessage())['message'];
}
/**
* @return string[]
*/
public function getPreviousExceptionMessages()
{
return array_map(function ($prev) {
/** @var \Throwable $prev */
return
$this->extractDocrefUrl($prev->getMessage())['message'];
}, $this->getPreviousExceptions());
}
/**
* @return int[]
*/
public function getPreviousExceptionCodes()
{
return array_map(function ($prev) {
/** @var \Throwable $prev */
return $prev->getCode();
}, $this->getPreviousExceptions());
}
/**
* Returns a url to the php-manual related to the underlying error -
when available.
*
* @return string|null
*/
public function getExceptionDocrefUrl()
{
return
$this->extractDocrefUrl($this->exception->getMessage())['url'];
}
private function extractDocrefUrl($message)
{
$docref = [
'message' => $message,
'url' => null,
];
// php embbeds urls to the manual into the Exception message with
the following ini-settings defined
//
http://php.net/manual/en/errorfunc.configuration.php#ini.docref-root
if (!ini_get('html_errors') ||
!ini_get('docref_root')) {
return $docref;
}
$pattern = "/\[<a
href='([^']+)'>(?:[^<]+)<\/a>\]/";
if (preg_match($pattern, $message, $matches)) {
// -> strip those automatically generated links from the
exception message
$docref['message'] = preg_replace($pattern,
'', $message, 1);
$docref['url'] = $matches[1];
}
return $docref;
}
/**
* Does the wrapped Exception has a previous Exception?
* @return bool
*/
public function hasPreviousException()
{
return $this->previousExceptionInspector ||
$this->exception->getPrevious();
}
/**
* Returns an Inspector for a previous Exception, if any.
* @todo Clean this up a bit, cache stuff a bit better.
* @return Inspector
*/
public function getPreviousExceptionInspector()
{
if ($this->previousExceptionInspector === null) {
$previousException = $this->exception->getPrevious();
if ($previousException) {
$this->previousExceptionInspector = new
Inspector($previousException);
}
}
return $this->previousExceptionInspector;
}
/**
* Returns an array of all previous exceptions for this
inspector's exception
* @return \Throwable[]
*/
public function getPreviousExceptions()
{
if ($this->previousExceptions === null) {
$this->previousExceptions = [];
$prev = $this->exception->getPrevious();
while ($prev !== null) {
$this->previousExceptions[] = $prev;
$prev = $prev->getPrevious();
}
}
return $this->previousExceptions;
}
/**
* Returns an iterator for the inspected exception's
* frames.
* @return \Whoops\Exception\FrameCollection
*/
public function getFrames()
{
if ($this->frames === null) {
$frames = $this->getTrace($this->exception);
// Fill empty line/file info for call_user_func_array usages
(PHP Bug #44428)
foreach ($frames as $k => $frame) {
if (empty($frame['file'])) {
// Default values when file and line are missing
$file = '[internal]';
$line = 0;
$next_frame = !empty($frames[$k + 1]) ? $frames[$k + 1]
: [];
if ($this->isValidNextFrame($next_frame)) {
$file = $next_frame['file'];
$line = $next_frame['line'];
}
$frames[$k]['file'] = $file;
$frames[$k]['line'] = $line;
}
}
// Find latest non-error handling frame index ($i) used to
remove error handling frames
$i = 0;
foreach ($frames as $k => $frame) {
if ($frame['file'] ==
$this->exception->getFile() && $frame['line'] ==
$this->exception->getLine()) {
$i = $k;
}
}
// Remove error handling frames
if ($i > 0) {
array_splice($frames, 0, $i);
}
$firstFrame =
$this->getFrameFromException($this->exception);
array_unshift($frames, $firstFrame);
$this->frames = new FrameCollection($frames);
if ($previousInspector =
$this->getPreviousExceptionInspector()) {
// Keep outer frame on top of the inner one
$outerFrames = $this->frames;
$newFrames = clone $previousInspector->getFrames();
// I assume it will always be set, but let's be safe
if (isset($newFrames[0])) {
$newFrames[0]->addComment(
$previousInspector->getExceptionMessage(),
'Exception message:'
);
}
$newFrames->prependFrames($outerFrames->topDiff($newFrames));
$this->frames = $newFrames;
}
}
return $this->frames;
}
/**
* Gets the backtrace from an exception.
*
* If xdebug is installed
*
* @param \Throwable $e
* @return array
*/
protected function getTrace($e)
{
$traces = $e->getTrace();
// Get trace from xdebug if enabled, failure exceptions only trace
to the shutdown handler by default
if (!$e instanceof \ErrorException) {
return $traces;
}
if (!Misc::isLevelFatal($e->getSeverity())) {
return $traces;
}
if (!extension_loaded('xdebug') || !xdebug_is_enabled())
{
return $traces;
}
// Use xdebug to get the full stack trace and remove the shutdown
handler stack trace
$stack = array_reverse(xdebug_get_function_stack());
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$traces = array_diff_key($stack, $trace);
return $traces;
}
/**
* Given an exception, generates an array in the format
* generated by Exception::getTrace()
* @param \Throwable $exception
* @return array
*/
protected function getFrameFromException($exception)
{
return [
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'class' => get_class($exception),
'args' => [
$exception->getMessage(),
],
];
}
/**
* Given an error, generates an array in the format
* generated by ErrorException
* @param ErrorException $exception
* @return array
*/
protected function getFrameFromError(ErrorException $exception)
{
return [
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'class' => null,
'args' => [],
];
}
/**
* Determine if the frame can be used to fill in previous frame's
missing info
* happens for call_user_func and call_user_func_array usages (PHP Bug
#44428)
*
* @param array $frame
* @return bool
*/
protected function isValidNextFrame(array $frame)
{
if (empty($frame['file'])) {
return false;
}
if (empty($frame['line'])) {
return false;
}
if (empty($frame['function']) ||
!stristr($frame['function'], 'call_user_func')) {
return false;
}
return true;
}
}
PK&d�[BU�$HH9vendor/filp/whoops/src/Whoops/Handler/CallbackHandler.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Handler;
use InvalidArgumentException;
/**
* Wrapper for Closures passed as handlers. Can be used
* directly, or will be instantiated automagically by Whoops\Run
* if passed to Run::pushHandler
*/
class CallbackHandler extends Handler
{
/**
* @var callable
*/
protected $callable;
/**
* @throws InvalidArgumentException If argument is not callable
* @param callable $callable
*/
public function __construct($callable)
{
if (!is_callable($callable)) {
throw new InvalidArgumentException(
'Argument to ' . __METHOD__ . ' must be
valid callable'
);
}
$this->callable = $callable;
}
/**
* @return int|null
*/
public function handle()
{
$exception = $this->getException();
$inspector = $this->getInspector();
$run = $this->getRun();
$callable = $this->callable;
// invoke the callable directly, to get simpler stacktraces (in
comparison to call_user_func).
// this assumes that $callable is a properly typed php-callable,
which we check in __construct().
return $callable($exception, $inspector, $run);
}
}
PK&d�[���MM1vendor/filp/whoops/src/Whoops/Handler/Handler.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Handler;
use Whoops\Exception\Inspector;
use Whoops\RunInterface;
/**
* Abstract implementation of a Handler.
*/
abstract class Handler implements HandlerInterface
{
/*
Return constants that can be returned from Handler::handle
to message the handler walker.
*/
const DONE = 0x10; // returning this is optional, only exists
for
// semantic purposes
/**
* The Handler has handled the Throwable in some way, and wishes to
skip any other Handler.
* Execution will continue.
*/
const LAST_HANDLER = 0x20;
/**
* The Handler has handled the Throwable in some way, and wishes to
quit/stop execution
*/
const QUIT = 0x30;
/**
* @var RunInterface
*/
private $run;
/**
* @var Inspector $inspector
*/
private $inspector;
/**
* @var \Throwable $exception
*/
private $exception;
/**
* @param RunInterface $run
*/
public function setRun(RunInterface $run)
{
$this->run = $run;
}
/**
* @return RunInterface
*/
protected function getRun()
{
return $this->run;
}
/**
* @param Inspector $inspector
*/
public function setInspector(Inspector $inspector)
{
$this->inspector = $inspector;
}
/**
* @return Inspector
*/
protected function getInspector()
{
return $this->inspector;
}
/**
* @param \Throwable $exception
*/
public function setException($exception)
{
$this->exception = $exception;
}
/**
* @return \Throwable
*/
protected function getException()
{
return $this->exception;
}
}
PK&d�[#�Y���:vendor/filp/whoops/src/Whoops/Handler/HandlerInterface.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Handler;
use Whoops\Exception\Inspector;
use Whoops\RunInterface;
interface HandlerInterface
{
/**
* @return int|null A handler may return nothing, or a
Handler::HANDLE_* constant
*/
public function handle();
/**
* @param RunInterface $run
* @return void
*/
public function setRun(RunInterface $run);
/**
* @param \Throwable $exception
* @return void
*/
public function setException($exception);
/**
* @param Inspector $inspector
* @return void
*/
public function setInspector(Inspector $inspector);
}
PK&d�[��1��=vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Handler;
use Whoops\Exception\Formatter;
/**
* Catches an exception and converts it to a JSON
* response. Additionally can also return exception
* frames for consumption by an API.
*/
class JsonResponseHandler extends Handler
{
/**
* @var bool
*/
private $returnFrames = false;
/**
* @var bool
*/
private $jsonApi = false;
/**
* Returns errors[[]] instead of error[] to be in compliance with the
json:api spec
* @param bool $jsonApi Default is false
* @return $this
*/
public function setJsonApi($jsonApi = false)
{
$this->jsonApi = (bool) $jsonApi;
return $this;
}
/**
* @param bool|null $returnFrames
* @return bool|$this
*/
public function addTraceToOutput($returnFrames = null)
{
if (func_num_args() == 0) {
return $this->returnFrames;
}
$this->returnFrames = (bool) $returnFrames;
return $this;
}
/**
* @return int
*/
public function handle()
{
if ($this->jsonApi === true) {
$response = [
'errors' => [
Formatter::formatExceptionAsDataArray(
$this->getInspector(),
$this->addTraceToOutput()
),
]
];
} else {
$response = [
'error' =>
Formatter::formatExceptionAsDataArray(
$this->getInspector(),
$this->addTraceToOutput()
),
];
}
echo json_encode($response,
defined('JSON_PARTIAL_OUTPUT_ON_ERROR') ?
JSON_PARTIAL_OUTPUT_ON_ERROR : 0);
return Handler::QUIT;
}
/**
* @return string
*/
public function contentType()
{
return 'application/json';
}
}
PK&d�[��\�s"s":vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
* Plaintext handler for command line and logs.
* @author Pierre-Yves Landuré <https://howto.biapy.com/>
*/
namespace Whoops\Handler;
use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Whoops\Exception\Frame;
/**
* Handler outputing plaintext error messages. Can be used
* directly, or will be instantiated automagically by Whoops\Run
* if passed to Run::pushHandler
*/
class PlainTextHandler extends Handler
{
const VAR_DUMP_PREFIX = ' | ';
/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* @var callable
*/
protected $dumper;
/**
* @var bool
*/
private $addTraceToOutput = true;
/**
* @var bool|integer
*/
private $addTraceFunctionArgsToOutput = false;
/**
* @var integer
*/
private $traceFunctionArgsOutputLimit = 1024;
/**
* @var bool
*/
private $addPreviousToOutput = true;
/**
* @var bool
*/
private $loggerOnly = false;
/**
* Constructor.
* @throws InvalidArgumentException If argument is not null or a
LoggerInterface
* @param \Psr\Log\LoggerInterface|null $logger
*/
public function __construct($logger = null)
{
$this->setLogger($logger);
}
/**
* Set the output logger interface.
* @throws InvalidArgumentException If argument is not null or a
LoggerInterface
* @param \Psr\Log\LoggerInterface|null $logger
*/
public function setLogger($logger = null)
{
if (! (is_null($logger)
|| $logger instanceof LoggerInterface)) {
throw new InvalidArgumentException(
'Argument to ' . __METHOD__ .
" must be a valid Logger Interface (aka. Monolog),
" .
get_class($logger) . ' given.'
);
}
$this->logger = $logger;
}
/**
* @return \Psr\Log\LoggerInterface|null
*/
public function getLogger()
{
return $this->logger;
}
/**
* Set var dumper callback function.
*
* @param callable $dumper
* @return void
*/
public function setDumper(callable $dumper)
{
$this->dumper = $dumper;
}
/**
* Add error trace to output.
* @param bool|null $addTraceToOutput
* @return bool|$this
*/
public function addTraceToOutput($addTraceToOutput = null)
{
if (func_num_args() == 0) {
return $this->addTraceToOutput;
}
$this->addTraceToOutput = (bool) $addTraceToOutput;
return $this;
}
/**
* Add previous exceptions to output.
* @param bool|null $addPreviousToOutput
* @return bool|$this
*/
public function addPreviousToOutput($addPreviousToOutput = null)
{
if (func_num_args() == 0) {
return $this->addPreviousToOutput;
}
$this->addPreviousToOutput = (bool) $addPreviousToOutput;
return $this;
}
/**
* Add error trace function arguments to output.
* Set to True for all frame args, or integer for the n first frame
args.
* @param bool|integer|null $addTraceFunctionArgsToOutput
* @return null|bool|integer
*/
public function
addTraceFunctionArgsToOutput($addTraceFunctionArgsToOutput = null)
{
if (func_num_args() == 0) {
return $this->addTraceFunctionArgsToOutput;
}
if (! is_integer($addTraceFunctionArgsToOutput)) {
$this->addTraceFunctionArgsToOutput = (bool)
$addTraceFunctionArgsToOutput;
} else {
$this->addTraceFunctionArgsToOutput =
$addTraceFunctionArgsToOutput;
}
}
/**
* Set the size limit in bytes of frame arguments var_dump output.
* If the limit is reached, the var_dump output is discarded.
* Prevent memory limit errors.
* @var integer
*/
public function
setTraceFunctionArgsOutputLimit($traceFunctionArgsOutputLimit)
{
$this->traceFunctionArgsOutputLimit = (integer)
$traceFunctionArgsOutputLimit;
}
/**
* Create plain text response and return it as a string
* @return string
*/
public function generateResponse()
{
$exception = $this->getException();
$message = $this->getExceptionOutput($exception);
if ($this->addPreviousToOutput) {
$previous = $exception->getPrevious();
while ($previous) {
$message .= "\n\nCaused by\n" .
$this->getExceptionOutput($previous);
$previous = $previous->getPrevious();
}
}
return $message . $this->getTraceOutput() . "\n";
}
/**
* Get the size limit in bytes of frame arguments var_dump output.
* If the limit is reached, the var_dump output is discarded.
* Prevent memory limit errors.
* @return integer
*/
public function getTraceFunctionArgsOutputLimit()
{
return $this->traceFunctionArgsOutputLimit;
}
/**
* Only output to logger.
* @param bool|null $loggerOnly
* @return null|bool
*/
public function loggerOnly($loggerOnly = null)
{
if (func_num_args() == 0) {
return $this->loggerOnly;
}
$this->loggerOnly = (bool) $loggerOnly;
}
/**
* Test if handler can output to stdout.
* @return bool
*/
private function canOutput()
{
return !$this->loggerOnly();
}
/**
* Get the frame args var_dump.
* @param \Whoops\Exception\Frame $frame [description]
* @param integer $line [description]
* @return string
*/
private function getFrameArgsOutput(Frame $frame, $line)
{
if ($this->addTraceFunctionArgsToOutput() === false
|| $this->addTraceFunctionArgsToOutput() < $line) {
return '';
}
// Dump the arguments:
ob_start();
$this->dump($frame->getArgs());
if (ob_get_length() >
$this->getTraceFunctionArgsOutputLimit()) {
// The argument var_dump is to big.
// Discarded to limit memory usage.
ob_clean();
return sprintf(
"\n%sArguments dump length greater than %d Bytes.
Discarded.",
self::VAR_DUMP_PREFIX,
$this->getTraceFunctionArgsOutputLimit()
);
}
return sprintf(
"\n%s",
preg_replace('/^/m', self::VAR_DUMP_PREFIX,
ob_get_clean())
);
}
/**
* Dump variable.
*
* @param mixed $var
* @return void
*/
protected function dump($var)
{
if ($this->dumper) {
call_user_func($this->dumper, $var);
} else {
var_dump($var);
}
}
/**
* Get the exception trace as plain text.
* @return string
*/
private function getTraceOutput()
{
if (! $this->addTraceToOutput()) {
return '';
}
$inspector = $this->getInspector();
$frames = $inspector->getFrames();
$response = "\nStack trace:";
$line = 1;
foreach ($frames as $frame) {
/** @var Frame $frame */
$class = $frame->getClass();
$template = "\n%3d. %s->%s() %s:%d%s";
if (! $class) {
// Remove method arrow (->) from output.
$template = "\n%3d. %s%s() %s:%d%s";
}
$response .= sprintf(
$template,
$line,
$class,
$frame->getFunction(),
$frame->getFile(),
$frame->getLine(),
$this->getFrameArgsOutput($frame, $line)
);
$line++;
}
return $response;
}
/**
* Get the exception as plain text.
* @param \Throwable $exception
* @return string
*/
private function getExceptionOutput($exception)
{
return sprintf(
"%s: %s in file %s on line %d",
get_class($exception),
$exception->getMessage(),
$exception->getFile(),
$exception->getLine()
);
}
/**
* @return int
*/
public function handle()
{
$response = $this->generateResponse();
if ($this->getLogger()) {
$this->getLogger()->error($response);
}
if (! $this->canOutput()) {
return Handler::DONE;
}
echo $response;
return Handler::QUIT;
}
/**
* @return string
*/
public function contentType()
{
return 'text/plain';
}
}
PK&d�[w9�_]_];vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Handler;
use InvalidArgumentException;
use RuntimeException;
use Symfony\Component\VarDumper\Cloner\AbstractCloner;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use UnexpectedValueException;
use Whoops\Exception\Formatter;
use Whoops\Util\Misc;
use Whoops\Util\TemplateHelper;
class PrettyPageHandler extends Handler
{
const EDITOR_SUBLIME = "sublime";
const EDITOR_TEXTMATE = "textmate";
const EDITOR_EMACS = "emacs";
const EDITOR_MACVIM = "macvim";
const EDITOR_PHPSTORM = "phpstorm";
const EDITOR_IDEA = "idea";
const EDITOR_VSCODE = "vscode";
const EDITOR_ATOM = "atom";
const EDITOR_ESPRESSO = "espresso";
const EDITOR_XDEBUG = "xdebug";
/**
* Search paths to be scanned for resources, in the reverse
* order they're declared.
*
* @var array
*/
private $searchPaths = [];
/**
* Fast lookup cache for known resource locations.
*
* @var array
*/
private $resourceCache = [];
/**
* The name of the custom css file.
*
* @var string
*/
private $customCss = null;
/**
* @var array[]
*/
private $extraTables = [];
/**
* @var bool
*/
private $handleUnconditionally = false;
/**
* @var string
*/
private $pageTitle = "Whoops! There was an error.";
/**
* @var array[]
*/
private $applicationPaths;
/**
* @var array[]
*/
private $blacklist = [
'_GET' => [],
'_POST' => [],
'_FILES' => [],
'_COOKIE' => [],
'_SESSION' => [],
'_SERVER' => [],
'_ENV' => [],
];
/**
* A string identifier for a known IDE/text editor, or a closure
* that resolves a string that can be used to open a given file
* in an editor. If the string contains the special substrings
* %file or %line, they will be replaced with the correct data.
*
* @example
* "txmt://open?url=%file&line=%line"
* @var mixed $editor
*/
protected $editor;
/**
* A list of known editor strings
* @var array
*/
protected $editors = [
"sublime" =>
"subl://open?url=file://%file&line=%line",
"textmate" =>
"txmt://open?url=file://%file&line=%line",
"emacs" =>
"emacs://open?url=file://%file&line=%line",
"macvim" =>
"mvim://open/?url=file://%file&line=%line",
"phpstorm" =>
"phpstorm://open?file=%file&line=%line",
"idea" =>
"idea://open?file=%file&line=%line",
"vscode" => "vscode://file/%file:%line",
"atom" =>
"atom://core/open/file?filename=%file&line=%line",
"espresso" =>
"x-espresso://open?filepath=%file&lines=%line",
];
/**
* @var TemplateHelper
*/
private $templateHelper;
/**
* Constructor.
*/
public function __construct()
{
if (ini_get('xdebug.file_link_format') ||
extension_loaded('xdebug')) {
// Register editor using xdebug's file_link_format option.
$this->editors['xdebug'] = function ($file, $line)
{
return str_replace(['%f', '%l'],
[$file, $line], ini_get('xdebug.file_link_format'));
};
// If xdebug is available, use it as default editor.
$this->setEditor('xdebug');
}
// Add the default, local resource search path:
$this->searchPaths[] = __DIR__ . "/../Resources";
// blacklist php provided auth based values
$this->blacklist('_SERVER', 'PHP_AUTH_PW');
$this->templateHelper = new TemplateHelper();
if
(class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) {
$cloner = new VarCloner();
// Only dump object internals if a custom caster exists for
performance reasons
// https://github.com/filp/whoops/pull/404
$cloner->addCasters(['*' => function ($obj, $a,
$stub, $isNested, $filter = 0) {
$class = $stub->class;
$classes = [$class => $class] + class_parents($class) +
class_implements($class);
foreach ($classes as $class) {
if (isset(AbstractCloner::$defaultCasters[$class])) {
return $a;
}
}
// Remove all internals
return [];
}]);
$this->templateHelper->setCloner($cloner);
}
}
/**
* @return int|null
*/
public function handle()
{
if (!$this->handleUnconditionally()) {
// Check conditions for outputting HTML:
// @todo: Make this more robust
if (PHP_SAPI === 'cli') {
// Help users who have been relying on an internal test
value
// fix their code to the proper method
if (isset($_ENV['whoops-test'])) {
throw new \Exception(
'Use handleUnconditionally instead of
whoops-test'
.' environment variable'
);
}
return Handler::DONE;
}
}
$templateFile =
$this->getResource("views/layout.html.php");
$cssFile =
$this->getResource("css/whoops.base.css");
$zeptoFile = $this->getResource("js/zepto.min.js");
$prettifyFile =
$this->getResource("js/prettify.min.js");
$clipboard =
$this->getResource("js/clipboard.min.js");
$jsFile =
$this->getResource("js/whoops.base.js");
if ($this->customCss) {
$customCssFile = $this->getResource($this->customCss);
}
$inspector = $this->getInspector();
$frames = $this->getExceptionFrames();
$code = $this->getExceptionCode();
// List of variables that will be passed to the layout template.
$vars = [
"page_title" => $this->getPageTitle(),
// @todo: Asset compiler
"stylesheet" => file_get_contents($cssFile),
"zepto" => file_get_contents($zeptoFile),
"prettify" => file_get_contents($prettifyFile),
"clipboard" => file_get_contents($clipboard),
"javascript" => file_get_contents($jsFile),
// Template paths:
"header" =>
$this->getResource("views/header.html.php"),
"header_outer" =>
$this->getResource("views/header_outer.html.php"),
"frame_list" =>
$this->getResource("views/frame_list.html.php"),
"frames_description" =>
$this->getResource("views/frames_description.html.php"),
"frames_container" =>
$this->getResource("views/frames_container.html.php"),
"panel_details" =>
$this->getResource("views/panel_details.html.php"),
"panel_details_outer" =>
$this->getResource("views/panel_details_outer.html.php"),
"panel_left" =>
$this->getResource("views/panel_left.html.php"),
"panel_left_outer" =>
$this->getResource("views/panel_left_outer.html.php"),
"frame_code" =>
$this->getResource("views/frame_code.html.php"),
"env_details" =>
$this->getResource("views/env_details.html.php"),
"title" => $this->getPageTitle(),
"name" => explode("\\",
$inspector->getExceptionName()),
"message" =>
$inspector->getExceptionMessage(),
"previousMessages" =>
$inspector->getPreviousExceptionMessages(),
"docref_url" =>
$inspector->getExceptionDocrefUrl(),
"code" => $code,
"previousCodes" =>
$inspector->getPreviousExceptionCodes(),
"plain_exception" =>
Formatter::formatExceptionPlain($inspector),
"frames" => $frames,
"has_frames" => !!count($frames),
"handler" => $this,
"handlers" =>
$this->getRun()->getHandlers(),
"active_frames_tab" => count($frames) &&
$frames->offsetGet(0)->isApplication() ? 'application' :
'all',
"has_frames_tabs" =>
$this->getApplicationPaths(),
"tables" => [
"GET Data" =>
$this->masked($_GET, '_GET'),
"POST Data" =>
$this->masked($_POST, '_POST'),
"Files" => isset($_FILES) ?
$this->masked($_FILES, '_FILES') : [],
"Cookies" =>
$this->masked($_COOKIE, '_COOKIE'),
"Session" => isset($_SESSION) ?
$this->masked($_SESSION, '_SESSION') : [],
"Server/Request Data" =>
$this->masked($_SERVER, '_SERVER'),
"Environment Variables" =>
$this->masked($_ENV, '_ENV'),
],
];
if (isset($customCssFile)) {
$vars["stylesheet"] .=
file_get_contents($customCssFile);
}
// Add extra entries list of data tables:
// @todo: Consolidate addDataTable and addDataTableCallback
$extraTables = array_map(function ($table) use ($inspector) {
return $table instanceof \Closure ? $table($inspector) :
$table;
}, $this->getDataTables());
$vars["tables"] = array_merge($extraTables,
$vars["tables"]);
$plainTextHandler = new PlainTextHandler();
$plainTextHandler->setException($this->getException());
$plainTextHandler->setInspector($this->getInspector());
$vars["preface"] = "<!--\n\n\n" .
$this->templateHelper->escape($plainTextHandler->generateResponse())
. "\n\n\n\n\n\n\n\n\n\n\n-->";
$this->templateHelper->setVariables($vars);
$this->templateHelper->render($templateFile);
return Handler::QUIT;
}
/**
* Get the stack trace frames of the exception that is currently being
handled.
*
* @return \Whoops\Exception\FrameCollection;
*/
protected function getExceptionFrames()
{
$frames = $this->getInspector()->getFrames();
if ($this->getApplicationPaths()) {
foreach ($frames as $frame) {
foreach ($this->getApplicationPaths() as $path) {
if (strpos($frame->getFile(), $path) === 0) {
$frame->setApplication(true);
break;
}
}
}
}
return $frames;
}
/**
* Get the code of the exception that is currently being handled.
*
* @return string
*/
protected function getExceptionCode()
{
$exception = $this->getException();
$code = $exception->getCode();
if ($exception instanceof \ErrorException) {
// ErrorExceptions wrap the php-error types within the
'severity' property
$code = Misc::translateErrorCode($exception->getSeverity());
}
return (string) $code;
}
/**
* @return string
*/
public function contentType()
{
return 'text/html';
}
/**
* Adds an entry to the list of tables displayed in the template.
* The expected data is a simple associative array. Any nested arrays
* will be flattened with print_r
* @param string $label
* @param array $data
*/
public function addDataTable($label, array $data)
{
$this->extraTables[$label] = $data;
}
/**
* Lazily adds an entry to the list of tables displayed in the table.
* The supplied callback argument will be called when the error is
rendered,
* it should produce a simple associative array. Any nested arrays will
* be flattened with print_r.
*
* @throws InvalidArgumentException If $callback is not callable
* @param string $label
* @param callable $callback Callable returning an
associative array
*/
public function addDataTableCallback($label, /* callable */ $callback)
{
if (!is_callable($callback)) {
throw new InvalidArgumentException('Expecting callback
argument to be callable');
}
$this->extraTables[$label] = function
(\Whoops\Exception\Inspector $inspector = null) use ($callback) {
try {
$result = call_user_func($callback, $inspector);
// Only return the result if it can be iterated over by
foreach().
return is_array($result) || $result instanceof \Traversable
? $result : [];
} catch (\Exception $e) {
// Don't allow failure to break the rendering of the
original exception.
return [];
}
};
}
/**
* Returns all the extra data tables registered with this handler.
* Optionally accepts a 'label' parameter, to only return the
data
* table under that label.
* @param string|null $label
* @return array[]|callable
*/
public function getDataTables($label = null)
{
if ($label !== null) {
return isset($this->extraTables[$label]) ?
$this->extraTables[$label] : [];
}
return $this->extraTables;
}
/**
* Allows to disable all attempts to dynamically decide whether to
* handle or return prematurely.
* Set this to ensure that the handler will perform no matter what.
* @param bool|null $value
* @return bool|null
*/
public function handleUnconditionally($value = null)
{
if (func_num_args() == 0) {
return $this->handleUnconditionally;
}
$this->handleUnconditionally = (bool) $value;
}
/**
* Adds an editor resolver, identified by a string
* name, and that may be a string path, or a callable
* resolver. If the callable returns a string, it will
* be set as the file reference's href attribute.
*
* @example
* $run->addEditor('macvim',
"mvim://open?url=file://%file&line=%line")
* @example
* $run->addEditor('remove-it', function($file, $line) {
* unlink($file);
* return "http://stackoverflow.com";
* });
* @param string $identifier
* @param string|callable $resolver
*/
public function addEditor($identifier, $resolver)
{
$this->editors[$identifier] = $resolver;
}
/**
* Set the editor to use to open referenced files, by a string
* identifier, or a callable that will be executed for every
* file reference, with a $file and $line argument, and should
* return a string.
*
* @example
* $run->setEditor(function($file, $line) { return
"file:///{$file}"; });
* @example
* $run->setEditor('sublime');
*
* @throws InvalidArgumentException If invalid argument identifier
provided
* @param string|callable $editor
*/
public function setEditor($editor)
{
if (!is_callable($editor) &&
!isset($this->editors[$editor])) {
throw new InvalidArgumentException(
"Unknown editor identifier: $editor. Known
editors:" .
implode(",", array_keys($this->editors))
);
}
$this->editor = $editor;
}
/**
* Given a string file path, and an integer file line,
* executes the editor resolver and returns, if available,
* a string that may be used as the href property for that
* file reference.
*
* @throws InvalidArgumentException If editor resolver does not return
a string
* @param string $filePath
* @param int $line
* @return string|bool
*/
public function getEditorHref($filePath, $line)
{
$editor = $this->getEditor($filePath, $line);
if (empty($editor)) {
return false;
}
// Check that the editor is a string, and replace the
// %line and %file placeholders:
if (!isset($editor['url']) ||
!is_string($editor['url'])) {
throw new UnexpectedValueException(
__METHOD__ . " should always resolve to a string or a
valid editor array; got something else instead."
);
}
$editor['url'] = str_replace("%line",
rawurlencode($line), $editor['url']);
$editor['url'] = str_replace("%file",
rawurlencode($filePath), $editor['url']);
return $editor['url'];
}
/**
* Given a boolean if the editor link should
* act as an Ajax request. The editor must be a
* valid callable function/closure
*
* @throws UnexpectedValueException If editor resolver does not return
a boolean
* @param string $filePath
* @param int $line
* @return bool
*/
public function getEditorAjax($filePath, $line)
{
$editor = $this->getEditor($filePath, $line);
// Check that the ajax is a bool
if (!isset($editor['ajax']) ||
!is_bool($editor['ajax'])) {
throw new UnexpectedValueException(
__METHOD__ . " should always resolve to a bool; got
something else instead."
);
}
return $editor['ajax'];
}
/**
* Given a boolean if the editor link should
* act as an Ajax request. The editor must be a
* valid callable function/closure
*
* @param string $filePath
* @param int $line
* @return array
*/
protected function getEditor($filePath, $line)
{
if (!$this->editor || (!is_string($this->editor) &&
!is_callable($this->editor))) {
return [];
}
if (is_string($this->editor) &&
isset($this->editors[$this->editor]) &&
!is_callable($this->editors[$this->editor])) {
return [
'ajax' => false,
'url' => $this->editors[$this->editor],
];
}
if (is_callable($this->editor) ||
(isset($this->editors[$this->editor]) &&
is_callable($this->editors[$this->editor]))) {
if (is_callable($this->editor)) {
$callback = call_user_func($this->editor, $filePath,
$line);
} else {
$callback =
call_user_func($this->editors[$this->editor], $filePath, $line);
}
if (empty($callback)) {
return [];
}
if (is_string($callback)) {
return [
'ajax' => false,
'url' => $callback,
];
}
return [
'ajax' => isset($callback['ajax']) ?
$callback['ajax'] : false,
'url' => isset($callback['url']) ?
$callback['url'] : $callback,
];
}
return [];
}
/**
* @param string $title
* @return void
*/
public function setPageTitle($title)
{
$this->pageTitle = (string) $title;
}
/**
* @return string
*/
public function getPageTitle()
{
return $this->pageTitle;
}
/**
* Adds a path to the list of paths to be searched for
* resources.
*
* @throws InvalidArgumentException If $path is not a valid directory
*
* @param string $path
* @return void
*/
public function addResourcePath($path)
{
if (!is_dir($path)) {
throw new InvalidArgumentException(
"'$path' is not a valid directory"
);
}
array_unshift($this->searchPaths, $path);
}
/**
* Adds a custom css file to be loaded.
*
* @param string $name
* @return void
*/
public function addCustomCss($name)
{
$this->customCss = $name;
}
/**
* @return array
*/
public function getResourcePaths()
{
return $this->searchPaths;
}
/**
* Finds a resource, by its relative path, in all available search
paths.
* The search is performed starting at the last search path, and all
the
* way back to the first, enabling a cascading-type system of overrides
* for all resources.
*
* @throws RuntimeException If resource cannot be found in any of the
available paths
*
* @param string $resource
* @return string
*/
protected function getResource($resource)
{
// If the resource was found before, we can speed things up
// by caching its absolute, resolved path:
if (isset($this->resourceCache[$resource])) {
return $this->resourceCache[$resource];
}
// Search through available search paths, until we find the
// resource we're after:
foreach ($this->searchPaths as $path) {
$fullPath = $path . "/$resource";
if (is_file($fullPath)) {
// Cache the result:
$this->resourceCache[$resource] = $fullPath;
return $fullPath;
}
}
// If we got this far, nothing was found.
throw new RuntimeException(
"Could not find resource '$resource' in any
resource paths."
. "(searched: " . join(", ",
$this->searchPaths). ")"
);
}
/**
* @deprecated
*
* @return string
*/
public function getResourcesPath()
{
$allPaths = $this->getResourcePaths();
// Compat: return only the first path added
return end($allPaths) ?: null;
}
/**
* @deprecated
*
* @param string $resourcesPath
* @return void
*/
public function setResourcesPath($resourcesPath)
{
$this->addResourcePath($resourcesPath);
}
/**
* Return the application paths.
*
* @return array
*/
public function getApplicationPaths()
{
return $this->applicationPaths;
}
/**
* Set the application paths.
*
* @param array $applicationPaths
*/
public function setApplicationPaths($applicationPaths)
{
$this->applicationPaths = $applicationPaths;
}
/**
* Set the application root path.
*
* @param string $applicationRootPath
*/
public function setApplicationRootPath($applicationRootPath)
{
$this->templateHelper->setApplicationRootPath($applicationRootPath);
}
/**
* blacklist a sensitive value within one of the superglobal arrays.
*
* @param $superGlobalName string the name of the superglobal array,
e.g. '_GET'
* @param $key string the key within the superglobal
*/
public function blacklist($superGlobalName, $key)
{
$this->blacklist[$superGlobalName][] = $key;
}
/**
* Checks all values within the given superGlobal array.
* Blacklisted values will be replaced by a equal length string
cointaining only '*' characters.
*
* We intentionally dont rely on $GLOBALS as it depends on
'auto_globals_jit' php.ini setting.
*
* @param $superGlobal array One of the superglobal arrays
* @param $superGlobalName string the name of the superglobal array,
e.g. '_GET'
* @return array $values without sensitive data
*/
private function masked(array $superGlobal, $superGlobalName)
{
$blacklisted = $this->blacklist[$superGlobalName];
$values = $superGlobal;
foreach ($blacklisted as $key) {
if (isset($superGlobal[$key]) &&
is_string($superGlobal[$key])) {
$values[$key] = str_repeat('*',
strlen($superGlobal[$key]));
}
}
return $values;
}
}
PK'd�[5Q��n
n
<vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Handler;
use SimpleXMLElement;
use Whoops\Exception\Formatter;
/**
* Catches an exception and converts it to an XML
* response. Additionally can also return exception
* frames for consumption by an API.
*/
class XmlResponseHandler extends Handler
{
/**
* @var bool
*/
private $returnFrames = false;
/**
* @param bool|null $returnFrames
* @return bool|$this
*/
public function addTraceToOutput($returnFrames = null)
{
if (func_num_args() == 0) {
return $this->returnFrames;
}
$this->returnFrames = (bool) $returnFrames;
return $this;
}
/**
* @return int
*/
public function handle()
{
$response = [
'error' => Formatter::formatExceptionAsDataArray(
$this->getInspector(),
$this->addTraceToOutput()
),
];
echo self::toXml($response);
return Handler::QUIT;
}
/**
* @return string
*/
public function contentType()
{
return 'application/xml';
}
/**
* @param SimpleXMLElement $node Node to append data to, will be
modified in place
* @param array|\Traversable $data
* @return SimpleXMLElement The modified node, for chaining
*/
private static function addDataToNode(\SimpleXMLElement $node, $data)
{
assert(is_array($data) || $data instanceof Traversable);
foreach ($data as $key => $value) {
if (is_numeric($key)) {
// Convert the key to a valid string
$key = "unknownNode_". (string) $key;
}
// Delete any char not allowed in XML element names
$key = preg_replace('/[^a-z0-9\-\_\.\:]/i',
'', $key);
if (is_array($value)) {
$child = $node->addChild($key);
self::addDataToNode($child, $value);
} else {
$value = str_replace('&',
'&', print_r($value, true));
$node->addChild($key, $value);
}
}
return $node;
}
/**
* The main function for converting to an XML document.
*
* @param array|\Traversable $data
* @return string XML
*/
private static function toXml($data)
{
assert(is_array($data) || $data instanceof Traversable);
$node = simplexml_load_string("<?xml
version='1.0' encoding='utf-8'?><root
/>");
return self::addDataToNode($node, $data)->asXML();
}
}
PK'd�[�N� . .;vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.cssnu�[���body
{
font: 12px "Helvetica Neue", helvetica, arial, sans-serif;
color: #131313;
background: #eeeeee;
padding:0;
margin: 0;
max-height: 100%;
text-rendering: optimizeLegibility;
}
a {
text-decoration: none;
}
.Whoops.container {
position: relative;
z-index: 9999999999;
}
.panel {
overflow-y: scroll;
height: 100%;
position: fixed;
margin: 0;
left: 0;
top: 0;
}
.branding {
position: absolute;
top: 10px;
right: 20px;
color: #777777;
font-size: 10px;
z-index: 100;
}
.branding a {
color: #e95353;
}
header {
color: white;
box-sizing: border-box;
background-color: #2a2a2a;
padding: 35px 40px;
max-height: 180px;
overflow: hidden;
transition: 0.5s;
}
header.header-expand {
max-height: 1000px;
}
.exc-title {
margin: 0;
color: #bebebe;
font-size: 14px;
}
.exc-title-primary, .exc-title-secondary {
color: #e95353;
}
.exc-message {
font-size: 20px;
word-wrap: break-word;
margin: 4px 0 0 0;
color: white;
}
.exc-message span {
display: block;
}
.exc-message-empty-notice {
color: #a29d9d;
font-weight: 300;
}
.prev-exc-title {
margin: 10px 0;
}
.prev-exc-title + ul {
margin: 0;
padding: 0 0 0 20px;
line-height: 12px;
}
.prev-exc-title + ul li {
font: 12px "Helvetica Neue", helvetica, arial, sans-serif;
}
.prev-exc-title + ul li .prev-exc-code {
display: inline-block;
color: #bebebe;
}
.details-container {
left: 30%;
width: 70%;
background: #fafafa;
}
.details {
padding: 5px;
}
.details-heading {
color: #4288CE;
font-weight: 300;
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px solid rgba(0, 0, 0, .1);
}
.details pre.sf-dump {
white-space: pre;
word-wrap: inherit;
}
.details pre.sf-dump,
.details pre.sf-dump .sf-dump-num,
.details pre.sf-dump .sf-dump-const,
.details pre.sf-dump .sf-dump-str,
.details pre.sf-dump .sf-dump-note,
.details pre.sf-dump .sf-dump-ref,
.details pre.sf-dump .sf-dump-public,
.details pre.sf-dump .sf-dump-protected,
.details pre.sf-dump .sf-dump-private,
.details pre.sf-dump .sf-dump-meta,
.details pre.sf-dump .sf-dump-key,
.details pre.sf-dump .sf-dump-index {
color: #463C54;
}
.left-panel {
width: 30%;
background: #ded8d8;
}
.frames-description {
background: rgba(0, 0, 0, .05);
padding: 8px 15px;
color: #a29d9d;
font-size: 11px;
}
.frames-description.frames-description-application {
text-align: center;
font-size: 12px;
}
.frames-container.frames-container-application
.frame:not(.frame-application) {
display: none;
}
.frames-tab {
color: #a29d9d;
display: inline-block;
padding: 4px 8px;
margin: 0 2px;
border-radius: 3px;
}
.frames-tab.frames-tab-active {
background-color: #2a2a2a;
color: #bebebe;
}
.frame {
padding: 14px;
cursor: pointer;
transition: all 0.1s ease;
background: #eeeeee;
}
.frame:not(:last-child) {
border-bottom: 1px solid rgba(0, 0, 0, .05);
}
.frame.active {
box-shadow: inset -5px 0 0 0 #4288CE;
color: #4288CE;
}
.frame:not(.active):hover {
background: #BEE9EA;
}
.frame-method-info {
margin-bottom: 10px;
}
.frame-class, .frame-function, .frame-index {
font-size: 14px;
}
.frame-index {
float: left;
}
.frame-method-info {
margin-left: 24px;
}
.frame-index {
font-size: 11px;
color: #a29d9d;
background-color: rgba(0, 0, 0, .05);
height: 18px;
width: 18px;
line-height: 18px;
border-radius: 5px;
padding: 0 1px 0 1px;
text-align: center;
display: inline-block;
}
.frame-application .frame-index {
background-color: #2a2a2a;
color: #bebebe;
}
.frame-file {
font-family: "Inconsolata", "Fira Mono",
"Source Code Pro", Monaco, Consolas, "Lucida Console",
monospace;
color: #a29d9d;
}
.frame-file .editor-link {
color: #a29d9d;
}
.frame-line {
font-weight: bold;
}
.frame-line:before {
content: ":";
}
.frame-code {
padding: 5px;
background: #303030;
display: none;
}
.frame-code.active {
display: block;
}
.frame-code .frame-file {
color: #a29d9d;
padding: 12px 6px;
border-bottom: none;
}
.code-block {
padding: 10px;
margin: 0;
border-radius: 6px;
box-shadow: 0 3px 0 rgba(0, 0, 0, .05),
0 10px 30px rgba(0, 0, 0, .05),
inset 0 0 1px 0 rgba(255, 255, 255, .07);
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
}
.linenums {
margin: 0;
margin-left: 10px;
}
.frame-comments {
border-top: none;
margin-top: 15px;
font-size: 12px;
}
.frame-comments.empty {
}
.frame-comments.empty:before {
content: "No comments for this stack frame.";
font-weight: 300;
color: #a29d9d;
}
.frame-comment {
padding: 10px;
color: #e3e3e3;
border-radius: 6px;
background-color: rgba(255, 255, 255, .05);
}
.frame-comment a {
font-weight: bold;
text-decoration: none;
}
.frame-comment a:hover {
color: #4bb1b1;
}
.frame-comment:not(:last-child) {
border-bottom: 1px dotted rgba(0, 0, 0, .3);
}
.frame-comment-context {
font-size: 10px;
color: white;
}
.delimiter {
display: inline-block;
}
.data-table-container label {
font-size: 16px;
color: #303030;
font-weight: bold;
margin: 10px 0;
display: block;
margin-bottom: 5px;
padding-bottom: 5px;
}
.data-table {
width: 100%;
margin-bottom: 10px;
}
.data-table tbody {
font: 13px "Inconsolata", "Fira Mono", "Source
Code Pro", Monaco, Consolas, "Lucida Console", monospace;
}
.data-table thead {
display: none;
}
.data-table tr {
padding: 5px 0;
}
.data-table td:first-child {
width: 20%;
min-width: 130px;
overflow: hidden;
font-weight: bold;
color: #463C54;
padding-right: 5px;
}
.data-table td:last-child {
width: 80%;
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
hyphens: auto;
}
.data-table span.empty {
color: rgba(0, 0, 0, .3);
font-weight: 300;
}
.data-table label.empty {
display: inline;
}
.handler {
padding: 4px 0;
font: 14px "Inconsolata", "Fira Mono", "Source
Code Pro", Monaco, Consolas, "Lucida Console", monospace;
}
/* prettify code style
Uses the Doxy theme as a base */
pre .str, code .str { color: #BCD42A; } /* string */
pre .kwd, code .kwd { color: #4bb1b1; font-weight: bold; } /* keyword*/
pre .com, code .com { color: #888; font-weight: bold; } /* comment */
pre .typ, code .typ { color: #ef7c61; } /* type */
pre .lit, code .lit { color: #BCD42A; } /* literal */
pre .pun, code .pun { color: #fff; font-weight: bold; } /* punctuation */
pre .pln, code .pln { color: #e9e4e5; } /* plaintext */
pre .tag, code .tag { color: #4bb1b1; } /* html/xml tag */
pre .htm, code .htm { color: #dda0dd; } /* html tag */
pre .xsl, code .xsl { color: #d0a0d0; } /* xslt tag */
pre .atn, code .atn { color: #ef7c61; font-weight: normal;} /* html/xml
attribute name */
pre .atv, code .atv { color: #bcd42a; } /* html/xml attribute value */
pre .dec, code .dec { color: #606; } /* decimal */
pre.code-block, code.code-block, .frame-args.code-block,
.frame-args.code-block samp {
font-family: "Inconsolata", "Fira Mono", "Source
Code Pro", Monaco, Consolas, "Lucida Console", monospace;
background: #333;
color: #e9e4e5;
}
pre.code-block {
white-space: pre-wrap;
}
pre.code-block a, code.code-block a {
text-decoration:none;
}
.linenums li {
color: #A5A5A5;
}
.linenums li.current{
background: rgba(255, 100, 100, .07);
}
.linenums li.current.active {
background: rgba(255, 100, 100, .17);
}
pre:not(.prettyprinted) {
padding-left: 60px;
}
#plain-exception {
display: none;
}
.rightButton {
cursor: pointer;
border: 0;
opacity: .8;
background: none;
color: rgba(255, 255, 255, 0.1);
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.1);
border-radius: 3px;
outline: none !important;
}
.rightButton:hover {
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.3);
color: rgba(255, 255, 255, 0.3);
}
/* inspired by githubs kbd styles */
kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #fcfcfc;
border-color: #ccc #ccc #bbb;
border-image: none;
border-style: solid;
border-width: 1px;
color: #555;
display: inline-block;
font-size: 11px;
line-height: 10px;
padding: 3px 5px;
vertical-align: middle;
}
/* == Media queries */
/* Expand the spacing in the details section */
@media (min-width: 1000px) {
.details, .frame-code {
padding: 20px 40px;
}
.details-container {
left: 32%;
width: 68%;
}
.frames-container {
margin: 5px;
}
.left-panel {
width: 32%;
}
}
/* Stack panels */
@media (max-width: 600px) {
.panel {
position: static;
width: 100%;
}
}
/* Stack details tables */
@media (max-width: 400px) {
.data-table,
.data-table tbody,
.data-table tbody tr,
.data-table tbody td {
display: block;
width: 100%;
}
.data-table tbody tr:first-child {
padding-top: 0;
}
.data-table tbody td:first-child,
.data-table tbody td:last-child {
padding-left: 0;
padding-right: 0;
}
.data-table tbody td:last-child {
padding-top: 3px;
}
}
.tooltipped {
position: relative
}
.tooltipped:after {
position: absolute;
z-index: 1000000;
display: none;
padding: 5px 8px;
color: #fff;
text-align: center;
text-decoration: none;
text-shadow: none;
text-transform: none;
letter-spacing: normal;
word-wrap: break-word;
white-space: pre;
pointer-events: none;
content: attr(aria-label);
background: rgba(0, 0, 0, 0.8);
border-radius: 3px;
-webkit-font-smoothing: subpixel-antialiased
}
.tooltipped:before {
position: absolute;
z-index: 1000001;
display: none;
width: 0;
height: 0;
color: rgba(0, 0, 0, 0.8);
pointer-events: none;
content: "";
border: 5px solid transparent
}
.tooltipped:hover:before,
.tooltipped:hover:after,
.tooltipped:active:before,
.tooltipped:active:after,
.tooltipped:focus:before,
.tooltipped:focus:after {
display: inline-block;
text-decoration: none
}
.tooltipped-s:after {
top: 100%;
right: 50%;
margin-top: 5px
}
.tooltipped-s:before {
top: auto;
right: 50%;
bottom: -5px;
margin-right: -5px;
border-bottom-color: rgba(0, 0, 0, 0.8)
}
pre.sf-dump {
padding: 0px !important;
margin: 0px !important;
}
.search-for-help {
width: 85%;
padding: 0;
margin: 10px 0;
list-style-type: none;
display: inline-block;
}
.search-for-help li {
display: inline-block;
margin-right: 5px;
}
.search-for-help li:last-child {
margin-right: 0;
}
.search-for-help li a {
}
.search-for-help li a i {
width: 16px;
height: 16px;
overflow: hidden;
display: block;
}
.search-for-help li a svg {
fill: #fff;
}
.search-for-help li a svg path {
background-size: contain;
}
PK'd�[��L"L";vendor/filp/whoops/src/Whoops/Resources/js/clipboard.min.jsnu�[���/*!
* clipboard.js v1.5.3
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
*/
!function(t){if("object"==typeof
exports&&"undefined"!=typeof
module)module.exports=t();else if("function"==typeof
define&&define.amd)define([],t);else{var
e;e="undefined"!=typeof
window?window:"undefined"!=typeof
global?global:"undefined"!=typeof
self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function
t(e,n,r){function o(a,c){if(!n[a]){if(!e[a]){var
s="function"==typeof
require&&require;if(!c&&s)return s(a,!0);if(i)return
i(a,!0);var u=new Error("Cannot find module
'"+a+"'");throw
u.code="MODULE_NOT_FOUND",u}var
l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var
n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return
n[a].exports}for(var i="function"==typeof
require&&require,a=0;a<r.length;a++)o(r[a]);return
o}({1:[function(t,e,n){var
r=t("matches-selector");e.exports=function(t,e,n){for(var
o=n?t:t.parentNode;o&&o!==document;){if(r(o,e))return
o;o=o.parentNode}}},{"matches-selector":2}],2:[function(t,e,n){function
r(t,e){if(i)return i.call(t,e);for(var
n=t.parentNode.querySelectorAll(e),r=0;r<n.length;++r)if(n[r]==t)return!0;return!1}var
o=Element.prototype,i=o.matchesSelector||o.webkitMatchesSelector||o.mozMatchesSelector||o.msMatchesSelector||o.oMatchesSelector;e.exports=r},{}],3:[function(t,e,n){function
r(t,e,n,r){var i=o.apply(this,arguments);return
t.addEventListener(n,i),{destroy:function(){t.removeEventListener(n,i)}}}function
o(t,e,n,r){return function(n){var
o=i(n.target,e,!0);o&&(Object.defineProperty(n,"target",{value:o}),r.call(t,n))}}var
i=t("closest");e.exports=r},{closest:1}],4:[function(t,e,n){n.node=function(t){return
void 0!==t&&t instanceof
HTMLElement&&1===t.nodeType},n.nodeList=function(t){var
e=Object.prototype.toString.call(t);return void
0!==t&&("[object NodeList]"===e||"[object
HTMLCollection]"===e)&&"length"in
t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof
t||t instanceof String},n.function=function(t){var
e=Object.prototype.toString.call(t);return"[object
Function]"===e}},{}],5:[function(t,e,n){function
r(t,e,n){if(!t&&!e&&!n)throw new Error("Missing
required arguments");if(!c.string(e))throw new TypeError("Second
argument must be a String");if(!c.function(n))throw new
TypeError("Third argument must be a
Function");if(c.node(t))return o(t,e,n);if(c.nodeList(t))return
i(t,e,n);if(c.string(t))return a(t,e,n);throw new TypeError("First
argument must be a String, HTMLElement, HTMLCollection, or
NodeList")}function o(t,e,n){return
t.addEventListener(e,n),{destroy:function(){t.removeEventListener(e,n)}}}function
i(t,e,n){return
Array.prototype.forEach.call(t,function(t){t.addEventListener(e,n)}),{destroy:function(){Array.prototype.forEach.call(t,function(t){t.removeEventListener(e,n)})}}}function
a(t,e,n){return s(document.body,t,e,n)}var
c=t("./is"),s=t("delegate");e.exports=r},{"./is":4,delegate:3}],6:[function(t,e,n){function
r(t){var
e;if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName)t.select(),e=t.value;else{var
n=window.getSelection(),r=document.createRange();r.selectNodeContents(t),n.removeAllRanges(),n.addRange(r),e=n.toString()}return
e}e.exports=r},{}],7:[function(t,e,n){function
r(){}r.prototype={on:function(t,e,n){var
r=this.e||(this.e={});return(r[t]||(r[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){function
r(){o.off(t,r),e.apply(n,arguments)}var o=this;return
r._=e,this.on(t,r,n)},emit:function(t){var
e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),r=0,o=n.length;for(r;o>r;r++)n[r].fn.apply(n[r].ctx,e);return
this},off:function(t,e){var
n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var
i=0,a=r.length;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return
o.length?n[t]=o:delete
n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use
strict";function r(t){return
t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t
instanceof e))throw new TypeError("Cannot call a class as a
function")}n.__esModule=!0;var i=function(){function t(t,e){for(var
n=0;n<e.length;n++){var
r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in
r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return
function(e,n,r){return
n&&t(e.prototype,n),r&&t(e,r),e}}(),a=t("select"),c=r(a),s=function(){function
t(e){o(this,t),this.resolveOptions(e),this.initSelection()}return
t.prototype.resolveOptions=function t(){var e=arguments.length<=0||void
0===arguments[0]?{}:arguments[0];this.action=e.action,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""},t.prototype.initSelection=function
t(){if(this.text&&this.target)throw new Error('Multiple
attributes declared, use either "target" or
"text"');if(this.text)this.selectFake();else{if(!this.target)throw
new Error('Missing required attributes, use either "target"
or
"text"');this.selectTarget()}},t.prototype.selectFake=function
t(){var
e=this;this.removeFake(),this.fakeHandler=document.body.addEventListener("click",function(){return
e.removeFake()}),this.fakeElem=document.createElement("textarea"),this.fakeElem.style.position="absolute",this.fakeElem.style.left="-9999px",this.fakeElem.style.top=(window.pageYOffset||document.documentElement.scrollTop)+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,document.body.appendChild(this.fakeElem),this.selectedText=c.default(this.fakeElem),this.copyText()},t.prototype.removeFake=function
t(){this.fakeHandler&&(document.body.removeEventListener("click"),this.fakeHandler=null),this.fakeElem&&(document.body.removeChild(this.fakeElem),this.fakeElem=null)},t.prototype.selectTarget=function
t(){this.selectedText=c.default(this.target),this.copyText()},t.prototype.copyText=function
t(){var e=void
0;try{e=document.execCommand(this.action)}catch(n){e=!1}this.handleResult(e)},t.prototype.handleResult=function
t(e){e?this.emitter.emit("success",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)}):this.emitter.emit("error",{action:this.action,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})},t.prototype.clearSelection=function
t(){this.target&&this.target.blur(),window.getSelection().removeAllRanges()},t.prototype.destroy=function
t(){this.removeFake()},i(t,[{key:"action",set:function t(){var
e=arguments.length<=0||void
0===arguments[0]?"copy":arguments[0];if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw
new Error('Invalid "action" value, use either
"copy" or "cut"')},get:function t(){return
this._action}},{key:"target",set:function t(e){if(void
0!==e){if(!e||"object"!=typeof e||1!==e.nodeType)throw new
Error('Invalid "target" value, use a valid
Element');this._target=e}},get:function t(){return
this._target}}]),t}();n.default=s,e.exports=n.default},{select:6}],9:[function(t,e,n){"use
strict";function r(t){return
t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t
instanceof e))throw new TypeError("Cannot call a class as a
function")}function i(t,e){if("function"!=typeof
e&&null!==e)throw new TypeError("Super expression must either
be null or a function, not "+typeof
e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function
a(t,e){var n="data-clipboard-"+t;if(e.hasAttribute(n))return
e.getAttribute(n)}n.__esModule=!0;var
c=t("./clipboard-action"),s=r(c),u=t("tiny-emitter"),l=r(u),f=t("good-listener"),d=r(f),h=function(t){function
e(n,r){o(this,e),t.call(this),this.resolveOptions(r),this.listenClick(n)}return
i(e,t),e.prototype.resolveOptions=function t(){var
e=arguments.length<=0||void
0===arguments[0]?{}:arguments[0];this.action="function"==typeof
e.action?e.action:this.defaultAction,this.target="function"==typeof
e.target?e.target:this.defaultTarget,this.text="function"==typeof
e.text?e.text:this.defaultText},e.prototype.listenClick=function t(e){var
n=this;this.listener=d.default(e,"click",function(t){return
n.onClick(t)})},e.prototype.onClick=function
t(e){this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new
s.default({action:this.action(e.target),target:this.target(e.target),text:this.text(e.target),trigger:e.target,emitter:this})},e.prototype.defaultAction=function
t(e){return a("action",e)},e.prototype.defaultTarget=function
t(e){var n=a("target",e);return n?document.querySelector(n):void
0},e.prototype.defaultText=function t(e){return
a("text",e)},e.prototype.destroy=function
t(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)},e}(l.default);n.default=h,e.exports=n.default},{"./clipboard-action":8,"good-listener":5,"tiny-emitter":7}]},{},[9])(9)});PK'd�[����5�5:vendor/filp/whoops/src/Whoops/Resources/js/prettify.min.jsnu�[���var
r=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function O(a){function i(d){var
a=d.charCodeAt(0);if(a!==92)return a;var
f=d.charAt(1);return(a=s[f])?a:"0"<=f&&f<="7"?parseInt(d.substring(1),8):f==="u"||f==="x"?parseInt(d.substring(2),16):d.charCodeAt(1)}function
g(d){if(d<32)return(d<16?"\\x0":"\\x")+d.toString(16);d=String.fromCharCode(d);return
d==="\\"||d==="-"||d==="]"||d==="^"?"\\"+d:d}function
j(d){var
a=d.substring(1,d.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),d=[],f=
a[0]==="^",b=["["];f&&b.push("^");for(var
f=f?1:0,c=a.length;f<c;++f){var
h=a[f];if(/\\[bdsw]/i.test(h))b.push(h);else{var
h=i(h),e;f+2<c&&"-"===a[f+1]?(e=i(a[f+2]),f+=2):e=h;d.push([h,e]);e<65||h>122||(e<65||h>90||d.push([Math.max(65,h)|32,Math.min(e,90)|32]),e<97||h>122||d.push([Math.max(97,h)&-33,Math.min(e,122)&-33]))}}d.sort(function(d,a){return
d[0]-a[0]||a[1]-d[1]});a=[];c=[];for(f=0;f<d.length;++f)h=d[f],h[0]<=c[1]+1?c[1]=Math.max(c[1],h[1]):a.push(c=h);for(f=0;f<a.length;++f)h=a[f],b.push(g(h[0])),
h[1]>h[0]&&(h[1]+1>h[0]&&b.push("-"),b.push(g(h[1])));b.push("]");return
b.join("")}function t(d){for(var
a=d.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=a.length,i=[],c=0,h=0;c<b;++c){var
e=a[c];e==="("?++h:"\\"===e.charAt(0)&&(e=+e.substring(1))&&(e<=h?i[e]=-1:a[c]=g(e))}for(c=1;c<i.length;++c)-1===i[c]&&(i[c]=++z);for(h=c=0;c<b;++c)e=a[c],e==="("?(++h,i[h]||(a[c]="(?:")):"\\"===e.charAt(0)&&(e=+e.substring(1))&&e<=h&&
(a[c]="\\"+i[e]);for(c=0;c<b;++c)"^"===a[c]&&"^"!==a[c+1]&&(a[c]="");if(d.ignoreCase&&w)for(c=0;c<b;++c)e=a[c],d=e.charAt(0),e.length>=2&&d==="["?a[c]=j(e):d!=="\\"&&(a[c]=e.replace(/[A-Za-z]/g,function(d){d=d.charCodeAt(0);return"["+String.fromCharCode(d&-33,d|32)+"]"}));return
a.join("")}for(var z=0,w=!1,k=!1,m=0,b=a.length;m<b;++m){var
o=a[m];if(o.ignoreCase)k=!0;else
if(/[a-z]/i.test(o.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){w=!0;k=!1;break}}for(var
s={b:8,t:9,n:10,v:11,
f:12,r:13},q=[],m=0,b=a.length;m<b;++m){o=a[m];if(o.global||o.multiline)throw
Error(""+o);q.push("(?:"+t(o)+")")}return
RegExp(q.join("|"),k?"gi":"g")}function
P(a,i){function g(a){switch(a.nodeType){case
1:if(j.test(a.className))break;for(var
b=a.firstChild;b;b=b.nextSibling)g(b);b=a.nodeName.toLowerCase();if("br"===b||"li"===b)t[k]="\n",w[k<<1]=z++,w[k++<<1|1]=a;break;case
3:case
4:b=a.nodeValue,b.length&&(b=i?b.replace(/\r\n?/g,"\n"):b.replace(/[\t\n\r
]+/g," "),t[k]=b,w[k<<1]=z,z+=b.length,w[k++<<
1|1]=a)}}var
j=/(?:^|\s)nocode(?:\s|$)/,t=[],z=0,w=[],k=0;g(a);return{a:t.join("").replace(/\n$/,""),d:w}}function
E(a,i,g,j){i&&(a={a:i,e:a},g(a),j.push.apply(j,a.g))}function
x(a,i){function g(a){for(var
k=a.e,m=[k,"pln"],b=0,o=a.a.match(t)||[],s={},q=0,d=o.length;q<d;++q){var
v=o[q],f=s[v],u=void 0,c;if(typeof f==="string")c=!1;else{var
h=j[v.charAt(0)];if(h)u=v.match(h[1]),f=h[0];else{for(c=0;c<z;++c)if(h=i[c],u=v.match(h[1])){f=h[0];break}u||(f="pln")}if((c=f.length>=5&&"lang-"===f.substring(0,
5))&&!(u&&typeof
u[1]==="string"))c=!1,f="src";c||(s[v]=f)}h=b;b+=v.length;if(c){c=u[1];var
e=v.indexOf(c),p=e+c.length;u[2]&&(p=v.length-u[2].length,e=p-c.length);f=f.substring(5);E(k+h,v.substring(0,e),g,m);E(k+h+e,c,F(f,c),m);E(k+h+p,v.substring(p),g,m)}else
m.push(k+h,f)}a.g=m}var j={},t;(function(){for(var
g=a.concat(i),k=[],m={},b=0,o=g.length;b<o;++b){var
s=g[b],q=s[3];if(q)for(var
d=q.length;--d>=0;)j[q.charAt(d)]=s;s=s[1];q=""+s;m.hasOwnProperty(q)||(k.push(s),m[q]=r)}k.push(/[\S\s]/);t=
O(k)})();var z=i.length;return g}function l(a){var
i=[],g=[];a.tripleQuotedStrings?i.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,r,"'\""]):a.multiLineStrings?i.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,r,"'\"`"]):i.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,r,"\"'"]);a.verbatimStrings&&
g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,r]);var
j=a.hashComments;j&&(a.cStyleComments?(j>1?i.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,r,"#"]):i.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,r,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,r])):i.push(["com",/^#[^\n\r]*/,r,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,r]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,
r]));a.regexLiterals&&g.push(["lang-regex",/^(?:^^\.?|[+-]|[!=]={0,2}|#|%=?|&&?=?|\(|\*=?|[+-]=|->|\/=?|::?|<<?=?|>{1,3}=?|[,;?@[{~]|\^\^?=?|\|\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(j=a.types)&&g.push(["typ",j]);a=(""+a.keywords).replace(/^
|
$/g,"");a.length&&g.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),r]);i.push(["pln",/^\s+/,r,"
\r\n\t\u00a0"]);g.push(["lit",
/^@[$_a-z][\w$@]*/i,r],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,r],["pln",/^[$_a-z][\w$@]*/i,r],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,r,"0123456789"],["pln",/^\\[\S\s]?/,r],["pun",/^.[^\s\w"$'./@\\`]*/,r]);return
x(i,g)}function G(a,i,g){function j(a){switch(a.nodeType){case
1:if(z.test(a.className))break;if("br"===a.nodeName)t(a),a.parentNode&&a.parentNode.removeChild(a);else
for(a=a.firstChild;a;a=a.nextSibling)j(a);break;case 3:case 4:if(g){var b=
a.nodeValue,f=b.match(n);if(f){var
i=b.substring(0,f.index);a.nodeValue=i;(b=b.substring(f.index+f[0].length))&&a.parentNode.insertBefore(k.createTextNode(b),a.nextSibling);t(a);i||a.parentNode.removeChild(a)}}}}function
t(a){function i(a,b){var d=b?a.cloneNode(!1):a,e=a.parentNode;if(e){var
e=i(e,1),f=a.nextSibling;e.appendChild(d);for(var
g=f;g;g=f)f=g.nextSibling,e.appendChild(g)}return
d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var
a=i(a.nextSibling,0),f;(f=a.parentNode)&&f.nodeType===
1;)a=f;b.push(a)}for(var
z=/(?:^|\s)nocode(?:\s|$)/,n=/\r\n?|\n/,k=a.ownerDocument,m=k.createElement("li");a.firstChild;)m.appendChild(a.firstChild);for(var
b=[m],o=0;o<b.length;++o)j(b[o]);i===(i|0)&&b[0].setAttribute("value",i);var
s=k.createElement("ol");s.className="linenums";for(var
i=Math.max(0,i-1|0)||0,o=0,q=b.length;o<q;++o)m=b[o],m.className="L"+(o+i)%10,m.firstChild||m.appendChild(k.createTextNode("\u00a0")),s.appendChild(m);a.appendChild(s)}function
n(a,i){for(var g=i.length;--g>=0;){var j=
i[g];A.hasOwnProperty(j)?C.console&&console.warn("cannot
override language handler %s",j):A[j]=a}}function
F(a,i){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(i)?"default-markup":"default-code";return
A[a]}function H(a){var i=a.h;try{var
g=P(a.c,a.i),j=g.a;a.a=j;a.d=g.d;a.e=0;F(i,j)(a);var
t=/\bMSIE\s(\d+)/.exec(navigator.userAgent),t=t&&+t[1]<=8,i=/\n/g,n=a.a,w=n.length,g=0,k=a.d,m=k.length,j=0,b=a.g,o=b.length,s=0;b[o]=w;var
q,d;for(d=q=0;d<o;)b[d]!==b[d+2]?(b[q++]=b[d++],b[q++]=b[d++]):d+=2;o=q;
for(d=q=0;d<o;){for(var
v=b[d],f=b[d+1],u=d+2;u+2<=o&&b[u+1]===f;)u+=2;b[q++]=v;b[q++]=f;d=u}b.length=q;var
c=a.c,h;if(c)h=c.style.display,c.style.display="none";try{for(;j<m;){var
e=k[j+2]||w,p=b[s+2]||w,u=Math.min(e,p),l=k[j+1],D;if(l.nodeType!==1&&(D=n.substring(g,u))){t&&(D=D.replace(i,"\r"));l.nodeValue=D;var
y=l.ownerDocument,x=y.createElement("span");x.className=b[s+1];var
B=l.parentNode;B.replaceChild(x,l);x.appendChild(l);g<e&&(k[j+1]=l=y.createTextNode(n.substring(u,e)),B.insertBefore(l,
x.nextSibling))}g=u;g>=e&&(j+=2);g>=p&&(s+=2)}}finally{if(c)c.style.display=h}}catch(A){C.console&&console.log(A&&A.stack?A.stack:A)}}var
C=window,y=["break,continue,do,else,for,if,return,while"],B=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],I=[B,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],
J=[B,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],K=[J,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],B=[B,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],
L=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],M=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],N=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
Q=/\S/,R=l({keywords:[I,K,B,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+L,M,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};n(R,["default-code"]);n(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);n(x([["pln",/^\s+/,r,"
\t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,r,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],
["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);n(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);n(l({keywords:I,hashComments:!0,cStyleComments:!0,types:N}),["c","cc","cpp","cxx","cyc","m"]);n(l({keywords:"null,true,false"}),["json"]);n(l({keywords:K,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:N}),
["cs"]);n(l({keywords:J,cStyleComments:!0}),["java"]);n(l({keywords:y,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);n(l({keywords:L,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py"]);n(l({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);n(l({keywords:M,hashComments:!0,
multiLineStrings:!0,regexLiterals:!0}),["rb"]);n(l({keywords:B,cStyleComments:!0,regexLiterals:!0}),["js"]);n(l({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);n(x([],[["str",/^[\S\s]+/]]),["regex"]);var
S=C.PR={createSimpleLexer:x,registerLangHandler:n,sourceDecorator:l,
PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:C.prettyPrintOne=function(a,i,g){var
j=document.createElement("pre");j.innerHTML=a;g&&G(j,g,!0);H({h:i,j:g,c:j,i:1});return
j.innerHTML},prettyPrint:C.prettyPrint=function(a){function i(){var
u;for(var
g=C.PR_SHOULD_USE_CONTINUATION?k.now()+250:Infinity;m<j.length&&
k.now()<g;m++){var
c=j[m],h=c.className;if(s.test(h)&&!q.test(h)){for(var
e=!1,p=c.parentNode;p;p=p.parentNode)if(f.test(p.tagName)&&p.className&&s.test(p.className)){e=!0;break}if(!e){c.className+="
prettyprinted";var h=h.match(o),n;if(e=!h){for(var e=c,p=void
0,l=e.firstChild;l;l=l.nextSibling)var
t=l.nodeType,p=t===1?p?e:l:t===3?Q.test(l.nodeValue)?e:p:p;e=(n=p===e?void
0:p)&&v.test(n.tagName)}e&&(h=n.className.match(o));h&&(h=h[1]);u=d.test(c.tagName)?1:(e=(e=c.currentStyle)?e.whiteSpace:document.defaultView&&
document.defaultView.getComputedStyle?document.defaultView.getComputedStyle(c,r).getPropertyValue("white-space"):0)&&"pre"===e.substring(0,3),e=u;(p=(p=c.className.match(/\blinenums\b(?::(\d+))?/))?p[1]&&p[1].length?+p[1]:!0:!1)&&G(c,p,e);b={h:h,c:c,j:p,i:e};H(b)}}}m<j.length?setTimeout(i,250):a&&a()}for(var
g=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],j=[],n=0;n<g.length;++n)for(var
l=0,w=g[n].length;l<w;++l)j.push(g[n][l]);var g=
r,k=Date;k.now||(k={now:function(){return+new Date}});var
m=0,b,o=/\blang(?:uage)?-([\w.]+)(?!\S)/,s=/\bprettyprint\b/,q=/\bprettyprinted\b/,d=/pre|xmp/i,v=/^code$/i,f=/^(?:pre|code|xmp)$/i;i()}};typeof
define==="function"&&define.amd&&define("google-code-prettify",[],function(){return
S})})();
PK'd�[g�����9vendor/filp/whoops/src/Whoops/Resources/js/whoops.base.jsnu�[���Zepto(function($)
{
var $leftPanel = $('.left-panel');
var $frameContainer = $('.frames-container');
var $appFramesTab = $('#application-frames-tab');
var $allFramesTab = $('#all-frames-tab');
var $container = $('.details-container');
var $activeLine = $frameContainer.find('.frame.active');
var $activeFrame = $container.find('.frame-code.active');
var $ajaxEditors = $('.editor-link[data-ajax]');
var $header = $('header');
$header.on('mouseenter', function () {
if ($header.find('.exception').height() >= 145) {
$header.addClass('header-expand');
}
});
$header.on('mouseleave', function () {
$header.removeClass('header-expand');
});
/*
* add prettyprint classes to our current active codeblock
* run prettyPrint() to highlight the active code
* scroll to the line when prettyprint is done
* highlight the current line
*/
var renderCurrentCodeblock = function(id) {
// remove previous codeblocks so we only render the active one
$('.code-block').removeClass('prettyprint');
// pass the id in when we can for speed
if (typeof(id) === 'undefined' || typeof(id) ===
'object') {
var id =
/frame\-line\-([\d]*)/.exec($activeLine.attr('id'))[1];
}
$('#frame-code-linenums-' +
id).addClass('prettyprint');
$('#frame-code-args-' +
id).addClass('prettyprint');
prettyPrint(highlightCurrentLine);
}
/*
* Highlight the active and neighboring lines for the current frame
* Adjust the offset to make sure that line is veritcally centered
*/
var highlightCurrentLine = function() {
var activeLineNumber =
+($activeLine.find('.frame-line').text());
var $lines = $activeFrame.find('.linenums li');
var firstLine = +($lines.first().val());
// We show more code than needed, purely for proper syntax highlighting
// Let’s hide a big chunk of that code and then scroll the remaining
block
$activeFrame.find('.code-block').first().css({
maxHeight: 345,
overflow: 'hidden',
});
var $offset = $($lines[activeLineNumber - firstLine - 10]);
if ($offset.length > 0) {
$offset[0].scrollIntoView();
}
$($lines[activeLineNumber - firstLine -
1]).addClass('current');
$($lines[activeLineNumber - firstLine]).addClass('current
active');
$($lines[activeLineNumber - firstLine +
1]).addClass('current');
$container.scrollTop(0);
}
/*
* click handler for loading codeblocks
*/
$frameContainer.on('click', '.frame', function() {
var $this = $(this);
var id =
/frame\-line\-([\d]*)/.exec($this.attr('id'))[1];
var $codeFrame = $('#frame-code-' + id);
if ($codeFrame) {
$activeLine.removeClass('active');
$activeFrame.removeClass('active');
$this.addClass('active');
$codeFrame.addClass('active');
$activeLine = $this;
$activeFrame = $codeFrame;
renderCurrentCodeblock(id);
}
});
var clipboard = new Clipboard('.clipboard');
var showTooltip = function(elem, msg) {
elem.setAttribute('class', 'clipboard tooltipped
tooltipped-s');
elem.setAttribute('aria-label', msg);
};
clipboard.on('success', function(e) {
e.clearSelection();
showTooltip(e.trigger, 'Copied!');
});
clipboard.on('error', function(e) {
showTooltip(e.trigger, fallbackMessage(e.action));
});
var btn = document.querySelector('.clipboard');
btn.addEventListener('mouseleave', function(e) {
e.currentTarget.setAttribute('class', 'clipboard');
e.currentTarget.removeAttribute('aria-label');
});
function fallbackMessage(action) {
var actionMsg = '';
var actionKey = (action === 'cut' ? 'X' :
'C');
if (/Mac/i.test(navigator.userAgent)) {
actionMsg = 'Press ⌘-' + actionKey + ' to ' +
action;
} else {
actionMsg = 'Press Ctrl-' + actionKey + ' to '
+ action;
}
return actionMsg;
}
function scrollIntoView($node, $parent) {
var nodeOffset = $node.offset();
var nodeTop = nodeOffset.top;
var nodeBottom = nodeTop + nodeOffset.height;
var parentScrollTop = $parent.scrollTop();
var parentHeight = $parent.height();
if (nodeTop < 0) {
$parent.scrollTop(parentScrollTop + nodeTop);
} else if (nodeBottom > parentHeight) {
$parent.scrollTop(parentScrollTop + nodeBottom - parentHeight);
}
}
$(document).on('keydown', function(e) {
var applicationFrames =
$frameContainer.hasClass('frames-container-application'),
frameClass = applicationFrames ?
'.frame.frame-application' : '.frame';
if(e.ctrlKey || e.which === 74 || e.which === 75) {
// CTRL+Arrow-UP/k and Arrow-Down/j support:
// 1) select the next/prev element
// 2) make sure the newly selected element is within the view-scope
// 3) focus the (right) container, so arrow-up/down (without ctrl)
scroll the details
if (e.which === 38 /* arrow up */ || e.which === 75 /* k */) {
$activeLine.prev(frameClass).click();
scrollIntoView($activeLine, $leftPanel);
$container.focus();
e.preventDefault();
} else if (e.which === 40 /* arrow down */ || e.which === 74 /* j */) {
$activeLine.next(frameClass).click();
scrollIntoView($activeLine, $leftPanel);
$container.focus();
e.preventDefault();
}
} else if (e.which == 78 /* n */) {
if ($appFramesTab.length) {
setActiveFramesTab($('.frames-tab:not(.frames-tab-active)'));
}
}
});
// Render late enough for highlightCurrentLine to be ready
renderCurrentCodeblock();
// Avoid to quit the page with some protocol (e.g. IntelliJ Platform REST
API)
$ajaxEditors.on('click', function(e){
e.preventDefault();
$.get(this.href);
});
// Symfony VarDumper: Close the by default expanded objects
$('.sf-dump-expanded')
.removeClass('sf-dump-expanded')
.addClass('sf-dump-compact');
$('.sf-dump-toggle span').html('▶');
// Make the given frames-tab active
function setActiveFramesTab($tab) {
$tab.addClass('frames-tab-active');
if ($tab.attr('id') == 'application-frames-tab') {
$frameContainer.addClass('frames-container-application');
$allFramesTab.removeClass('frames-tab-active');
} else {
$frameContainer.removeClass('frames-container-application');
$appFramesTab.removeClass('frames-tab-active');
}
}
$('a.frames-tab').on('click', function(e) {
e.preventDefault();
setActiveFramesTab($(this));
});
});
PK'd�[�/0�<`<`7vendor/filp/whoops/src/Whoops/Resources/js/zepto.min.jsnu�[���/*
Zepto v1.1.3 - zepto event ajax form ie - zeptojs.com/license */
var Zepto=function(){function L(t){return
null==t?String(t):j[T.call(t)]||"object"}function
Z(t){return"function"==L(t)}function $(t){return
null!=t&&t==t.window}function _(t){return
null!=t&&t.nodeType==t.DOCUMENT_NODE}function
D(t){return"object"==L(t)}function R(t){return
D(t)&&!$(t)&&Object.getPrototypeOf(t)==Object.prototype}function
M(t){return"number"==typeof t.length}function k(t){return
s.call(t,function(t){return null!=t})}function z(t){return
t.length>0?n.fn.concat.apply([],t):t}function F(t){return
t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function
q(t){return t in f?f[t]:f[t]=new
RegExp("(^|\\s)"+t+"(\\s|$)")}function
H(t,e){return"number"!=typeof
e||c[F(t)]?e:e+"px"}function I(t){var e,n;return
u[t]||(e=a.createElement(t),a.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),u[t]=n),u[t]}function
V(t){return"children"in
t?o.call(t.children):n.map(t.childNodes,function(t){return
1==t.nodeType?t:void 0})}function U(n,i,r){for(e in
i)r&&(R(i[e])||A(i[e]))?(R(i[e])&&!R(n[e])&&(n[e]={}),A(i[e])&&!A(n[e])&&(n[e]=[]),U(n[e],i[e],r)):i[e]!==t&&(n[e]=i[e])}function
B(t,e){return null==e?n(t):n(t).filter(e)}function J(t,e,n,i){return
Z(e)?e.call(t,n,i):e}function
X(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function
W(e,n){var i=e.className,r=i&&i.baseVal!==t;return
n===t?r?i.baseVal:i:void(r?i.baseVal=n:e.className=n)}function Y(t){var
e;try{return
t?"true"==t||("false"==t?!1:"null"==t?null:/^0/.test(t)||isNaN(e=Number(t))?/^[\[\{]/.test(t)?n.parseJSON(t):t:e):t}catch(i){return
t}}function G(t,e){e(t);for(var n in t.childNodes)G(t.childNodes[n],e)}var
t,e,n,i,C,N,r=[],o=r.slice,s=r.filter,a=window.document,u={},f={},c={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},l=/^\s*<(\w+|!)[^>]*>/,h=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,p=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,d=/^(?:body|html)$/i,m=/([A-Z])/g,g=["val","css","html","text","data","width","height","offset"],v=["after","prepend","before","append"],y=a.createElement("table"),x=a.createElement("tr"),b={tr:a.createElement("tbody"),tbody:y,thead:y,tfoot:y,td:x,th:x,"*":a.createElement("div")},w=/complete|loaded|interactive/,E=/^[\w-]*$/,j={},T=j.toString,S={},O=a.createElement("div"),P={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},A=Array.isArray||function(t){return
t instanceof Array};return
S.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var
n=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return
n.call(t,e);var i,r=t.parentNode,o=!r;return
o&&(r=O).appendChild(t),i=~S.qsa(r,e).indexOf(t),o&&O.removeChild(t),i},C=function(t){return
t.replace(/-+(.)?/g,function(t,e){return
e?e.toUpperCase():""})},N=function(t){return
s.call(t,function(e,n){return
t.indexOf(e)==n})},S.fragment=function(e,i,r){var s,u,f;return
h.test(e)&&(s=n(a.createElement(RegExp.$1))),s||(e.replace&&(e=e.replace(p,"<$1></$2>")),i===t&&(i=l.test(e)&&RegExp.$1),i
in
b||(i="*"),f=b[i],f.innerHTML=""+e,s=n.each(o.call(f.childNodes),function(){f.removeChild(this)})),R(r)&&(u=n(s),n.each(r,function(t,e){g.indexOf(t)>-1?u[t](e):u.attr(t,e)})),s},S.Z=function(t,e){return
t=t||[],t.__proto__=n.fn,t.selector=e||"",t},S.isZ=function(t){return
t instanceof S.Z},S.init=function(e,i){var r;if(!e)return
S.Z();if("string"==typeof
e)if(e=e.trim(),"<"==e[0]&&l.test(e))r=S.fragment(e,RegExp.$1,i),e=null;else{if(i!==t)return
n(i).find(e);r=S.qsa(a,e)}else{if(Z(e))return
n(a).ready(e);if(S.isZ(e))return e;if(A(e))r=k(e);else
if(D(e))r=[e],e=null;else
if(l.test(e))r=S.fragment(e.trim(),RegExp.$1,i),e=null;else{if(i!==t)return
n(i).find(e);r=S.qsa(a,e)}}return S.Z(r,e)},n=function(t,e){return
S.init(t,e)},n.extend=function(t){var
e,n=o.call(arguments,1);return"boolean"==typeof
t&&(e=t,t=n.shift()),n.forEach(function(n){U(t,n,e)}),t},S.qsa=function(t,e){var
n,i="#"==e[0],r=!i&&"."==e[0],s=i||r?e.slice(1):e,a=E.test(s);return
_(t)&&a&&i?(n=t.getElementById(s))?[n]:[]:1!==t.nodeType&&9!==t.nodeType?[]:o.call(a&&!i?r?t.getElementsByClassName(s):t.getElementsByTagName(e):t.querySelectorAll(e))},n.contains=function(t,e){return
t!==e&&t.contains(e)},n.type=L,n.isFunction=Z,n.isWindow=$,n.isArray=A,n.isPlainObject=R,n.isEmptyObject=function(t){var
e;for(e in t)return!1;return!0},n.inArray=function(t,e,n){return
r.indexOf.call(e,t,n)},n.camelCase=C,n.trim=function(t){return
null==t?"":String.prototype.trim.call(t)},n.uuid=0,n.support={},n.expr={},n.map=function(t,e){var
n,r,o,i=[];if(M(t))for(r=0;r<t.length;r++)n=e(t[r],r),null!=n&&i.push(n);else
for(o in t)n=e(t[o],o),null!=n&&i.push(n);return
z(i)},n.each=function(t,e){var
n,i;if(M(t)){for(n=0;n<t.length;n++)if(e.call(t[n],n,t[n])===!1)return
t}else for(i in t)if(e.call(t[i],i,t[i])===!1)return t;return
t},n.grep=function(t,e){return
s.call(t,e)},window.JSON&&(n.parseJSON=JSON.parse),n.each("Boolean
Number String Function Array Date RegExp Object Error".split("
"),function(t,e){j["[object
"+e+"]"]=e.toLowerCase()}),n.fn={forEach:r.forEach,reduce:r.reduce,push:r.push,sort:r.sort,indexOf:r.indexOf,concat:r.concat,map:function(t){return
n(n.map(this,function(e,n){return t.call(e,n,e)}))},slice:function(){return
n(o.apply(this,arguments))},ready:function(t){return
w.test(a.readyState)&&a.body?t(n):a.addEventListener("DOMContentLoaded",function(){t(n)},!1),this},get:function(e){return
e===t?o.call(this):this[e>=0?e:e+this.length]},toArray:function(){return
this.get()},size:function(){return this.length},remove:function(){return
this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return
r.every.call(this,function(e,n){return
t.call(e,n,e)!==!1}),this},filter:function(t){return
Z(t)?this.not(this.not(t)):n(s.call(this,function(e){return
S.matches(e,t)}))},add:function(t,e){return
n(N(this.concat(n(t,e))))},is:function(t){return
this.length>0&&S.matches(this[0],t)},not:function(e){var
i=[];if(Z(e)&&e.call!==t)this.each(function(t){e.call(this,t)||i.push(this)});else{var
r="string"==typeof
e?this.filter(e):M(e)&&Z(e.item)?o.call(e):n(e);this.forEach(function(t){r.indexOf(t)<0&&i.push(t)})}return
n(i)},has:function(t){return this.filter(function(){return
D(t)?n.contains(this,t):n(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var
t=this[0];return t&&!D(t)?t:n(t)},last:function(){var
t=this[this.length-1];return t&&!D(t)?t:n(t)},find:function(t){var
e,i=this;return e="object"==typeof t?n(t).filter(function(){var
t=this;return r.some.call(i,function(e){return
n.contains(e,t)})}):1==this.length?n(S.qsa(this[0],t)):this.map(function(){return
S.qsa(this,t)})},closest:function(t,e){var
i=this[0],r=!1;for("object"==typeof
t&&(r=n(t));i&&!(r?r.indexOf(i)>=0:S.matches(i,t));)i=i!==e&&!_(i)&&i.parentNode;return
n(i)},parents:function(t){for(var
e=[],i=this;i.length>0;)i=n.map(i,function(t){return(t=t.parentNode)&&!_(t)&&e.indexOf(t)<0?(e.push(t),t):void
0});return B(e,t)},parent:function(t){return
B(N(this.pluck("parentNode")),t)},children:function(t){return
B(this.map(function(){return V(this)}),t)},contents:function(){return
this.map(function(){return
o.call(this.childNodes)})},siblings:function(t){return
B(this.map(function(t,e){return s.call(V(e.parentNode),function(t){return
t!==e})}),t)},empty:function(){return
this.each(function(){this.innerHTML=""})},pluck:function(t){return
n.map(this,function(e){return e[t]})},show:function(){return
this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=I(this.nodeName))})},replaceWith:function(t){return
this.before(t).remove()},wrap:function(t){var
e=Z(t);if(this[0]&&!e)var
i=n(t).get(0),r=i.parentNode||this.length>1;return
this.each(function(o){n(this).wrapAll(e?t.call(this,o):r?i.cloneNode(!0):i)})},wrapAll:function(t){if(this[0]){n(this[0]).before(t=n(t));for(var
e;(e=t.children()).length;)t=e.first();n(t).append(this)}return
this},wrapInner:function(t){var e=Z(t);return this.each(function(i){var
r=n(this),o=r.contents(),s=e?t.call(this,i):t;o.length?o.wrapAll(s):r.append(s)})},unwrap:function(){return
this.parent().each(function(){n(this).replaceWith(n(this).children())}),this},clone:function(){return
this.map(function(){return this.cloneNode(!0)})},hide:function(){return
this.css("display","none")},toggle:function(e){return
this.each(function(){var
i=n(this);(e===t?"none"==i.css("display"):e)?i.show():i.hide()})},prev:function(t){return
n(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return
n(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return
0===arguments.length?this.length>0?this[0].innerHTML:null:this.each(function(e){var
i=this.innerHTML;n(this).empty().append(J(this,t,e,i))})},text:function(e){return
0===arguments.length?this.length>0?this[0].textContent:null:this.each(function(){this.textContent=e===t?"":""+e})},attr:function(n,i){var
r;return"string"==typeof
n&&i===t?0==this.length||1!==this[0].nodeType?t:"value"==n&&"INPUT"==this[0].nodeName?this.val():!(r=this[0].getAttribute(n))&&n
in
this[0]?this[0][n]:r:this.each(function(t){if(1===this.nodeType)if(D(n))for(e
in n)X(this,e,n[e]);else
X(this,n,J(this,i,t,this.getAttribute(n)))})},removeAttr:function(t){return
this.each(function(){1===this.nodeType&&X(this,t)})},prop:function(e,n){return
e=P[e]||e,n===t?this[0]&&this[0][e]:this.each(function(t){this[e]=J(this,n,t,this[e])})},data:function(e,n){var
i=this.attr("data-"+e.replace(m,"-$1").toLowerCase(),n);return
null!==i?Y(i):t},val:function(t){return
0===arguments.length?this[0]&&(this[0].multiple?n(this[0]).find("option").filter(function(){return
this.selected}).pluck("value"):this[0].value):this.each(function(e){this.value=J(this,t,e,this.value)})},offset:function(t){if(t)return
this.each(function(e){var
i=n(this),r=J(this,t,e,i.offset()),o=i.offsetParent().offset(),s={top:r.top-o.top,left:r.left-o.left};"static"==i.css("position")&&(s.position="relative"),i.css(s)});if(0==this.length)return
null;var
e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(t,i){if(arguments.length<2){var
r=this[0],o=getComputedStyle(r,"");if(!r)return;if("string"==typeof
t)return r.style[C(t)]||o.getPropertyValue(t);if(A(t)){var s={};return
n.each(A(t)?t:[t],function(t,e){s[e]=r.style[C(e)]||o.getPropertyValue(e)}),s}}var
a="";if("string"==L(t))i||0===i?a=F(t)+":"+H(t,i):this.each(function(){this.style.removeProperty(F(t))});else
for(e in
t)t[e]||0===t[e]?a+=F(e)+":"+H(e,t[e])+";":this.each(function(){this.style.removeProperty(F(e))});return
this.each(function(){this.style.cssText+=";"+a})},index:function(t){return
t?this.indexOf(n(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return
t?r.some.call(this,function(t){return
this.test(W(t))},q(t)):!1},addClass:function(t){return
t?this.each(function(e){i=[];var
r=W(this),o=J(this,t,e,r);o.split(/\s+/g).forEach(function(t){n(this).hasClass(t)||i.push(t)},this),i.length&&W(this,r+(r?"
":"")+i.join("
"))}):this},removeClass:function(e){return
this.each(function(n){return
e===t?W(this,""):(i=W(this),J(this,e,n,i).split(/\s+/g).forEach(function(t){i=i.replace(q(t),"
")}),void W(this,i.trim()))})},toggleClass:function(e,i){return
e?this.each(function(r){var
o=n(this),s=J(this,e,r,W(this));s.split(/\s+/g).forEach(function(e){(i===t?!o.hasClass(e):i)?o.addClass(e):o.removeClass(e)})}):this},scrollTop:function(e){if(this.length){var
n="scrollTop"in this[0];return
e===t?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=e}:function(){this.scrollTo(this.scrollX,e)})}},scrollLeft:function(e){if(this.length){var
n="scrollLeft"in this[0];return
e===t?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=e}:function(){this.scrollTo(e,this.scrollY)})}},position:function(){if(this.length){var
t=this[0],e=this.offsetParent(),i=this.offset(),r=d.test(e[0].nodeName)?{top:0,left:0}:e.offset();return
i.top-=parseFloat(n(t).css("margin-top"))||0,i.left-=parseFloat(n(t).css("margin-left"))||0,r.top+=parseFloat(n(e[0]).css("border-top-width"))||0,r.left+=parseFloat(n(e[0]).css("border-left-width"))||0,{top:i.top-r.top,left:i.left-r.left}}},offsetParent:function(){return
this.map(function(){for(var
t=this.offsetParent||a.body;t&&!d.test(t.nodeName)&&"static"==n(t).css("position");)t=t.offsetParent;return
t})}},n.fn.detach=n.fn.remove,["width","height"].forEach(function(e){var
i=e.replace(/./,function(t){return
t[0].toUpperCase()});n.fn[e]=function(r){var o,s=this[0];return
r===t?$(s)?s["inner"+i]:_(s)?s.documentElement["scroll"+i]:(o=this.offset())&&o[e]:this.each(function(t){s=n(this),s.css(e,J(this,r,t,s[e]()))})}}),v.forEach(function(t,e){var
i=e%2;n.fn[t]=function(){var t,o,r=n.map(arguments,function(e){return
t=L(e),"object"==t||"array"==t||null==e?e:S.fragment(e)}),s=this.length>1;return
r.length<1?this:this.each(function(t,a){o=i?a:a.parentNode,a=0==e?a.nextSibling:1==e?a.firstChild:2==e?a:null,r.forEach(function(t){if(s)t=t.cloneNode(!0);else
if(!o)return
n(t).remove();G(o.insertBefore(t,a),function(t){null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})},n.fn[i?t+"To":"insert"+(e?"Before":"After")]=function(e){return
n(e)[t](this),this}}),S.Z.prototype=n.fn,S.uniq=N,S.deserializeValue=Y,n.zepto=S,n}();window.Zepto=Zepto,void
0===window.$&&(window.$=Zepto),function(t){function l(t){return
t._zid||(t._zid=e++)}function h(t,e,n,i){if(e=p(e),e.ns)var
r=d(e.ns);return(s[l(t)]||[]).filter(function(t){return!(!t||e.e&&t.e!=e.e||e.ns&&!r.test(t.ns)||n&&l(t.fn)!==l(n)||i&&t.sel!=i)})}function
p(t){var
e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join("
")}}function d(t){return new RegExp("(?:^|
)"+t.replace(" "," .* ?")+"(?:
|$)")}function m(t,e){return t.del&&!u&&t.e in
f||!!e}function g(t){return c[t]||u&&f[t]||t}function
v(e,i,r,o,a,u,f){var
h=l(e),d=s[h]||(s[h]=[]);i.split(/\s/).forEach(function(i){if("ready"==i)return
t(document).ready(r);var s=p(i);s.fn=r,s.sel=a,s.e in
c&&(r=function(e){var
n=e.relatedTarget;return!n||n!==this&&!t.contains(this,n)?s.fn.apply(this,arguments):void
0}),s.del=u;var
l=u||r;s.proxy=function(t){if(t=j(t),!t.isImmediatePropagationStopped()){t.data=o;var
i=l.apply(e,t._args==n?[t]:[t].concat(t._args));return
i===!1&&(t.preventDefault(),t.stopPropagation()),i}},s.i=d.length,d.push(s),"addEventListener"in
e&&e.addEventListener(g(s.e),s.proxy,m(s,f))})}function
y(t,e,n,i,r){var
o=l(t);(e||"").split(/\s/).forEach(function(e){h(t,e,n,i).forEach(function(e){delete
s[o][e.i],"removeEventListener"in
t&&t.removeEventListener(g(e.e),e.proxy,m(e,r))})})}function
j(e,i){return(i||!e.isDefaultPrevented)&&(i||(i=e),t.each(E,function(t,n){var
r=i[t];e[t]=function(){return
this[n]=x,r&&r.apply(i,arguments)},e[n]=b}),(i.defaultPrevented!==n?i.defaultPrevented:"returnValue"in
i?i.returnValue===!1:i.getPreventDefault&&i.getPreventDefault())&&(e.isDefaultPrevented=x)),e}function
T(t){var e,i={originalEvent:t};for(e in
t)w.test(e)||t[e]===n||(i[e]=t[e]);return j(i,t)}var
n,e=1,i=Array.prototype.slice,r=t.isFunction,o=function(t){return"string"==typeof
t},s={},a={},u="onfocusin"in
window,f={focus:"focusin",blur:"focusout"},c={mouseenter:"mouseover",mouseleave:"mouseout"};a.click=a.mousedown=a.mouseup=a.mousemove="MouseEvents",t.event={add:v,remove:y},t.proxy=function(e,n){if(r(e)){var
i=function(){return e.apply(n,arguments)};return
i._zid=l(e),i}if(o(n))return t.proxy(e[n],e);throw new
TypeError("expected function")},t.fn.bind=function(t,e,n){return
this.on(t,e,n)},t.fn.unbind=function(t,e){return
this.off(t,e)},t.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var
x=function(){return!0},b=function(){return!1},w=/^([A-Z]|returnValue$|layer[XY]$)/,E={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};t.fn.delegate=function(t,e,n){return
this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return
this.off(e,t,n)},t.fn.live=function(e,n){return
t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return
t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,s,a,u,f){var
c,l,h=this;return
e&&!o(e)?(t.each(e,function(t,e){h.on(t,s,a,e,f)}),h):(o(s)||r(u)||u===!1||(u=a,a=s,s=n),(r(a)||a===!1)&&(u=a,a=n),u===!1&&(u=b),h.each(function(n,r){f&&(c=function(t){return
y(r,t.type,u),u.apply(this,arguments)}),s&&(l=function(e){var
n,o=t(e.target).closest(s,r).get(0);return
o&&o!==r?(n=t.extend(T(e),{currentTarget:o,liveFired:r}),(c||u).apply(o,[n].concat(i.call(arguments,1)))):void
0}),v(r,e,u,a,s,l||c)}))},t.fn.off=function(e,i,s){var a=this;return
e&&!o(e)?(t.each(e,function(t,e){a.off(t,i,e)}),a):(o(i)||r(s)||s===!1||(s=i,i=n),s===!1&&(s=b),a.each(function(){y(this,e,s,i)}))},t.fn.trigger=function(e,n){return
e=o(e)||t.isPlainObject(e)?t.Event(e):j(e),e._args=n,this.each(function(){"dispatchEvent"in
this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,n){var
i,r;return
this.each(function(s,a){i=T(o(e)?t.Event(e):e),i._args=n,i.target=a,t.each(h(a,e.type||e),function(t,e){return
r=e.proxy(i),i.isImmediatePropagationStopped()?!1:void
0})}),r},"focusin focusout load resize scroll unload click dblclick
mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change
select keydown keypress keyup error".split("
").forEach(function(e){t.fn[e]=function(t){return
t?this.bind(e,t):this.trigger(e)}}),["focus","blur"].forEach(function(e){t.fn[e]=function(t){return
t?this.bind(e,t):this.each(function(){try{this[e]()}catch(t){}}),this}}),t.Event=function(t,e){o(t)||(e=t,t=e.type);var
n=document.createEvent(a[t]||"Events"),i=!0;if(e)for(var r in
e)"bubbles"==r?i=!!e[r]:n[r]=e[r];return
n.initEvent(t,i,!0),j(n)}}(Zepto),function(t){function l(e,n,i){var
r=t.Event(n);return t(e).trigger(r,i),!r.isDefaultPrevented()}function
h(t,e,i,r){return t.global?l(e||n,i,r):void 0}function
p(e){e.global&&0===t.active++&&h(e,null,"ajaxStart")}function
d(e){e.global&&!--t.active&&h(e,null,"ajaxStop")}function
m(t,e){var n=e.context;return
e.beforeSend.call(n,t,e)===!1||h(e,n,"ajaxBeforeSend",[t,e])===!1?!1:void
h(e,n,"ajaxSend",[t,e])}function g(t,e,n,i){var
r=n.context,o="success";n.success.call(r,t,o,e),i&&i.resolveWith(r,[t,o,e]),h(n,r,"ajaxSuccess",[e,n,t]),y(o,e,n)}function
v(t,e,n,i,r){var
o=i.context;i.error.call(o,n,e,t),r&&r.rejectWith(o,[n,e,t]),h(i,o,"ajaxError",[n,i,t||e]),y(e,n,i)}function
y(t,e,n){var
i=n.context;n.complete.call(i,e,t),h(n,i,"ajaxComplete",[e,n]),d(n)}function
x(){}function b(t){return
t&&(t=t.split(";",2)[0]),t&&(t==f?"html":t==u?"json":s.test(t)?"script":a.test(t)&&"xml")||"text"}function
w(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function
E(e){e.processData&&e.data&&"string"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&"GET"!=e.type.toUpperCase()||(e.url=w(e.url,e.data),e.data=void
0)}function j(e,n,i,r){return t.isFunction(n)&&(r=i,i=n,n=void
0),t.isFunction(i)||(r=i,i=void
0),{url:e,data:n,success:i,dataType:r}}function S(e,n,i,r){var
o,s=t.isArray(n),a=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),r&&(n=i?r:r+"["+(a||"object"==o||"array"==o?n:"")+"]"),!r&&s?e.add(u.name,u.value):"array"==o||!i&&"object"==o?S(e,u,i,n):e.add(n,u)})}var
i,r,e=0,n=window.document,o=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,s=/^(?:text|application)\/javascript/i,a=/^(?:text|application)\/xml/i,u="application/json",f="text/html",c=/^\s*$/;t.active=0,t.ajaxJSONP=function(i,r){if(!("type"in
i))return t.ajax(i);var
f,h,o=i.jsonpCallback,s=(t.isFunction(o)?o():o)||"jsonp"+
++e,a=n.createElement("script"),u=window[s],c=function(e){t(a).triggerHandler("error",e||"abort")},l={abort:c};return
r&&r.promise(l),t(a).on("load
error",function(e,n){clearTimeout(h),t(a).off().remove(),"error"!=e.type&&f?g(f[0],l,i,r):v(null,n||"error",l,i,r),window[s]=u,f&&t.isFunction(u)&&u(f[0]),u=f=void
0}),m(l,i)===!1?(c("abort"),l):(window[s]=function(){f=arguments},a.src=i.url.replace(/\?(.+)=\?/,"?$1="+s),n.head.appendChild(a),i.timeout>0&&(h=setTimeout(function(){c("timeout")},i.timeout)),l)},t.ajaxSettings={type:"GET",beforeSend:x,success:x,error:x,complete:x,context:null,global:!0,xhr:function(){return
new window.XMLHttpRequest},accepts:{script:"text/javascript,
application/javascript,
application/x-javascript",json:u,xml:"application/xml,
text/xml",html:f,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0},t.ajax=function(e){var
n=t.extend({},e||{}),o=t.Deferred&&t.Deferred();for(i in
t.ajaxSettings)void
0===n[i]&&(n[i]=t.ajaxSettings[i]);p(n),n.crossDomain||(n.crossDomain=/^([\w-]+:)?\/\/([^\/]+)/.test(n.url)&&RegExp.$2!=window.location.host),n.url||(n.url=window.location.toString()),E(n),n.cache===!1&&(n.url=w(n.url,"_="+Date.now()));var
s=n.dataType,a=/\?.+=\?/.test(n.url);if("jsonp"==s||a)return
a||(n.url=w(n.url,n.jsonp?n.jsonp+"=?":n.jsonp===!1?"":"callback=?")),t.ajaxJSONP(n,o);var
j,u=n.accepts[s],f={},l=function(t,e){f[t.toLowerCase()]=[t,e]},h=/^([\w-]+:)\/\//.test(n.url)?RegExp.$1:window.location.protocol,d=n.xhr(),y=d.setRequestHeader;if(o&&o.promise(d),n.crossDomain||l("X-Requested-With","XMLHttpRequest"),l("Accept",u||"*/*"),(u=n.mimeType||u)&&(u.indexOf(",")>-1&&(u=u.split(",",2)[0]),d.overrideMimeType&&d.overrideMimeType(u)),(n.contentType||n.contentType!==!1&&n.data&&"GET"!=n.type.toUpperCase())&&l("Content-Type",n.contentType||"application/x-www-form-urlencoded"),n.headers)for(r
in
n.headers)l(r,n.headers[r]);if(d.setRequestHeader=l,d.onreadystatechange=function(){if(4==d.readyState){d.onreadystatechange=x,clearTimeout(j);var
e,i=!1;if(d.status>=200&&d.status<300||304==d.status||0==d.status&&"file:"==h){s=s||b(n.mimeType||d.getResponseHeader("content-type")),e=d.responseText;try{"script"==s?(1,eval)(e):"xml"==s?e=d.responseXML:"json"==s&&(e=c.test(e)?null:t.parseJSON(e))}catch(r){i=r}i?v(i,"parsererror",d,n,o):g(e,d,n,o)}else
v(d.statusText||null,d.status?"error":"abort",d,n,o)}},m(d,n)===!1)return
d.abort(),v(null,"abort",d,n,o),d;if(n.xhrFields)for(r in
n.xhrFields)d[r]=n.xhrFields[r];var T="async"in
n?n.async:!0;d.open(n.type,n.url,T,n.username,n.password);for(r in
f)y.apply(d,f[r]);return
n.timeout>0&&(j=setTimeout(function(){d.onreadystatechange=x,d.abort(),v(null,"timeout",d,n,o)},n.timeout)),d.send(n.data?n.data:null),d},t.get=function(){return
t.ajax(j.apply(null,arguments))},t.post=function(){var
e=j.apply(null,arguments);return
e.type="POST",t.ajax(e)},t.getJSON=function(){var
e=j.apply(null,arguments);return
e.dataType="json",t.ajax(e)},t.fn.load=function(e,n,i){if(!this.length)return
this;var a,r=this,s=e.split(/\s/),u=j(e,n,i),f=u.success;return
s.length>1&&(u.url=s[0],a=s[1]),u.success=function(e){r.html(a?t("<div>").html(e.replace(o,"")).find(a):e),f&&f.apply(r,arguments)},t.ajax(u),this};var
T=encodeURIComponent;t.param=function(t,e){var n=[];return
n.add=function(t,e){this.push(T(t)+"="+T(e))},S(n,t,e),n.join("&").replace(/%20/g,"+")}}(Zepto),function(t){t.fn.serializeArray=function(){var
n,e=[];return
t([].slice.call(this.get(0).elements)).each(function(){n=t(this);var
i=n.attr("type");"fieldset"!=this.nodeName.toLowerCase()&&!this.disabled&&"submit"!=i&&"reset"!=i&&"button"!=i&&("radio"!=i&&"checkbox"!=i||this.checked)&&e.push({name:n.attr("name"),value:n.val()})}),e},t.fn.serialize=function(){var
t=[];return
this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(e)this.bind("submit",e);else
if(this.length){var
n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return
this}}(Zepto),function(t){"__proto__"in{}||t.extend(t.zepto,{Z:function(e,n){return
e=e||[],t.extend(e,t.fn),e.selector=n||"",e.__Z=!0,e},isZ:function(e){return"array"===t.type(e)&&"__Z"in
e}});try{getComputedStyle(void 0)}catch(e){var
n=getComputedStyle;window.getComputedStyle=function(t){try{return
n(t)}catch(e){return null}}}}(Zepto);
PK(d�[�-_Bvendor/filp/whoops/src/Whoops/Resources/views/env_details.html.phpnu�[���<?php
/* List data-table values, i.e: $_SERVER, $_GET, .... */ ?>
<div class="details">
<h2 class="details-heading">Environment &
details:</h2>
<div class="data-table-container"
id="data-tables">
<?php foreach ($tables as $label => $data): ?>
<div class="data-table" id="sg-<?php echo
$tpl->escape($tpl->slug($label)) ?>">
<?php if (!empty($data)): ?>
<label><?php echo $tpl->escape($label)
?></label>
<table class="data-table">
<thead>
<tr>
<td class="data-table-k">Key</td>
<td class="data-table-v">Value</td>
</tr>
</thead>
<?php foreach ($data as $k => $value): ?>
<tr>
<td><?php echo $tpl->escape($k)
?></td>
<td><?php echo $tpl->dump($value)
?></td>
</tr>
<?php endforeach ?>
</table>
<?php else: ?>
<label class="empty"><?php echo
$tpl->escape($label) ?></label>
<span class="empty">empty</span>
<?php endif ?>
</div>
<?php endforeach ?>
</div>
<?php /* List registered handlers, in order of first to last
registered */ ?>
<div class="data-table-container"
id="handlers">
<label>Registered Handlers</label>
<?php foreach ($handlers as $i => $h): ?>
<div class="handler <?php echo ($h === $handler) ?
'active' : ''?>">
<?php echo $i ?>. <?php echo
$tpl->escape(get_class($h)) ?>
</div>
<?php endforeach ?>
</div>
</div>
PK(d�[
��W��Gvendor/filp/whoops/src/Whoops/Resources/views/frames_container.html.phpnu�[���<div
class="frames-container <?php echo $active_frames_tab ==
'application' ? 'frames-container-application' :
'' ?>">
<?php $tpl->render($frame_list) ?>
</div>PK(d�[�����Ivendor/filp/whoops/src/Whoops/Resources/views/frames_description.html.phpnu�[���<div
class="frames-description <?php echo $has_frames_tabs ?
'frames-description-application' : '' ?>">
<?php if ($has_frames_tabs): ?>
<a href="#" id="application-frames-tab"
class="frames-tab <?php echo $active_frames_tab ==
'application' ? 'frames-tab-active' : ''
?>">
Application frames (<?php echo $frames->countIsApplication()
?>)
</a>
<a href="#" id="all-frames-tab"
class="frames-tab <?php echo $active_frames_tab == 'all'
? 'frames-tab-active' : '' ?>">
All frames (<?php echo count($frames) ?>)
</a>
<?php else: ?>
<span>
Stack frames (<?php echo count($frames) ?>)
</span>
<?php endif; ?>
</div>
PK(d�[В:�
�
Avendor/filp/whoops/src/Whoops/Resources/views/frame_code.html.phpnu�[���<?php
/* Display a code block for all frames in the stack.
* @todo: This should PROBABLY be done on-demand, lest
* we get 200 frames to process. */ ?>
<div class="frame-code-container <?php echo (!$has_frames ?
'empty' : '') ?>">
<?php foreach ($frames as $i => $frame): ?>
<?php $line = $frame->getLine(); ?>
<div class="frame-code <?php echo ($i == 0 ) ?
'active' : '' ?>" id="frame-code-<?php
echo $i ?>">
<div class="frame-file">
<?php $filePath = $frame->getFile(); ?>
<?php if ($filePath && $editorHref =
$handler->getEditorHref($filePath, (int) $line)): ?>
<a href="<?php echo $editorHref ?>"
class="editor-link"<?php echo
($handler->getEditorAjax($filePath, (int) $line) ? '
data-ajax' : '') ?>>
Open:
<strong><?php echo
$tpl->breakOnDelimiter('/', $tpl->escape($filePath ?:
'<#unknown>')) ?></strong>
</a>
<?php else: ?>
<strong><?php echo
$tpl->breakOnDelimiter('/', $tpl->escape($filePath ?:
'<#unknown>')) ?></strong>
<?php endif ?>
</div>
<?php
// Do nothing if there's no line to work off
if ($line !== null):
// the $line is 1-indexed, we nab -1 where needed to account for
this
$range = $frame->getFileLines($line - 20, 40);
// getFileLines can return null if there is no source code
if ($range):
$range = array_map(function ($line) { return empty($line) ?
' ' : $line;}, $range);
$start = key($range) + 1;
$code = join("\n", $range);
?>
<pre id="frame-code-linenums-<?=$i?>"
class="code-block linenums:<?php echo $start
?>"><?php echo $tpl->escape($code) ?></pre>
<?php endif ?>
<?php endif ?>
<?php $frameArgs = $tpl->dumpArgs($frame); ?>
<?php if ($frameArgs): ?>
<div class="frame-file">
Arguments
</div>
<div id="frame-code-args-<?=$i?>"
class="code-block frame-args">
<?php echo $frameArgs; ?>
</div>
<?php endif ?>
<?php
// Append comments for this frame
$comments = $frame->getComments();
?>
<div class="frame-comments <?php echo empty($comments) ?
'empty' : '' ?>">
<?php foreach ($comments as $commentNo => $comment): ?>
<?php extract($comment) ?>
<div class="frame-comment"
id="comment-<?php echo $i . '-' . $commentNo
?>">
<span class="frame-comment-context"><?php
echo $tpl->escape($context) ?></span>
<?php echo $tpl->escapeButPreserveUris($comment) ?>
</div>
<?php endforeach ?>
</div>
</div>
<?php endforeach ?>
</div>
PK(d�[���Avendor/filp/whoops/src/Whoops/Resources/views/frame_list.html.phpnu�[���<?php
/* List file names & line numbers for all stack frames;
clicking these links/buttons will display the code view
for that particular frame */ ?>
<?php foreach ($frames as $i => $frame): ?>
<div class="frame <?php echo ($i == 0 ? 'active' :
'') ?> <?php echo ($frame->isApplication() ?
'frame-application' : '') ?>"
id="frame-line-<?php echo $i ?>">
<span class="frame-index"><?php echo
(count($frames) - $i - 1) ?></span>
<div class="frame-method-info">
<span class="frame-class"><?php echo
$tpl->breakOnDelimiter('\\',
$tpl->escape($frame->getClass() ?: '')) ?></span>
<span class="frame-function"><?php echo
$tpl->breakOnDelimiter('\\',
$tpl->escape($frame->getFunction() ?: ''))
?></span>
</div>
<div class="frame-file">
<?php echo $frame->getFile() ?
$tpl->breakOnDelimiter('/',
$tpl->shorten($tpl->escape($frame->getFile()))) :
'<#unknown>' ?><!--
--><span class="frame-line"><?php echo (int)
$frame->getLine() ?></span>
</div>
</div>
<?php endforeach;
PK(d�[kg%�$�$=vendor/filp/whoops/src/Whoops/Resources/views/header.html.phpnu�[���<div
class="exception">
<div class="exc-title">
<?php foreach ($name as $i => $nameSection): ?>
<?php if ($i == count($name) - 1): ?>
<span class="exc-title-primary"><?php echo
$tpl->escape($nameSection) ?></span>
<?php else: ?>
<?php echo $tpl->escape($nameSection) . ' \\' ?>
<?php endif ?>
<?php endforeach ?>
<?php if ($code): ?>
<span title="Exception Code">(<?php echo
$tpl->escape($code) ?>)</span>
<?php endif ?>
</div>
<div class="exc-message">
<?php if (!empty($message)): ?>
<span><?php echo $tpl->escape($message)
?></span>
<?php if (count($previousMessages)): ?>
<div class="exc-title prev-exc-title">
<span class="exc-title-secondary">Previous
exceptions</span>
</div>
<ul>
<?php foreach ($previousMessages as $i =>
$previousMessage): ?>
<li>
<?php echo $tpl->escape($previousMessage) ?>
<span class="prev-exc-code">(<?php echo
$previousCodes[$i] ?>)</span>
</li>
<?php endforeach; ?>
</ul>
<?php endif ?>
<?php else: ?>
<span class="exc-message-empty-notice">No
message</span>
<?php endif ?>
<ul class="search-for-help">
<?php if (!empty($docref_url)): ?>
<li>
<a rel="noopener noreferrer" target="_blank"
href="<?php echo $docref_url; ?>" title="Search for
help in the PHP manual.">
<!-- PHP icon by Icons Solid -->
<!-- https://www.iconfinder.com/icons/322421/book_icon -->
<!-- Free for commercial use -->
<svg height="16px" id="Layer_1"
style="enable-background:new 0 0 32 32;" version="1.1"
viewBox="0 0 32 32" width="16px"
xml:space="preserve" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"><g
transform="translate(240 0)"><path
d="M-211,4v26h-24c-1.104,0-2-0.895-2-2s0.896-2,2-2h22V0h-22c-2.209,0-4,1.791-4,4v24c0,2.209,1.791,4,4,4h26V4H-211z
M-235,8V2h20v22h-20V8z M-219,6h-12V4h12V6z M-223,10h-8V8h8V10z
M-227,14h-4v-2h4V14z"/></g></svg>
</a>
</li>
<?php endif ?>
<li>
<a rel="noopener noreferrer" target="_blank"
href="https://google.com/search?q=<?php echo
urlencode(implode('\\', $name).' '.$message)
?>" title="Search for help on Google.">
<!-- Google icon by Alfredo H, from
https://www.iconfinder.com/alfredoh -->
<!-- Creative Commons (Attribution 3.0 Unported) -->
<!-- http://creativecommons.org/licenses/by/3.0/ -->
<svg class="google" height="16"
viewBox="0 0 512 512" width="16"
xmlns="http://www.w3.org/2000/svg">
<path d="M457.732 216.625c2.628 14.04 4.063 28.743
4.063 44.098C461.795 380.688 381.48 466 260.205 466c-116.024
0-210-93.977-210-210s93.976-210 210-210c56.703 0 104.076 20.867 140.44
54.73l-59.205 59.197v-.135c-22.046-21.002-50-31.762-81.236-31.762-69.297
0-125.604 58.537-125.604 127.84 0 69.29 56.306 127.97 125.604 127.97 62.87
0 105.653-35.966 114.46-85.313h-114.46v-81.902h197.528z"/>
</svg>
</a>
</li>
<li>
<a rel="noopener noreferrer" target="_blank"
href="https://duckduckgo.com/?q=<?php echo
urlencode(implode('\\', $name).' '.$message)
?>" title="Search for help on DuckDuckGo.">
<!-- DuckDuckGo icon by IconBaandar Team, from
https://www.iconfinder.com/iconbaandar -->
<!-- Creative Commons (Attribution 3.0 Unported) -->
<!-- http://creativecommons.org/licenses/by/3.0/ -->
<svg class="duckduckgo" height="16"
viewBox="150 150 1675 1675" width="16"
xmlns="http://www.w3.org/2000/svg">
<path d="M1792 1024c0 204.364-80.472 398.56-224.955
543.04-144.483 144.48-338.68 224.95-543.044 224.95-204.36
0-398.56-80.47-543.04-224.95-144.48-144.482-224.95-338.676-224.95-543.04
0-204.365 80.47-398.562 224.96-543.045C625.44 336.47 819.64 256 1024
256c204.367 0 398.565 80.47 543.05 224.954C1711.532 625.437 1792 819.634
1792 1024zm-270.206 497.787C1654.256 1389.327 1728 1211.36 1728
1024c0-187.363-73.74-365.332-206.203-497.796C1389.332 393.74 1211.363 320
1024 320s-365.33 73.742-497.795 206.205C393.742 658.67 320 836.637 320
1024c0 187.36 73.744 365.326 206.206 497.787C658.67 1654.25 836.638 1727.99
1024 1727.99c187.362 0 365.33-73.74 497.794-206.203z"/>
<path d="M1438.64
1177.41c0-.03-.005-.017-.01.004l.01-.004z"/>
<path d="M1499.8
976.878c.03-.156-.024-.048-.11.107l.11-.107z"/>
<path d="M1105.19
991.642zm-68.013-376.128c-8.087-10.14-18.028-19.965-29.89-29.408-13.29-10.582-29-20.76-47.223-30.443-35.07-18.624-74.482-31.61-115.265-38.046-39.78-6.28-80.84-6.256-120.39.917l1.37
31.562c1.8.164 7.7 3.9 14.36 8.32-20.68 5.94-39.77 14.447-39.48 39.683l.2
17.48 17.3-1.73c29.38-2.95 60.17-2.06 90.32 2.61 9.21 1.42 18.36 3.2 27.38
5.32l-4.33 1.15c-20.45 5.58-38.93 12.52-54.25 20.61-46.28 24.32-75.51
60.85-90.14 108.37-14.14 45.95-14.27 101.81-2.72 166.51l.06.06c15.14 84.57
64.16 316.39 104.11 505.39 19.78 93.59 37.38 176.83 47.14 224.4 3.26 15.84
5.03 31.02 5.52 45.52.3 9.08.09 17.96-.58 26.62-.45 5.8-1.11 11.51-1.96
17.112l31.62 4.75c.71-4.705 1.3-9.494 1.76-14.373 48.964 10.517 99.78 16.05
151.88 16.05 60.68 0 119.61-7.505 175.91-21.64 3.04 6.08 6.08 12.19 9.11
18.32l28.62-14.128c-2.11-4.27-4.235-8.55-6.37-12.84-23.005-46.124-47.498-93.01-68.67-133.534-15.39-29.466-29.01-55.53-39.046-75.58-26.826-53.618-53.637-119.47-68.28-182.368-8.78-37.705-13.128-74.098-10.308-105.627-15.31-6.28-26.69-11.8-31.968-15.59l-.01.015c-14.22-10.2-31.11-28.12-41.82-49.717-8.618-17.376-13.4-37.246-10.147-57.84
3.17-19.84 27.334-46.714 57.843-67.46v-.063c26.554-18.05 58.75-32.506
86.32-34.31 7.835-.51 16.31-1.008 23.99-1.45 33.45-1.95 50.243-2.93
84.475-11.42 10.88-2.697 26.19-6.56 43.53-11.09
2.364-40.7-5.947-87.596-21.04-133.234-22.004-66.53-58.68-131.25-97.627-170.21-12.543-12.55-28.17-22.79-45.9-30.933-16.88-7.753-35.64-13.615-55.436-17.782zm-10.658
178.553s6.77-42.485 58.39-33.977c27.96 4.654 37.89 29.833 37.89
29.833s-25.31-14.46-44.95-14.198c-40.33.53-51.35 18.342-51.35
18.342zm-240.45-18.802c48.49-19.853 72.11 11.298 72.11
11.298s-35.21-15.928-69.46 5.59c-34.19 21.477-32.92 43.452-32.92
43.452s-18.17-40.5 30.26-60.34zm296.5 95.4c0-6.677 2.68-12.694 7.01-17.02
4.37-4.37 10.42-7.074 17.1-7.074 6.73 0 12.79 2.7 17.15 7.05 4.33 4.33 7.01
10.36 7.01 17.05 0 6.74-2.7 12.81-7.07 17.18-4.33 4.33-10.37 7.01-17.1
7.01-6.68 0-12.72-2.69-17.05-7.03-4.36-4.37-7.07-10.43-7.07-17.16zm-268.42
51.27c0-8.535 3.41-16.22 8.93-21.738 5.55-5.55 13.25-8.982 21.81-8.982 8.51
0 16.18 3.415 21.7 8.934 5.55 5.55 8.98 13.25 8.98 21.78 0 8.53-3.44
16.23-8.98 21.79-5.52 5.52-13.19 8.93-21.71 8.93-8.55
0-16.26-3.43-21.82-8.99-5.52-5.52-8.93-13.2-8.93-21.74z"/>
<path d="M1102.48
986.34zm390.074-64.347c-28.917-11.34-74.89-12.68-93.32-3.778-11.5
5.567-35.743 13.483-63.565 21.707-25.75 7.606-53.9 15.296-78.15
21.702-17.69 4.67-33.3 8.66-44.4 11.435-34.92 8.76-52.05 9.77-86.17
11.78-7.84.46-16.48.97-24.48 1.5-28.12 1.86-60.97 16.77-88.05
35.4v.06c-31.12 21.4-55.77 49.12-59.01 69.59-3.32 21.24 1.56 41.74 10.35
59.67 10.92 22.28 28.15 40.77 42.66 51.29l.01-.02c5.38 3.9 16.98 9.6 32.6
16.08 26.03 10.79 63.2 23.76 101.25 34.23 43.6 11.99 89.11 21.05 121.69
20.41 34.26-.69 77.73-10.52 114.54-24.67 22.15-8.52 42.21-18.71 56.88-29.58
17.85-13.22 28.7-28.42
28.4-44.74-.07-3.89-.72-7.63-1.97-11.21l-.02.01c-11.6-33.06-50.37-23.59-105.53-10.12-46.86
11.445-107.94 26.365-169.01
20.434-32.56-3.167-54.45-10.61-67.88-20.133-5.96-4.224-9.93-8.67-12.18-13.11-1.96-3.865-2.68-7.84-2.33-11.714.39-4.42
2.17-9.048 5.1-13.57l-.05-.03c7.86-12.118 23.082-9.72 43.93-6.43 25.91 4.08
58.2 9.172 99.013-3.61 39.63-12.378 87.76-29.9 131.184-47.39 42.405-17.08
80.08-34.078 100.74-46.18 25.46-14.87 37.57-29.428 40.59-42.866
2.725-12.152-.89-22.48-8.903-31.07-5.87-6.29-14.254-11.31-23.956-15.115z"/>
</svg>
</a>
</li>
<li>
<a rel="noopener noreferrer" target="_blank"
href="https://stackoverflow.com/search?q=<?php echo
urlencode(implode('\\', $name).' '.$message)
?>" title="Search for help on Stack Overflow.">
<!-- Stack Overflow icon by Picons.me, from
https://www.iconfinder.com/Picons -->
<!-- Free for commercial use -->
<svg class="stackoverflow" height="16"
viewBox="-1163 1657.697 56.693 56.693" width="16"
xmlns="http://www.w3.org/2000/svg">
<path d="M-1126.04 1689.533l-16.577-9.778 2.088-3.54
16.578 9.778zM-1127.386 1694.635l-18.586-4.996 1.068-3.97 18.586
4.995zM-1127.824 1700.137l-19.165-1.767.378-4.093 19.165 1.767zM-1147.263
1701.293h19.247v4.11h-19.247z"/>
<path d="M-1121.458 1710.947s0
.96-.032.96v.016h-30.796s-.96
0-.96-.016h-.032v-20.03h3.288v16.805h25.244v-16.804h3.288v19.07zM-1130.667
1667.04l10.844 15.903-3.396 2.316-10.843-15.903zM-1118.313 1663.044l3.29
18.963-4.05.703-3.29-18.963z"/>
</svg>
</a>
</li>
</ul>
<span id="plain-exception"><?php echo
$tpl->escape($plain_exception) ?></span>
<button id="copy-button" class="rightButton
clipboard" data-clipboard-text="<?php echo
$tpl->escape($plain_exception) ?>" title="Copy exception
details to clipboard">
COPY
</button>
<button id="hide-error" class="rightButton"
title="Hide error message"
onclick="document.getElementsByClassName('Whoops')[0].style.display
= 'none';">
HIDE
</button>
</div>
</div>
PK)d�[�.|w44Cvendor/filp/whoops/src/Whoops/Resources/views/header_outer.html.phpnu�[���<header>
<?php $tpl->render($header) ?>
</header>
PK)d�[b�>77=vendor/filp/whoops/src/Whoops/Resources/views/layout.html.phpnu�[���<?php
/**
* Layout template file for Whoops's pretty error output.
*/
?>
<!DOCTYPE html><?php echo $preface; ?>
<html>
<head>
<meta charset="utf-8">
<meta name="robots"
content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width,
initial-scale=1, shrink-to-fit=no"/>
<title><?php echo $tpl->escape($page_title)
?></title>
<style><?php echo $stylesheet ?></style>
</head>
<body>
<div class="Whoops container">
<div class="stack-container">
<?php $tpl->render($panel_left_outer) ?>
<?php $tpl->render($panel_details_outer) ?>
</div>
</div>
<script><?php echo $prettify ?></script>
<script><?php echo $zepto ?></script>
<script><?php echo $clipboard ?></script>
<script><?php echo $javascript ?></script>
</body>
</html>
PK)d�[�\FFDvendor/filp/whoops/src/Whoops/Resources/views/panel_details.html.phpnu�[���<?php
$tpl->render($frame_code) ?>
<?php $tpl->render($env_details)
?>PK)d�[G�w"WWJvendor/filp/whoops/src/Whoops/Resources/views/panel_details_outer.html.phpnu�[���<div
class="panel details-container cf">
<?php $tpl->render($panel_details) ?>
</div>PK)d�[�"hhAvendor/filp/whoops/src/Whoops/Resources/views/panel_left.html.phpnu�[���<?php
$tpl->render($header_outer);
$tpl->render($frames_description);
$tpl->render($frames_container);
PK)d�[Y��yyGvendor/filp/whoops/src/Whoops/Resources/views/panel_left_outer.html.phpnu�[���<div
class="panel left-panel cf <?php echo (!$has_frames ?
'empty' : '') ?>">
<?php $tpl->render($panel_left) ?>
</div>PK)d�[D&�66%vendor/filp/whoops/src/Whoops/Run.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops;
use InvalidArgumentException;
use Whoops\Exception\ErrorException;
use Whoops\Exception\Inspector;
use Whoops\Handler\CallbackHandler;
use Whoops\Handler\Handler;
use Whoops\Handler\HandlerInterface;
use Whoops\Util\Misc;
use Whoops\Util\SystemFacade;
final class Run implements RunInterface
{
private $isRegistered;
private $allowQuit = true;
private $sendOutput = true;
/**
* @var integer|false
*/
private $sendHttpCode = 500;
/**
* @var HandlerInterface[]
*/
private $handlerQueue = [];
private $silencedPatterns = [];
private $system;
public function __construct(SystemFacade $system = null)
{
$this->system = $system ?: new SystemFacade;
}
/**
* Prepends a handler to the start of the queue
*
* @throws InvalidArgumentException If argument is not callable or
instance of HandlerInterface
* @param Callable|HandlerInterface $handler
* @return Run
* @deprecated use appendHandler and prependHandler instead
*/
public function pushHandler($handler)
{
return $this->prependHandler($handler);
}
/**
* Appends a handler to the end of the queue
*
* @throws InvalidArgumentException If argument is not callable or
instance of HandlerInterface
* @param Callable|HandlerInterface $handler
* @return Run
*/
public function appendHandler($handler)
{
array_push($this->handlerQueue,
$this->resolveHandler($handler));
return $this;
}
/**
* Prepends a handler to the start of the queue
*
* @throws InvalidArgumentException If argument is not callable or
instance of HandlerInterface
* @param Callable|HandlerInterface $handler
* @return Run
*/
public function prependHandler($handler)
{
array_unshift($this->handlerQueue,
$this->resolveHandler($handler));
return $this;
}
/**
* Create a CallbackHandler from callable and throw if handler is
invalid
*
* @throws InvalidArgumentException If argument is not callable or
instance of HandlerInterface
* @param Callable|HandlerInterface $handler
* @return HandlerInterface
*/
private function resolveHandler($handler)
{
if (is_callable($handler)) {
$handler = new CallbackHandler($handler);
}
if (!$handler instanceof HandlerInterface) {
throw new InvalidArgumentException(
"Argument to " . __METHOD__ . " must be a
callable, or instance of "
. "Whoops\\Handler\\HandlerInterface"
);
}
return $handler;
}
/**
* Removes the last handler in the queue and returns it.
* Returns null if there"s nothing else to pop.
* @return null|HandlerInterface
*/
public function popHandler()
{
return array_pop($this->handlerQueue);
}
/**
* Removes the first handler in the queue and returns it.
* Returns null if there"s nothing else to shift.
* @return null|HandlerInterface
*/
public function shiftHandler()
{
return array_shift($this->handlerQueue);
}
/**
* Returns an array with all handlers, in the
* order they were added to the queue.
* @return array
*/
public function getHandlers()
{
return $this->handlerQueue;
}
/**
* Clears all handlers in the handlerQueue, including
* the default PrettyPage handler.
* @return Run
*/
public function clearHandlers()
{
$this->handlerQueue = [];
return $this;
}
/**
* @param \Throwable $exception
* @return Inspector
*/
private function getInspector($exception)
{
return new Inspector($exception);
}
/**
* Registers this instance as an error handler.
* @return Run
*/
public function register()
{
if (!$this->isRegistered) {
// Workaround PHP bug 42098
// https://bugs.php.net/bug.php?id=42098
class_exists("\\Whoops\\Exception\\ErrorException");
class_exists("\\Whoops\\Exception\\FrameCollection");
class_exists("\\Whoops\\Exception\\Frame");
class_exists("\\Whoops\\Exception\\Inspector");
$this->system->setErrorHandler([$this,
self::ERROR_HANDLER]);
$this->system->setExceptionHandler([$this,
self::EXCEPTION_HANDLER]);
$this->system->registerShutdownFunction([$this,
self::SHUTDOWN_HANDLER]);
$this->isRegistered = true;
}
return $this;
}
/**
* Unregisters all handlers registered by this Whoops\Run instance
* @return Run
*/
public function unregister()
{
if ($this->isRegistered) {
$this->system->restoreExceptionHandler();
$this->system->restoreErrorHandler();
$this->isRegistered = false;
}
return $this;
}
/**
* Should Whoops allow Handlers to force the script to quit?
* @param bool|int $exit
* @return bool
*/
public function allowQuit($exit = null)
{
if (func_num_args() == 0) {
return $this->allowQuit;
}
return $this->allowQuit = (bool) $exit;
}
/**
* Silence particular errors in particular files
* @param array|string $patterns List or a single regex pattern to
match
* @param int $levels Defaults to E_STRICT | E_DEPRECATED
* @return \Whoops\Run
*/
public function silenceErrorsInPaths($patterns, $levels = 10240)
{
$this->silencedPatterns = array_merge(
$this->silencedPatterns,
array_map(
function ($pattern) use ($levels) {
return [
"pattern" => $pattern,
"levels" => $levels,
];
},
(array) $patterns
)
);
return $this;
}
/**
* Returns an array with silent errors in path configuration
*
* @return array
*/
public function getSilenceErrorsInPaths()
{
return $this->silencedPatterns;
}
/*
* Should Whoops send HTTP error code to the browser if possible?
* Whoops will by default send HTTP code 500, but you may wish to
* use 502, 503, or another 5xx family code.
*
* @param bool|int $code
* @return int|false
*/
public function sendHttpCode($code = null)
{
if (func_num_args() == 0) {
return $this->sendHttpCode;
}
if (!$code) {
return $this->sendHttpCode = false;
}
if ($code === true) {
$code = 500;
}
if ($code < 400 || 600 <= $code) {
throw new InvalidArgumentException(
"Invalid status code '$code', must be 4xx
or 5xx"
);
}
return $this->sendHttpCode = $code;
}
/**
* Should Whoops push output directly to the client?
* If this is false, output will be returned by handleException
* @param bool|int $send
* @return bool
*/
public function writeToOutput($send = null)
{
if (func_num_args() == 0) {
return $this->sendOutput;
}
return $this->sendOutput = (bool) $send;
}
/**
* Handles an exception, ultimately generating a Whoops error
* page.
*
* @param \Throwable $exception
* @return string Output generated by handlers
*/
public function handleException($exception)
{
// Walk the registered handlers in the reverse order
// they were registered, and pass off the exception
$inspector = $this->getInspector($exception);
// Capture output produced while handling the exception,
// we might want to send it straight away to the client,
// or return it silently.
$this->system->startOutputBuffering();
// Just in case there are no handlers:
$handlerResponse = null;
$handlerContentType = null;
try {
foreach ($this->handlerQueue as $handler) {
$handler->setRun($this);
$handler->setInspector($inspector);
$handler->setException($exception);
// The HandlerInterface does not require an Exception
passed to handle()
// and neither of our bundled handlers use it.
// However, 3rd party handlers may have already relied on
this parameter,
// and removing it would be possibly breaking for users.
$handlerResponse = $handler->handle($exception);
// Collect the content type for possible sending in the
headers.
$handlerContentType = method_exists($handler,
'contentType') ? $handler->contentType() : null;
if (in_array($handlerResponse, [Handler::LAST_HANDLER,
Handler::QUIT])) {
// The Handler has handled the exception in some way,
and
// wishes to quit execution (Handler::QUIT), or skip
any
// other handlers (Handler::LAST_HANDLER). If
$this->allowQuit
// is false, Handler::QUIT behaves like
Handler::LAST_HANDLER
break;
}
}
$willQuit = $handlerResponse == Handler::QUIT &&
$this->allowQuit();
} finally {
$output = $this->system->cleanOutputBuffer();
}
// If we're allowed to, send output generated by handlers
directly
// to the output, otherwise, and if the script doesn't quit,
return
// it so that it may be used by the caller
if ($this->writeToOutput()) {
// @todo Might be able to clean this up a bit better
if ($willQuit) {
// Cleanup all other output buffers before sending our
output:
while ($this->system->getOutputBufferLevel() > 0)
{
$this->system->endOutputBuffering();
}
// Send any headers if needed:
if (Misc::canSendHeaders() && $handlerContentType)
{
header("Content-Type:
{$handlerContentType}");
}
}
$this->writeToOutputNow($output);
}
if ($willQuit) {
// HHVM fix for https://github.com/facebook/hhvm/issues/4055
$this->system->flushOutputBuffer();
$this->system->stopExecution(1);
}
return $output;
}
/**
* Converts generic PHP errors to \ErrorException
* instances, before passing them off to be handled.
*
* This method MUST be compatible with set_error_handler.
*
* @param int $level
* @param string $message
* @param string $file
* @param int $line
*
* @return bool
* @throws ErrorException
*/
public function handleError($level, $message, $file = null, $line =
null)
{
if ($level & $this->system->getErrorReportingLevel()) {
foreach ($this->silencedPatterns as $entry) {
$pathMatches = (bool)
preg_match($entry["pattern"], $file);
$levelMatches = $level & $entry["levels"];
if ($pathMatches && $levelMatches) {
// Ignore the error, abort handling
// See https://github.com/filp/whoops/issues/418
return true;
}
}
// XXX we pass $level for the "code" param only for
BC reasons.
// see https://github.com/filp/whoops/issues/267
$exception = new ErrorException($message, /*code*/ $level,
/*severity*/ $level, $file, $line);
if ($this->canThrowExceptions) {
throw $exception;
} else {
$this->handleException($exception);
}
// Do not propagate errors which were already handled by
Whoops.
return true;
}
// Propagate error to the next handler, allows error_get_last() to
// work on silenced errors.
return false;
}
/**
* Special case to deal with Fatal errors and the like.
*/
public function handleShutdown()
{
// If we reached this step, we are in shutdown handler.
// An exception thrown in a shutdown handler will not be propagated
// to the exception handler. Pass that information along.
$this->canThrowExceptions = false;
$error = $this->system->getLastError();
if ($error && Misc::isLevelFatal($error['type']))
{
// If there was a fatal error,
// it was not handled in handleError yet.
$this->allowQuit = false;
$this->handleError(
$error['type'],
$error['message'],
$error['file'],
$error['line']
);
}
}
/**
* In certain scenarios, like in shutdown handler, we can not throw
exceptions
* @var bool
*/
private $canThrowExceptions = true;
/**
* Echo something to the browser
* @param string $output
* @return $this
*/
private function writeToOutputNow($output)
{
if ($this->sendHttpCode() &&
\Whoops\Util\Misc::canSendHeaders()) {
$this->system->setHttpResponseCode(
$this->sendHttpCode()
);
}
echo $output;
return $this;
}
}
PK)d�[-2�G
G
.vendor/filp/whoops/src/Whoops/RunInterface.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops;
use InvalidArgumentException;
use Whoops\Exception\ErrorException;
use Whoops\Handler\HandlerInterface;
interface RunInterface
{
const EXCEPTION_HANDLER = "handleException";
const ERROR_HANDLER = "handleError";
const SHUTDOWN_HANDLER = "handleShutdown";
/**
* Pushes a handler to the end of the stack
*
* @throws InvalidArgumentException If argument is not callable or
instance of HandlerInterface
* @param Callable|HandlerInterface $handler
* @return Run
*/
public function pushHandler($handler);
/**
* Removes the last handler in the stack and returns it.
* Returns null if there"s nothing else to pop.
*
* @return null|HandlerInterface
*/
public function popHandler();
/**
* Returns an array with all handlers, in the
* order they were added to the stack.
*
* @return array
*/
public function getHandlers();
/**
* Clears all handlers in the handlerStack, including
* the default PrettyPage handler.
*
* @return Run
*/
public function clearHandlers();
/**
* Registers this instance as an error handler.
*
* @return Run
*/
public function register();
/**
* Unregisters all handlers registered by this Whoops\Run instance
*
* @return Run
*/
public function unregister();
/**
* Should Whoops allow Handlers to force the script to quit?
*
* @param bool|int $exit
* @return bool
*/
public function allowQuit($exit = null);
/**
* Silence particular errors in particular files
*
* @param array|string $patterns List or a single regex pattern to
match
* @param int $levels Defaults to E_STRICT | E_DEPRECATED
* @return \Whoops\Run
*/
public function silenceErrorsInPaths($patterns, $levels = 10240);
/**
* Should Whoops send HTTP error code to the browser if possible?
* Whoops will by default send HTTP code 500, but you may wish to
* use 502, 503, or another 5xx family code.
*
* @param bool|int $code
* @return int|false
*/
public function sendHttpCode($code = null);
/**
* Should Whoops push output directly to the client?
* If this is false, output will be returned by handleException
*
* @param bool|int $send
* @return bool
*/
public function writeToOutput($send = null);
/**
* Handles an exception, ultimately generating a Whoops error
* page.
*
* @param \Throwable $exception
* @return string Output generated by handlers
*/
public function handleException($exception);
/**
* Converts generic PHP errors to \ErrorException
* instances, before passing them off to be handled.
*
* This method MUST be compatible with set_error_handler.
*
* @param int $level
* @param string $message
* @param string $file
* @param int $line
*
* @return bool
* @throws ErrorException
*/
public function handleError($level, $message, $file = null, $line =
null);
/**
* Special case to deal with Fatal errors and the like.
*/
public function handleShutdown();
}
PK)d�[��Z���7vendor/filp/whoops/src/Whoops/Util/HtmlDumperOutput.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Util;
/**
* Used as output callable for
Symfony\Component\VarDumper\Dumper\HtmlDumper::dump()
*
* @see TemplateHelper::dump()
*/
class HtmlDumperOutput
{
private $output;
public function __invoke($line, $depth)
{
// A negative depth means "end of dump"
if ($depth >= 0) {
// Adds a two spaces indentation to the line
$this->output .= str_repeat(' ', $depth) . $line
. "\n";
}
}
public function getOutput()
{
return $this->output;
}
public function clear()
{
$this->output = null;
}
}
PK)d�[������+vendor/filp/whoops/src/Whoops/Util/Misc.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Util;
class Misc
{
/**
* Can we at this point in time send HTTP headers?
*
* Currently this checks if we are even serving an HTTP request,
* as opposed to running from a command line.
*
* If we are serving an HTTP request, we check if it's not too
late.
*
* @return bool
*/
public static function canSendHeaders()
{
return isset($_SERVER["REQUEST_URI"]) &&
!headers_sent();
}
public static function isAjaxRequest()
{
return (
!empty($_SERVER['HTTP_X_REQUESTED_WITH'])
&&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) ==
'xmlhttprequest');
}
/**
* Check, if possible, that this execution was triggered by a command
line.
* @return bool
*/
public static function isCommandLine()
{
return PHP_SAPI == 'cli';
}
/**
* Translate ErrorException code into the represented constant.
*
* @param int $error_code
* @return string
*/
public static function translateErrorCode($error_code)
{
$constants = get_defined_constants(true);
if (array_key_exists('Core', $constants)) {
foreach ($constants['Core'] as $constant =>
$value) {
if (substr($constant, 0, 2) == 'E_' &&
$value == $error_code) {
return $constant;
}
}
}
return "E_UNKNOWN";
}
/**
* Determine if an error level is fatal (halts execution)
*
* @param int $level
* @return bool
*/
public static function isLevelFatal($level)
{
$errors = E_ERROR;
$errors |= E_PARSE;
$errors |= E_CORE_ERROR;
$errors |= E_CORE_WARNING;
$errors |= E_COMPILE_ERROR;
$errors |= E_COMPILE_WARNING;
return ($level & $errors) > 0;
}
}
PK)d�[��'� � 3vendor/filp/whoops/src/Whoops/Util/SystemFacade.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Util;
class SystemFacade
{
/**
* Turns on output buffering.
*
* @return bool
*/
public function startOutputBuffering()
{
return ob_start();
}
/**
* @param callable $handler
* @param int $types
*
* @return callable|null
*/
public function setErrorHandler(callable $handler, $types =
'use-php-defaults')
{
// Since PHP 5.4 the constant E_ALL contains all errors (even
E_STRICT)
if ($types === 'use-php-defaults') {
$types = E_ALL;
}
return set_error_handler($handler, $types);
}
/**
* @param callable $handler
*
* @return callable|null
*/
public function setExceptionHandler(callable $handler)
{
return set_exception_handler($handler);
}
/**
* @return void
*/
public function restoreExceptionHandler()
{
restore_exception_handler();
}
/**
* @return void
*/
public function restoreErrorHandler()
{
restore_error_handler();
}
/**
* @param callable $function
*
* @return void
*/
public function registerShutdownFunction(callable $function)
{
register_shutdown_function($function);
}
/**
* @return string|false
*/
public function cleanOutputBuffer()
{
return ob_get_clean();
}
/**
* @return int
*/
public function getOutputBufferLevel()
{
return ob_get_level();
}
/**
* @return bool
*/
public function endOutputBuffering()
{
return ob_end_clean();
}
/**
* @return void
*/
public function flushOutputBuffer()
{
flush();
}
/**
* @return int
*/
public function getErrorReportingLevel()
{
return error_reporting();
}
/**
* @return array|null
*/
public function getLastError()
{
return error_get_last();
}
/**
* @param int $httpCode
*
* @return int
*/
public function setHttpResponseCode($httpCode)
{
return http_response_code($httpCode);
}
/**
* @param int $exitStatus
*/
public function stopExecution($exitStatus)
{
exit($exitStatus);
}
}
PK)d�[{��S%S%5vendor/filp/whoops/src/Whoops/Util/TemplateHelper.phpnu�[���<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops\Util;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Cloner\AbstractCloner;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Whoops\Exception\Frame;
/**
* Exposes useful tools for working with/in templates
*/
class TemplateHelper
{
/**
* An array of variables to be passed to all templates
* @var array
*/
private $variables = [];
/**
* @var HtmlDumper
*/
private $htmlDumper;
/**
* @var HtmlDumperOutput
*/
private $htmlDumperOutput;
/**
* @var AbstractCloner
*/
private $cloner;
/**
* @var string
*/
private $applicationRootPath;
public function __construct()
{
// root path for ordinary composer projects
$this->applicationRootPath =
dirname(dirname(dirname(dirname(dirname(dirname(__DIR__))))));
}
/**
* Escapes a string for output in an HTML document
*
* @param string $raw
* @return string
*/
public function escape($raw)
{
$flags = ENT_QUOTES;
// HHVM has all constants defined, but only ENT_IGNORE
// works at the moment
if (defined("ENT_SUBSTITUTE") &&
!defined("HHVM_VERSION")) {
$flags |= ENT_SUBSTITUTE;
} else {
// This is for 5.3.
// The documentation warns of a potential security issue,
// but it seems it does not apply in our case, because
// we do not blacklist anything anywhere.
$flags |= ENT_IGNORE;
}
$raw = str_replace(chr(9), ' ', $raw);
return htmlspecialchars($raw, $flags, "UTF-8");
}
/**
* Escapes a string for output in an HTML document, but preserves
* URIs within it, and converts them to clickable anchor elements.
*
* @param string $raw
* @return string
*/
public function escapeButPreserveUris($raw)
{
$escaped = $this->escape($raw);
return preg_replace(
"@([A-z]+?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@",
"<a href=\"$1\" target=\"_blank\"
rel=\"noreferrer noopener\">$1</a>",
$escaped
);
}
/**
* Makes sure that the given string breaks on the delimiter.
*
* @param string $delimiter
* @param string $s
* @return string
*/
public function breakOnDelimiter($delimiter, $s)
{
$parts = explode($delimiter, $s);
foreach ($parts as &$part) {
$part = '<span class="delimiter">' .
$part . '</span>';
}
return implode($delimiter, $parts);
}
/**
* Replace the part of the path that all files have in common.
*
* @param string $path
* @return string
*/
public function shorten($path)
{
if ($this->applicationRootPath != "/") {
$path = str_replace($this->applicationRootPath,
'…', $path);
}
return $path;
}
private function getDumper()
{
if (!$this->htmlDumper &&
class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) {
$this->htmlDumperOutput = new HtmlDumperOutput();
// re-use the same var-dumper instance, so it won't
re-render the global styles/scripts on each dump.
$this->htmlDumper = new
HtmlDumper($this->htmlDumperOutput);
$styles = [
'default' => 'color:#FFFFFF;
line-height:normal; font:12px "Inconsolata", "Fira
Mono", "Source Code Pro", Monaco, Consolas, "Lucida
Console", monospace !important; word-wrap: break-word; white-space:
pre-wrap; position:relative; z-index:99999; word-break: normal',
'num' => 'color:#BCD42A',
'const' => 'color: #4bb1b1;',
'str' => 'color:#BCD42A',
'note' => 'color:#ef7c61',
'ref' => 'color:#A0A0A0',
'public' => 'color:#FFFFFF',
'protected' => 'color:#FFFFFF',
'private' => 'color:#FFFFFF',
'meta' => 'color:#FFFFFF',
'key' => 'color:#BCD42A',
'index' => 'color:#ef7c61',
];
$this->htmlDumper->setStyles($styles);
}
return $this->htmlDumper;
}
/**
* Format the given value into a human readable string.
*
* @param mixed $value
* @return string
*/
public function dump($value)
{
$dumper = $this->getDumper();
if ($dumper) {
// re-use the same DumpOutput instance, so it won't
re-render the global styles/scripts on each dump.
// exclude verbose information (e.g. exception stack traces)
if
(class_exists('Symfony\Component\VarDumper\Caster\Caster')) {
$cloneVar = $this->getCloner()->cloneVar($value,
Caster::EXCLUDE_VERBOSE);
// Symfony VarDumper 2.6 Caster class dont exist.
} else {
$cloneVar = $this->getCloner()->cloneVar($value);
}
$dumper->dump(
$cloneVar,
$this->htmlDumperOutput
);
$output = $this->htmlDumperOutput->getOutput();
$this->htmlDumperOutput->clear();
return $output;
}
return htmlspecialchars(print_r($value, true));
}
/**
* Format the args of the given Frame as a human readable html string
*
* @param Frame $frame
* @return string the rendered html
*/
public function dumpArgs(Frame $frame)
{
// we support frame args only when the optional dumper is available
if (!$this->getDumper()) {
return '';
}
$html = '';
$numFrames = count($frame->getArgs());
if ($numFrames > 0) {
$html = '<ol class="linenums">';
foreach ($frame->getArgs() as $j => $frameArg) {
$html .= '<li>'. $this->dump($frameArg)
.'</li>';
}
$html .= '</ol>';
}
return $html;
}
/**
* Convert a string to a slug version of itself
*
* @param string $original
* @return string
*/
public function slug($original)
{
$slug = str_replace(" ", "-", $original);
$slug = preg_replace('/[^\w\d\-\_]/i', '',
$slug);
return strtolower($slug);
}
/**
* Given a template path, render it within its own scope. This
* method also accepts an array of additional variables to be
* passed to the template.
*
* @param string $template
* @param array $additionalVariables
*/
public function render($template, array $additionalVariables = null)
{
$variables = $this->getVariables();
// Pass the helper to the template:
$variables["tpl"] = $this;
if ($additionalVariables !== null) {
$variables = array_replace($variables, $additionalVariables);
}
call_user_func(function () {
extract(func_get_arg(1));
require func_get_arg(0);
}, $template, $variables);
}
/**
* Sets the variables to be passed to all templates rendered
* by this template helper.
*
* @param array $variables
*/
public function setVariables(array $variables)
{
$this->variables = $variables;
}
/**
* Sets a single template variable, by its name:
*
* @param string $variableName
* @param mixed $variableValue
*/
public function setVariable($variableName, $variableValue)
{
$this->variables[$variableName] = $variableValue;
}
/**
* Gets a single template variable, by its name, or
* $defaultValue if the variable does not exist
*
* @param string $variableName
* @param mixed $defaultValue
* @return mixed
*/
public function getVariable($variableName, $defaultValue = null)
{
return isset($this->variables[$variableName]) ?
$this->variables[$variableName] : $defaultValue;
}
/**
* Unsets a single template variable, by its name
*
* @param string $variableName
*/
public function delVariable($variableName)
{
unset($this->variables[$variableName]);
}
/**
* Returns all variables for this helper
*
* @return array
*/
public function getVariables()
{
return $this->variables;
}
/**
* Set the cloner used for dumping variables.
*
* @param AbstractCloner $cloner
*/
public function setCloner($cloner)
{
$this->cloner = $cloner;
}
/**
* Get the cloner used for dumping variables.
*
* @return AbstractCloner
*/
public function getCloner()
{
if (!$this->cloner) {
$this->cloner = new VarCloner();
}
return $this->cloner;
}
/**
* Set the application root path.
*
* @param string $applicationRootPath
*/
public function setApplicationRootPath($applicationRootPath)
{
$this->applicationRootPath = $applicationRootPath;
}
/**
* Return the application root path.
*
* @return string
*/
public function getApplicationRootPath()
{
return $this->applicationRootPath;
}
}
PK)d�[���WW"vendor/leafo/scssphp/composer.jsonnu�[���{
"name": "leafo/scssphp",
"type": "library",
"description": "scssphp is a compiler for SCSS written
in PHP.",
"keywords": ["css", "stylesheet",
"scss", "sass", "less"],
"homepage": "http://leafo.github.io/scssphp/",
"license": [
"MIT"
],
"authors": [
{
"name": "Leaf Corcoran",
"email": "leafot@gmail.com",
"homepage": "http://leafo.net"
}
],
"autoload": {
"psr-4": { "Leafo\\ScssPhp\\": "src/"
}
},
"autoload-dev": {
"psr-4": { "Leafo\\ScssPhp\\Test\\":
"tests/" }
},
"require": {
"php": "^5.4.0 || ^7"
},
"require-dev": {
"squizlabs/php_codesniffer": "~2.5",
"phpunit/phpunit": "~4.6",
"twbs/bootstrap": "~4.3",
"zurb/foundation": "~6.5"
},
"bin": ["bin/pscss"],
"archive": {
"exclude": [
"/Makefile",
"/.gitattributes",
"/.gitignore",
"/.travis.yml",
"/phpunit.xml.dist",
"/tests"
]
},
"abandoned": "scssphp/scssphp"
}
PK)d�[��zb�6�6'vendor/leafo/scssphp/example/Server.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2017 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Compiler;
use Leafo\ScssPhp\Exception\ServerException;
use Leafo\ScssPhp\Version;
/**
* Server
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Server
{
/**
* @var boolean
*/
private $showErrorsAsCSS;
/**
* @var string
*/
private $dir;
/**
* @var string
*/
private $cacheDir;
/**
* @var \Leafo\ScssPhp\Compiler
*/
private $scss;
/**
* Join path components
*
* @param string $left Path component, left of the directory separator
* @param string $right Path component, right of the directory
separator
*
* @return string
*/
protected function join($left, $right)
{
return rtrim($left, '/\\') . DIRECTORY_SEPARATOR .
ltrim($right, '/\\');
}
/**
* Get name of requested .scss file
*
* @return string|null
*/
protected function inputName()
{
switch (true) {
case isset($_GET['p']):
return $_GET['p'];
case isset($_SERVER['PATH_INFO']):
return $_SERVER['PATH_INFO'];
case isset($_SERVER['DOCUMENT_URI']):
return substr($_SERVER['DOCUMENT_URI'],
strlen($_SERVER['SCRIPT_NAME']));
}
}
/**
* Get path to requested .scss file
*
* @return string
*/
protected function findInput()
{
if (($input = $this->inputName())
&& strpos($input, '..') === false
&& substr($input, -5) === '.scss'
) {
$name = $this->join($this->dir, $input);
if (is_file($name) && is_readable($name)) {
return $name;
}
}
return false;
}
/**
* Get path to cached .css file
*
* @return string
*/
protected function cacheName($fname)
{
return $this->join($this->cacheDir, md5($fname) .
'.css');
}
/**
* Get path to meta data
*
* @return string
*/
protected function metadataName($out)
{
return $out . '.meta';
}
/**
* Determine whether .scss file needs to be re-compiled.
*
* @param string $out Output path
* @param string $etag ETag
*
* @return boolean True if compile required.
*/
protected function needsCompile($out, &$etag)
{
if (! is_file($out)) {
return true;
}
$mtime = filemtime($out);
$metadataName = $this->metadataName($out);
if (is_readable($metadataName)) {
$metadata = unserialize(file_get_contents($metadataName));
foreach ($metadata['imports'] as $import =>
$originalMtime) {
$currentMtime = filemtime($import);
if ($currentMtime !== $originalMtime || $currentMtime >
$mtime) {
return true;
}
}
$metaVars =
crc32(serialize($this->scss->getVariables()));
if ($metaVars !== $metadata['vars']) {
return true;
}
$etag = $metadata['etag'];
return false;
}
return true;
}
/**
* Get If-Modified-Since header from client request
*
* @return string|null
*/
protected function getIfModifiedSinceHeader()
{
$modifiedSince = null;
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$modifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
if (false !== ($semicolonPos = strpos($modifiedSince,
';'))) {
$modifiedSince = substr($modifiedSince, 0, $semicolonPos);
}
}
return $modifiedSince;
}
/**
* Get If-None-Match header from client request
*
* @return string|null
*/
protected function getIfNoneMatchHeader()
{
$noneMatch = null;
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
$noneMatch = $_SERVER['HTTP_IF_NONE_MATCH'];
}
return $noneMatch;
}
/**
* Compile .scss file
*
* @param string $in Input path (.scss)
* @param string $out Output path (.css)
*
* @return array
*/
protected function compile($in, $out)
{
$start = microtime(true);
$css = $this->scss->compile(file_get_contents($in), $in);
$elapsed = round((microtime(true) - $start), 4);
$v = Version::VERSION;
$t = gmdate('r');
$css = "/* compiled by scssphp $v on $t (${elapsed}s)
*/\n\n" . $css;
$etag = md5($css);
file_put_contents($out, $css);
file_put_contents(
$this->metadataName($out),
serialize([
'etag' => $etag,
'imports' =>
$this->scss->getParsedFiles(),
'vars' =>
crc32(serialize($this->scss->getVariables())),
])
);
return [$css, $etag];
}
/**
* Format error as a pseudo-element in CSS
*
* @param \Exception $error
*
* @return string
*/
protected function createErrorCSS(\Exception $error)
{
$message = str_replace(
["'", "\n"],
["\\'", "\\A"],
$error->getfile() . ":\n\n" .
$error->getMessage()
);
return "body { display: none !important; }
html:after {
background: white;
color: black;
content: '$message';
display: block !important;
font-family: mono;
padding: 1em;
white-space: pre;
}";
}
/**
* Render errors as a pseudo-element within valid CSS, displaying the
errors on any
* page that includes this CSS.
*
* @param boolean $show
*/
public function showErrorsAsCSS($show = true)
{
$this->showErrorsAsCSS = $show;
}
/**
* Compile .scss file
*
* @param string $in Input file (.scss)
* @param string $out Output file (.css) optional
*
* @return string|bool
*
* @throws \Leafo\ScssPhp\Exception\ServerException
*/
public function compileFile($in, $out = null)
{
if (! is_readable($in)) {
throw new ServerException('load error: failed to find
' . $in);
}
$pi = pathinfo($in);
$this->scss->addImportPath($pi['dirname'] .
'/');
$compiled = $this->scss->compile(file_get_contents($in),
$in);
if ($out !== null) {
return file_put_contents($out, $compiled);
}
return $compiled;
}
/**
* Check if file need compiling
*
* @param string $in Input file (.scss)
* @param string $out Output file (.css)
*
* @return bool
*/
public function checkedCompile($in, $out)
{
if (! is_file($out) || filemtime($in) > filemtime($out)) {
$this->compileFile($in, $out);
return true;
}
return false;
}
/**
* Compile requested scss and serve css. Outputs HTTP response.
*
* @param string $salt Prefix a string to the filename for creating the
cache name hash
*/
public function serve($salt = '')
{
$protocol = isset($_SERVER['SERVER_PROTOCOL'])
? $_SERVER['SERVER_PROTOCOL']
: 'HTTP/1.0';
if ($input = $this->findInput()) {
$output = $this->cacheName($salt . $input);
$etag = $noneMatch = trim($this->getIfNoneMatchHeader(),
'"');
if ($this->needsCompile($output, $etag)) {
try {
list($css, $etag) = $this->compile($input, $output);
$lastModified = gmdate('r',
filemtime($output));
header('Last-Modified: ' . $lastModified);
header('Content-type: text/css');
header('ETag: "' . $etag .
'"');
echo $css;
} catch (\Exception $e) {
if ($this->showErrorsAsCSS) {
header('Content-type: text/css');
echo $this->createErrorCSS($e);
} else {
header($protocol . ' 500 Internal Server
Error');
header('Content-type: text/plain');
echo 'Parse error: ' .
$e->getMessage() . "\n";
}
}
return;
}
header('X-SCSS-Cache: true');
header('Content-type: text/css');
header('ETag: "' . $etag . '"');
if ($etag === $noneMatch) {
header($protocol . ' 304 Not Modified');
return;
}
$modifiedSince = $this->getIfModifiedSinceHeader();
$mtime = filemtime($output);
if (strtotime($modifiedSince) === $mtime) {
header($protocol . ' 304 Not Modified');
return;
}
$lastModified = gmdate('r', $mtime);
header('Last-Modified: ' . $lastModified);
echo file_get_contents($output);
return;
}
header($protocol . ' 404 Not Found');
header('Content-type: text/plain');
$v = Version::VERSION;
echo "/* INPUT NOT FOUND scss $v */\n";
}
/**
* Based on explicit input/output files does a full change check on
cache before compiling.
*
* @param string $in
* @param string $out
* @param boolean $force
*
* @return string Compiled CSS results
*
* @throws \Leafo\ScssPhp\Exception\ServerException
*/
public function checkedCachedCompile($in, $out, $force = false)
{
if (! is_file($in) || ! is_readable($in)) {
throw new ServerException('Invalid or unreadable input
file specified.');
}
if (is_dir($out) || ! is_writable(file_exists($out) ? $out :
dirname($out))) {
throw new ServerException('Invalid or unwritable output
file specified.');
}
if ($force || $this->needsCompile($out, $etag)) {
list($css, $etag) = $this->compile($in, $out);
} else {
$css = file_get_contents($out);
}
return $css;
}
/**
* Execute scssphp on a .scss file or a scssphp cache structure
*
* The scssphp cache structure contains information about a specific
* scss file having been parsed. It can be used as a hint for future
* calls to determine whether or not a rebuild is required.
*
* The cache structure contains two important keys that may be used
* externally:
*
* compiled: The final compiled CSS
* updated: The time (in seconds) the CSS was last compiled
*
* The cache structure is a plain-ol' PHP associative array and
can
* be serialized and unserialized without a hitch.
*
* @param mixed $in Input
* @param boolean $force Force rebuild?
*
* @return array scssphp cache structure
*/
public function cachedCompile($in, $force = false)
{
// assume no root
$root = null;
if (is_string($in)) {
$root = $in;
} elseif (is_array($in) and isset($in['root'])) {
if ($force or ! isset($in['files'])) {
// If we are forcing a recompile or if for some reason the
// structure does not contain any file information we
should
// specify the root to trigger a rebuild.
$root = $in['root'];
} elseif (isset($in['files']) and
is_array($in['files'])) {
foreach ($in['files'] as $fname => $ftime) {
if (! file_exists($fname) or filemtime($fname) >
$ftime) {
// One of the files we knew about previously has
changed
// so we should look at our incoming root again.
$root = $in['root'];
break;
}
}
}
} else {
// TODO: Throw an exception? We got neither a string nor
something
// that looks like a compatible lessphp cache structure.
return null;
}
if ($root !== null) {
// If we have a root value which means we should rebuild.
$out = [];
$out['root'] = $root;
$out['compiled'] = $this->compileFile($root);
$out['files'] = $this->scss->getParsedFiles();
$out['updated'] = time();
return $out;
} else {
// No changes, pass back the structure
// we were given initially.
return $in;
}
}
/**
* Constructor
*
* @param string $dir Root directory to
.scss files
* @param string $cacheDir Cache directory
* @param \Leafo\ScssPhp\Compiler|null $scss SCSS compiler instance
*/
public function __construct($dir, $cacheDir = null, $scss = null)
{
$this->dir = $dir;
if (! isset($cacheDir)) {
$cacheDir = $this->join($dir, 'scss_cache');
}
$this->cacheDir = $cacheDir;
if (! is_dir($this->cacheDir)) {
throw new ServerException('Cache directory doesn\'t
exist: ' . $cacheDir);
}
if (! isset($scss)) {
$scss = new Compiler();
$scss->setImportPaths($this->dir);
}
$this->scss = $scss;
$this->showErrorsAsCSS = false;
date_default_timezone_set('UTC');
}
}
PK)d�[^��kk!vendor/leafo/scssphp/scss.inc.phpnu�[���<?php
if (version_compare(PHP_VERSION, '5.4') < 0) {
throw new \Exception('scssphp requires PHP 5.4 or above');
}
if (! class_exists('Leafo\ScssPhp\Version', false)) {
include_once __DIR__ . '/src/Base/Range.php';
include_once __DIR__ . '/src/Block.php';
include_once __DIR__ . '/src/Cache.php';
include_once __DIR__ . '/src/Colors.php';
include_once __DIR__ . '/src/Compiler.php';
include_once __DIR__ . '/src/Compiler/Environment.php';
include_once __DIR__ .
'/src/Exception/CompilerException.php';
include_once __DIR__ . '/src/Exception/ParserException.php';
include_once __DIR__ . '/src/Exception/RangeException.php';
include_once __DIR__ . '/src/Exception/ServerException.php';
include_once __DIR__ . '/src/Formatter.php';
include_once __DIR__ . '/src/Formatter/Compact.php';
include_once __DIR__ . '/src/Formatter/Compressed.php';
include_once __DIR__ . '/src/Formatter/Crunched.php';
include_once __DIR__ . '/src/Formatter/Debug.php';
include_once __DIR__ . '/src/Formatter/Expanded.php';
include_once __DIR__ . '/src/Formatter/Nested.php';
include_once __DIR__ . '/src/Formatter/OutputBlock.php';
include_once __DIR__ . '/src/Node.php';
include_once __DIR__ . '/src/Node/Number.php';
include_once __DIR__ . '/src/Parser.php';
include_once __DIR__ . '/src/SourceMap/Base64.php';
include_once __DIR__ . '/src/SourceMap/Base64VLQ.php';
include_once __DIR__ .
'/src/SourceMap/SourceMapGenerator.php';
include_once __DIR__ . '/src/Type.php';
include_once __DIR__ . '/src/Util.php';
include_once __DIR__ . '/src/Version.php';
}
PK)d�[�)[\'vendor/leafo/scssphp/src/Base/Range.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2015-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Base;
/**
* Range
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Range
{
public $first;
public $last;
/**
* Initialize range
*
* @param integer|float $first
* @param integer|float $last
*/
public function __construct($first, $last)
{
$this->first = $first;
$this->last = $last;
}
/**
* Test for inclusion in range
*
* @param integer|float $value
*
* @return boolean
*/
public function includes($value)
{
return $value >= $this->first && $value <=
$this->last;
}
}
PK*d�[a֊xx"vendor/leafo/scssphp/src/Block.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* Block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Block
{
/**
* @var string
*/
public $type;
/**
* @var \Leafo\ScssPhp\Block
*/
public $parent;
/**
* @var string
*/
public $sourceName;
/**
* @var integer
*/
public $sourceIndex;
/**
* @var integer
*/
public $sourceLine;
/**
* @var integer
*/
public $sourceColumn;
/**
* @var array
*/
public $selectors;
/**
* @var array
*/
public $comments;
/**
* @var array
*/
public $children;
/**
* @var \Leafo\ScssPhp\Block
*/
public $selfParent;
}
PK*d�[���GG"vendor/leafo/scssphp/src/Cache.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Exception;
/**
* The scss cache manager.
*
* In short:
*
* allow to put in cache/get from cache a generic result from a known
operation on a generic dataset,
* taking in account options that affects the result
*
* The cache manager is agnostic about data format and only the operation
is expected to be described by string
*
*/
/**
* SCSS cache
*
* @author Cedric Morin
*/
class Cache
{
const CACHE_VERSION = 0;
// directory used for storing data
public static $cacheDir = false;
// prefix for the storing data
public static $prefix = 'scssphp_';
// force a refresh : 'once' for refreshing the first hit on a
cache only, true to never use the cache in this hit
public static $forceFefresh = false;
// specifies the number of seconds after which data cached will be seen
as 'garbage' and potentially cleaned up
public static $gcLifetime = 604800;
// array of already refreshed cache if $forceFefresh==='once'
protected static $refreshed = [];
/**
* Constructor
*
* @param array $options
*/
public function __construct($options)
{
// check $cacheDir
if (isset($options['cache_dir'])) {
self::$cacheDir = $options['cache_dir'];
}
if (empty(self::$cacheDir)) {
throw new Exception('cache_dir not set');
}
if (isset($options['prefix'])) {
self::$prefix = $options['prefix'];
}
if (empty(self::$prefix)) {
throw new Exception('prefix not set');
}
if (isset($options['forceRefresh'])) {
self::$forceFefresh = $options['force_refresh'];
}
self::checkCacheDir();
}
/**
* Get the cached result of $operation on $what,
* which is known as dependant from the content of $options
*
* @param string $operation parse, compile...
* @param mixed $what content key (e.g., filename to be
treated)
* @param array $options any option that affect the operation
result on the content
* @param integer $lastModified last modified timestamp
*
* @return mixed
*
* @throws \Exception
*/
public function getCache($operation, $what, $options = [],
$lastModified = null)
{
$fileCache = self::$cacheDir . self::cacheName($operation, $what,
$options);
if ((! self::$forceRefresh || (self::$forceRefresh ===
'once' && isset(self::$refreshed[$fileCache])))
&& file_exists($fileCache)
) {
$cacheTime = filemtime($fileCache);
if ((is_null($lastModified) || $cacheTime > $lastModified)
&& $cacheTime + self::$gcLifetime > time()
) {
$c = file_get_contents($fileCache);
$c = unserialize($c);
if (is_array($c) && isset($c['value'])) {
return $c['value'];
}
}
}
return null;
}
/**
* Put in cache the result of $operation on $what,
* which is known as dependant from the content of $options
*
* @param string $operation
* @param mixed $what
* @param mixed $value
* @param array $options
*/
public function setCache($operation, $what, $value, $options = [])
{
$fileCache = self::$cacheDir . self::cacheName($operation, $what,
$options);
$c = ['value' => $value];
$c = serialize($c);
file_put_contents($fileCache, $c);
if (self::$forceRefresh === 'once') {
self::$refreshed[$fileCache] = true;
}
}
/**
* Get the cache name for the caching of $operation on $what,
* which is known as dependant from the content of $options
*
* @param string $operation
* @param mixed $what
* @param array $options
*
* @return string
*/
private static function cacheName($operation, $what, $options = [])
{
$t = [
'version' => self::CACHE_VERSION,
'operation' => $operation,
'what' => $what,
'options' => $options
];
$t = self::$prefix
. sha1(json_encode($t))
. ".$operation"
. ".scsscache";
return $t;
}
/**
* Check that the cache dir exists and is writeable
*
* @throws \Exception
*/
public static function checkCacheDir()
{
self::$cacheDir = str_replace('\\', '/',
self::$cacheDir);
self::$cacheDir = rtrim(self::$cacheDir, '/') .
'/';
if (! file_exists(self::$cacheDir)) {
if (! mkdir(self::$cacheDir)) {
throw new Exception('Cache directory couldn\'t be
created: ' . self::$cacheDir);
}
} elseif (! is_dir(self::$cacheDir)) {
throw new Exception('Cache directory doesn\'t exist:
' . self::$cacheDir);
} elseif (! is_writable(self::$cacheDir)) {
throw new Exception('Cache directory isn\'t writable:
' . self::$cacheDir);
}
}
/**
* Delete unused cached files
*/
public static function cleanCache()
{
static $clean = false;
if ($clean || empty(self::$cacheDir)) {
return;
}
$clean = true;
// only remove files with extensions created by SCSSPHP Cache
// css files removed based on the list files
$removeTypes = ['scsscache' => 1];
$files = scandir(self::$cacheDir);
if (! $files) {
return;
}
$checkTime = time() - self::$gcLifetime;
foreach ($files as $file) {
// don't delete if the file wasn't created with
SCSSPHP Cache
if (strpos($file, self::$prefix) !== 0) {
continue;
}
$parts = explode('.', $file);
$type = array_pop($parts);
if (! isset($removeTypes[$type])) {
continue;
}
$fullPath = self::$cacheDir . $file;
$mtime = filemtime($fullPath);
// don't delete if it's a relatively new file
if ($mtime > $checkTime) {
continue;
}
unlink($fullPath);
}
}
}
PK*d�[ߗ��((#vendor/leafo/scssphp/src/Colors.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* CSS Colors
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Colors
{
/**
* CSS Colors
*
* @see http://www.w3.org/TR/css3-color
*
* @var array
*/
public static $cssColors = [
'aliceblue' => '240,248,255',
'antiquewhite' => '250,235,215',
'aqua' => '0,255,255',
'aquamarine' => '127,255,212',
'azure' => '240,255,255',
'beige' => '245,245,220',
'bisque' => '255,228,196',
'black' => '0,0,0',
'blanchedalmond' => '255,235,205',
'blue' => '0,0,255',
'blueviolet' => '138,43,226',
'brown' => '165,42,42',
'burlywood' => '222,184,135',
'cadetblue' => '95,158,160',
'chartreuse' => '127,255,0',
'chocolate' => '210,105,30',
'coral' => '255,127,80',
'cornflowerblue' => '100,149,237',
'cornsilk' => '255,248,220',
'crimson' => '220,20,60',
'cyan' => '0,255,255',
'darkblue' => '0,0,139',
'darkcyan' => '0,139,139',
'darkgoldenrod' => '184,134,11',
'darkgray' => '169,169,169',
'darkgreen' => '0,100,0',
'darkgrey' => '169,169,169',
'darkkhaki' => '189,183,107',
'darkmagenta' => '139,0,139',
'darkolivegreen' => '85,107,47',
'darkorange' => '255,140,0',
'darkorchid' => '153,50,204',
'darkred' => '139,0,0',
'darksalmon' => '233,150,122',
'darkseagreen' => '143,188,143',
'darkslateblue' => '72,61,139',
'darkslategray' => '47,79,79',
'darkslategrey' => '47,79,79',
'darkturquoise' => '0,206,209',
'darkviolet' => '148,0,211',
'deeppink' => '255,20,147',
'deepskyblue' => '0,191,255',
'dimgray' => '105,105,105',
'dimgrey' => '105,105,105',
'dodgerblue' => '30,144,255',
'firebrick' => '178,34,34',
'floralwhite' => '255,250,240',
'forestgreen' => '34,139,34',
'fuchsia' => '255,0,255',
'gainsboro' => '220,220,220',
'ghostwhite' => '248,248,255',
'gold' => '255,215,0',
'goldenrod' => '218,165,32',
'gray' => '128,128,128',
'green' => '0,128,0',
'greenyellow' => '173,255,47',
'grey' => '128,128,128',
'honeydew' => '240,255,240',
'hotpink' => '255,105,180',
'indianred' => '205,92,92',
'indigo' => '75,0,130',
'ivory' => '255,255,240',
'khaki' => '240,230,140',
'lavender' => '230,230,250',
'lavenderblush' => '255,240,245',
'lawngreen' => '124,252,0',
'lemonchiffon' => '255,250,205',
'lightblue' => '173,216,230',
'lightcoral' => '240,128,128',
'lightcyan' => '224,255,255',
'lightgoldenrodyellow' => '250,250,210',
'lightgray' => '211,211,211',
'lightgreen' => '144,238,144',
'lightgrey' => '211,211,211',
'lightpink' => '255,182,193',
'lightsalmon' => '255,160,122',
'lightseagreen' => '32,178,170',
'lightskyblue' => '135,206,250',
'lightslategray' => '119,136,153',
'lightslategrey' => '119,136,153',
'lightsteelblue' => '176,196,222',
'lightyellow' => '255,255,224',
'lime' => '0,255,0',
'limegreen' => '50,205,50',
'linen' => '250,240,230',
'magenta' => '255,0,255',
'maroon' => '128,0,0',
'mediumaquamarine' => '102,205,170',
'mediumblue' => '0,0,205',
'mediumorchid' => '186,85,211',
'mediumpurple' => '147,112,219',
'mediumseagreen' => '60,179,113',
'mediumslateblue' => '123,104,238',
'mediumspringgreen' => '0,250,154',
'mediumturquoise' => '72,209,204',
'mediumvioletred' => '199,21,133',
'midnightblue' => '25,25,112',
'mintcream' => '245,255,250',
'mistyrose' => '255,228,225',
'moccasin' => '255,228,181',
'navajowhite' => '255,222,173',
'navy' => '0,0,128',
'oldlace' => '253,245,230',
'olive' => '128,128,0',
'olivedrab' => '107,142,35',
'orange' => '255,165,0',
'orangered' => '255,69,0',
'orchid' => '218,112,214',
'palegoldenrod' => '238,232,170',
'palegreen' => '152,251,152',
'paleturquoise' => '175,238,238',
'palevioletred' => '219,112,147',
'papayawhip' => '255,239,213',
'peachpuff' => '255,218,185',
'peru' => '205,133,63',
'pink' => '255,192,203',
'plum' => '221,160,221',
'powderblue' => '176,224,230',
'purple' => '128,0,128',
'rebeccapurple' => '102,51,153',
'red' => '255,0,0',
'rosybrown' => '188,143,143',
'royalblue' => '65,105,225',
'saddlebrown' => '139,69,19',
'salmon' => '250,128,114',
'sandybrown' => '244,164,96',
'seagreen' => '46,139,87',
'seashell' => '255,245,238',
'sienna' => '160,82,45',
'silver' => '192,192,192',
'skyblue' => '135,206,235',
'slateblue' => '106,90,205',
'slategray' => '112,128,144',
'slategrey' => '112,128,144',
'snow' => '255,250,250',
'springgreen' => '0,255,127',
'steelblue' => '70,130,180',
'tan' => '210,180,140',
'teal' => '0,128,128',
'thistle' => '216,191,216',
'tomato' => '255,99,71',
'transparent' => '0,0,0,0',
'turquoise' => '64,224,208',
'violet' => '238,130,238',
'wheat' => '245,222,179',
'white' => '255,255,255',
'whitesmoke' => '245,245,245',
'yellow' => '255,255,0',
'yellowgreen' => '154,205,50',
];
}
PK*d�[��ruuu1vendor/leafo/scssphp/src/Compiler/Environment.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Compiler;
/**
* Compiler environment
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Environment
{
/**
* @var \Leafo\ScssPhp\Block
*/
public $block;
/**
* @var \Leafo\ScssPhp\Compiler\Environment
*/
public $parent;
/**
* @var array
*/
public $store;
/**
* @var array
*/
public $storeUnreduced;
/**
* @var integer
*/
public $depth;
}
PK*d�[h������%vendor/leafo/scssphp/src/Compiler.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Base\Range;
use Leafo\ScssPhp\Block;
use Leafo\ScssPhp\Cache;
use Leafo\ScssPhp\Colors;
use Leafo\ScssPhp\Compiler\Environment;
use Leafo\ScssPhp\Exception\CompilerException;
use Leafo\ScssPhp\Formatter\OutputBlock;
use Leafo\ScssPhp\Node;
use Leafo\ScssPhp\SourceMap\SourceMapGenerator;
use Leafo\ScssPhp\Type;
use Leafo\ScssPhp\Parser;
use Leafo\ScssPhp\Util;
/**
* The scss compiler and parser.
*
* Converting SCSS to CSS is a three stage process. The incoming file is
parsed
* by `Parser` into a syntax tree, then it is compiled into another tree
* representing the CSS structure by `Compiler`. The CSS tree is fed into a
* formatter, like `Formatter` which then outputs CSS as a string.
*
* During the first compile, all values are *reduced*, which means that
their
* types are brought to the lowest form before being dump as strings. This
* handles math equations, variable dereferences, and the like.
*
* The `compile` function of `Compiler` is the entry point.
*
* In summary:
*
* The `Compiler` class creates an instance of the parser, feeds it SCSS
code,
* then transforms the resulting tree to a CSS tree. This class also holds
the
* evaluation context, such as all available mixins and variables at any
given
* time.
*
* The `Parser` class is only concerned with parsing its input.
*
* The `Formatter` takes a CSS tree, and dumps it to a formatted string,
* handling things like indentation.
*/
/**
* SCSS compiler
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Compiler
{
const LINE_COMMENTS = 1;
const DEBUG_INFO = 2;
const WITH_RULE = 1;
const WITH_MEDIA = 2;
const WITH_SUPPORTS = 4;
const WITH_ALL = 7;
const SOURCE_MAP_NONE = 0;
const SOURCE_MAP_INLINE = 1;
const SOURCE_MAP_FILE = 2;
/**
* @var array
*/
static protected $operatorNames = [
'+' => 'add',
'-' => 'sub',
'*' => 'mul',
'/' => 'div',
'%' => 'mod',
'==' => 'eq',
'!=' => 'neq',
'<' => 'lt',
'>' => 'gt',
'<=' => 'lte',
'>=' => 'gte',
'<=>' => 'cmp',
];
/**
* @var array
*/
static protected $namespaces = [
'special' => '%',
'mixin' => '@',
'function' => '^',
];
static public $true = [Type::T_KEYWORD, 'true'];
static public $false = [Type::T_KEYWORD, 'false'];
static public $null = [Type::T_NULL];
static public $nullString = [Type::T_STRING, '', []];
static public $defaultValue = [Type::T_KEYWORD, ''];
static public $selfSelector = [Type::T_SELF];
static public $emptyList = [Type::T_LIST, '', []];
static public $emptyMap = [Type::T_MAP, [], []];
static public $emptyString = [Type::T_STRING, '"', []];
static public $with = [Type::T_KEYWORD, 'with'];
static public $without = [Type::T_KEYWORD, 'without'];
protected $importPaths = [''];
protected $importCache = [];
protected $importedFiles = [];
protected $userFunctions = [];
protected $registeredVars = [];
protected $registeredFeatures = [
'extend-selector-pseudoclass' => false,
'at-error' => true,
'units-level-3' => false,
'global-variable-shadowing' => false,
];
protected $encoding = null;
protected $lineNumberStyle = null;
protected $sourceMap = self::SOURCE_MAP_NONE;
protected $sourceMapOptions = [];
/**
* @var string|\Leafo\ScssPhp\Formatter
*/
protected $formatter = 'Leafo\ScssPhp\Formatter\Nested';
protected $rootEnv;
protected $rootBlock;
/**
* @var \Leafo\ScssPhp\Compiler\Environment
*/
protected $env;
protected $scope;
protected $storeEnv;
protected $charsetSeen;
protected $sourceNames;
protected $cache;
protected $indentLevel;
protected $extends;
protected $extendsMap;
protected $parsedFiles;
protected $parser;
protected $sourceIndex;
protected $sourceLine;
protected $sourceColumn;
protected $stderr;
protected $shouldEvaluate;
protected $ignoreErrors;
protected $callStack = [];
/**
* Constructor
*/
public function __construct($cacheOptions = null)
{
$this->parsedFiles = [];
$this->sourceNames = [];
if ($cacheOptions) {
$this->cache = new Cache($cacheOptions);
}
}
public function getCompileOptions()
{
$options = [
'importPaths' => $this->importPaths,
'registeredVars' => $this->registeredVars,
'registeredFeatures' =>
$this->registeredFeatures,
'encoding' => $this->encoding,
'sourceMap' =>
serialize($this->sourceMap),
'sourceMapOptions' =>
$this->sourceMapOptions,
'formatter' => $this->formatter,
];
return $options;
}
/**
* Compile scss
*
* @api
*
* @param string $code
* @param string $path
*
* @return string
*/
public function compile($code, $path = null)
{
if ($this->cache) {
$cacheKey = ($path ? $path : "(stdin)") .
":" . md5($code);
$compileOptions = $this->getCompileOptions();
$cache = $this->cache->getCache("compile",
$cacheKey, $compileOptions);
if (is_array($cache)
&& isset($cache['dependencies'])
&& isset($cache['out'])
) {
// check if any dependency file changed before accepting
the cache
foreach ($cache['dependencies'] as $file =>
$mtime) {
if (! file_exists($file)
|| filemtime($file) !== $mtime
) {
unset($cache);
break;
}
}
if (isset($cache)) {
return $cache['out'];
}
}
}
$this->indentLevel = -1;
$this->extends = [];
$this->extendsMap = [];
$this->sourceIndex = null;
$this->sourceLine = null;
$this->sourceColumn = null;
$this->env = null;
$this->scope = null;
$this->storeEnv = null;
$this->charsetSeen = null;
$this->shouldEvaluate = null;
$this->stderr = fopen('php://stderr',
'w');
$this->parser = $this->parserFactory($path);
$tree = $this->parser->parse($code);
$this->parser = null;
$this->formatter = new $this->formatter();
$this->rootBlock = null;
$this->rootEnv = $this->pushEnv($tree);
$this->injectVariables($this->registeredVars);
$this->compileRoot($tree);
$this->popEnv();
$sourceMapGenerator = null;
if ($this->sourceMap) {
if (is_object($this->sourceMap) &&
$this->sourceMap instanceof SourceMapGenerator) {
$sourceMapGenerator = $this->sourceMap;
$this->sourceMap = self::SOURCE_MAP_FILE;
} elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) {
$sourceMapGenerator = new
SourceMapGenerator($this->sourceMapOptions);
}
}
$out = $this->formatter->format($this->scope,
$sourceMapGenerator);
if (! empty($out) && $this->sourceMap &&
$this->sourceMap !== self::SOURCE_MAP_NONE) {
$sourceMap = $sourceMapGenerator->generateJson();
$sourceMapUrl = null;
switch ($this->sourceMap) {
case self::SOURCE_MAP_INLINE:
$sourceMapUrl =
sprintf('data:application/json,%s',
Util::encodeURIComponent($sourceMap));
break;
case self::SOURCE_MAP_FILE:
$sourceMapUrl =
$sourceMapGenerator->saveMap($sourceMap);
break;
}
$out .= sprintf('/*# sourceMappingURL=%s */',
$sourceMapUrl);
}
if ($this->cache && isset($cacheKey) &&
isset($compileOptions)) {
$v = [
'dependencies' => $this->getParsedFiles(),
'out' => &$out,
];
$this->cache->setCache("compile", $cacheKey,
$v, $compileOptions);
}
return $out;
}
/**
* Instantiate parser
*
* @param string $path
*
* @return \Leafo\ScssPhp\Parser
*/
protected function parserFactory($path)
{
$parser = new Parser($path, count($this->sourceNames),
$this->encoding, $this->cache);
$this->sourceNames[] = $path;
$this->addParsedFile($path);
return $parser;
}
/**
* Is self extend?
*
* @param array $target
* @param array $origin
*
* @return boolean
*/
protected function isSelfExtend($target, $origin)
{
foreach ($origin as $sel) {
if (in_array($target, $sel)) {
return true;
}
}
return false;
}
/**
* Push extends
*
* @param array $target
* @param array $origin
* @param \stdClass $block
*/
protected function pushExtends($target, $origin, $block)
{
if ($this->isSelfExtend($target, $origin)) {
return;
}
$i = count($this->extends);
$this->extends[] = [$target, $origin, $block];
foreach ($target as $part) {
if (isset($this->extendsMap[$part])) {
$this->extendsMap[$part][] = $i;
} else {
$this->extendsMap[$part] = [$i];
}
}
}
/**
* Make output block
*
* @param string $type
* @param array $selectors
*
* @return \Leafo\ScssPhp\Formatter\OutputBlock
*/
protected function makeOutputBlock($type, $selectors = null)
{
$out = new OutputBlock;
$out->type = $type;
$out->lines = [];
$out->children = [];
$out->parent = $this->scope;
$out->selectors = $selectors;
$out->depth = $this->env->depth;
if ($this->env->block instanceof Block) {
$out->sourceName = $this->env->block->sourceName;
$out->sourceLine = $this->env->block->sourceLine;
$out->sourceColumn =
$this->env->block->sourceColumn;
} else {
$out->sourceName = null;
$out->sourceLine = null;
$out->sourceColumn = null;
}
return $out;
}
/**
* Compile root
*
* @param \Leafo\ScssPhp\Block $rootBlock
*/
protected function compileRoot(Block $rootBlock)
{
$this->rootBlock = $this->scope =
$this->makeOutputBlock(Type::T_ROOT);
$this->compileChildrenNoReturn($rootBlock->children,
$this->scope);
$this->flattenSelectors($this->scope);
$this->missingSelectors();
}
/**
* Report missing selectors
*/
protected function missingSelectors()
{
foreach ($this->extends as $extend) {
if (isset($extend[3])) {
continue;
}
list($target, $origin, $block) = $extend;
// ignore if !optional
if ($block[2]) {
continue;
}
$target = implode(' ', $target);
$origin = $this->collapseSelectors($origin);
$this->sourceLine = $block[Parser::SOURCE_LINE];
$this->throwError("\"$origin\" failed to
@extend \"$target\". The selector \"$target\" was not
found.");
}
}
/**
* Flatten selectors
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
* @param string $parentKey
*/
protected function flattenSelectors(OutputBlock $block, $parentKey =
null)
{
if ($block->selectors) {
$selectors = [];
foreach ($block->selectors as $s) {
$selectors[] = $s;
if (! is_array($s)) {
continue;
}
// check extends
if (! empty($this->extendsMap)) {
$this->matchExtends($s, $selectors);
// remove duplicates
array_walk($selectors, function (&$value) {
$value = serialize($value);
});
$selectors = array_unique($selectors);
array_walk($selectors, function (&$value) {
$value = unserialize($value);
});
}
}
$block->selectors = [];
$placeholderSelector = false;
foreach ($selectors as $selector) {
if ($this->hasSelectorPlaceholder($selector)) {
$placeholderSelector = true;
continue;
}
$block->selectors[] =
$this->compileSelector($selector);
}
if ($placeholderSelector && 0 ===
count($block->selectors) && null !== $parentKey) {
unset($block->parent->children[$parentKey]);
return;
}
}
foreach ($block->children as $key => $child) {
$this->flattenSelectors($child, $key);
}
}
/**
* Glue parts of :not( or :nth-child( ... that are in general splitted
in selectors parts
*
* @param array $parts
*
* @return array
*/
protected function glueFunctionSelectors($parts)
{
$new = [];
foreach ($parts as $part) {
if (is_array($part)) {
$part = $this->glueFunctionSelectors($part);
$new[] = $part;
} else {
// a selector part finishing with a ) is the last part of a
:not( or :nth-child(
// and need to be joined to this
if (count($new) && is_string($new[count($new) - 1])
&& strlen($part) && substr($part, -1)
=== ')' && strpos($part, '(') === false
) {
$new[count($new) - 1] .= $part;
} else {
$new[] = $part;
}
}
}
return $new;
}
/**
* Match extends
*
* @param array $selector
* @param array $out
* @param integer $from
* @param boolean $initial
*/
protected function matchExtends($selector, &$out, $from = 0,
$initial = true)
{
static $partsPile = [];
$selector = $this->glueFunctionSelectors($selector);
foreach ($selector as $i => $part) {
if ($i < $from) {
continue;
}
// check that we are not building an infinite loop of
extensions
// if the new part is just including a previous part don't
try to extend anymore
if (count($part) > 1) {
foreach ($partsPile as $previousPart) {
if (! count(array_diff($previousPart, $part))) {
continue 2;
}
}
}
if ($this->matchExtendsSingle($part, $origin)) {
$partsPile[] = $part;
$after = array_slice($selector, $i + 1);
$before = array_slice($selector, 0, $i);
list($before, $nonBreakableBefore) =
$this->extractRelationshipFromFragment($before);
foreach ($origin as $new) {
$k = 0;
// remove shared parts
if (count($new) > 1) {
while ($k < $i && isset($new[$k])
&& $selector[$k] === $new[$k]) {
$k++;
}
}
$replacement = [];
$tempReplacement = $k > 0 ? array_slice($new, $k) :
$new;
for ($l = count($tempReplacement) - 1; $l >= 0;
$l--) {
$slice = [];
foreach ($tempReplacement[$l] as $chunk) {
if (! in_array($chunk, $slice)) {
$slice[] = $chunk;
}
}
array_unshift($replacement, $slice);
if (!
$this->isImmediateRelationshipCombinator(end($slice))) {
break;
}
}
$afterBefore = $l != 0 ? array_slice($tempReplacement,
0, $l) : [];
// Merge shared direct relationships.
$mergedBefore =
$this->mergeDirectRelationships($afterBefore, $nonBreakableBefore);
$result = array_merge(
$before,
$mergedBefore,
$replacement,
$after
);
if ($result === $selector) {
continue;
}
$out[] = $result;
// recursively check for more matches
$startRecurseFrom = count($before) +
min(count($nonBreakableBefore), count($mergedBefore));
$this->matchExtends($result, $out,
$startRecurseFrom, false);
// selector sequence merging
if (! empty($before) && count($new) > 1) {
$preSharedParts = $k > 0 ? array_slice($before,
0, $k) : [];
$postSharedParts = $k > 0 ? array_slice($before,
$k) : $before;
list($betweenSharedParts, $nonBreakable2) =
$this->extractRelationshipFromFragment($afterBefore);
$result2 = array_merge(
$preSharedParts,
$betweenSharedParts,
$postSharedParts,
$nonBreakable2,
$nonBreakableBefore,
$replacement,
$after
);
$out[] = $result2;
}
}
array_pop($partsPile);
}
}
}
/**
* Match extends single
*
* @param array $rawSingle
* @param array $outOrigin
*
* @return boolean
*/
protected function matchExtendsSingle($rawSingle, &$outOrigin)
{
$counts = [];
$single = [];
// simple usual cases, no need to do the whole trick
if (in_array($rawSingle,
[['>'],['+'],['~']])) {
return false;
}
foreach ($rawSingle as $part) {
// matches Number
if (! is_string($part)) {
return false;
}
if (! preg_match('/^[\[.:#%]/', $part) &&
count($single)) {
$single[count($single) - 1] .= $part;
} else {
$single[] = $part;
}
}
$extendingDecoratedTag = false;
if (count($single) > 1) {
$matches = null;
$extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i',
$single[0], $matches) ? $matches[0] : false;
}
foreach ($single as $part) {
if (isset($this->extendsMap[$part])) {
foreach ($this->extendsMap[$part] as $idx) {
$counts[$idx] = isset($counts[$idx]) ? $counts[$idx] +
1 : 1;
}
}
}
$outOrigin = [];
$found = false;
foreach ($counts as $idx => $count) {
list($target, $origin, /* $block */) = $this->extends[$idx];
$origin = $this->glueFunctionSelectors($origin);
// check count
if ($count !== count($target)) {
continue;
}
$this->extends[$idx][3] = true;
$rem = array_diff($single, $target);
foreach ($origin as $j => $new) {
// prevent infinite loop when target extends itself
if ($this->isSelfExtend($single, $origin)) {
return false;
}
$replacement = end($new);
// Extending a decorated tag with another tag is not
possible.
if ($extendingDecoratedTag && $replacement[0] !=
$extendingDecoratedTag &&
preg_match('/^[a-z0-9]+$/i', $replacement[0])
) {
unset($origin[$j]);
continue;
}
$combined = $this->combineSelectorSingle($replacement,
$rem);
if (count(array_diff($combined,
$origin[$j][count($origin[$j]) - 1]))) {
$origin[$j][count($origin[$j]) - 1] = $combined;
}
}
$outOrigin = array_merge($outOrigin, $origin);
$found = true;
}
return $found;
}
/**
* Extract a relationship from the fragment.
*
* When extracting the last portion of a selector we will be left with
a
* fragment which may end with a direction relationship combinator.
This
* method will extract the relationship fragment and return it along
side
* the rest.
*
* @param array $fragment The selector fragment maybe ending with a
direction relationship combinator.
*
* @return array The selector without the relationship fragment if any,
the relationship fragment.
*/
protected function extractRelationshipFromFragment(array $fragment)
{
$parents = [];
$children = [];
$j = $i = count($fragment);
for (;;) {
$children = $j != $i ? array_slice($fragment, $j, $i - $j) :
[];
$parents = array_slice($fragment, 0, $j);
$slice = end($parents);
if (empty($slice) || !
$this->isImmediateRelationshipCombinator($slice[0])) {
break;
}
$j -= 2;
}
return [$parents, $children];
}
/**
* Combine selector single
*
* @param array $base
* @param array $other
*
* @return array
*/
protected function combineSelectorSingle($base, $other)
{
$tag = [];
$out = [];
$wasTag = true;
foreach ([$base, $other] as $single) {
foreach ($single as $part) {
if (preg_match('/^[\[.:#]/', $part)) {
$out[] = $part;
$wasTag = false;
} elseif (preg_match('/^[^_-]/', $part)) {
$tag[] = $part;
$wasTag = true;
} elseif ($wasTag) {
$tag[count($tag) - 1] .= $part;
} else {
$out[count($out) - 1] .= $part;
}
}
}
if (count($tag)) {
array_unshift($out, $tag[0]);
}
return $out;
}
/**
* Compile media
*
* @param \Leafo\ScssPhp\Block $media
*/
protected function compileMedia(Block $media)
{
$this->pushEnv($media);
$mediaQueries =
$this->compileMediaQuery($this->multiplyMedia($this->env));
if (! empty($mediaQueries) && $mediaQueries) {
$previousScope = $this->scope;
$parentScope = $this->mediaParent($this->scope);
foreach ($mediaQueries as $mediaQuery) {
$this->scope = $this->makeOutputBlock(Type::T_MEDIA,
[$mediaQuery]);
$parentScope->children[] = $this->scope;
$parentScope = $this->scope;
}
// top level properties in a media cause it to be wrapped
$needsWrap = false;
foreach ($media->children as $child) {
$type = $child[0];
if ($type !== Type::T_BLOCK &&
$type !== Type::T_MEDIA &&
$type !== Type::T_DIRECTIVE &&
$type !== Type::T_IMPORT
) {
$needsWrap = true;
break;
}
}
if ($needsWrap) {
$wrapped = new Block;
$wrapped->sourceName = $media->sourceName;
$wrapped->sourceIndex = $media->sourceIndex;
$wrapped->sourceLine = $media->sourceLine;
$wrapped->sourceColumn = $media->sourceColumn;
$wrapped->selectors = [];
$wrapped->comments = [];
$wrapped->parent = $media;
$wrapped->children = $media->children;
$media->children = [[Type::T_BLOCK, $wrapped]];
if (isset($this->lineNumberStyle)) {
$annotation =
$this->makeOutputBlock(Type::T_COMMENT);
$annotation->depth = 0;
$file = $this->sourceNames[$media->sourceIndex];
$line = $media->sourceLine;
switch ($this->lineNumberStyle) {
case static::LINE_COMMENTS:
$annotation->lines[] = '/* line '
. $line
. ($file ? ', '
. $file : '')
. ' */';
break;
case static::DEBUG_INFO:
$annotation->lines[] = '@media
-sass-debug-info{'
. ($file ?
'filename{font-family:"' . $file . '"}' :
'')
.
'line{font-family:' . $line . '}}';
break;
}
$this->scope->children[] = $annotation;
}
}
$this->compileChildrenNoReturn($media->children,
$this->scope);
$this->scope = $previousScope;
}
$this->popEnv();
}
/**
* Media parent
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
*
* @return \Leafo\ScssPhp\Formatter\OutputBlock
*/
protected function mediaParent(OutputBlock $scope)
{
while (! empty($scope->parent)) {
if (! empty($scope->type) && $scope->type !==
Type::T_MEDIA) {
break;
}
$scope = $scope->parent;
}
return $scope;
}
/**
* Compile directive
*
* @param \Leafo\ScssPhp\Block $block
*/
protected function compileDirective(Block $block)
{
$s = '@' . $block->name;
if (! empty($block->value)) {
$s .= ' ' . $this->compileValue($block->value);
}
if ($block->name === 'keyframes' ||
substr($block->name, -10) === '-keyframes') {
$this->compileKeyframeBlock($block, [$s]);
} else {
$this->compileNestedBlock($block, [$s]);
}
}
/**
* Compile at-root
*
* @param \Leafo\ScssPhp\Block $block
*/
protected function compileAtRoot(Block $block)
{
$env = $this->pushEnv($block);
$envs = $this->compactEnv($env);
$without = isset($block->with) ?
$this->compileWith($block->with) : static::WITH_RULE;
// wrap inline selector
if ($block->selector) {
$wrapped = new Block;
$wrapped->sourceName = $block->sourceName;
$wrapped->sourceIndex = $block->sourceIndex;
$wrapped->sourceLine = $block->sourceLine;
$wrapped->sourceColumn = $block->sourceColumn;
$wrapped->selectors = $block->selector;
$wrapped->comments = [];
$wrapped->parent = $block;
$wrapped->children = $block->children;
$wrapped->selfParent = $block->selfParent;
$block->children = [[Type::T_BLOCK, $wrapped]];
$block->selector = null;
}
$selfParent = $block->selfParent;
if (! $block->selfParent->selectors &&
isset($block->parent) && $block->parent &&
isset($block->parent->selectors) &&
$block->parent->selectors
) {
$selfParent = $block->parent;
}
$this->env = $this->filterWithout($envs, $without);
$saveScope = $this->scope;
$this->scope = $this->filterScopeWithout($saveScope,
$without);
// propagate selfParent to the children where they still can be
useful
$this->compileChildrenNoReturn($block->children,
$this->scope, $selfParent);
$this->scope = $this->completeScope($this->scope,
$saveScope);
$this->scope = $saveScope;
$this->env = $this->extractEnv($envs);
$this->popEnv();
}
/**
* Filter at-root scope depending of with/without option
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
* @param mixed $without
*
* @return mixed
*/
protected function filterScopeWithout($scope, $without)
{
$filteredScopes = [];
if ($scope->type === TYPE::T_ROOT) {
return $scope;
}
// start from the root
while ($scope->parent && $scope->parent->type !==
TYPE::T_ROOT) {
$scope = $scope->parent;
}
for (;;) {
if (! $scope) {
break;
}
if (! $this->isWithout($without, $scope)) {
$s = clone $scope;
$s->children = [];
$s->lines = [];
$s->parent = null;
if ($s->type !== Type::T_MEDIA && $s->type
!== Type::T_DIRECTIVE) {
$s->selectors = [];
}
$filteredScopes[] = $s;
}
if ($scope->children) {
$scope = end($scope->children);
} else {
$scope = null;
}
}
if (! count($filteredScopes)) {
return $this->rootBlock;
}
$newScope = array_shift($filteredScopes);
$newScope->parent = $this->rootBlock;
$this->rootBlock->children[] = $newScope;
$p = &$newScope;
while (count($filteredScopes)) {
$s = array_shift($filteredScopes);
$s->parent = $p;
$p->children[] = &$s;
$p = $s;
}
return $newScope;
}
/**
* found missing selector from a at-root compilation in the previous
scope
* (if at-root is just enclosing a property, the selector is in the
parent tree)
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
* @param \Leafo\ScssPhp\Formatter\OutputBlock $previousScope
*
* @return mixed
*/
protected function completeScope($scope, $previousScope)
{
if (! $scope->type && (! $scope->selectors || !
count($scope->selectors)) && count($scope->lines)) {
$scope->selectors =
$this->findScopeSelectors($previousScope, $scope->depth);
}
if ($scope->children) {
foreach ($scope->children as $k => $c) {
$scope->children[$k] = $this->completeScope($c,
$previousScope);
}
}
return $scope;
}
/**
* Find a selector by the depth node in the scope
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $scope
* @param integer $depth
*
* @return array
*/
protected function findScopeSelectors($scope, $depth)
{
if ($scope->depth === $depth && $scope->selectors) {
return $scope->selectors;
}
if ($scope->children) {
foreach (array_reverse($scope->children) as $c) {
if ($s = $this->findScopeSelectors($c, $depth)) {
return $s;
}
}
}
return [];
}
/**
* Compile @at-root's with: inclusion / without: exclusion into
filter flags
*
* @param array $with
*
* @return integer
*/
protected function compileWith($with)
{
static $mapping = [
'rule' => self::WITH_RULE,
'media' => self::WITH_MEDIA,
'supports' => self::WITH_SUPPORTS,
'all' => self::WITH_ALL,
];
// exclude selectors by default
$without = static::WITH_RULE;
if ($this->libMapHasKey([$with, static::$with])) {
$without = static::WITH_ALL;
$list = $this->coerceList($this->libMapGet([$with,
static::$with]));
foreach ($list[2] as $item) {
$keyword =
$this->compileStringContent($this->coerceString($item));
if (array_key_exists($keyword, $mapping)) {
$without &= ~($mapping[$keyword]);
}
}
}
if ($this->libMapHasKey([$with, static::$without])) {
$without = 0;
$list = $this->coerceList($this->libMapGet([$with,
static::$without]));
foreach ($list[2] as $item) {
$keyword =
$this->compileStringContent($this->coerceString($item));
if (array_key_exists($keyword, $mapping)) {
$without |= $mapping[$keyword];
}
}
}
return $without;
}
/**
* Filter env stack
*
* @param array $envs
* @param integer $without
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function filterWithout($envs, $without)
{
$filtered = [];
foreach ($envs as $e) {
if ($e->block && $this->isWithout($without,
$e->block)) {
$ec = clone $e;
$ec->block = null;
$ec->selectors = [];
$filtered[] = $ec;
} else {
$filtered[] = $e;
}
}
return $this->extractEnv($filtered);
}
/**
* Filter WITH rules
*
* @param integer
$without
* @param \Leafo\ScssPhp\Block|\Leafo\ScssPhp\Formatter\OutputBlock
$block
*
* @return boolean
*/
protected function isWithout($without, $block)
{
if (isset($block->type)) {
if ($block->type === Type::T_MEDIA) {
return ($without & static::WITH_MEDIA) ? true : false;
}
if ($block->type === Type::T_DIRECTIVE) {
if (isset($block->name) && $block->name ===
'supports') {
return ($without & static::WITH_SUPPORTS) ? true :
false;
}
if (isset($block->selectors) &&
strpos(serialize($block->selectors), '@supports') !== false) {
return ($without & static::WITH_SUPPORTS) ? true :
false;
}
}
}
if ((($without & static::WITH_RULE) &&
isset($block->selectors))) {
return true;
}
return false;
}
/**
* Compile keyframe block
*
* @param \Leafo\ScssPhp\Block $block
* @param array $selectors
*/
protected function compileKeyframeBlock(Block $block, $selectors)
{
$env = $this->pushEnv($block);
$envs = $this->compactEnv($env);
$this->env = $this->extractEnv(array_filter($envs, function
(Environment $e) {
return ! isset($e->block->selectors);
}));
$this->scope = $this->makeOutputBlock($block->type,
$selectors);
$this->scope->depth = 1;
$this->scope->parent->children[] = $this->scope;
$this->compileChildrenNoReturn($block->children,
$this->scope);
$this->scope = $this->scope->parent;
$this->env = $this->extractEnv($envs);
$this->popEnv();
}
/**
* Compile nested block
*
* @param \Leafo\ScssPhp\Block $block
* @param array $selectors
*/
protected function compileNestedBlock(Block $block, $selectors)
{
$this->pushEnv($block);
$this->scope = $this->makeOutputBlock($block->type,
$selectors);
$this->scope->parent->children[] = $this->scope;
// wrap assign children in a block
// except for @font-face
if ($block->type !== Type::T_DIRECTIVE || $block->name !==
"font-face") {
// need wrapping?
$needWrapping = false;
foreach ($block->children as $child) {
if ($child[0] === Type::T_ASSIGN) {
$needWrapping = true;
break;
}
}
if ($needWrapping) {
$wrapped = new Block;
$wrapped->sourceName = $block->sourceName;
$wrapped->sourceIndex = $block->sourceIndex;
$wrapped->sourceLine = $block->sourceLine;
$wrapped->sourceColumn = $block->sourceColumn;
$wrapped->selectors = [];
$wrapped->comments = [];
$wrapped->parent = $block;
$wrapped->children = $block->children;
$wrapped->selfParent = $block->selfParent;
$block->children = [[Type::T_BLOCK, $wrapped]];
}
}
$this->compileChildrenNoReturn($block->children,
$this->scope);
$this->scope = $this->scope->parent;
$this->popEnv();
}
/**
* Recursively compiles a block.
*
* A block is analogous to a CSS block in most cases. A single SCSS
document
* is encapsulated in a block when parsed, but it does not have parent
tags
* so all of its children appear on the root level when compiled.
*
* Blocks are made up of selectors and children.
*
* The children of a block are just all the blocks that are defined
within.
*
* Compiling the block involves pushing a fresh environment on the
stack,
* and iterating through the props, compiling each one.
*
* @see Compiler::compileChild()
*
* @param \Leafo\ScssPhp\Block $block
*/
protected function compileBlock(Block $block)
{
$env = $this->pushEnv($block);
$env->selectors = $this->evalSelectors($block->selectors);
$out = $this->makeOutputBlock(null);
if (isset($this->lineNumberStyle) &&
count($env->selectors) && count($block->children)) {
$annotation = $this->makeOutputBlock(Type::T_COMMENT);
$annotation->depth = 0;
$file = $this->sourceNames[$block->sourceIndex];
$line = $block->sourceLine;
switch ($this->lineNumberStyle) {
case static::LINE_COMMENTS:
$annotation->lines[] = '/* line ' . $line
. ($file ? ', ' . $file
: '')
. ' */';
break;
case static::DEBUG_INFO:
$annotation->lines[] = '@media
-sass-debug-info{'
. ($file ?
'filename{font-family:"' . $file . '"}' :
'')
. 'line{font-family:' .
$line . '}}';
break;
}
$this->scope->children[] = $annotation;
}
$this->scope->children[] = $out;
if (count($block->children)) {
$out->selectors = $this->multiplySelectors($env,
$block->selfParent);
// propagate selfParent to the children where they still can be
useful
$selfParentSelectors = null;
if (isset($block->selfParent->selectors)) {
$selfParentSelectors = $block->selfParent->selectors;
$block->selfParent->selectors = $out->selectors;
}
$this->compileChildrenNoReturn($block->children, $out,
$block->selfParent);
// and revert for the following childs of the same block
if ($selfParentSelectors) {
$block->selfParent->selectors = $selfParentSelectors;
}
}
$this->formatter->stripSemicolon($out->lines);
$this->popEnv();
}
/**
* Compile root level comment
*
* @param array $block
*/
protected function compileComment($block)
{
$out = $this->makeOutputBlock(Type::T_COMMENT);
$out->lines[] = is_string($block[1]) ? $block[1] :
$this->compileValue($block[1]);
$this->scope->children[] = $out;
}
/**
* Evaluate selectors
*
* @param array $selectors
*
* @return array
*/
protected function evalSelectors($selectors)
{
$this->shouldEvaluate = false;
$selectors = array_map([$this, 'evalSelector'],
$selectors);
// after evaluating interpolates, we might need a second pass
if ($this->shouldEvaluate) {
$selectors = $this->revertSelfSelector($selectors);
$buffer = $this->collapseSelectors($selectors);
$parser = $this->parserFactory(__METHOD__);
if ($parser->parseSelector($buffer, $newSelectors)) {
$selectors = array_map([$this, 'evalSelector'],
$newSelectors);
}
}
return $selectors;
}
/**
* Evaluate selector
*
* @param array $selector
*
* @return array
*/
protected function evalSelector($selector)
{
return array_map([$this, 'evalSelectorPart'], $selector);
}
/**
* Evaluate selector part; replaces all the interpolates, stripping
quotes
*
* @param array $part
*
* @return array
*/
protected function evalSelectorPart($part)
{
foreach ($part as &$p) {
if (is_array($p) && ($p[0] === Type::T_INTERPOLATE ||
$p[0] === Type::T_STRING)) {
$p = $this->compileValue($p);
// force re-evaluation
if (strpos($p, '&') !== false || strpos($p,
',') !== false) {
$this->shouldEvaluate = true;
}
} elseif (is_string($p) && strlen($p) >= 2
&&
($first = $p[0]) && ($first === '"'
|| $first === "'") &&
substr($p, -1) === $first
) {
$p = substr($p, 1, -1);
}
}
return $this->flattenSelectorSingle($part);
}
/**
* Collapse selectors
*
* @param array $selectors
* @param boolean $selectorFormat
* if false return a collapsed string
* if true return an array description of a structured selector
*
* @return string
*/
protected function collapseSelectors($selectors, $selectorFormat =
false)
{
$parts = [];
foreach ($selectors as $selector) {
$output = [];
$glueNext = false;
foreach ($selector as $node) {
$compound = '';
array_walk_recursive(
$node,
function ($value, $key) use (&$compound) {
$compound .= $value;
}
);
if ($selectorFormat &&
$this->isImmediateRelationshipCombinator($compound)) {
if (count($output)) {
$output[count($output) - 1] .= ' ' .
$compound;
} else {
$output[] = $compound;
}
$glueNext = true;
} elseif ($glueNext) {
$output[count($output) - 1] .= ' ' .
$compound;
$glueNext = false;
} else {
$output[] = $compound;
}
}
if ($selectorFormat) {
foreach ($output as &$o) {
$o = [Type::T_STRING, '', [$o]];
}
$output = [Type::T_LIST, ' ', $output];
} else {
$output = implode(' ', $output);
}
$parts[] = $output;
}
if ($selectorFormat) {
$parts = [Type::T_LIST, ',', $parts];
} else {
$parts = implode(', ', $parts);
}
return $parts;
}
/**
* Parse down the selector and revert [self] to "&"
before a reparsing
*
* @param array $selectors
*
* @return array
*/
protected function revertSelfSelector($selectors)
{
foreach ($selectors as &$part) {
if (is_array($part)) {
if ($part === [Type::T_SELF]) {
$part = '&';
} else {
$part = $this->revertSelfSelector($part);
}
}
}
return $selectors;
}
/**
* Flatten selector single; joins together .classes and #ids
*
* @param array $single
*
* @return array
*/
protected function flattenSelectorSingle($single)
{
$joined = [];
foreach ($single as $part) {
if (empty($joined) ||
! is_string($part) ||
preg_match('/[\[.:#%]/', $part)
) {
$joined[] = $part;
continue;
}
if (is_array(end($joined))) {
$joined[] = $part;
} else {
$joined[count($joined) - 1] .= $part;
}
}
return $joined;
}
/**
* Compile selector to string; self(&) should have been replaced by
now
*
* @param string|array $selector
*
* @return string
*/
protected function compileSelector($selector)
{
if (! is_array($selector)) {
return $selector; // media and the like
}
return implode(
' ',
array_map(
[$this, 'compileSelectorPart'],
$selector
)
);
}
/**
* Compile selector part
*
* @param array $piece
*
* @return string
*/
protected function compileSelectorPart($piece)
{
foreach ($piece as &$p) {
if (! is_array($p)) {
continue;
}
switch ($p[0]) {
case Type::T_SELF:
$p = '&';
break;
default:
$p = $this->compileValue($p);
break;
}
}
return implode($piece);
}
/**
* Has selector placeholder?
*
* @param array $selector
*
* @return boolean
*/
protected function hasSelectorPlaceholder($selector)
{
if (! is_array($selector)) {
return false;
}
foreach ($selector as $parts) {
foreach ($parts as $part) {
if (strlen($part) && '%' === $part[0]) {
return true;
}
}
}
return false;
}
protected function pushCallStack($name = '')
{
$this->callStack[] = [
'n' => $name,
Parser::SOURCE_INDEX => $this->sourceIndex,
Parser::SOURCE_LINE => $this->sourceLine,
Parser::SOURCE_COLUMN => $this->sourceColumn
];
// infinite calling loop
if (count($this->callStack) > 25000) {
// not displayed but you can var_dump it to deep debug
$msg = $this->callStackMessage(true, 100);
$msg = "Infinite calling loop";
$this->throwError($msg);
}
}
protected function popCallStack()
{
array_pop($this->callStack);
}
/**
* Compile children and return result
*
* @param array $stms
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
* @param string $traceName
*
* @return array|null
*/
protected function compileChildren($stms, OutputBlock $out, $traceName
= '')
{
$this->pushCallStack($traceName);
foreach ($stms as $stm) {
$ret = $this->compileChild($stm, $out);
if (isset($ret)) {
return $ret;
}
}
$this->popCallStack();
return null;
}
/**
* Compile children and throw exception if unexpected @return
*
* @param array $stms
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
* @param \Leafo\ScssPhp\Block $selfParent
* @param string $traceName
*
* @throws \Exception
*/
protected function compileChildrenNoReturn($stms, OutputBlock $out,
$selfParent = null, $traceName = '')
{
$this->pushCallStack($traceName);
foreach ($stms as $stm) {
if ($selfParent && isset($stm[1]) &&
is_object($stm[1]) && $stm[1] instanceof Block) {
$stm[1]->selfParent = $selfParent;
$ret = $this->compileChild($stm, $out);
$stm[1]->selfParent = null;
} elseif ($selfParent && $stm[0] === TYPE::T_INCLUDE) {
$stm['selfParent'] = $selfParent;
$ret = $this->compileChild($stm, $out);
unset($stm['selfParent']);
} else {
$ret = $this->compileChild($stm, $out);
}
if (isset($ret)) {
$this->throwError('@return may only be used within
a function');
return;
}
}
$this->popCallStack();
}
/**
* evaluate media query : compile internal value keeping the structure
inchanged
*
* @param array $queryList
*
* @return array
*/
protected function evaluateMediaQuery($queryList)
{
foreach ($queryList as $kql => $query) {
foreach ($query as $kq => $q) {
for ($i = 1; $i < count($q); $i++) {
$value = $this->compileValue($q[$i]);
// the parser had no mean to know if media type or
expression if it was an interpolation
if ($q[0] == Type::T_MEDIA_TYPE &&
(strpos($value, '(') !== false ||
strpos($value, ')') !== false ||
strpos($value, ':') !== false)
) {
$queryList[$kql][$kq][0] =
Type::T_MEDIA_EXPRESSION;
if (strpos($value, 'and') !== false) {
$values = explode('and', $value);
$value = trim(array_pop($values));
while ($v = trim(array_pop($values))) {
$type = Type::T_MEDIA_EXPRESSION;
if (strpos($v, '(') === false
&&
strpos($v, ')') === false
&&
strpos($v, ':') === false
) {
$type = Type::T_MEDIA_TYPE;
}
if (substr($v, 0, 1) === '('
&& substr($v, -1) === ')') {
$v = substr($v, 1, -1);
}
$queryList[$kql][] =
[$type,[Type::T_KEYWORD, $v]];
}
}
if (substr($value, 0, 1) === '('
&& substr($value, -1) === ')') {
$value = substr($value, 1, -1);
}
}
$queryList[$kql][$kq][$i] = [Type::T_KEYWORD, $value];
}
}
}
return $queryList;
}
/**
* Compile media query
*
* @param array $queryList
*
* @return array
*/
protected function compileMediaQuery($queryList)
{
$start = '@media ';
$default = trim($start);
$out = [];
$current = "";
foreach ($queryList as $query) {
$type = null;
$parts = [];
$mediaTypeOnly = true;
foreach ($query as $q) {
if ($q[0] !== Type::T_MEDIA_TYPE) {
$mediaTypeOnly = false;
break;
}
}
foreach ($query as $q) {
switch ($q[0]) {
case Type::T_MEDIA_TYPE:
$newType = array_map([$this,
'compileValue'], array_slice($q, 1));
// combining not and anything else than media type
is too risky and should be avoided
if (! $mediaTypeOnly) {
if (in_array(Type::T_NOT, $newType) || ($type
&& in_array(Type::T_NOT, $type) )) {
if ($type) {
array_unshift($parts, implode('
', array_filter($type)));
}
if (! empty($parts)) {
if (strlen($current)) {
$current .=
$this->formatter->tagSeparator;
}
$current .= implode(' and ',
$parts);
}
if ($current) {
$out[] = $start . $current;
}
$current = "";
$type = null;
$parts = [];
}
}
if ($newType === ['all'] &&
$default) {
$default = $start . 'all';
}
// all can be safely ignored and mixed with
whatever else
if ($newType !== ['all']) {
if ($type) {
$type = $this->mergeMediaTypes($type,
$newType);
if (empty($type)) {
// merge failed : ignore this query
that is not valid, skip to the next one
$parts = [];
$default = ''; // if
everything fail, no @media at all
continue 3;
}
} else {
$type = $newType;
}
}
break;
case Type::T_MEDIA_EXPRESSION:
if (isset($q[2])) {
$parts[] = '('
. $this->compileValue($q[1])
. $this->formatter->assignSeparator
. $this->compileValue($q[2])
. ')';
} else {
$parts[] = '('
. $this->compileValue($q[1])
. ')';
}
break;
case Type::T_MEDIA_VALUE:
$parts[] = $this->compileValue($q[1]);
break;
}
}
if ($type) {
array_unshift($parts, implode(' ',
array_filter($type)));
}
if (! empty($parts)) {
if (strlen($current)) {
$current .= $this->formatter->tagSeparator;
}
$current .= implode(' and ', $parts);
}
}
if ($current) {
$out[] = $start . $current;
}
// no @media type except all, and no conflict?
if (! $out && $default) {
$out[] = $default;
}
return $out;
}
/**
* Merge direct relationships between selectors
*
* @param array $selectors1
* @param array $selectors2
*
* @return array
*/
protected function mergeDirectRelationships($selectors1, $selectors2)
{
if (empty($selectors1) || empty($selectors2)) {
return array_merge($selectors1, $selectors2);
}
$part1 = end($selectors1);
$part2 = end($selectors2);
if (! $this->isImmediateRelationshipCombinator($part1[0])
&& $part1 !== $part2) {
return array_merge($selectors1, $selectors2);
}
$merged = [];
do {
$part1 = array_pop($selectors1);
$part2 = array_pop($selectors2);
if (! $this->isImmediateRelationshipCombinator($part1[0])
&& $part1 !== $part2) {
if
($this->isImmediateRelationshipCombinator(reset($merged)[0])) {
array_unshift($merged, [$part1[0] . $part2[0]]);
$merged = array_merge($selectors1, $selectors2,
$merged);
} else {
$merged = array_merge($selectors1, [$part1],
$selectors2, [$part2], $merged);
}
break;
}
array_unshift($merged, $part1);
} while (! empty($selectors1) && ! empty($selectors2));
return $merged;
}
/**
* Merge media types
*
* @param array $type1
* @param array $type2
*
* @return array|null
*/
protected function mergeMediaTypes($type1, $type2)
{
if (empty($type1)) {
return $type2;
}
if (empty($type2)) {
return $type1;
}
$m1 = '';
$t1 = '';
if (count($type1) > 1) {
$m1= strtolower($type1[0]);
$t1= strtolower($type1[1]);
} else {
$t1 = strtolower($type1[0]);
}
$m2 = '';
$t2 = '';
if (count($type2) > 1) {
$m2 = strtolower($type2[0]);
$t2 = strtolower($type2[1]);
} else {
$t2 = strtolower($type2[0]);
}
if (($m1 === Type::T_NOT) ^ ($m2 === Type::T_NOT)) {
if ($t1 === $t2) {
return null;
}
return [
$m1 === Type::T_NOT ? $m2 : $m1,
$m1 === Type::T_NOT ? $t2 : $t1,
];
}
if ($m1 === Type::T_NOT && $m2 === Type::T_NOT) {
// CSS has no way of representing "neither screen nor
print"
if ($t1 !== $t2) {
return null;
}
return [Type::T_NOT, $t1];
}
if ($t1 !== $t2) {
return null;
}
// t1 == t2, neither m1 nor m2 are "not"
return [empty($m1)? $m2 : $m1, $t1];
}
/**
* Compile import; returns true if the value was something that could
be imported
*
* @param array $rawPath
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
* @param boolean $once
*
* @return boolean
*/
protected function compileImport($rawPath, OutputBlock $out, $once =
false)
{
if ($rawPath[0] === Type::T_STRING) {
$path = $this->compileStringContent($rawPath);
if ($path = $this->findImport($path)) {
if (! $once || ! in_array($path, $this->importedFiles))
{
$this->importFile($path, $out);
$this->importedFiles[] = $path;
}
return true;
}
return false;
}
if ($rawPath[0] === Type::T_LIST) {
// handle a list of strings
if (count($rawPath[2]) === 0) {
return false;
}
foreach ($rawPath[2] as $path) {
if ($path[0] !== Type::T_STRING) {
return false;
}
}
foreach ($rawPath[2] as $path) {
$this->compileImport($path, $out);
}
return true;
}
return false;
}
/**
* Compile child; returns a value to halt execution
*
* @param array $child
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
*
* @return array
*/
protected function compileChild($child, OutputBlock $out)
{
if (isset($child[Parser::SOURCE_LINE])) {
$this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ?
$child[Parser::SOURCE_INDEX] : null;
$this->sourceLine = isset($child[Parser::SOURCE_LINE]) ?
$child[Parser::SOURCE_LINE] : -1;
$this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ?
$child[Parser::SOURCE_COLUMN] : -1;
} elseif (is_array($child) &&
isset($child[1]->sourceLine)) {
$this->sourceIndex = $child[1]->sourceIndex;
$this->sourceLine = $child[1]->sourceLine;
$this->sourceColumn = $child[1]->sourceColumn;
} elseif (! empty($out->sourceLine) && !
empty($out->sourceName)) {
$this->sourceLine = $out->sourceLine;
$this->sourceIndex = array_search($out->sourceName,
$this->sourceNames);
if ($this->sourceIndex === false) {
$this->sourceIndex = null;
}
}
switch ($child[0]) {
case Type::T_SCSSPHP_IMPORT_ONCE:
$rawPath = $this->reduce($child[1]);
if (! $this->compileImport($rawPath, $out, true)) {
$out->lines[] = '@import ' .
$this->compileValue($rawPath) . ';';
}
break;
case Type::T_IMPORT:
$rawPath = $this->reduce($child[1]);
if (! $this->compileImport($rawPath, $out)) {
$out->lines[] = '@import ' .
$this->compileValue($rawPath) . ';';
}
break;
case Type::T_DIRECTIVE:
$this->compileDirective($child[1]);
break;
case Type::T_AT_ROOT:
$this->compileAtRoot($child[1]);
break;
case Type::T_MEDIA:
$this->compileMedia($child[1]);
break;
case Type::T_BLOCK:
$this->compileBlock($child[1]);
break;
case Type::T_CHARSET:
if (! $this->charsetSeen) {
$this->charsetSeen = true;
$out->lines[] = '@charset ' .
$this->compileValue($child[1]) . ';';
}
break;
case Type::T_ASSIGN:
list(, $name, $value) = $child;
if ($name[0] === Type::T_VARIABLE) {
$flags = isset($child[3]) ? $child[3] : [];
$isDefault = in_array('!default', $flags);
$isGlobal = in_array('!global', $flags);
if ($isGlobal) {
$this->set($name[1], $this->reduce($value),
false, $this->rootEnv, $value);
break;
}
$shouldSet = $isDefault &&
(($result = $this->get($name[1], false)) ===
null
|| $result === static::$null);
if (! $isDefault || $shouldSet) {
$this->set($name[1], $this->reduce($value),
true, null, $value);
}
break;
}
$compiledName = $this->compileValue($name);
// handle shorthand syntax: size / line-height
if ($compiledName === 'font' || $compiledName ===
'grid-row' || $compiledName === 'grid-column') {
if ($value[0] === Type::T_VARIABLE) {
// if the font value comes from variable, the
content is already reduced
// (i.e., formulas were already calculated), so we
need the original unreduced value
$value = $this->get($value[1], true, null,
true);
}
$fontValue=&$value;
if ($value[0] === Type::T_LIST &&
$value[1]==',') {
// this is the case if more than one font is given:
example: "font: 400 1em/1.3 arial,helvetica"
// we need to handle the first list element
$fontValue=&$value[2][0];
}
if ($fontValue[0] === Type::T_EXPRESSION &&
$fontValue[1] === '/') {
$fontValue = $this->expToString($fontValue);
} elseif ($fontValue[0] === Type::T_LIST) {
foreach ($fontValue[2] as &$item) {
if ($item[0] === Type::T_EXPRESSION &&
$item[1] === '/') {
$item = $this->expToString($item);
}
}
}
}
// if the value reduces to null from something else then
// the property should be discarded
if ($value[0] !== Type::T_NULL) {
$value = $this->reduce($value);
if ($value[0] === Type::T_NULL || $value ===
static::$nullString) {
break;
}
}
$compiledValue = $this->compileValue($value);
$out->lines[] = $this->formatter->property(
$compiledName,
$compiledValue
);
break;
case Type::T_COMMENT:
if ($out->type === Type::T_ROOT) {
$this->compileComment($child);
break;
}
$out->lines[] = $child[1];
break;
case Type::T_MIXIN:
case Type::T_FUNCTION:
list(, $block) = $child;
$this->set(static::$namespaces[$block->type] .
$block->name, $block);
break;
case Type::T_EXTEND:
foreach ($child[1] as $sel) {
$results = $this->evalSelectors([$sel]);
foreach ($results as $result) {
// only use the first one
$result = current($result);
$this->pushExtends($result, $out->selectors,
$child);
}
}
break;
case Type::T_IF:
list(, $if) = $child;
if ($this->isTruthy($this->reduce($if->cond,
true))) {
return $this->compileChildren($if->children,
$out);
}
foreach ($if->cases as $case) {
if ($case->type === Type::T_ELSE ||
$case->type === Type::T_ELSEIF &&
$this->isTruthy($this->reduce($case->cond))
) {
return
$this->compileChildren($case->children, $out);
}
}
break;
case Type::T_EACH:
list(, $each) = $child;
$list =
$this->coerceList($this->reduce($each->list));
$this->pushEnv();
foreach ($list[2] as $item) {
if (count($each->vars) === 1) {
$this->set($each->vars[0], $item, true);
} else {
list(,, $values) = $this->coerceList($item);
foreach ($each->vars as $i => $var) {
$this->set($var, isset($values[$i]) ?
$values[$i] : static::$null, true);
}
}
$ret = $this->compileChildren($each->children,
$out);
if ($ret) {
if ($ret[0] !== Type::T_CONTROL) {
$this->popEnv();
return $ret;
}
if ($ret[1]) {
break;
}
}
}
$this->popEnv();
break;
case Type::T_WHILE:
list(, $while) = $child;
while ($this->isTruthy($this->reduce($while->cond,
true))) {
$ret = $this->compileChildren($while->children,
$out);
if ($ret) {
if ($ret[0] !== Type::T_CONTROL) {
return $ret;
}
if ($ret[1]) {
break;
}
}
}
break;
case Type::T_FOR:
list(, $for) = $child;
$start = $this->reduce($for->start, true);
$end = $this->reduce($for->end, true);
if (! ($start[2] == $end[2] || $end->unitless())) {
$this->throwError('Incompatible units:
"%s" and "%s".', $start->unitStr(),
$end->unitStr());
break;
}
$unit = $start[2];
$start = $start[1];
$end = $end[1];
$d = $start < $end ? 1 : -1;
for (;;) {
if ((! $for->until && $start - $d == $end)
||
($for->until && $start == $end)
) {
break;
}
$this->set($for->var, new Node\Number($start,
$unit));
$start += $d;
$ret = $this->compileChildren($for->children,
$out);
if ($ret) {
if ($ret[0] !== Type::T_CONTROL) {
return $ret;
}
if ($ret[1]) {
break;
}
}
}
break;
case Type::T_BREAK:
return [Type::T_CONTROL, true];
case Type::T_CONTINUE:
return [Type::T_CONTROL, false];
case Type::T_RETURN:
return $this->reduce($child[1], true);
case Type::T_NESTED_PROPERTY:
list(, $prop) = $child;
$prefixed = [];
$prefix = $this->compileValue($prop->prefix) .
'-';
foreach ($prop->children as $child) {
switch ($child[0]) {
case Type::T_ASSIGN:
array_unshift($child[1][2], $prefix);
break;
case Type::T_NESTED_PROPERTY:
array_unshift($child[1]->prefix[2],
$prefix);
break;
}
$prefixed[] = $child;
}
$this->compileChildrenNoReturn($prefixed, $out);
break;
case Type::T_INCLUDE:
// including a mixin
list(, $name, $argValues, $content) = $child;
$mixin =
$this->get(static::$namespaces['mixin'] . $name, false);
if (! $mixin) {
$this->throwError("Undefined mixin
$name");
break;
}
$callingScope = $this->getStoreEnv();
// push scope, apply args
$this->pushEnv();
$this->env->depth--;
$storeEnv = $this->storeEnv;
$this->storeEnv = $this->env;
// Find the parent selectors in the env to be able to know
what '&' refers to in the mixin
// and assign this fake parent to childs
$selfParent = null;
if (isset($child['selfParent']) &&
isset($child['selfParent']->selectors)) {
$selfParent = $child['selfParent'];
} else {
$parentSelectors =
$this->multiplySelectors($this->env);
if ($parentSelectors) {
$parent = new Block();
$parent->selectors = $parentSelectors;
foreach ($mixin->children as $k => $child) {
if (isset($child[1]) &&
is_object($child[1]) && $child[1] instanceof Block) {
$mixin->children[$k][1]->parent =
$parent;
}
}
}
}
// clone the stored content to not have its scope spoiled
by a further call to the same mixin
// i.e., recursive @include of the same mixin
if (isset($content)) {
$copyContent = clone $content;
$copyContent->scope = $callingScope;
$this->setRaw(static::$namespaces['special'] .
'content', $copyContent, $this->env);
}
if (isset($mixin->args)) {
$this->applyArguments($mixin->args, $argValues);
}
$this->env->marker = 'mixin';
$this->compileChildrenNoReturn($mixin->children,
$out, $selfParent, $this->env->marker . " " . $name);
$this->storeEnv = $storeEnv;
$this->popEnv();
break;
case Type::T_MIXIN_CONTENT:
$env = isset($this->storeEnv) ? $this->storeEnv :
$this->env;
$content =
$this->get(static::$namespaces['special'] .
'content', false, $env);
if (! $content) {
$content = new \stdClass();
$content->scope = new \stdClass();
$content->children =
$this->storeEnv->parent->block->children;
break;
}
$storeEnv = $this->storeEnv;
$this->storeEnv = $content->scope;
$this->compileChildrenNoReturn($content->children,
$out);
$this->storeEnv = $storeEnv;
break;
case Type::T_DEBUG:
list(, $value) = $child;
$fname = $this->sourceNames[$this->sourceIndex];
$line = $this->sourceLine;
$value = $this->compileValue($this->reduce($value,
true));
fwrite($this->stderr, "File $fname on line $line
DEBUG: $value\n");
break;
case Type::T_WARN:
list(, $value) = $child;
$fname = $this->sourceNames[$this->sourceIndex];
$line = $this->sourceLine;
$value = $this->compileValue($this->reduce($value,
true));
fwrite($this->stderr, "File $fname on line $line
WARN: $value\n");
break;
case Type::T_ERROR:
list(, $value) = $child;
$fname = $this->sourceNames[$this->sourceIndex];
$line = $this->sourceLine;
$value = $this->compileValue($this->reduce($value,
true));
$this->throwError("File $fname on line $line ERROR:
$value\n");
break;
case Type::T_CONTROL:
$this->throwError('@break/@continue not permitted
in this scope');
break;
default:
$this->throwError("unknown child type:
$child[0]");
}
}
/**
* Reduce expression to string
*
* @param array $exp
*
* @return array
*/
protected function expToString($exp)
{
list(, $op, $left, $right, /* $inParens */, $whiteLeft,
$whiteRight) = $exp;
$content = [$this->reduce($left)];
if ($whiteLeft) {
$content[] = ' ';
}
$content[] = $op;
if ($whiteRight) {
$content[] = ' ';
}
$content[] = $this->reduce($right);
return [Type::T_STRING, '', $content];
}
/**
* Is truthy?
*
* @param array $value
*
* @return boolean
*/
protected function isTruthy($value)
{
return $value !== static::$false && $value !==
static::$null;
}
/**
* Is the value a direct relationship combinator?
*
* @param string $value
*
* @return boolean
*/
protected function isImmediateRelationshipCombinator($value)
{
return $value === '>' || $value === '+' ||
$value === '~';
}
/**
* Should $value cause its operand to eval
*
* @param array $value
*
* @return boolean
*/
protected function shouldEval($value)
{
switch ($value[0]) {
case Type::T_EXPRESSION:
if ($value[1] === '/') {
return $this->shouldEval($value[2]) ||
$this->shouldEval($value[3]);
}
// fall-thru
case Type::T_VARIABLE:
case Type::T_FUNCTION_CALL:
return true;
}
return false;
}
/**
* Reduce value
*
* @param array $value
* @param boolean $inExp
*
* @return array|\Leafo\ScssPhp\Node\Number
*/
protected function reduce($value, $inExp = false)
{
switch ($value[0]) {
case Type::T_EXPRESSION:
list(, $op, $left, $right, $inParens) = $value;
$opName = isset(static::$operatorNames[$op]) ?
static::$operatorNames[$op] : $op;
$inExp = $inExp || $this->shouldEval($left) ||
$this->shouldEval($right);
$left = $this->reduce($left, true);
if ($op !== 'and' && $op !==
'or') {
$right = $this->reduce($right, true);
}
// special case: looks like css shorthand
if ($opName == 'div' && ! $inParens
&& ! $inExp && isset($right[2])
&& (($right[0] !== Type::T_NUMBER &&
$right[2] != '')
|| ($right[0] === Type::T_NUMBER && !
$right->unitless()))
) {
return $this->expToString($value);
}
$left = $this->coerceForExpression($left);
$right = $this->coerceForExpression($right);
$ltype = $left[0];
$rtype = $right[0];
$ucOpName = ucfirst($opName);
$ucLType = ucfirst($ltype);
$ucRType = ucfirst($rtype);
// this tries:
// 1. op[op name][left type][right type]
// 2. op[left type][right type] (passing the op as first
arg
// 3. op[op name]
$fn = "op${ucOpName}${ucLType}${ucRType}";
if (is_callable([$this, $fn]) ||
(($fn = "op${ucLType}${ucRType}") &&
is_callable([$this, $fn]) &&
$passOp = true) ||
(($fn = "op${ucOpName}") &&
is_callable([$this, $fn]) &&
$genOp = true)
) {
$coerceUnit = false;
if (! isset($genOp) &&
$left[0] === Type::T_NUMBER && $right[0]
=== Type::T_NUMBER
) {
$coerceUnit = true;
switch ($opName) {
case 'mul':
$targetUnit = $left[2];
foreach ($right[2] as $unit => $exp) {
$targetUnit[$unit] =
(isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) + $exp;
}
break;
case 'div':
$targetUnit = $left[2];
foreach ($right[2] as $unit => $exp) {
$targetUnit[$unit] =
(isset($targetUnit[$unit]) ? $targetUnit[$unit] : 0) - $exp;
}
break;
case 'mod':
$targetUnit = $left[2];
break;
default:
$targetUnit = $left->unitless() ?
$right[2] : $left[2];
}
if (! $left->unitless() && !
$right->unitless()) {
$left = $left->normalize();
$right = $right->normalize();
}
}
$shouldEval = $inParens || $inExp;
if (isset($passOp)) {
$out = $this->$fn($op, $left, $right,
$shouldEval);
} else {
$out = $this->$fn($left, $right, $shouldEval);
}
if (isset($out)) {
if ($coerceUnit && $out[0] ===
Type::T_NUMBER) {
$out = $out->coerce($targetUnit);
}
return $out;
}
}
return $this->expToString($value);
case Type::T_UNARY:
list(, $op, $exp, $inParens) = $value;
$inExp = $inExp || $this->shouldEval($exp);
$exp = $this->reduce($exp);
if ($exp[0] === Type::T_NUMBER) {
switch ($op) {
case '+':
return new Node\Number($exp[1], $exp[2]);
case '-':
return new Node\Number(-$exp[1], $exp[2]);
}
}
if ($op === 'not') {
if ($inExp || $inParens) {
if ($exp === static::$false || $exp ===
static::$null) {
return static::$true;
}
return static::$false;
}
$op = $op . ' ';
}
return [Type::T_STRING, '', [$op, $exp]];
case Type::T_VARIABLE:
return $this->reduce($this->get($value[1]));
case Type::T_LIST:
foreach ($value[2] as &$item) {
$item = $this->reduce($item);
}
return $value;
case Type::T_MAP:
foreach ($value[1] as &$item) {
$item = $this->reduce($item);
}
foreach ($value[2] as &$item) {
$item = $this->reduce($item);
}
return $value;
case Type::T_STRING:
foreach ($value[2] as &$item) {
if (is_array($item) || $item instanceof \ArrayAccess) {
$item = $this->reduce($item);
}
}
return $value;
case Type::T_INTERPOLATE:
$value[1] = $this->reduce($value[1]);
if ($inExp) {
return $value[1];
}
return $value;
case Type::T_FUNCTION_CALL:
return $this->fncall($value[1], $value[2]);
case Type::T_SELF:
$selfSelector = $this->multiplySelectors($this->env);
$selfSelector = $this->collapseSelectors($selfSelector,
true);
return $selfSelector;
default:
return $value;
}
}
/**
* Function caller
*
* @param string $name
* @param array $argValues
*
* @return array|null
*/
protected function fncall($name, $argValues)
{
// SCSS @function
if ($this->callScssFunction($name, $argValues, $returnValue)) {
return $returnValue;
}
// native PHP functions
if ($this->callNativeFunction($name, $argValues, $returnValue))
{
return $returnValue;
}
// for CSS functions, simply flatten the arguments into a list
$listArgs = [];
foreach ((array) $argValues as $arg) {
if (empty($arg[0])) {
$listArgs[] = $this->reduce($arg[1]);
}
}
return [Type::T_FUNCTION, $name, [Type::T_LIST, ',',
$listArgs]];
}
/**
* Normalize name
*
* @param string $name
*
* @return string
*/
protected function normalizeName($name)
{
return str_replace('-', '_', $name);
}
/**
* Normalize value
*
* @param array $value
*
* @return array
*/
public function normalizeValue($value)
{
$value = $this->coerceForExpression($this->reduce($value));
switch ($value[0]) {
case Type::T_LIST:
$value = $this->extractInterpolation($value);
if ($value[0] !== Type::T_LIST) {
return [Type::T_KEYWORD,
$this->compileValue($value)];
}
foreach ($value[2] as $key => $item) {
$value[2][$key] = $this->normalizeValue($item);
}
return $value;
case Type::T_STRING:
return [$value[0], '"',
[$this->compileStringContent($value)]];
case Type::T_NUMBER:
return $value->normalize();
case Type::T_INTERPOLATE:
return [Type::T_KEYWORD, $this->compileValue($value)];
default:
return $value;
}
}
/**
* Add numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opAddNumberNumber($left, $right)
{
return new Node\Number($left[1] + $right[1], $left[2]);
}
/**
* Multiply numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opMulNumberNumber($left, $right)
{
return new Node\Number($left[1] * $right[1], $left[2]);
}
/**
* Subtract numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opSubNumberNumber($left, $right)
{
return new Node\Number($left[1] - $right[1], $left[2]);
}
/**
* Divide numbers
*
* @param array $left
* @param array $right
*
* @return array|\Leafo\ScssPhp\Node\Number
*/
protected function opDivNumberNumber($left, $right)
{
if ($right[1] == 0) {
return [Type::T_STRING, '', [$left[1] . $left[2] .
'/' . $right[1] . $right[2]]];
}
return new Node\Number($left[1] / $right[1], $left[2]);
}
/**
* Mod numbers
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opModNumberNumber($left, $right)
{
return new Node\Number($left[1] % $right[1], $left[2]);
}
/**
* Add strings
*
* @param array $left
* @param array $right
*
* @return array|null
*/
protected function opAdd($left, $right)
{
if ($strLeft = $this->coerceString($left)) {
if ($right[0] === Type::T_STRING) {
$right[1] = '';
}
$strLeft[2][] = $right;
return $strLeft;
}
if ($strRight = $this->coerceString($right)) {
if ($left[0] === Type::T_STRING) {
$left[1] = '';
}
array_unshift($strRight[2], $left);
return $strRight;
}
return null;
}
/**
* Boolean and
*
* @param array $left
* @param array $right
* @param boolean $shouldEval
*
* @return array|null
*/
protected function opAnd($left, $right, $shouldEval)
{
$truthy = ($left === static::$null || $right === static::$null) ||
($left === static::$false || $left === static::$true)
&&
($right === static::$false || $right === static::$true);
if (! $shouldEval) {
if (! $truthy) {
return null;
}
}
if ($left !== static::$false && $left !== static::$null) {
return $this->reduce($right, true);
}
return $left;
}
/**
* Boolean or
*
* @param array $left
* @param array $right
* @param boolean $shouldEval
*
* @return array|null
*/
protected function opOr($left, $right, $shouldEval)
{
$truthy = ($left === static::$null || $right === static::$null) ||
($left === static::$false || $left === static::$true)
&&
($right === static::$false || $right === static::$true);
if (! $shouldEval) {
if (! $truthy) {
return null;
}
}
if ($left !== static::$false && $left !== static::$null) {
return $left;
}
return $this->reduce($right, true);
}
/**
* Compare colors
*
* @param string $op
* @param array $left
* @param array $right
*
* @return array
*/
protected function opColorColor($op, $left, $right)
{
$out = [Type::T_COLOR];
foreach ([1, 2, 3] as $i) {
$lval = isset($left[$i]) ? $left[$i] : 0;
$rval = isset($right[$i]) ? $right[$i] : 0;
switch ($op) {
case '+':
$out[] = $lval + $rval;
break;
case '-':
$out[] = $lval - $rval;
break;
case '*':
$out[] = $lval * $rval;
break;
case '%':
$out[] = $lval % $rval;
break;
case '/':
if ($rval == 0) {
$this->throwError("color: Can't divide
by zero");
break 2;
}
$out[] = (int) ($lval / $rval);
break;
case '==':
return $this->opEq($left, $right);
case '!=':
return $this->opNeq($left, $right);
default:
$this->throwError("color: unknown op
$op");
break 2;
}
}
if (isset($left[4])) {
$out[4] = $left[4];
} elseif (isset($right[4])) {
$out[4] = $right[4];
}
return $this->fixColor($out);
}
/**
* Compare color and number
*
* @param string $op
* @param array $left
* @param array $right
*
* @return array
*/
protected function opColorNumber($op, $left, $right)
{
$value = $right[1];
return $this->opColorColor(
$op,
$left,
[Type::T_COLOR, $value, $value, $value]
);
}
/**
* Compare number and color
*
* @param string $op
* @param array $left
* @param array $right
*
* @return array
*/
protected function opNumberColor($op, $left, $right)
{
$value = $left[1];
return $this->opColorColor(
$op,
[Type::T_COLOR, $value, $value, $value],
$right
);
}
/**
* Compare number1 == number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opEq($left, $right)
{
if (($lStr = $this->coerceString($left)) && ($rStr =
$this->coerceString($right))) {
$lStr[1] = '';
$rStr[1] = '';
$left = $this->compileValue($lStr);
$right = $this->compileValue($rStr);
}
return $this->toBool($left === $right);
}
/**
* Compare number1 != number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opNeq($left, $right)
{
if (($lStr = $this->coerceString($left)) && ($rStr =
$this->coerceString($right))) {
$lStr[1] = '';
$rStr[1] = '';
$left = $this->compileValue($lStr);
$right = $this->compileValue($rStr);
}
return $this->toBool($left !== $right);
}
/**
* Compare number1 >= number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opGteNumberNumber($left, $right)
{
return $this->toBool($left[1] >= $right[1]);
}
/**
* Compare number1 > number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opGtNumberNumber($left, $right)
{
return $this->toBool($left[1] > $right[1]);
}
/**
* Compare number1 <= number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opLteNumberNumber($left, $right)
{
return $this->toBool($left[1] <= $right[1]);
}
/**
* Compare number1 < number2
*
* @param array $left
* @param array $right
*
* @return array
*/
protected function opLtNumberNumber($left, $right)
{
return $this->toBool($left[1] < $right[1]);
}
/**
* Three-way comparison, aka spaceship operator
*
* @param array $left
* @param array $right
*
* @return \Leafo\ScssPhp\Node\Number
*/
protected function opCmpNumberNumber($left, $right)
{
$n = $left[1] - $right[1];
return new Node\Number($n ? $n / abs($n) : 0, '');
}
/**
* Cast to boolean
*
* @api
*
* @param mixed $thing
*
* @return array
*/
public function toBool($thing)
{
return $thing ? static::$true : static::$false;
}
/**
* Compiles a primitive value into a CSS property value.
*
* Values in scssphp are typed by being wrapped in arrays, their format
is
* typically:
*
* array(type, contents [, additional_contents]*)
*
* The input is expected to be reduced. This function will not work on
* things like expressions and variables.
*
* @api
*
* @param array $value
*
* @return string
*/
public function compileValue($value)
{
$value = $this->reduce($value);
switch ($value[0]) {
case Type::T_KEYWORD:
return $value[1];
case Type::T_COLOR:
// [1] - red component (either number for a %)
// [2] - green component
// [3] - blue component
// [4] - optional alpha component
list(, $r, $g, $b) = $value;
$r = round($r);
$g = round($g);
$b = round($b);
if (count($value) === 5 && $value[4] !== 1) { //
rgba
$a = new Node\Number($value[4], '');
return 'rgba(' . $r . ', ' . $g .
', ' . $b . ', ' . $a . ')';
}
$h = sprintf('#%02x%02x%02x', $r, $g, $b);
// Converting hex color to short notation (e.g. #003399 to
#039)
if ($h[1] === $h[2] && $h[3] === $h[4] &&
$h[5] === $h[6]) {
$h = '#' . $h[1] . $h[3] . $h[5];
}
return $h;
case Type::T_NUMBER:
return $value->output($this);
case Type::T_STRING:
return $value[1] . $this->compileStringContent($value) .
$value[1];
case Type::T_FUNCTION:
$args = ! empty($value[2]) ?
$this->compileValue($value[2]) : '';
return "$value[1]($args)";
case Type::T_LIST:
$value = $this->extractInterpolation($value);
if ($value[0] !== Type::T_LIST) {
return $this->compileValue($value);
}
list(, $delim, $items) = $value;
if ($delim !== ' ') {
$delim .= ' ';
}
$filtered = [];
foreach ($items as $item) {
if ($item[0] === Type::T_NULL) {
continue;
}
$filtered[] = $this->compileValue($item);
}
return implode("$delim", $filtered);
case Type::T_MAP:
$keys = $value[1];
$values = $value[2];
$filtered = [];
for ($i = 0, $s = count($keys); $i < $s; $i++) {
$filtered[$this->compileValue($keys[$i])] =
$this->compileValue($values[$i]);
}
array_walk($filtered, function (&$value, $key) {
$value = $key . ': ' . $value;
});
return '(' . implode(', ', $filtered) .
')';
case Type::T_INTERPOLATED:
// node created by extractInterpolation
list(, $interpolate, $left, $right) = $value;
list(,, $whiteLeft, $whiteRight) = $interpolate;
$left = count($left[2]) > 0 ?
$this->compileValue($left) . $whiteLeft :
'';
$right = count($right[2]) > 0 ?
$whiteRight . $this->compileValue($right) :
'';
return $left . $this->compileValue($interpolate) .
$right;
case Type::T_INTERPOLATE:
// strip quotes if it's a string
$reduced = $this->reduce($value[1]);
switch ($reduced[0]) {
case Type::T_LIST:
$reduced =
$this->extractInterpolation($reduced);
if ($reduced[0] !== Type::T_LIST) {
break;
}
list(, $delim, $items) = $reduced;
if ($delim !== ' ') {
$delim .= ' ';
}
$filtered = [];
foreach ($items as $item) {
if ($item[0] === Type::T_NULL) {
continue;
}
$temp =
$this->compileValue([Type::T_KEYWORD, $item]);
if ($temp[0] === Type::T_STRING) {
$filtered[] =
$this->compileStringContent($temp);
} elseif ($temp[0] === Type::T_KEYWORD) {
$filtered[] = $temp[1];
} else {
$filtered[] =
$this->compileValue($temp);
}
}
$reduced = [Type::T_KEYWORD,
implode("$delim", $filtered)];
break;
case Type::T_STRING:
$reduced = [Type::T_KEYWORD,
$this->compileStringContent($reduced)];
break;
case Type::T_NULL:
$reduced = [Type::T_KEYWORD, ''];
}
return $this->compileValue($reduced);
case Type::T_NULL:
return 'null';
default:
$this->throwError("unknown value type:
$value[0]");
}
}
/**
* Flatten list
*
* @param array $list
*
* @return string
*/
protected function flattenList($list)
{
return $this->compileValue($list);
}
/**
* Compile string content
*
* @param array $string
*
* @return string
*/
protected function compileStringContent($string)
{
$parts = [];
foreach ($string[2] as $part) {
if (is_array($part) || $part instanceof \ArrayAccess) {
$parts[] = $this->compileValue($part);
} else {
$parts[] = $part;
}
}
return implode($parts);
}
/**
* Extract interpolation; it doesn't need to be recursive,
compileValue will handle that
*
* @param array $list
*
* @return array
*/
protected function extractInterpolation($list)
{
$items = $list[2];
foreach ($items as $i => $item) {
if ($item[0] === Type::T_INTERPOLATE) {
$before = [Type::T_LIST, $list[1], array_slice($items, 0,
$i)];
$after = [Type::T_LIST, $list[1], array_slice($items, $i +
1)];
return [Type::T_INTERPOLATED, $item, $before, $after];
}
}
return $list;
}
/**
* Find the final set of selectors
*
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param \Leafo\ScssPhp\Block $selfParent
*
* @return array
*/
protected function multiplySelectors(Environment $env, $selfParent =
null)
{
$envs = $this->compactEnv($env);
$selectors = [];
$parentSelectors = [[]];
$selfParentSelectors = null;
if (! is_null($selfParent) && $selfParent->selectors) {
$selfParentSelectors =
$this->evalSelectors($selfParent->selectors);
}
while ($env = array_pop($envs)) {
if (empty($env->selectors)) {
continue;
}
$selectors = $env->selectors;
do {
$stillHasSelf = false;
$prevSelectors = $selectors;
$selectors = [];
foreach ($prevSelectors as $selector) {
foreach ($parentSelectors as $parent) {
if ($selfParentSelectors) {
foreach ($selfParentSelectors as $selfParent) {
// if no '&' in the selector,
each call will give same result, only add once
$s = $this->joinSelectors($parent,
$selector, $stillHasSelf, $selfParent);
$selectors[serialize($s)] = $s;
}
} else {
$s = $this->joinSelectors($parent,
$selector, $stillHasSelf);
$selectors[serialize($s)] = $s;
}
}
}
} while ($stillHasSelf);
$parentSelectors = $selectors;
}
$selectors = array_values($selectors);
return $selectors;
}
/**
* Join selectors; looks for & to replace, or append parent before
child
*
* @param array $parent
* @param array $child
* @param boolean &$stillHasSelf
* @param array $selfParentSelectors
* @return array
*/
protected function joinSelectors($parent, $child, &$stillHasSelf,
$selfParentSelectors = null)
{
$setSelf = false;
$out = [];
foreach ($child as $part) {
$newPart = [];
foreach ($part as $p) {
// only replace & once and should be recalled to be
able to make combinations
if ($p === static::$selfSelector && $setSelf) {
$stillHasSelf = true;
}
if ($p === static::$selfSelector && ! $setSelf) {
$setSelf = true;
if (is_null($selfParentSelectors)) {
$selfParentSelectors = $parent;
}
foreach ($selfParentSelectors as $i => $parentPart)
{
if ($i > 0) {
$out[] = $newPart;
$newPart = [];
}
foreach ($parentPart as $pp) {
if (is_array($pp)) {
$flatten = [];
array_walk_recursive($pp, function ($a) use
(&$flatten) {
$flatten[] = $a;
});
$pp = implode($flatten);
}
$newPart[] = $pp;
}
}
} else {
$newPart[] = $p;
}
}
$out[] = $newPart;
}
return $setSelf ? $out : array_merge($parent, $child);
}
/**
* Multiply media
*
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param array $childQueries
*
* @return array
*/
protected function multiplyMedia(Environment $env = null, $childQueries
= null)
{
if (! isset($env) ||
! empty($env->block->type) &&
$env->block->type !== Type::T_MEDIA
) {
return $childQueries;
}
// plain old block, skip
if (empty($env->block->type)) {
return $this->multiplyMedia($env->parent, $childQueries);
}
$parentQueries = isset($env->block->queryList)
? $env->block->queryList
: [[[Type::T_MEDIA_VALUE, $env->block->value]]];
$store = [$this->env, $this->storeEnv];
$this->env = $env;
$this->storeEnv = null;
$parentQueries = $this->evaluateMediaQuery($parentQueries);
list($this->env, $this->storeEnv) = $store;
if ($childQueries === null) {
$childQueries = $parentQueries;
} else {
$originalQueries = $childQueries;
$childQueries = [];
foreach ($parentQueries as $parentQuery) {
foreach ($originalQueries as $childQuery) {
$childQueries[] = array_merge(
$parentQuery,
[[Type::T_MEDIA_TYPE, [Type::T_KEYWORD,
'all']]],
$childQuery
);
}
}
}
return $this->multiplyMedia($env->parent, $childQueries);
}
/**
* Convert env linked list to stack
*
* @param \Leafo\ScssPhp\Compiler\Environment $env
*
* @return array
*/
protected function compactEnv(Environment $env)
{
for ($envs = []; $env; $env = $env->parent) {
$envs[] = $env;
}
return $envs;
}
/**
* Convert env stack to singly linked list
*
* @param array $envs
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function extractEnv($envs)
{
for ($env = null; $e = array_pop($envs);) {
$e->parent = $env;
$env = $e;
}
return $env;
}
/**
* Push environment
*
* @param \Leafo\ScssPhp\Block $block
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function pushEnv(Block $block = null)
{
$env = new Environment;
$env->parent = $this->env;
$env->store = [];
$env->block = $block;
$env->depth = isset($this->env->depth) ?
$this->env->depth + 1 : 0;
$this->env = $env;
return $env;
}
/**
* Pop environment
*/
protected function popEnv()
{
$this->env = $this->env->parent;
}
/**
* Get store environment
*
* @return \Leafo\ScssPhp\Compiler\Environment
*/
protected function getStoreEnv()
{
return isset($this->storeEnv) ? $this->storeEnv :
$this->env;
}
/**
* Set variable
*
* @param string $name
* @param mixed $value
* @param boolean $shadow
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param mixed $valueUnreduced
*/
protected function set($name, $value, $shadow = false, Environment $env
= null, $valueUnreduced = null)
{
$name = $this->normalizeName($name);
if (! isset($env)) {
$env = $this->getStoreEnv();
}
if ($shadow) {
$this->setRaw($name, $value, $env, $valueUnreduced);
} else {
$this->setExisting($name, $value, $env, $valueUnreduced);
}
}
/**
* Set existing variable
*
* @param string $name
* @param mixed $value
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param mixed $valueUnreduced
*/
protected function setExisting($name, $value, Environment $env,
$valueUnreduced = null)
{
$storeEnv = $env;
$hasNamespace = $name[0] === '^' || $name[0] ===
'@' || $name[0] === '%';
for (;;) {
if (array_key_exists($name, $env->store)) {
break;
}
if (! $hasNamespace && isset($env->marker)) {
$env = $storeEnv;
break;
}
if (! isset($env->parent)) {
$env = $storeEnv;
break;
}
$env = $env->parent;
}
$env->store[$name] = $value;
if ($valueUnreduced) {
$env->storeUnreduced[$name] = $valueUnreduced;
}
}
/**
* Set raw variable
*
* @param string $name
* @param mixed $value
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param mixed $valueUnreduced
*/
protected function setRaw($name, $value, Environment $env,
$valueUnreduced = null)
{
$env->store[$name] = $value;
if ($valueUnreduced) {
$env->storeUnreduced[$name] = $valueUnreduced;
}
}
/**
* Get variable
*
* @api
*
* @param string $name
* @param boolean $shouldThrow
* @param \Leafo\ScssPhp\Compiler\Environment $env
* @param boolean $unreduced
*
* @return mixed|null
*/
public function get($name, $shouldThrow = true, Environment $env =
null, $unreduced = false)
{
$normalizedName = $this->normalizeName($name);
$specialContentKey = static::$namespaces['special'] .
'content';
if (! isset($env)) {
$env = $this->getStoreEnv();
}
$nextIsRoot = false;
$hasNamespace = $normalizedName[0] === '^' ||
$normalizedName[0] === '@' || $normalizedName[0] ===
'%';
$maxDepth = 10000;
for (;;) {
if ($maxDepth-- <= 0) {
break;
}
if (array_key_exists($normalizedName, $env->store)) {
if ($unreduced &&
isset($env->storeUnreduced[$normalizedName])) {
return $env->storeUnreduced[$normalizedName];
}
return $env->store[$normalizedName];
}
if (! $hasNamespace && isset($env->marker)) {
if (! $nextIsRoot && !
empty($env->store[$specialContentKey])) {
$env = $env->store[$specialContentKey]->scope;
continue;
}
$env = $this->rootEnv;
continue;
}
if (! isset($env->parent)) {
break;
}
$env = $env->parent;
}
if ($shouldThrow) {
$this->throwError("Undefined variable \$$name" .
($maxDepth<=0 ? " (infinite recursion)" : ""));
}
// found nothing
return null;
}
/**
* Has variable?
*
* @param string $name
* @param \Leafo\ScssPhp\Compiler\Environment $env
*
* @return boolean
*/
protected function has($name, Environment $env = null)
{
return $this->get($name, false, $env) !== null;
}
/**
* Inject variables
*
* @param array $args
*/
protected function injectVariables(array $args)
{
if (empty($args)) {
return;
}
$parser = $this->parserFactory(__METHOD__);
foreach ($args as $name => $strValue) {
if ($name[0] === '$') {
$name = substr($name, 1);
}
if (! $parser->parseValue($strValue, $value)) {
$value = $this->coerceValue($strValue);
}
$this->set($name, $value);
}
}
/**
* Set variables
*
* @api
*
* @param array $variables
*/
public function setVariables(array $variables)
{
$this->registeredVars = array_merge($this->registeredVars,
$variables);
}
/**
* Unset variable
*
* @api
*
* @param string $name
*/
public function unsetVariable($name)
{
unset($this->registeredVars[$name]);
}
/**
* Returns list of variables
*
* @api
*
* @return array
*/
public function getVariables()
{
return $this->registeredVars;
}
/**
* Adds to list of parsed files
*
* @api
*
* @param string $path
*/
public function addParsedFile($path)
{
if (isset($path) && file_exists($path)) {
$this->parsedFiles[realpath($path)] = filemtime($path);
}
}
/**
* Returns list of parsed files
*
* @api
*
* @return array
*/
public function getParsedFiles()
{
return $this->parsedFiles;
}
/**
* Add import path
*
* @api
*
* @param string|callable $path
*/
public function addImportPath($path)
{
if (! in_array($path, $this->importPaths)) {
$this->importPaths[] = $path;
}
}
/**
* Set import paths
*
* @api
*
* @param string|array $path
*/
public function setImportPaths($path)
{
$this->importPaths = (array) $path;
}
/**
* Set number precision
*
* @api
*
* @param integer $numberPrecision
*/
public function setNumberPrecision($numberPrecision)
{
Node\Number::$precision = $numberPrecision;
}
/**
* Set formatter
*
* @api
*
* @param string $formatterName
*/
public function setFormatter($formatterName)
{
$this->formatter = $formatterName;
}
/**
* Set line number style
*
* @api
*
* @param string $lineNumberStyle
*/
public function setLineNumberStyle($lineNumberStyle)
{
$this->lineNumberStyle = $lineNumberStyle;
}
/**
* Enable/disable source maps
*
* @api
*
* @param integer $sourceMap
*/
public function setSourceMap($sourceMap)
{
$this->sourceMap = $sourceMap;
}
/**
* Set source map options
*
* @api
*
* @param array $sourceMapOptions
*/
public function setSourceMapOptions($sourceMapOptions)
{
$this->sourceMapOptions = $sourceMapOptions;
}
/**
* Register function
*
* @api
*
* @param string $name
* @param callable $func
* @param array $prototype
*/
public function registerFunction($name, $func, $prototype = null)
{
$this->userFunctions[$this->normalizeName($name)] = [$func,
$prototype];
}
/**
* Unregister function
*
* @api
*
* @param string $name
*/
public function unregisterFunction($name)
{
unset($this->userFunctions[$this->normalizeName($name)]);
}
/**
* Add feature
*
* @api
*
* @param string $name
*/
public function addFeature($name)
{
$this->registeredFeatures[$name] = true;
}
/**
* Import file
*
* @param string $path
* @param \Leafo\ScssPhp\Formatter\OutputBlock $out
*/
protected function importFile($path, OutputBlock $out)
{
// see if tree is cached
$realPath = realpath($path);
if (isset($this->importCache[$realPath])) {
$this->handleImportLoop($realPath);
$tree = $this->importCache[$realPath];
} else {
$code = file_get_contents($path);
$parser = $this->parserFactory($path);
$tree = $parser->parse($code);
$this->importCache[$realPath] = $tree;
}
$pi = pathinfo($path);
array_unshift($this->importPaths, $pi['dirname']);
$this->compileChildrenNoReturn($tree->children, $out);
array_shift($this->importPaths);
}
/**
* Return the file path for an import url if it exists
*
* @api
*
* @param string $url
*
* @return string|null
*/
public function findImport($url)
{
$urls = [];
// for "normal" scss imports (ignore vanilla css and
external requests)
if (! preg_match('/\.css$|^https?:\/\//', $url)) {
// try both normal and the _partial filename
$urls = [$url, preg_replace('/[^\/]+$/',
'_\0', $url)];
}
$hasExtension = preg_match('/[.]s?css$/', $url);
foreach ($this->importPaths as $dir) {
if (is_string($dir)) {
// check urls for normal import paths
foreach ($urls as $full) {
$separator = (
! empty($dir) &&
substr($dir, -1) !== '/' &&
substr($full, 0, 1) !== '/'
) ? '/' : '';
$full = $dir . $separator . $full;
if ($this->fileExists($file = $full .
'.scss') ||
($hasExtension &&
$this->fileExists($file = $full))
) {
return $file;
}
}
} elseif (is_callable($dir)) {
// check custom callback for import path
$file = call_user_func($dir, $url);
if ($file !== null) {
return $file;
}
}
}
return null;
}
/**
* Set encoding
*
* @api
*
* @param string $encoding
*/
public function setEncoding($encoding)
{
$this->encoding = $encoding;
}
/**
* Ignore errors?
*
* @api
*
* @param boolean $ignoreErrors
*
* @return \Leafo\ScssPhp\Compiler
*/
public function setIgnoreErrors($ignoreErrors)
{
$this->ignoreErrors = $ignoreErrors;
return $this;
}
/**
* Throw error (exception)
*
* @api
*
* @param string $msg Message with optional sprintf()-style vararg
parameters
*
* @throws \Leafo\ScssPhp\Exception\CompilerException
*/
public function throwError($msg)
{
if ($this->ignoreErrors) {
return;
}
$line = $this->sourceLine;
$column = $this->sourceColumn;
$loc = isset($this->sourceNames[$this->sourceIndex])
? $this->sourceNames[$this->sourceIndex] . " on
line $line, at column $column"
: "line: $line, column: $column";
if (func_num_args() > 1) {
$msg = call_user_func_array('sprintf',
func_get_args());
}
$msg = "$msg: $loc";
$callStackMsg = $this->callStackMessage();
if ($callStackMsg) {
$msg .= "\nCall Stack:\n" . $callStackMsg;
}
throw new CompilerException($msg);
}
/**
* Beautify call stack for output
*
* @param boolean $all
* @param null $limit
*
* @return string
*/
protected function callStackMessage($all = false, $limit = null)
{
$callStackMsg = [];
$ncall = 0;
if ($this->callStack) {
foreach (array_reverse($this->callStack) as $call) {
if ($all || (isset($call['n']) &&
$call['n'])) {
$msg = "#" . $ncall++ . " " .
$call['n'] . " ";
$msg .=
(isset($this->sourceNames[$call[Parser::SOURCE_INDEX]])
?
$this->sourceNames[$call[Parser::SOURCE_INDEX]]
: '(unknown file)');
$msg .= " on line " .
$call[Parser::SOURCE_LINE];
$callStackMsg[] = $msg;
if (! is_null($limit) && $ncall>$limit) {
break;
}
}
}
}
return implode("\n", $callStackMsg);
}
/**
* Handle import loop
*
* @param string $name
*
* @throws \Exception
*/
protected function handleImportLoop($name)
{
for ($env = $this->env; $env; $env = $env->parent) {
$file = $this->sourceNames[$env->block->sourceIndex];
if (realpath($file) === $name) {
$this->throwError('An @import loop has been found:
%s imports %s', $file, basename($file));
break;
}
}
}
/**
* Does file exist?
*
* @param string $name
*
* @return boolean
*/
protected function fileExists($name)
{
return file_exists($name) && is_file($name);
}
/**
* Call SCSS @function
*
* @param string $name
* @param array $argValues
* @param array $returnValue
*
* @return boolean Returns true if returnValue is set; otherwise, false
*/
protected function callScssFunction($name, $argValues,
&$returnValue)
{
$func = $this->get(static::$namespaces['function'] .
$name, false);
if (! $func) {
return false;
}
$this->pushEnv();
$storeEnv = $this->storeEnv;
$this->storeEnv = $this->env;
// set the args
if (isset($func->args)) {
$this->applyArguments($func->args, $argValues);
}
// throw away lines and children
$tmp = new OutputBlock;
$tmp->lines = [];
$tmp->children = [];
$this->env->marker = 'function';
$ret = $this->compileChildren($func->children, $tmp,
$this->env->marker . " " . $name);
$this->storeEnv = $storeEnv;
$this->popEnv();
$returnValue = ! isset($ret) ? static::$defaultValue : $ret;
return true;
}
/**
* Call built-in and registered (PHP) functions
*
* @param string $name
* @param array $args
* @param array $returnValue
*
* @return boolean Returns true if returnValue is set; otherwise, false
*/
protected function callNativeFunction($name, $args, &$returnValue)
{
// try a lib function
$name = $this->normalizeName($name);
if (isset($this->userFunctions[$name])) {
// see if we can find a user function
list($f, $prototype) = $this->userFunctions[$name];
} elseif (($f = $this->getBuiltinFunction($name)) &&
is_callable($f)) {
$libName = $f[1];
$prototype = isset(static::$$libName) ? static::$$libName :
null;
} else {
return false;
}
@list($sorted, $kwargs) = $this->sortArgs($prototype, $args);
if ($name !== 'if' && $name !== 'call')
{
foreach ($sorted as &$val) {
$val = $this->reduce($val, true);
}
}
$returnValue = call_user_func($f, $sorted, $kwargs);
if (! isset($returnValue)) {
return false;
}
$returnValue = $this->coerceValue($returnValue);
return true;
}
/**
* Get built-in function
*
* @param string $name Normalized name
*
* @return array
*/
protected function getBuiltinFunction($name)
{
$libName = 'lib' . preg_replace_callback(
'/_(.)/',
function ($m) {
return ucfirst($m[1]);
},
ucfirst($name)
);
return [$this, $libName];
}
/**
* Sorts keyword arguments
*
* @param array $prototype
* @param array $args
*
* @return array
*/
protected function sortArgs($prototype, $args)
{
$keyArgs = [];
$posArgs = [];
// separate positional and keyword arguments
foreach ($args as $arg) {
list($key, $value) = $arg;
$key = $key[1];
if (empty($key)) {
$posArgs[] = empty($arg[2]) ? $value : $arg;
} else {
$keyArgs[$key] = $value;
}
}
if (! isset($prototype)) {
return [$posArgs, $keyArgs];
}
// copy positional args
$finalArgs = array_pad($posArgs, count($prototype), null);
// overwrite positional args with keyword args
foreach ($prototype as $i => $names) {
foreach ((array) $names as $name) {
if (isset($keyArgs[$name])) {
$finalArgs[$i] = $keyArgs[$name];
}
}
}
return [$finalArgs, $keyArgs];
}
/**
* Apply argument values per definition
*
* @param array $argDef
* @param array $argValues
*
* @throws \Exception
*/
protected function applyArguments($argDef, $argValues)
{
$storeEnv = $this->getStoreEnv();
$env = new Environment;
$env->store = $storeEnv->store;
$hasVariable = false;
$args = [];
foreach ($argDef as $i => $arg) {
list($name, $default, $isVariable) = $argDef[$i];
$args[$name] = [$i, $name, $default, $isVariable];
$hasVariable |= $isVariable;
}
$keywordArgs = [];
$deferredKeywordArgs = [];
$remaining = [];
// assign the keyword args
foreach ((array) $argValues as $arg) {
if (! empty($arg[0])) {
if (! isset($args[$arg[0][1]])) {
if ($hasVariable) {
$deferredKeywordArgs[$arg[0][1]] = $arg[1];
} else {
$this->throwError("Mixin or function
doesn't have an argument named $%s.", $arg[0][1]);
break;
}
} elseif ($args[$arg[0][1]][0] < count($remaining)) {
$this->throwError("The argument $%s was passed
both by position and by name.", $arg[0][1]);
break;
} else {
$keywordArgs[$arg[0][1]] = $arg[1];
}
} elseif (count($keywordArgs)) {
$this->throwError('Positional arguments must come
before keyword arguments.');
break;
} elseif ($arg[2] === true) {
$val = $this->reduce($arg[1], true);
if ($val[0] === Type::T_LIST) {
foreach ($val[2] as $name => $item) {
if (! is_numeric($name)) {
$keywordArgs[$name] = $item;
} else {
$remaining[] = $item;
}
}
} elseif ($val[0] === Type::T_MAP) {
foreach ($val[1] as $i => $name) {
$name =
$this->compileStringContent($this->coerceString($name));
$item = $val[2][$i];
if (! is_numeric($name)) {
$keywordArgs[$name] = $item;
} else {
$remaining[] = $item;
}
}
} else {
$remaining[] = $val;
}
} else {
$remaining[] = $arg[1];
}
}
foreach ($args as $arg) {
list($i, $name, $default, $isVariable) = $arg;
if ($isVariable) {
$val = [Type::T_LIST, ',', [], $isVariable];
for ($count = count($remaining); $i < $count; $i++) {
$val[2][] = $remaining[$i];
}
foreach ($deferredKeywordArgs as $itemName => $item) {
$val[2][$itemName] = $item;
}
} elseif (isset($remaining[$i])) {
$val = $remaining[$i];
} elseif (isset($keywordArgs[$name])) {
$val = $keywordArgs[$name];
} elseif (! empty($default)) {
continue;
} else {
$this->throwError("Missing argument $name");
break;
}
$this->set($name, $this->reduce($val, true), true, $env);
}
$storeEnv->store = $env->store;
foreach ($args as $arg) {
list($i, $name, $default, $isVariable) = $arg;
if ($isVariable || isset($remaining[$i]) ||
isset($keywordArgs[$name]) || empty($default)) {
continue;
}
$this->set($name, $this->reduce($default, true), true);
}
}
/**
* Coerce a php value into a scss one
*
* @param mixed $value
*
* @return array|\Leafo\ScssPhp\Node\Number
*/
protected function coerceValue($value)
{
if (is_array($value) || $value instanceof \ArrayAccess) {
return $value;
}
if (is_bool($value)) {
return $this->toBool($value);
}
if ($value === null) {
return static::$null;
}
if (is_numeric($value)) {
return new Node\Number($value, '');
}
if ($value === '') {
return static::$emptyString;
}
if (preg_match('/^(#([0-9a-f]{6})|#([0-9a-f]{3}))$/i',
$value, $m)) {
$color = [Type::T_COLOR];
if (isset($m[3])) {
$num = hexdec($m[3]);
foreach ([3, 2, 1] as $i) {
$t = $num & 0xf;
$color[$i] = $t << 4 | $t;
$num >>= 4;
}
} else {
$num = hexdec($m[2]);
foreach ([3, 2, 1] as $i) {
$color[$i] = $num & 0xff;
$num >>= 8;
}
}
return $color;
}
return [Type::T_KEYWORD, $value];
}
/**
* Coerce something to map
*
* @param array $item
*
* @return array
*/
protected function coerceMap($item)
{
if ($item[0] === Type::T_MAP) {
return $item;
}
if ($item === static::$emptyList) {
return static::$emptyMap;
}
return [Type::T_MAP, [$item], [static::$null]];
}
/**
* Coerce something to list
*
* @param array $item
* @param string $delim
*
* @return array
*/
protected function coerceList($item, $delim = ',')
{
if (isset($item) && $item[0] === Type::T_LIST) {
return $item;
}
if (isset($item) && $item[0] === Type::T_MAP) {
$keys = $item[1];
$values = $item[2];
$list = [];
for ($i = 0, $s = count($keys); $i < $s; $i++) {
$key = $keys[$i];
$value = $values[$i];
$list[] = [
Type::T_LIST,
'',
[[Type::T_KEYWORD,
$this->compileStringContent($this->coerceString($key))], $value]
];
}
return [Type::T_LIST, ',', $list];
}
return [Type::T_LIST, $delim, ! isset($item) ? []: [$item]];
}
/**
* Coerce color for expression
*
* @param array $value
*
* @return array|null
*/
protected function coerceForExpression($value)
{
if ($color = $this->coerceColor($value)) {
return $color;
}
return $value;
}
/**
* Coerce value to color
*
* @param array $value
*
* @return array|null
*/
protected function coerceColor($value)
{
switch ($value[0]) {
case Type::T_COLOR:
return $value;
case Type::T_KEYWORD:
$name = strtolower($value[1]);
if (isset(Colors::$cssColors[$name])) {
$rgba = explode(',',
Colors::$cssColors[$name]);
return isset($rgba[3])
? [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1],
(int) $rgba[2], (int) $rgba[3]]
: [Type::T_COLOR, (int) $rgba[0], (int) $rgba[1],
(int) $rgba[2]];
}
return null;
}
return null;
}
/**
* Coerce value to string
*
* @param array $value
*
* @return array|null
*/
protected function coerceString($value)
{
if ($value[0] === Type::T_STRING) {
return $value;
}
return [Type::T_STRING, '',
[$this->compileValue($value)]];
}
/**
* Coerce value to a percentage
*
* @param array $value
*
* @return integer|float
*/
protected function coercePercent($value)
{
if ($value[0] === Type::T_NUMBER) {
if (! empty($value[2]['%'])) {
return $value[1] / 100;
}
return $value[1];
}
return 0;
}
/**
* Assert value is a map
*
* @api
*
* @param array $value
*
* @return array
*
* @throws \Exception
*/
public function assertMap($value)
{
$value = $this->coerceMap($value);
if ($value[0] !== Type::T_MAP) {
$this->throwError('expecting map, %s received',
$value[0]);
}
return $value;
}
/**
* Assert value is a list
*
* @api
*
* @param array $value
*
* @return array
*
* @throws \Exception
*/
public function assertList($value)
{
if ($value[0] !== Type::T_LIST) {
$this->throwError('expecting list, %s received',
$value[0]);
}
return $value;
}
/**
* Assert value is a color
*
* @api
*
* @param array $value
*
* @return array
*
* @throws \Exception
*/
public function assertColor($value)
{
if ($color = $this->coerceColor($value)) {
return $color;
}
$this->throwError('expecting color, %s received',
$value[0]);
}
/**
* Assert value is a number
*
* @api
*
* @param array $value
*
* @return integer|float
*
* @throws \Exception
*/
public function assertNumber($value)
{
if ($value[0] !== Type::T_NUMBER) {
$this->throwError('expecting number, %s received',
$value[0]);
}
return $value[1];
}
/**
* Make sure a color's components don't go out of bounds
*
* @param array $c
*
* @return array
*/
protected function fixColor($c)
{
foreach ([1, 2, 3] as $i) {
if ($c[$i] < 0) {
$c[$i] = 0;
}
if ($c[$i] > 255) {
$c[$i] = 255;
}
}
return $c;
}
/**
* Convert RGB to HSL
*
* @api
*
* @param integer $red
* @param integer $green
* @param integer $blue
*
* @return array
*/
public function toHSL($red, $green, $blue)
{
$min = min($red, $green, $blue);
$max = max($red, $green, $blue);
$l = $min + $max;
$d = $max - $min;
if ((int) $d === 0) {
$h = $s = 0;
} else {
if ($l < 255) {
$s = $d / $l;
} else {
$s = $d / (510 - $l);
}
if ($red == $max) {
$h = 60 * ($green - $blue) / $d;
} elseif ($green == $max) {
$h = 60 * ($blue - $red) / $d + 120;
} elseif ($blue == $max) {
$h = 60 * ($red - $green) / $d + 240;
}
}
return [Type::T_HSL, fmod($h, 360), $s * 100, $l / 5.1];
}
/**
* Hue to RGB helper
*
* @param float $m1
* @param float $m2
* @param float $h
*
* @return float
*/
protected function hueToRGB($m1, $m2, $h)
{
if ($h < 0) {
$h += 1;
} elseif ($h > 1) {
$h -= 1;
}
if ($h * 6 < 1) {
return $m1 + ($m2 - $m1) * $h * 6;
}
if ($h * 2 < 1) {
return $m2;
}
if ($h * 3 < 2) {
return $m1 + ($m2 - $m1) * (2/3 - $h) * 6;
}
return $m1;
}
/**
* Convert HSL to RGB
*
* @api
*
* @param integer $hue H from 0 to 360
* @param integer $saturation S from 0 to 100
* @param integer $lightness L from 0 to 100
*
* @return array
*/
public function toRGB($hue, $saturation, $lightness)
{
if ($hue < 0) {
$hue += 360;
}
$h = $hue / 360;
$s = min(100, max(0, $saturation)) / 100;
$l = min(100, max(0, $lightness)) / 100;
$m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;
$m1 = $l * 2 - $m2;
$r = $this->hueToRGB($m1, $m2, $h + 1/3) * 255;
$g = $this->hueToRGB($m1, $m2, $h) * 255;
$b = $this->hueToRGB($m1, $m2, $h - 1/3) * 255;
$out = [Type::T_COLOR, $r, $g, $b];
return $out;
}
// Built in functions
//protected static $libCall = ['name', 'args...'];
protected function libCall($args, $kwargs)
{
$name =
$this->compileStringContent($this->coerceString($this->reduce(array_shift($args),
true)));
$posArgs = [];
foreach ($args as $arg) {
if (empty($arg[0])) {
if ($arg[2] === true) {
$tmp = $this->reduce($arg[1]);
if ($tmp[0] === Type::T_LIST) {
foreach ($tmp[2] as $item) {
$posArgs[] = [null, $item, false];
}
} else {
$posArgs[] = [null, $tmp, true];
}
continue;
}
$posArgs[] = [null, $this->reduce($arg), false];
continue;
}
$posArgs[] = [null, $arg, false];
}
if (count($kwargs)) {
foreach ($kwargs as $key => $value) {
$posArgs[] = [[Type::T_VARIABLE, $key], $value, false];
}
}
return $this->reduce([Type::T_FUNCTION_CALL, $name, $posArgs]);
}
protected static $libIf = ['condition', 'if-true',
'if-false'];
protected function libIf($args)
{
list($cond, $t, $f) = $args;
if (! $this->isTruthy($this->reduce($cond, true))) {
return $this->reduce($f, true);
}
return $this->reduce($t, true);
}
protected static $libIndex = ['list', 'value'];
protected function libIndex($args)
{
list($list, $value) = $args;
if ($value[0] === Type::T_MAP) {
return static::$null;
}
if ($list[0] === Type::T_MAP ||
$list[0] === Type::T_STRING ||
$list[0] === Type::T_KEYWORD ||
$list[0] === Type::T_INTERPOLATE
) {
$list = $this->coerceList($list, ' ');
}
if ($list[0] !== Type::T_LIST) {
return static::$null;
}
$values = [];
foreach ($list[2] as $item) {
$values[] = $this->normalizeValue($item);
}
$key = array_search($this->normalizeValue($value), $values);
return false === $key ? static::$null : $key + 1;
}
protected static $libRgb = ['red', 'green',
'blue'];
protected function libRgb($args)
{
list($r, $g, $b) = $args;
return [Type::T_COLOR, $r[1], $g[1], $b[1]];
}
protected static $libRgba = [
['red', 'color'],
'green', 'blue', 'alpha'];
protected function libRgba($args)
{
if ($color = $this->coerceColor($args[0])) {
$num = isset($args[3]) ? $args[3] : $args[1];
$alpha = $this->assertNumber($num);
$color[4] = $alpha;
return $color;
}
list($r, $g, $b, $a) = $args;
return [Type::T_COLOR, $r[1], $g[1], $b[1], $a[1]];
}
// helper function for adjust_color, change_color, and scale_color
protected function alterColor($args, $fn)
{
$color = $this->assertColor($args[0]);
foreach ([1, 2, 3, 7] as $i) {
if (isset($args[$i])) {
$val = $this->assertNumber($args[$i]);
$ii = $i === 7 ? 4 : $i; // alpha
$color[$ii] = call_user_func($fn, isset($color[$ii]) ?
$color[$ii] : 0, $val, $i);
}
}
if (isset($args[4]) || isset($args[5]) || isset($args[6])) {
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
foreach ([4, 5, 6] as $i) {
if (isset($args[$i])) {
$val = $this->assertNumber($args[$i]);
$hsl[$i - 3] = call_user_func($fn, $hsl[$i - 3], $val,
$i);
}
}
$rgb = $this->toRGB($hsl[1], $hsl[2], $hsl[3]);
if (isset($color[4])) {
$rgb[4] = $color[4];
}
$color = $rgb;
}
return $color;
}
protected static $libAdjustColor = [
'color', 'red', 'green',
'blue',
'hue', 'saturation', 'lightness',
'alpha'
];
protected function libAdjustColor($args)
{
return $this->alterColor($args, function ($base, $alter, $i) {
return $base + $alter;
});
}
protected static $libChangeColor = [
'color', 'red', 'green',
'blue',
'hue', 'saturation', 'lightness',
'alpha'
];
protected function libChangeColor($args)
{
return $this->alterColor($args, function ($base, $alter, $i) {
return $alter;
});
}
protected static $libScaleColor = [
'color', 'red', 'green',
'blue',
'hue', 'saturation', 'lightness',
'alpha'
];
protected function libScaleColor($args)
{
return $this->alterColor($args, function ($base, $scale, $i) {
// 1, 2, 3 - rgb
// 4, 5, 6 - hsl
// 7 - a
switch ($i) {
case 1:
case 2:
case 3:
$max = 255;
break;
case 4:
$max = 360;
break;
case 7:
$max = 1;
break;
default:
$max = 100;
}
$scale = $scale / 100;
if ($scale < 0) {
return $base * $scale + $base;
}
return ($max - $base) * $scale + $base;
});
}
protected static $libIeHexStr = ['color'];
protected function libIeHexStr($args)
{
$color = $this->coerceColor($args[0]);
$color[4] = isset($color[4]) ? round(255 * $color[4]) : 255;
return sprintf('#%02X%02X%02X%02X', $color[4], $color[1],
$color[2], $color[3]);
}
protected static $libRed = ['color'];
protected function libRed($args)
{
$color = $this->coerceColor($args[0]);
return $color[1];
}
protected static $libGreen = ['color'];
protected function libGreen($args)
{
$color = $this->coerceColor($args[0]);
return $color[2];
}
protected static $libBlue = ['color'];
protected function libBlue($args)
{
$color = $this->coerceColor($args[0]);
return $color[3];
}
protected static $libAlpha = ['color'];
protected function libAlpha($args)
{
if ($color = $this->coerceColor($args[0])) {
return isset($color[4]) ? $color[4] : 1;
}
// this might be the IE function, so return value unchanged
return null;
}
protected static $libOpacity = ['color'];
protected function libOpacity($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
return $this->libAlpha($args);
}
// mix two colors
protected static $libMix = ['color-1', 'color-2',
'weight'];
protected function libMix($args)
{
list($first, $second, $weight) = $args;
$first = $this->assertColor($first);
$second = $this->assertColor($second);
if (! isset($weight)) {
$weight = 0.5;
} else {
$weight = $this->coercePercent($weight);
}
$firstAlpha = isset($first[4]) ? $first[4] : 1;
$secondAlpha = isset($second[4]) ? $second[4] : 1;
$w = $weight * 2 - 1;
$a = $firstAlpha - $secondAlpha;
$w1 = (($w * $a === -1 ? $w : ($w + $a) / (1 + $w * $a)) + 1) /
2.0;
$w2 = 1.0 - $w1;
$new = [Type::T_COLOR,
$w1 * $first[1] + $w2 * $second[1],
$w1 * $first[2] + $w2 * $second[2],
$w1 * $first[3] + $w2 * $second[3],
];
if ($firstAlpha != 1.0 || $secondAlpha != 1.0) {
$new[] = $firstAlpha * $weight + $secondAlpha * (1 - $weight);
}
return $this->fixColor($new);
}
protected static $libHsl = ['hue', 'saturation',
'lightness'];
protected function libHsl($args)
{
list($h, $s, $l) = $args;
return $this->toRGB($h[1], $s[1], $l[1]);
}
protected static $libHsla = ['hue', 'saturation',
'lightness', 'alpha'];
protected function libHsla($args)
{
list($h, $s, $l, $a) = $args;
$color = $this->toRGB($h[1], $s[1], $l[1]);
$color[4] = $a[1];
return $color;
}
protected static $libHue = ['color'];
protected function libHue($args)
{
$color = $this->assertColor($args[0]);
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
return new Node\Number($hsl[1], 'deg');
}
protected static $libSaturation = ['color'];
protected function libSaturation($args)
{
$color = $this->assertColor($args[0]);
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
return new Node\Number($hsl[2], '%');
}
protected static $libLightness = ['color'];
protected function libLightness($args)
{
$color = $this->assertColor($args[0]);
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
return new Node\Number($hsl[3], '%');
}
protected function adjustHsl($color, $idx, $amount)
{
$hsl = $this->toHSL($color[1], $color[2], $color[3]);
$hsl[$idx] += $amount;
$out = $this->toRGB($hsl[1], $hsl[2], $hsl[3]);
if (isset($color[4])) {
$out[4] = $color[4];
}
return $out;
}
protected static $libAdjustHue = ['color',
'degrees'];
protected function libAdjustHue($args)
{
$color = $this->assertColor($args[0]);
$degrees = $this->assertNumber($args[1]);
return $this->adjustHsl($color, 1, $degrees);
}
protected static $libLighten = ['color', 'amount'];
protected function libLighten($args)
{
$color = $this->assertColor($args[0]);
$amount = Util::checkRange('amount', new Range(0, 100),
$args[1], '%');
return $this->adjustHsl($color, 3, $amount);
}
protected static $libDarken = ['color', 'amount'];
protected function libDarken($args)
{
$color = $this->assertColor($args[0]);
$amount = Util::checkRange('amount', new Range(0, 100),
$args[1], '%');
return $this->adjustHsl($color, 3, -$amount);
}
protected static $libSaturate = ['color',
'amount'];
protected function libSaturate($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
$color = $this->assertColor($value);
$amount = 100 * $this->coercePercent($args[1]);
return $this->adjustHsl($color, 2, $amount);
}
protected static $libDesaturate = ['color',
'amount'];
protected function libDesaturate($args)
{
$color = $this->assertColor($args[0]);
$amount = 100 * $this->coercePercent($args[1]);
return $this->adjustHsl($color, 2, -$amount);
}
protected static $libGrayscale = ['color'];
protected function libGrayscale($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
return $this->adjustHsl($this->assertColor($value), 2, -100);
}
protected static $libComplement = ['color'];
protected function libComplement($args)
{
return $this->adjustHsl($this->assertColor($args[0]), 1,
180);
}
protected static $libInvert = ['color'];
protected function libInvert($args)
{
$value = $args[0];
if ($value[0] === Type::T_NUMBER) {
return null;
}
$color = $this->assertColor($value);
$color[1] = 255 - $color[1];
$color[2] = 255 - $color[2];
$color[3] = 255 - $color[3];
return $color;
}
// increases opacity by amount
protected static $libOpacify = ['color', 'amount'];
protected function libOpacify($args)
{
$color = $this->assertColor($args[0]);
$amount = $this->coercePercent($args[1]);
$color[4] = (isset($color[4]) ? $color[4] : 1) + $amount;
$color[4] = min(1, max(0, $color[4]));
return $color;
}
protected static $libFadeIn = ['color', 'amount'];
protected function libFadeIn($args)
{
return $this->libOpacify($args);
}
// decreases opacity by amount
protected static $libTransparentize = ['color',
'amount'];
protected function libTransparentize($args)
{
$color = $this->assertColor($args[0]);
$amount = $this->coercePercent($args[1]);
$color[4] = (isset($color[4]) ? $color[4] : 1) - $amount;
$color[4] = min(1, max(0, $color[4]));
return $color;
}
protected static $libFadeOut = ['color', 'amount'];
protected function libFadeOut($args)
{
return $this->libTransparentize($args);
}
protected static $libUnquote = ['string'];
protected function libUnquote($args)
{
$str = $args[0];
if ($str[0] === Type::T_STRING) {
$str[1] = '';
}
return $str;
}
protected static $libQuote = ['string'];
protected function libQuote($args)
{
$value = $args[0];
if ($value[0] === Type::T_STRING && ! empty($value[1])) {
return $value;
}
return [Type::T_STRING, '"', [$value]];
}
protected static $libPercentage = ['value'];
protected function libPercentage($args)
{
return new Node\Number($this->coercePercent($args[0]) * 100,
'%');
}
protected static $libRound = ['value'];
protected function libRound($args)
{
$num = $args[0];
return new Node\Number(round($num[1]), $num[2]);
}
protected static $libFloor = ['value'];
protected function libFloor($args)
{
$num = $args[0];
return new Node\Number(floor($num[1]), $num[2]);
}
protected static $libCeil = ['value'];
protected function libCeil($args)
{
$num = $args[0];
return new Node\Number(ceil($num[1]), $num[2]);
}
protected static $libAbs = ['value'];
protected function libAbs($args)
{
$num = $args[0];
return new Node\Number(abs($num[1]), $num[2]);
}
protected function libMin($args)
{
$numbers = $this->getNormalizedNumbers($args);
$min = null;
foreach ($numbers as $key => $number) {
if (null === $min || $number[1] <= $min[1]) {
$min = [$key, $number[1]];
}
}
return $args[$min[0]];
}
protected function libMax($args)
{
$numbers = $this->getNormalizedNumbers($args);
$max = null;
foreach ($numbers as $key => $number) {
if (null === $max || $number[1] >= $max[1]) {
$max = [$key, $number[1]];
}
}
return $args[$max[0]];
}
/**
* Helper to normalize args containing numbers
*
* @param array $args
*
* @return array
*/
protected function getNormalizedNumbers($args)
{
$unit = null;
$originalUnit = null;
$numbers = [];
foreach ($args as $key => $item) {
if ($item[0] !== Type::T_NUMBER) {
$this->throwError('%s is not a number',
$item[0]);
break;
}
$number = $item->normalize();
if (null === $unit) {
$unit = $number[2];
$originalUnit = $item->unitStr();
} elseif ($number[1] && $unit !== $number[2]) {
$this->throwError('Incompatible units:
"%s" and "%s".', $originalUnit,
$item->unitStr());
break;
}
$numbers[$key] = $number;
}
return $numbers;
}
protected static $libLength = ['list'];
protected function libLength($args)
{
$list = $this->coerceList($args[0]);
return count($list[2]);
}
//protected static $libListSeparator = ['list...'];
protected function libListSeparator($args)
{
if (count($args) > 1) {
return 'comma';
}
$list = $this->coerceList($args[0]);
if (count($list[2]) <= 1) {
return 'space';
}
if ($list[1] === ',') {
return 'comma';
}
return 'space';
}
protected static $libNth = ['list', 'n'];
protected function libNth($args)
{
$list = $this->coerceList($args[0]);
$n = $this->assertNumber($args[1]);
if ($n > 0) {
$n--;
} elseif ($n < 0) {
$n += count($list[2]);
}
return isset($list[2][$n]) ? $list[2][$n] : static::$defaultValue;
}
protected static $libSetNth = ['list', 'n',
'value'];
protected function libSetNth($args)
{
$list = $this->coerceList($args[0]);
$n = $this->assertNumber($args[1]);
if ($n > 0) {
$n--;
} elseif ($n < 0) {
$n += count($list[2]);
}
if (! isset($list[2][$n])) {
$this->throwError('Invalid argument for
"n"');
return null;
}
$list[2][$n] = $args[2];
return $list;
}
protected static $libMapGet = ['map', 'key'];
protected function libMapGet($args)
{
$map = $this->assertMap($args[0]);
$key =
$this->compileStringContent($this->coerceString($args[1]));
for ($i = count($map[1]) - 1; $i >= 0; $i--) {
if ($key ===
$this->compileStringContent($this->coerceString($map[1][$i]))) {
return $map[2][$i];
}
}
return static::$null;
}
protected static $libMapKeys = ['map'];
protected function libMapKeys($args)
{
$map = $this->assertMap($args[0]);
$keys = $map[1];
return [Type::T_LIST, ',', $keys];
}
protected static $libMapValues = ['map'];
protected function libMapValues($args)
{
$map = $this->assertMap($args[0]);
$values = $map[2];
return [Type::T_LIST, ',', $values];
}
protected static $libMapRemove = ['map', 'key'];
protected function libMapRemove($args)
{
$map = $this->assertMap($args[0]);
$key =
$this->compileStringContent($this->coerceString($args[1]));
for ($i = count($map[1]) - 1; $i >= 0; $i--) {
if ($key ===
$this->compileStringContent($this->coerceString($map[1][$i]))) {
array_splice($map[1], $i, 1);
array_splice($map[2], $i, 1);
}
}
return $map;
}
protected static $libMapHasKey = ['map', 'key'];
protected function libMapHasKey($args)
{
$map = $this->assertMap($args[0]);
$key =
$this->compileStringContent($this->coerceString($args[1]));
for ($i = count($map[1]) - 1; $i >= 0; $i--) {
if ($key ===
$this->compileStringContent($this->coerceString($map[1][$i]))) {
return true;
}
}
return false;
}
protected static $libMapMerge = ['map-1', 'map-2'];
protected function libMapMerge($args)
{
$map1 = $this->assertMap($args[0]);
$map2 = $this->assertMap($args[1]);
foreach ($map2[1] as $i2 => $key2) {
$key =
$this->compileStringContent($this->coerceString($key2));
foreach ($map1[1] as $i1 => $key1) {
if ($key ===
$this->compileStringContent($this->coerceString($key1))) {
$map1[2][$i1] = $map2[2][$i2];
continue 2;
}
}
$map1[1][] = $map2[1][$i2];
$map1[2][] = $map2[2][$i2];
}
return $map1;
}
protected static $libKeywords = ['args'];
protected function libKeywords($args)
{
$this->assertList($args[0]);
$keys = [];
$values = [];
foreach ($args[0][2] as $name => $arg) {
$keys[] = [Type::T_KEYWORD, $name];
$values[] = $arg;
}
return [Type::T_MAP, $keys, $values];
}
protected function listSeparatorForJoin($list1, $sep)
{
if (! isset($sep)) {
return $list1[1];
}
switch ($this->compileValue($sep)) {
case 'comma':
return ',';
case 'space':
return '';
default:
return $list1[1];
}
}
protected static $libJoin = ['list1', 'list2',
'separator'];
protected function libJoin($args)
{
list($list1, $list2, $sep) = $args;
$list1 = $this->coerceList($list1, ' ');
$list2 = $this->coerceList($list2, ' ');
$sep = $this->listSeparatorForJoin($list1, $sep);
return [Type::T_LIST, $sep, array_merge($list1[2], $list2[2])];
}
protected static $libAppend = ['list', 'val',
'separator'];
protected function libAppend($args)
{
list($list1, $value, $sep) = $args;
$list1 = $this->coerceList($list1, ' ');
$sep = $this->listSeparatorForJoin($list1, $sep);
return [Type::T_LIST, $sep, array_merge($list1[2], [$value])];
}
protected function libZip($args)
{
foreach ($args as $arg) {
$this->assertList($arg);
}
$lists = [];
$firstList = array_shift($args);
foreach ($firstList[2] as $key => $item) {
$list = [Type::T_LIST, '', [$item]];
foreach ($args as $arg) {
if (isset($arg[2][$key])) {
$list[2][] = $arg[2][$key];
} else {
break 2;
}
}
$lists[] = $list;
}
return [Type::T_LIST, ',', $lists];
}
protected static $libTypeOf = ['value'];
protected function libTypeOf($args)
{
$value = $args[0];
switch ($value[0]) {
case Type::T_KEYWORD:
if ($value === static::$true || $value === static::$false)
{
return 'bool';
}
if ($this->coerceColor($value)) {
return 'color';
}
// fall-thru
case Type::T_FUNCTION:
return 'string';
case Type::T_LIST:
if (isset($value[3]) && $value[3]) {
return 'arglist';
}
// fall-thru
default:
return $value[0];
}
}
protected static $libUnit = ['number'];
protected function libUnit($args)
{
$num = $args[0];
if ($num[0] === Type::T_NUMBER) {
return [Type::T_STRING, '"',
[$num->unitStr()]];
}
return '';
}
protected static $libUnitless = ['number'];
protected function libUnitless($args)
{
$value = $args[0];
return $value[0] === Type::T_NUMBER &&
$value->unitless();
}
protected static $libComparable = ['number-1',
'number-2'];
protected function libComparable($args)
{
list($number1, $number2) = $args;
if (! isset($number1[0]) || $number1[0] !== Type::T_NUMBER ||
! isset($number2[0]) || $number2[0] !== Type::T_NUMBER
) {
$this->throwError('Invalid argument(s) for
"comparable"');
return null;
}
$number1 = $number1->normalize();
$number2 = $number2->normalize();
return $number1[2] === $number2[2] || $number1->unitless() ||
$number2->unitless();
}
protected static $libStrIndex = ['string',
'substring'];
protected function libStrIndex($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$substring = $this->coerceString($args[1]);
$substringContent = $this->compileStringContent($substring);
$result = strpos($stringContent, $substringContent);
return $result === false ? static::$null : new Node\Number($result
+ 1, '');
}
protected static $libStrInsert = ['string',
'insert', 'index'];
protected function libStrInsert($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$insert = $this->coerceString($args[1]);
$insertContent = $this->compileStringContent($insert);
list(, $index) = $args[2];
$string[2] = [substr_replace($stringContent, $insertContent, $index
- 1, 0)];
return $string;
}
protected static $libStrLength = ['string'];
protected function libStrLength($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
return new Node\Number(strlen($stringContent), '');
}
protected static $libStrSlice = ['string',
'start-at', 'end-at'];
protected function libStrSlice($args)
{
if (isset($args[2]) && $args[2][1] == 0) {
return static::$nullString;
}
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$start = (int) $args[1][1];
if ($start > 0) {
$start--;
}
$end = (int) $args[2][1];
$length = $end < 0 ? $end + 1 : ($end > 0 ? $end - $start :
$end);
$string[2] = $length
? [substr($stringContent, $start, $length)]
: [substr($stringContent, $start)];
return $string;
}
protected static $libToLowerCase = ['string'];
protected function libToLowerCase($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$string[2] = [function_exists('mb_strtolower') ?
mb_strtolower($stringContent) : strtolower($stringContent)];
return $string;
}
protected static $libToUpperCase = ['string'];
protected function libToUpperCase($args)
{
$string = $this->coerceString($args[0]);
$stringContent = $this->compileStringContent($string);
$string[2] = [function_exists('mb_strtoupper') ?
mb_strtoupper($stringContent) : strtoupper($stringContent)];
return $string;
}
protected static $libFeatureExists = ['feature'];
protected function libFeatureExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->toBool(
array_key_exists($name, $this->registeredFeatures) ?
$this->registeredFeatures[$name] : false
);
}
protected static $libFunctionExists = ['name'];
protected function libFunctionExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
// user defined functions
if ($this->has(static::$namespaces['function'] .
$name)) {
return true;
}
$name = $this->normalizeName($name);
if (isset($this->userFunctions[$name])) {
return true;
}
// built-in functions
$f = $this->getBuiltinFunction($name);
return $this->toBool(is_callable($f));
}
protected static $libGlobalVariableExists = ['name'];
protected function libGlobalVariableExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->has($name, $this->rootEnv);
}
protected static $libMixinExists = ['name'];
protected function libMixinExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->has(static::$namespaces['mixin'] .
$name);
}
protected static $libVariableExists = ['name'];
protected function libVariableExists($args)
{
$string = $this->coerceString($args[0]);
$name = $this->compileStringContent($string);
return $this->has($name);
}
/**
* Workaround IE7's content counter bug.
*
* @param array $args
*
* @return array
*/
protected function libCounter($args)
{
$list = array_map([$this, 'compileValue'], $args);
return [Type::T_STRING, '', ['counter(' .
implode(',', $list) . ')']];
}
protected static $libRandom = ['limit'];
protected function libRandom($args)
{
if (isset($args[0])) {
$n = $this->assertNumber($args[0]);
if ($n < 1) {
$this->throwError("limit must be greater than or
equal to 1");
return null;
}
return new Node\Number(mt_rand(1, $n), '');
}
return new Node\Number(mt_rand(1, mt_getrandmax()), '');
}
protected function libUniqueId()
{
static $id;
if (! isset($id)) {
$id = mt_rand(0, pow(36, 8));
}
$id += mt_rand(0, 10) + 1;
return [Type::T_STRING, '', ['u' .
str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT)]];
}
protected static $libInspect = ['value'];
protected function libInspect($args)
{
if ($args[0] === static::$null) {
return [Type::T_KEYWORD, 'null'];
}
return $args[0];
}
/**
* Preprocess selector args
*
* @param array $arg
*
* @return array|boolean
*/
protected function getSelectorArg($arg)
{
static $parser = null;
if (is_null($parser)) {
$parser = $this->parserFactory(__METHOD__);
}
$arg = $this->libUnquote([$arg]);
$arg = $this->compileValue($arg);
$parsedSelector = [];
if ($parser->parseSelector($arg, $parsedSelector)) {
$selector = $this->evalSelectors($parsedSelector);
$gluedSelector = $this->glueFunctionSelectors($selector);
return $gluedSelector;
}
return false;
}
/**
* Postprocess selector to output in right format
*
* @param array $selectors
*
* @return string
*/
protected function formatOutputSelector($selectors)
{
$selectors = $this->collapseSelectors($selectors, true);
return $selectors;
}
protected static $libIsSuperselector = ['super',
'sub'];
protected function libIsSuperselector($args)
{
list($super, $sub) = $args;
$super = $this->getSelectorArg($super);
$sub = $this->getSelectorArg($sub);
return $this->isSuperSelector($super, $sub);
}
/**
* Test a $super selector again $sub
*
* @param array $super
* @param array $sub
*
* @return boolean
*/
protected function isSuperSelector($super, $sub)
{
// one and only one selector for each arg
if (! $super || count($super) !== 1) {
$this->throwError("Invalid super selector for
isSuperSelector()");
}
if (! $sub || count($sub) !== 1) {
$this->throwError("Invalid sub selector for
isSuperSelector()");
}
$super = reset($super);
$sub = reset($sub);
$i = 0;
$nextMustMatch = false;
foreach ($super as $node) {
$compound = '';
array_walk_recursive(
$node,
function ($value, $key) use (&$compound) {
$compound .= $value;
}
);
if ($this->isImmediateRelationshipCombinator($compound)) {
if ($node !== $sub[$i]) {
return false;
}
$nextMustMatch = true;
$i++;
} else {
while ($i < count($sub) && !
$this->isSuperPart($node, $sub[$i])) {
if ($nextMustMatch) {
return false;
}
$i++;
}
if ($i >= count($sub)) {
return false;
}
$nextMustMatch = false;
$i++;
}
}
return true;
}
/**
* Test a part of super selector again a part of sub selector
*
* @param array $superParts
* @param array $subParts
*
* @return boolean
*/
protected function isSuperPart($superParts, $subParts)
{
$i = 0;
foreach ($superParts as $superPart) {
while ($i < count($subParts) && $subParts[$i] !==
$superPart) {
$i++;
}
if ($i >= count($subParts)) {
return false;
}
$i++;
}
return true;
}
//protected static $libSelectorAppend = ['selector...'];
protected function libSelectorAppend($args)
{
if (count($args) < 1) {
$this->throwError("selector-append() needs at least 1
argument");
}
$selectors = array_map([$this, 'getSelectorArg'], $args);
return
$this->formatOutputSelector($this->selectorAppend($selectors));
}
/**
* Append parts of the last selector in the list to the previous,
recursively
*
* @param array $selectors
*
* @return array
*
* @throws \Leafo\ScssPhp\Exception\CompilerException
*/
protected function selectorAppend($selectors)
{
$lastSelectors = array_pop($selectors);
if (! $lastSelectors) {
$this->throwError("Invalid selector list in
selector-append()");
}
while (count($selectors)) {
$previousSelectors = array_pop($selectors);
if (! $previousSelectors) {
$this->throwError("Invalid selector list in
selector-append()");
}
// do the trick, happening $lastSelector to $previousSelector
$appended = [];
foreach ($lastSelectors as $lastSelector) {
$previous = $previousSelectors;
foreach ($lastSelector as $lastSelectorParts) {
foreach ($lastSelectorParts as $lastSelectorPart) {
foreach ($previous as $i => $previousSelector) {
foreach ($previousSelector as $j =>
$previousSelectorParts) {
$previous[$i][$j][] = $lastSelectorPart;
}
}
}
}
foreach ($previous as $ps) {
$appended[] = $ps;
}
}
$lastSelectors = $appended;
}
return $lastSelectors;
}
protected static $libSelectorExtend = ['selectors',
'extendee', 'extender'];
protected function libSelectorExtend($args)
{
list($selectors, $extendee, $extender) = $args;
$selectors = $this->getSelectorArg($selectors);
$extendee = $this->getSelectorArg($extendee);
$extender = $this->getSelectorArg($extender);
if (! $selectors || ! $extendee || ! $extender) {
$this->throwError("selector-extend() invalid
arguments");
}
$extended = $this->extendOrReplaceSelectors($selectors,
$extendee, $extender);
return $this->formatOutputSelector($extended);
}
protected static $libSelectorReplace = ['selectors',
'original', 'replacement'];
protected function libSelectorReplace($args)
{
list($selectors, $original, $replacement) = $args;
$selectors = $this->getSelectorArg($selectors);
$original = $this->getSelectorArg($original);
$replacement = $this->getSelectorArg($replacement);
if (! $selectors || ! $original || ! $replacement) {
$this->throwError("selector-replace() invalid
arguments");
}
$replaced = $this->extendOrReplaceSelectors($selectors,
$original, $replacement, true);
return $this->formatOutputSelector($replaced);
}
/**
* Extend/replace in selectors
* used by selector-extend and selector-replace that use the same logic
*
* @param array $selectors
* @param array $extendee
* @param array $extender
* @param boolean $replace
*
* @return array
*/
protected function extendOrReplaceSelectors($selectors, $extendee,
$extender, $replace = false)
{
$saveExtends = $this->extends;
$saveExtendsMap = $this->extendsMap;
$this->extends = [];
$this->extendsMap = [];
foreach ($extendee as $es) {
// only use the first one
$this->pushExtends(reset($es), $extender, null);
}
$extended = [];
foreach ($selectors as $selector) {
if (! $replace) {
$extended[] = $selector;
}
$n = count($extended);
$this->matchExtends($selector, $extended);
// if didnt match, keep the original selector if we are in a
replace operation
if ($replace and count($extended) === $n) {
$extended[] = $selector;
}
}
$this->extends = $saveExtends;
$this->extendsMap = $saveExtendsMap;
return $extended;
}
//protected static $libSelectorNest = ['selector...'];
protected function libSelectorNest($args)
{
if (count($args) < 1) {
$this->throwError("selector-nest() needs at least 1
argument");
}
$selectorsMap = array_map([$this, 'getSelectorArg'],
$args);
$envs = [];
foreach ($selectorsMap as $selectors) {
$env = new Environment();
$env->selectors = $selectors;
$envs[] = $env;
}
$envs = array_reverse($envs);
$env = $this->extractEnv($envs);
$outputSelectors = $this->multiplySelectors($env);
return $this->formatOutputSelector($outputSelectors);
}
protected static $libSelectorParse = ['selectors'];
protected function libSelectorParse($args)
{
$selectors = reset($args);
$selectors = $this->getSelectorArg($selectors);
return $this->formatOutputSelector($selectors);
}
protected static $libSelectorUnify = ['selectors1',
'selectors2'];
protected function libSelectorUnify($args)
{
list($selectors1, $selectors2) = $args;
$selectors1 = $this->getSelectorArg($selectors1);
$selectors2 = $this->getSelectorArg($selectors2);
if (! $selectors1 || ! $selectors2) {
$this->throwError("selector-unify() invalid
arguments");
}
// only consider the first compound of each
$compound1 = reset($selectors1);
$compound2 = reset($selectors2);
// unify them and that's it
$unified = $this->unifyCompoundSelectors($compound1,
$compound2);
return $this->formatOutputSelector($unified);
}
/**
* The selector-unify magic as its best
* (at least works as expected on test cases)
*
* @param array $compound1
* @param array $compound2
* @return array|mixed
*/
protected function unifyCompoundSelectors($compound1, $compound2)
{
if (! count($compound1)) {
return $compound2;
}
if (! count($compound2)) {
return $compound1;
}
// check that last part are compatible
$lastPart1 = array_pop($compound1);
$lastPart2 = array_pop($compound2);
$last = $this->mergeParts($lastPart1, $lastPart2);
if (! $last) {
return [[]];
}
$unifiedCompound = [$last];
$unifiedSelectors = [$unifiedCompound];
// do the rest
while (count($compound1) || count($compound2)) {
$part1 = end($compound1);
$part2 = end($compound2);
if ($part1 && ($match2 =
$this->matchPartInCompound($part1, $compound2))) {
list($compound2, $part2, $after2) = $match2;
if ($after2) {
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, $after2);
}
$c = $this->mergeParts($part1, $part2);
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, [$c]);
$part1 = $part2 = null;
array_pop($compound1);
}
if ($part2 && ($match1 =
$this->matchPartInCompound($part2, $compound1))) {
list($compound1, $part1, $after1) = $match1;
if ($after1) {
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, $after1);
}
$c = $this->mergeParts($part2, $part1);
$unifiedSelectors =
$this->prependSelectors($unifiedSelectors, [$c]);
$part1 = $part2 = null;
array_pop($compound2);
}
$new = [];
if ($part1 && $part2) {
array_pop($compound1);
array_pop($compound2);
$s = $this->prependSelectors($unifiedSelectors,
[$part2]);
$new = array_merge($new, $this->prependSelectors($s,
[$part1]));
$s = $this->prependSelectors($unifiedSelectors,
[$part1]);
$new = array_merge($new, $this->prependSelectors($s,
[$part2]));
} elseif ($part1) {
array_pop($compound1);
$new = array_merge($new,
$this->prependSelectors($unifiedSelectors, [$part1]));
} elseif ($part2) {
array_pop($compound2);
$new = array_merge($new,
$this->prependSelectors($unifiedSelectors, [$part2]));
}
if ($new) {
$unifiedSelectors = $new;
}
}
return $unifiedSelectors;
}
/**
* Prepend each selector from $selectors with $parts
*
* @param array $selectors
* @param array $parts
*
* @return array
*/
protected function prependSelectors($selectors, $parts)
{
$new = [];
foreach ($selectors as $compoundSelector) {
array_unshift($compoundSelector, $parts);
$new[] = $compoundSelector;
}
return $new;
}
/**
* Try to find a matching part in a compound:
* - with same html tag name
* - with some class or id or something in common
*
* @param array $part
* @param array $compound
*
* @return array|boolean
*/
protected function matchPartInCompound($part, $compound)
{
$partTag = $this->findTagName($part);
$before = $compound;
$after = [];
// try to find a match by tag name first
while (count($before)) {
$p = array_pop($before);
if ($partTag && $partTag !== '*' &&
$partTag == $this->findTagName($p)) {
return [$before, $p, $after];
}
$after[] = $p;
}
// try again matching a non empty intersection and a compatible
tagname
$before = $compound;
$after = [];
while (count($before)) {
$p = array_pop($before);
if ($this->checkCompatibleTags($partTag,
$this->findTagName($p))) {
if (count(array_intersect($part, $p))) {
return [$before, $p, $after];
}
}
$after[] = $p;
}
return false;
}
/**
* Merge two part list taking care that
* - the html tag is coming first - if any
* - the :something are coming last
*
* @param array $parts1
* @param array $parts2
*
* @return array
*/
protected function mergeParts($parts1, $parts2)
{
$tag1 = $this->findTagName($parts1);
$tag2 = $this->findTagName($parts2);
$tag = $this->checkCompatibleTags($tag1, $tag2);
// not compatible tags
if ($tag === false) {
return [];
}
if ($tag) {
if ($tag1) {
$parts1 = array_diff($parts1, [$tag1]);
}
if ($tag2) {
$parts2 = array_diff($parts2, [$tag2]);
}
}
$mergedParts = array_merge($parts1, $parts2);
$mergedOrderedParts = [];
foreach ($mergedParts as $part) {
if (strpos($part, ':') === 0) {
$mergedOrderedParts[] = $part;
}
}
$mergedParts = array_diff($mergedParts, $mergedOrderedParts);
$mergedParts = array_merge($mergedParts, $mergedOrderedParts);
if ($tag) {
array_unshift($mergedParts, $tag);
}
return $mergedParts;
}
/**
* Check the compatibility between two tag names:
* if both are defined they should be identical or one has to be
'*'
*
* @param string $tag1
* @param string $tag2
*
* @return array|boolean
*/
protected function checkCompatibleTags($tag1, $tag2)
{
$tags = [$tag1, $tag2];
$tags = array_unique($tags);
$tags = array_filter($tags);
if (count($tags)>1) {
$tags = array_diff($tags, ['*']);
}
// not compatible nodes
if (count($tags)>1) {
return false;
}
return $tags;
}
/**
* Find the html tag name in a selector parts list
*
* @param array $parts
*
* @return mixed|string
*/
protected function findTagName($parts)
{
foreach ($parts as $part) {
if (! preg_match('/^[\[.:#%_-]/', $part)) {
return $part;
}
}
return '';
}
protected static $libSimpleSelectors = ['selector'];
protected function libSimpleSelectors($args)
{
$selector = reset($args);
$selector = $this->getSelectorArg($selector);
// remove selectors list layer, keeping the first one
$selector = reset($selector);
// remove parts list layer, keeping the first part
$part = reset($selector);
$listParts = [];
foreach ($part as $p) {
$listParts[] = [Type::T_STRING, '', [$p]];
}
return [Type::T_LIST, ',', $listParts];
}
}
PK*d�[�/�NN8vendor/leafo/scssphp/src/Exception/CompilerException.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Exception;
/**
* Compiler exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*/
class CompilerException extends \Exception
{
}
PK*d�[��iJJ6vendor/leafo/scssphp/src/Exception/ParserException.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Exception;
/**
* Parser Exception
*
* @author Oleksandr Savchenko <traveltino@gmail.com>
*/
class ParserException extends \Exception
{
}
PK*d�[�
vAA5vendor/leafo/scssphp/src/Exception/RangeException.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Exception;
/**
* Range exception
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class RangeException extends \Exception
{
}
PK*d�[��CC6vendor/leafo/scssphp/src/Exception/ServerException.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Exception;
/**
* Server Exception
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class ServerException extends \Exception
{
}
PK*d�[�&��.vendor/leafo/scssphp/src/Formatter/Compact.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
/**
* Compact formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Compact extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = '';
$this->break = '';
$this->open = ' {';
$this->close = "}\n\n";
$this->tagSeparator = ',';
$this->assignSeparator = ':';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
public function indentStr()
{
return ' ';
}
}
PK*d�[�BtwFF1vendor/leafo/scssphp/src/Formatter/Compressed.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Compressed formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Compressed extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = '';
$this->open = '{';
$this->close = '}';
$this->tagSeparator = ',';
$this->assignSeparator = ':';
$this->keepSemicolons = false;
}
/**
* {@inheritdoc}
*/
public function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*' &&
substr($line, 2, 1) !== '!') {
unset($block->lines[$index]);
} elseif (substr($line, 0, 3) === '/*!') {
$block->lines[$index] = '/*' . substr($line,
3);
}
}
$this->write($inner . implode($glue, $block->lines));
if (! empty($block->children)) {
$this->write($this->break);
}
}
/**
* Output block selectors
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockSelectors(OutputBlock $block)
{
$inner = $this->indentStr();
$this->write(
$inner
. implode(
$this->tagSeparator,
str_replace([' > ', ' + ', ' ~
'], ['>', '+', '~'],
$block->selectors)
)
. $this->open . $this->break
);
}
}
PK*d�[�?�!��/vendor/leafo/scssphp/src/Formatter/Crunched.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Crunched formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Crunched extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = '';
$this->open = '{';
$this->close = '}';
$this->tagSeparator = ',';
$this->assignSeparator = ':';
$this->keepSemicolons = false;
}
/**
* {@inheritdoc}
*/
public function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
unset($block->lines[$index]);
}
}
$this->write($inner . implode($glue, $block->lines));
if (! empty($block->children)) {
$this->write($this->break);
}
}
/**
* Output block selectors
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockSelectors(OutputBlock $block)
{
$inner = $this->indentStr();
$this->write(
$inner
. implode(
$this->tagSeparator,
str_replace([' > ', ' + ', ' ~
'], ['>', '+', '~'],
$block->selectors)
)
. $this->open . $this->break
);
}
}
PK*d�[�GFH� � ,vendor/leafo/scssphp/src/Formatter/Debug.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Debug formatter
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Debug extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = '';
$this->break = "\n";
$this->open = ' {';
$this->close = ' }';
$this->tagSeparator = ', ';
$this->assignSeparator = ': ';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
protected function indentStr()
{
return str_repeat(' ', $this->indentLevel);
}
/**
* {@inheritdoc}
*/
protected function blockLines(OutputBlock $block)
{
$indent = $this->indentStr();
if (empty($block->lines)) {
$this->write("{$indent}block->lines: []\n");
return;
}
foreach ($block->lines as $index => $line) {
$this->write("{$indent}block->lines[{$index}]:
$line\n");
}
}
/**
* {@inheritdoc}
*/
protected function blockSelectors(OutputBlock $block)
{
$indent = $this->indentStr();
if (empty($block->selectors)) {
$this->write("{$indent}block->selectors:
[]\n");
return;
}
foreach ($block->selectors as $index => $selector) {
$this->write("{$indent}block->selectors[{$index}]:
$selector\n");
}
}
/**
* {@inheritdoc}
*/
protected function blockChildren(OutputBlock $block)
{
$indent = $this->indentStr();
if (empty($block->children)) {
$this->write("{$indent}block->children: []\n");
return;
}
$this->indentLevel++;
foreach ($block->children as $i => $child) {
$this->block($child);
}
$this->indentLevel--;
}
/**
* {@inheritdoc}
*/
protected function block(OutputBlock $block)
{
$indent = $this->indentStr();
$this->write("{$indent}block->type:
{$block->type}\n" .
"{$indent}block->depth: {$block->depth}\n");
$this->currentBlock = $block;
$this->blockSelectors($block);
$this->blockLines($block);
$this->blockChildren($block);
}
}
PK*d�[�:�~��/vendor/leafo/scssphp/src/Formatter/Expanded.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Expanded formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Expanded extends Formatter
{
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = "\n";
$this->open = ' {';
$this->close = '}';
$this->tagSeparator = ', ';
$this->assignSeparator = ': ';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
protected function indentStr()
{
return str_repeat($this->indentChar, $this->indentLevel);
}
/**
* {@inheritdoc}
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$block->lines[$index] =
preg_replace('/(\r|\n)+/', $glue, $line);
}
}
$this->write($inner . implode($glue, $block->lines));
if (empty($block->selectors) || ! empty($block->children)) {
$this->write($this->break);
}
}
}
PK+d�[�v�mjj-vendor/leafo/scssphp/src/Formatter/Nested.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter;
use Leafo\ScssPhp\Formatter\OutputBlock;
/**
* Nested formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Nested extends Formatter
{
/**
* @var integer
*/
private $depth;
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->indentLevel = 0;
$this->indentChar = ' ';
$this->break = "\n";
$this->open = ' {';
$this->close = ' }';
$this->tagSeparator = ', ';
$this->assignSeparator = ': ';
$this->keepSemicolons = true;
}
/**
* {@inheritdoc}
*/
protected function indentStr()
{
$n = $this->depth - 1;
return str_repeat($this->indentChar, max($this->indentLevel +
$n, 0));
}
/**
* {@inheritdoc}
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
foreach ($block->lines as $index => $line) {
if (substr($line, 0, 2) === '/*') {
$block->lines[$index] =
preg_replace('/(\r|\n)+/', $glue, $line);
}
}
$this->write($inner . implode($glue, $block->lines));
if (! empty($block->children)) {
$this->write($this->break);
}
}
/**
* {@inheritdoc}
*/
protected function blockSelectors(OutputBlock $block)
{
$inner = $this->indentStr();
$this->write($inner
. implode($this->tagSeparator, $block->selectors)
. $this->open . $this->break);
}
/**
* {@inheritdoc}
*/
protected function blockChildren(OutputBlock $block)
{
foreach ($block->children as $i => $child) {
$this->block($child);
if ($i < count($block->children) - 1) {
$this->write($this->break);
if (isset($block->children[$i + 1])) {
$next = $block->children[$i + 1];
if ($next->depth === max($block->depth, 1)
&& $child->depth >= $next->depth) {
$this->write($this->break);
}
}
}
}
}
/**
* {@inheritdoc}
*/
protected function block(OutputBlock $block)
{
if ($block->type === 'root') {
$this->adjustAllChildren($block);
}
if (empty($block->lines) && empty($block->children))
{
return;
}
$this->currentBlock = $block;
$this->depth = $block->depth;
if (! empty($block->selectors)) {
$this->blockSelectors($block);
$this->indentLevel++;
}
if (! empty($block->lines)) {
$this->blockLines($block);
}
if (! empty($block->children)) {
$this->blockChildren($block);
}
if (! empty($block->selectors)) {
$this->indentLevel--;
$this->write($this->close);
}
if ($block->type === 'root') {
$this->write($this->break);
}
}
/**
* Adjust the depths of all children, depth first
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
private function adjustAllChildren(OutputBlock $block)
{
// flatten empty nested blocks
$children = [];
foreach ($block->children as $i => $child) {
if (empty($child->lines) &&
empty($child->children)) {
if (isset($block->children[$i + 1])) {
$block->children[$i + 1]->depth =
$child->depth;
}
continue;
}
$children[] = $child;
}
$count = count($children);
for ($i = 0; $i < $count; $i++) {
$depth = $children[$i]->depth;
$j = $i + 1;
if (isset($children[$j]) && $depth <
$children[$j]->depth) {
$childDepth = $children[$j]->depth;
for (; $j < $count; $j++) {
if ($depth < $children[$j]->depth &&
$childDepth >= $children[$j]->depth) {
$children[$j]->depth = $depth + 1;
}
}
}
}
$block->children = $children;
// make relative to parent
foreach ($block->children as $child) {
$this->adjustAllChildren($child);
$child->depth = $child->depth - $block->depth;
}
}
}
PK+d�[i�LL2vendor/leafo/scssphp/src/Formatter/OutputBlock.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Formatter;
/**
* Output block
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class OutputBlock
{
/**
* @var string
*/
public $type;
/**
* @var integer
*/
public $depth;
/**
* @var array
*/
public $selectors;
/**
* @var array
*/
public $lines;
/**
* @var array
*/
public $children;
/**
* @var \Leafo\ScssPhp\Formatter\OutputBlock
*/
public $parent;
/**
* @var string
*/
public $sourceName;
/**
* @var integer
*/
public $sourceLine;
/**
* @var integer
*/
public $sourceColumn;
}
PK+d�[� T�jj&vendor/leafo/scssphp/src/Formatter.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Formatter\OutputBlock;
use Leafo\ScssPhp\SourceMap\SourceMapGenerator;
/**
* Base formatter
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
abstract class Formatter
{
/**
* @var integer
*/
public $indentLevel;
/**
* @var string
*/
public $indentChar;
/**
* @var string
*/
public $break;
/**
* @var string
*/
public $open;
/**
* @var string
*/
public $close;
/**
* @var string
*/
public $tagSeparator;
/**
* @var string
*/
public $assignSeparator;
/**
* @var boolean
*/
public $keepSemicolons;
/**
* @var \Leafo\ScssPhp\Formatter\OutputBlock
*/
protected $currentBlock;
/**
* @var integer
*/
protected $currentLine;
/**
* @var integer
*/
protected $currentColumn;
/**
* @var \Leafo\ScssPhp\SourceMap\SourceMapGenerator
*/
protected $sourceMapGenerator;
/**
* Initialize formatter
*
* @api
*/
abstract public function __construct();
/**
* Return indentation (whitespace)
*
* @return string
*/
protected function indentStr()
{
return '';
}
/**
* Return property assignment
*
* @api
*
* @param string $name
* @param mixed $value
*
* @return string
*/
public function property($name, $value)
{
return rtrim($name) . $this->assignSeparator . $value .
';';
}
/**
* Strip semi-colon appended by property(); it's a separator, not
a terminator
*
* @api
*
* @param array $lines
*/
public function stripSemicolon(&$lines)
{
if ($this->keepSemicolons) {
return;
}
if (($count = count($lines))
&& substr($lines[$count - 1], -1) === ';'
) {
$lines[$count - 1] = substr($lines[$count - 1], 0, -1);
}
}
/**
* Output lines inside a block
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockLines(OutputBlock $block)
{
$inner = $this->indentStr();
$glue = $this->break . $inner;
$this->write($inner . implode($glue, $block->lines));
if (! empty($block->children)) {
$this->write($this->break);
}
}
/**
* Output block selectors
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockSelectors(OutputBlock $block)
{
$inner = $this->indentStr();
$this->write($inner
. implode($this->tagSeparator, $block->selectors)
. $this->open . $this->break);
}
/**
* Output block children
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function blockChildren(OutputBlock $block)
{
foreach ($block->children as $child) {
$this->block($child);
}
}
/**
* Output non-empty block
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
*/
protected function block(OutputBlock $block)
{
if (empty($block->lines) && empty($block->children))
{
return;
}
$this->currentBlock = $block;
$pre = $this->indentStr();
if (! empty($block->selectors)) {
$this->blockSelectors($block);
$this->indentLevel++;
}
if (! empty($block->lines)) {
$this->blockLines($block);
}
if (! empty($block->children)) {
$this->blockChildren($block);
}
if (! empty($block->selectors)) {
$this->indentLevel--;
if (empty($block->children)) {
$this->write($this->break);
}
$this->write($pre . $this->close . $this->break);
}
}
/**
* Entry point to formatting a block
*
* @api
*
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block
An abstract syntax tree
* @param \Leafo\ScssPhp\SourceMap\SourceMapGenerator|null
$sourceMapGenerator Optional source map generator
*
* @return string
*/
public function format(OutputBlock $block, SourceMapGenerator
$sourceMapGenerator = null)
{
$this->sourceMapGenerator = null;
if ($sourceMapGenerator) {
$this->currentLine = 1;
$this->currentColumn = 0;
$this->sourceMapGenerator = $sourceMapGenerator;
}
ob_start();
$this->block($block);
$out = ob_get_clean();
return $out;
}
/**
* @param string $str
*/
protected function write($str)
{
if ($this->sourceMapGenerator) {
$this->sourceMapGenerator->addMapping(
$this->currentLine,
$this->currentColumn,
$this->currentBlock->sourceLine,
//columns from parser are off by one
$this->currentBlock->sourceColumn > 0 ?
$this->currentBlock->sourceColumn - 1 : 0,
$this->currentBlock->sourceName
);
$lines = explode("\n", $str);
$lineCount = count($lines);
$this->currentLine += $lineCount-1;
$lastLine = array_pop($lines);
$this->currentColumn = ($lineCount === 1 ?
$this->currentColumn : 0) + strlen($lastLine);
}
echo $str;
}
}
PK+d�[�a�dd(vendor/leafo/scssphp/src/Node/Number.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\Node;
use Leafo\ScssPhp\Compiler;
use Leafo\ScssPhp\Node;
use Leafo\ScssPhp\Type;
/**
* Dimension + optional units
*
* {@internal
* This is a work-in-progress.
*
* The \ArrayAccess interface is temporary until the migration is
complete.
* }}
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Number extends Node implements \ArrayAccess
{
/**
* @var integer
*/
static public $precision = 10;
/**
* @see http://www.w3.org/TR/2012/WD-css3-values-20120308/
*
* @var array
*/
static protected $unitTable = [
'in' => [
'in' => 1,
'pc' => 6,
'pt' => 72,
'px' => 96,
'cm' => 2.54,
'mm' => 25.4,
'q' => 101.6,
],
'turn' => [
'deg' => 360,
'grad' => 400,
'rad' => 6.28318530717958647692528676, // 2 *
M_PI
'turn' => 1,
],
's' => [
's' => 1,
'ms' => 1000,
],
'Hz' => [
'Hz' => 1,
'kHz' => 0.001,
],
'dpi' => [
'dpi' => 1,
'dpcm' => 2.54,
'dppx' => 96,
],
];
/**
* @var integer|float
*/
public $dimension;
/**
* @var array
*/
public $units;
/**
* Initialize number
*
* @param mixed $dimension
* @param mixed $initialUnit
*/
public function __construct($dimension, $initialUnit)
{
$this->type = Type::T_NUMBER;
$this->dimension = $dimension;
$this->units = is_array($initialUnit)
? $initialUnit
: ($initialUnit ? [$initialUnit => 1]
: []);
}
/**
* Coerce number to target units
*
* @param array $units
*
* @return \Leafo\ScssPhp\Node\Number
*/
public function coerce($units)
{
if ($this->unitless()) {
return new Number($this->dimension, $units);
}
$dimension = $this->dimension;
foreach (static::$unitTable['in'] as $unit => $conv) {
$from = isset($this->units[$unit]) ?
$this->units[$unit] : 0;
$to = isset($units[$unit]) ? $units[$unit] : 0;
$factor = pow($conv, $from - $to);
$dimension /= $factor;
}
return new Number($dimension, $units);
}
/**
* Normalize number
*
* @return \Leafo\ScssPhp\Node\Number
*/
public function normalize()
{
$dimension = $this->dimension;
$units = [];
$this->normalizeUnits($dimension, $units, 'in');
return new Number($dimension, $units);
}
/**
* {@inheritdoc}
*/
public function offsetExists($offset)
{
if ($offset === -3) {
return $this->sourceColumn !== null;
}
if ($offset === -2) {
return $this->sourceLine !== null;
}
if ($offset === -1
|| $offset === 0
|| $offset === 1
|| $offset === 2
) {
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function offsetGet($offset)
{
switch ($offset) {
case -3:
return $this->sourceColumn;
case -2:
return $this->sourceLine;
case -1:
return $this->sourceIndex;
case 0:
return $this->type;
case 1:
return $this->dimension;
case 2:
return $this->units;
}
}
/**
* {@inheritdoc}
*/
public function offsetSet($offset, $value)
{
if ($offset === 1) {
$this->dimension = $value;
} elseif ($offset === 2) {
$this->units = $value;
} elseif ($offset == -1) {
$this->sourceIndex = $value;
} elseif ($offset == -2) {
$this->sourceLine = $value;
} elseif ($offset == -3) {
$this->sourceColumn = $value;
}
}
/**
* {@inheritdoc}
*/
public function offsetUnset($offset)
{
if ($offset === 1) {
$this->dimension = null;
} elseif ($offset === 2) {
$this->units = null;
} elseif ($offset === -1) {
$this->sourceIndex = null;
} elseif ($offset === -2) {
$this->sourceLine = null;
} elseif ($offset === -3) {
$this->sourceColumn = null;
}
}
/**
* Returns true if the number is unitless
*
* @return boolean
*/
public function unitless()
{
return ! array_sum($this->units);
}
/**
* Returns unit(s) as the product of numerator units divided by the
product of denominator units
*
* @return string
*/
public function unitStr()
{
$numerators = [];
$denominators = [];
foreach ($this->units as $unit => $unitSize) {
if ($unitSize > 0) {
$numerators = array_pad($numerators, count($numerators) +
$unitSize, $unit);
continue;
}
if ($unitSize < 0) {
$denominators = array_pad($denominators,
count($denominators) + $unitSize, $unit);
continue;
}
}
return implode('*', $numerators) . (count($denominators)
? '/' . implode('*', $denominators) : '');
}
/**
* Output number
*
* @param \Leafo\ScssPhp\Compiler $compiler
*
* @return string
*/
public function output(Compiler $compiler = null)
{
$dimension = round($this->dimension, static::$precision);
$units = array_filter($this->units, function ($unitSize) {
return $unitSize;
});
if (count($units) > 1 && array_sum($units) === 0) {
$dimension = $this->dimension;
$units = [];
$this->normalizeUnits($dimension, $units, 'in');
$dimension = round($dimension, static::$precision);
$units = array_filter($units, function ($unitSize) {
return $unitSize;
});
}
$unitSize = array_sum($units);
if ($compiler && ($unitSize > 1 || $unitSize < 0 ||
count($units) > 1)) {
$compiler->throwError((string) $dimension .
$this->unitStr() . " isn't a valid CSS value.");
}
reset($units);
$unit = key($units);
$dimension = number_format($dimension, static::$precision,
'.', '');
return (static::$precision ? rtrim(rtrim($dimension,
'0'), '.') : $dimension) . $unit;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->output();
}
/**
* Normalize units
*
* @param integer|float $dimension
* @param array $units
* @param string $baseUnit
*/
private function normalizeUnits(&$dimension, &$units, $baseUnit
= 'in')
{
$dimension = $this->dimension;
$units = [];
foreach ($this->units as $unit => $exp) {
if (isset(static::$unitTable[$baseUnit][$unit])) {
$factor = pow(static::$unitTable[$baseUnit][$unit], $exp);
$unit = $baseUnit;
$dimension /= $factor;
}
$units[$unit] = $exp + (isset($units[$unit]) ? $units[$unit] :
0);
}
}
}
PK+d�[wY��!vendor/leafo/scssphp/src/Node.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* Base node
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
abstract class Node
{
/**
* @var string
*/
public $type;
/**
* @var integer
*/
public $sourceIndex;
/**
* @var integer
*/
public $sourceLine;
/**
* @var integer
*/
public $sourceColumn;
}
PK+d�[�R��#vendor/leafo/scssphp/src/Parser.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Block;
use Leafo\ScssPhp\Cache;
use Leafo\ScssPhp\Compiler;
use Leafo\ScssPhp\Exception\ParserException;
use Leafo\ScssPhp\Node;
use Leafo\ScssPhp\Type;
/**
* Parser
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Parser
{
const SOURCE_INDEX = -1;
const SOURCE_LINE = -2;
const SOURCE_COLUMN = -3;
/**
* @var array
*/
protected static $precedence = [
'=' => 0,
'or' => 1,
'and' => 2,
'==' => 3,
'!=' => 3,
'<=>' => 3,
'<=' => 4,
'>=' => 4,
'<' => 4,
'>' => 4,
'+' => 5,
'-' => 5,
'*' => 6,
'/' => 6,
'%' => 6,
];
protected static $commentPattern;
protected static $operatorPattern;
protected static $whitePattern;
protected $cache;
private $sourceName;
private $sourceIndex;
private $sourcePositions;
private $charset;
private $count;
private $env;
private $inParens;
private $eatWhiteDefault;
private $buffer;
private $utf8;
private $encoding;
private $patternModifiers;
private $commentsSeen;
/**
* Constructor
*
* @api
*
* @param string $sourceName
* @param integer $sourceIndex
* @param string $encoding
* @param \Leafo\ScssPhp\Cache $cache
*/
public function __construct($sourceName, $sourceIndex = 0, $encoding =
'utf-8', $cache = null)
{
$this->sourceName = $sourceName ?: '(stdin)';
$this->sourceIndex = $sourceIndex;
$this->charset = null;
$this->utf8 = ! $encoding || strtolower($encoding)
=== 'utf-8';
$this->patternModifiers = $this->utf8 ? 'Aisu' :
'Ais';
$this->commentsSeen = [];
if (empty(static::$operatorPattern)) {
static::$operatorPattern =
'([*\/%+-]|[!=]\=|\>\=?|\<\=\>|\<\=?|and|or)';
$commentSingle = '\/\/';
$commentMultiLeft = '\/\*';
$commentMultiRight = '\*\/';
static::$commentPattern = $commentMultiLeft . '.*?' .
$commentMultiRight;
static::$whitePattern = $this->utf8
? '/' . $commentSingle . '[^\n]*\s*|('
. static::$commentPattern . ')\s*|\s+/AisuS'
: '/' . $commentSingle . '[^\n]*\s*|('
. static::$commentPattern . ')\s*|\s+/AisS';
}
if ($cache) {
$this->cache = $cache;
}
}
/**
* Get source file name
*
* @api
*
* @return string
*/
public function getSourceName()
{
return $this->sourceName;
}
/**
* Throw parser error
*
* @api
*
* @param string $msg
*
* @throws \Leafo\ScssPhp\Exception\ParserException
*/
public function throwParseError($msg = 'parse error')
{
list($line, $column) =
$this->getSourcePosition($this->count);
$loc = empty($this->sourceName)
? "line: $line, column: $column"
: "$this->sourceName on line $line, at column
$column";
if ($this->peek("(.*?)(\n|$)", $m, $this->count)) {
throw new ParserException("$msg: failed at `$m[1]`
$loc");
}
throw new ParserException("$msg: $loc");
}
/**
* Parser buffer
*
* @api
*
* @param string $buffer
*
* @return \Leafo\ScssPhp\Block
*/
public function parse($buffer)
{
if ($this->cache) {
$cacheKey = $this->sourceName . ":" .
md5($buffer);
$parseOptions = [
'charset' => $this->charset,
'utf8' => $this->utf8,
];
$v = $this->cache->getCache("parse", $cacheKey,
$parseOptions);
if (! is_null($v)) {
return $v;
}
}
// strip BOM (byte order marker)
if (substr($buffer, 0, 3) === "\xef\xbb\xbf") {
$buffer = substr($buffer, 3);
}
$this->buffer = rtrim($buffer, "\x00..\x1f");
$this->count = 0;
$this->env = null;
$this->inParens = false;
$this->eatWhiteDefault = true;
$this->saveEncoding();
$this->extractLineNumbers($buffer);
$this->pushBlock(null); // root block
$this->whitespace();
$this->pushBlock(null);
$this->popBlock();
while ($this->parseChunk()) {
;
}
if ($this->count !== strlen($this->buffer)) {
$this->throwParseError();
}
if (! empty($this->env->parent)) {
$this->throwParseError('unclosed block');
}
if ($this->charset) {
array_unshift($this->env->children, $this->charset);
}
$this->restoreEncoding();
if ($this->cache) {
$this->cache->setCache("parse", $cacheKey,
$this->env, $parseOptions);
}
return $this->env;
}
/**
* Parse a value or value list
*
* @api
*
* @param string $buffer
* @param string $out
*
* @return boolean
*/
public function parseValue($buffer, &$out)
{
$this->count = 0;
$this->env = null;
$this->inParens = false;
$this->eatWhiteDefault = true;
$this->buffer = (string) $buffer;
$this->saveEncoding();
$list = $this->valueList($out);
$this->restoreEncoding();
return $list;
}
/**
* Parse a selector or selector list
*
* @api
*
* @param string $buffer
* @param string $out
*
* @return boolean
*/
public function parseSelector($buffer, &$out)
{
$this->count = 0;
$this->env = null;
$this->inParens = false;
$this->eatWhiteDefault = true;
$this->buffer = (string) $buffer;
$this->saveEncoding();
$selector = $this->selectors($out);
$this->restoreEncoding();
return $selector;
}
/**
* Parse a single chunk off the head of the buffer and append it to the
* current parse environment.
*
* Returns false when the buffer is empty, or when there is an error.
*
* This function is called repeatedly until the entire document is
* parsed.
*
* This parser is most similar to a recursive descent parser. Single
* functions represent discrete grammatical rules for the language, and
* they are able to capture the text that represents those rules.
*
* Consider the function Compiler::keyword(). (All parse functions are
* structured the same.)
*
* The function takes a single reference argument. When calling the
* function it will attempt to match a keyword on the head of the
buffer.
* If it is successful, it will place the keyword in the referenced
* argument, advance the position in the buffer, and return true. If it
* fails then it won't advance the buffer and it will return
false.
*
* All of these parse functions are powered by Compiler::match(), which
behaves
* the same way, but takes a literal regular expression. Sometimes it
is
* more convenient to use match instead of creating a new function.
*
* Because of the format of the functions, to parse an entire string of
* grammatical rules, you can chain them together using &&.
*
* But, if some of the rules in the chain succeed before one fails,
then
* the buffer position will be left at an invalid state. In order to
* avoid this, Compiler::seek() is used to remember and set buffer
positions.
*
* Before parsing a chain, use $s = $this->count to remember the
current
* position into $s. Then if a chain fails, use $this->seek($s) to
* go back where we started.
*
* @return boolean
*/
protected function parseChunk()
{
$s = $this->count;
// the directives
if (isset($this->buffer[$this->count]) &&
$this->buffer[$this->count] === '@') {
if ($this->literal('@at-root', 8) &&
($this->selectors($selector) || true) &&
($this->map($with) || true) &&
$this->matchChar('{')
) {
$atRoot = $this->pushSpecialBlock(Type::T_AT_ROOT, $s);
$atRoot->selector = $selector;
$atRoot->with = $with;
return true;
}
$this->seek($s);
if ($this->literal('@media', 6) &&
$this->mediaQueryList($mediaQueryList) &&
$this->matchChar('{')) {
$media = $this->pushSpecialBlock(Type::T_MEDIA, $s);
$media->queryList = $mediaQueryList[2];
return true;
}
$this->seek($s);
if ($this->literal('@mixin', 6) &&
$this->keyword($mixinName) &&
($this->argumentDef($args) || true) &&
$this->matchChar('{')
) {
$mixin = $this->pushSpecialBlock(Type::T_MIXIN, $s);
$mixin->name = $mixinName;
$mixin->args = $args;
return true;
}
$this->seek($s);
if ($this->literal('@include', 8) &&
$this->keyword($mixinName) &&
($this->matchChar('(') &&
($this->argValues($argValues) || true) &&
$this->matchChar(')') || true) &&
($this->end() ||
$this->matchChar('{') && $hasBlock
= true)
) {
$child = [Type::T_INCLUDE, $mixinName, isset($argValues) ?
$argValues : null, null];
if (! empty($hasBlock)) {
$include = $this->pushSpecialBlock(Type::T_INCLUDE,
$s);
$include->child = $child;
} else {
$this->append($child, $s);
}
return true;
}
$this->seek($s);
if ($this->literal('@scssphp-import-once', 20)
&&
$this->valueList($importPath) &&
$this->end()
) {
$this->append([Type::T_SCSSPHP_IMPORT_ONCE,
$importPath], $s);
return true;
}
$this->seek($s);
if ($this->literal('@import', 7) &&
$this->valueList($importPath) &&
$this->end()
) {
$this->append([Type::T_IMPORT, $importPath], $s);
return true;
}
$this->seek($s);
if ($this->literal('@import', 7) &&
$this->url($importPath) &&
$this->end()
) {
$this->append([Type::T_IMPORT, $importPath], $s);
return true;
}
$this->seek($s);
if ($this->literal('@extend', 7) &&
$this->selectors($selectors) &&
$this->end()
) {
// check for '!flag'
$optional = $this->stripOptionalFlag($selectors);
$this->append([Type::T_EXTEND, $selectors, $optional],
$s);
return true;
}
$this->seek($s);
if ($this->literal('@function', 9) &&
$this->keyword($fnName) &&
$this->argumentDef($args) &&
$this->matchChar('{')
) {
$func = $this->pushSpecialBlock(Type::T_FUNCTION, $s);
$func->name = $fnName;
$func->args = $args;
return true;
}
$this->seek($s);
if ($this->literal('@break', 6) &&
$this->end()) {
$this->append([Type::T_BREAK], $s);
return true;
}
$this->seek($s);
if ($this->literal('@continue', 9) &&
$this->end()) {
$this->append([Type::T_CONTINUE], $s);
return true;
}
$this->seek($s);
if ($this->literal('@return', 7) &&
($this->valueList($retVal) || true) && $this->end()) {
$this->append([Type::T_RETURN, isset($retVal) ? $retVal
: [Type::T_NULL]], $s);
return true;
}
$this->seek($s);
if ($this->literal('@each', 5) &&
$this->genericList($varNames, 'variable',
',', false) &&
$this->literal('in', 2) &&
$this->valueList($list) &&
$this->matchChar('{')
) {
$each = $this->pushSpecialBlock(Type::T_EACH, $s);
foreach ($varNames[2] as $varName) {
$each->vars[] = $varName[1];
}
$each->list = $list;
return true;
}
$this->seek($s);
if ($this->literal('@while', 6) &&
$this->expression($cond) &&
$this->matchChar('{')
) {
$while = $this->pushSpecialBlock(Type::T_WHILE, $s);
$while->cond = $cond;
return true;
}
$this->seek($s);
if ($this->literal('@for', 4) &&
$this->variable($varName) &&
$this->literal('from', 4) &&
$this->expression($start) &&
($this->literal('through', 7) ||
($forUntil = true &&
$this->literal('to', 2))) &&
$this->expression($end) &&
$this->matchChar('{')
) {
$for = $this->pushSpecialBlock(Type::T_FOR, $s);
$for->var = $varName[1];
$for->start = $start;
$for->end = $end;
$for->until = isset($forUntil);
return true;
}
$this->seek($s);
if ($this->literal('@if', 3) &&
$this->valueList($cond) && $this->matchChar('{')) {
$if = $this->pushSpecialBlock(Type::T_IF, $s);
$if->cond = $cond;
$if->cases = [];
return true;
}
$this->seek($s);
if ($this->literal('@debug', 6) &&
$this->valueList($value) &&
$this->end()
) {
$this->append([Type::T_DEBUG, $value], $s);
return true;
}
$this->seek($s);
if ($this->literal('@warn', 5) &&
$this->valueList($value) &&
$this->end()
) {
$this->append([Type::T_WARN, $value], $s);
return true;
}
$this->seek($s);
if ($this->literal('@error', 6) &&
$this->valueList($value) &&
$this->end()
) {
$this->append([Type::T_ERROR, $value], $s);
return true;
}
$this->seek($s);
if ($this->literal('@content', 8) &&
$this->end()) {
$this->append([Type::T_MIXIN_CONTENT], $s);
return true;
}
$this->seek($s);
$last = $this->last();
if (isset($last) && $last[0] === Type::T_IF) {
list(, $if) = $last;
if ($this->literal('@else', 5)) {
if ($this->matchChar('{')) {
$else = $this->pushSpecialBlock(Type::T_ELSE,
$s);
} elseif ($this->literal('if', 2)
&& $this->valueList($cond) &&
$this->matchChar('{')) {
$else = $this->pushSpecialBlock(Type::T_ELSEIF,
$s);
$else->cond = $cond;
}
if (isset($else)) {
$else->dontAppend = true;
$if->cases[] = $else;
return true;
}
}
$this->seek($s);
}
// only retain the first @charset directive encountered
if ($this->literal('@charset', 8) &&
$this->valueList($charset) &&
$this->end()
) {
if (! isset($this->charset)) {
$statement = [Type::T_CHARSET, $charset];
list($line, $column) = $this->getSourcePosition($s);
$statement[static::SOURCE_LINE] = $line;
$statement[static::SOURCE_COLUMN] = $column;
$statement[static::SOURCE_INDEX] =
$this->sourceIndex;
$this->charset = $statement;
}
return true;
}
$this->seek($s);
// doesn't match built in directive, do generic one
if ($this->matchChar('@', false) &&
$this->keyword($dirName) &&
($this->variable($dirValue) ||
$this->openString('{', $dirValue) || true) &&
$this->matchChar('{')
) {
if ($dirName === 'media') {
$directive = $this->pushSpecialBlock(Type::T_MEDIA,
$s);
} else {
$directive =
$this->pushSpecialBlock(Type::T_DIRECTIVE, $s);
$directive->name = $dirName;
}
if (isset($dirValue)) {
$directive->value = $dirValue;
}
return true;
}
$this->seek($s);
return false;
}
// property shortcut
// captures most properties before having to parse a selector
if ($this->keyword($name, false) &&
$this->literal(': ', 2) &&
$this->valueList($value) &&
$this->end()
) {
$name = [Type::T_STRING, '', [$name]];
$this->append([Type::T_ASSIGN, $name, $value], $s);
return true;
}
$this->seek($s);
// variable assigns
if ($this->variable($name) &&
$this->matchChar(':') &&
$this->valueList($value) &&
$this->end()
) {
// check for '!flag'
$assignmentFlags = $this->stripAssignmentFlags($value);
$this->append([Type::T_ASSIGN, $name, $value,
$assignmentFlags], $s);
return true;
}
$this->seek($s);
// misc
if ($this->literal('-->', 3)) {
return true;
}
// opening css block
if ($this->selectors($selectors) &&
$this->matchChar('{', false)) {
$this->pushBlock($selectors, $s);
if ($this->eatWhiteDefault) {
$this->whitespace();
$this->append(null); // collect comments at the begining
if needed
}
return true;
}
$this->seek($s);
// property assign, or nested assign
if ($this->propertyName($name) &&
$this->matchChar(':')) {
$foundSomething = false;
if ($this->valueList($value)) {
if (empty($this->env->parent)) {
$this->throwParseError('expected
"{"');
}
$this->append([Type::T_ASSIGN, $name, $value], $s);
$foundSomething = true;
}
if ($this->matchChar('{')) {
$propBlock =
$this->pushSpecialBlock(Type::T_NESTED_PROPERTY, $s);
$propBlock->prefix = $name;
$foundSomething = true;
} elseif ($foundSomething) {
$foundSomething = $this->end();
}
if ($foundSomething) {
return true;
}
}
$this->seek($s);
// closing a block
if ($this->matchChar('}')) {
$block = $this->popBlock();
if (isset($block->type) && $block->type ===
Type::T_INCLUDE) {
$include = $block->child;
unset($block->child);
$include[3] = $block;
$this->append($include, $s);
} elseif (empty($block->dontAppend)) {
$type = isset($block->type) ? $block->type :
Type::T_BLOCK;
$this->append([$type, $block], $s);
}
return true;
}
// extra stuff
if ($this->matchChar(';') ||
$this->literal('<!--', 4)
) {
return true;
}
return false;
}
/**
* Push block onto parse tree
*
* @param array $selectors
* @param integer $pos
*
* @return \Leafo\ScssPhp\Block
*/
protected function pushBlock($selectors, $pos = 0)
{
list($line, $column) = $this->getSourcePosition($pos);
$b = new Block;
$b->sourceName = $this->sourceName;
$b->sourceLine = $line;
$b->sourceColumn = $column;
$b->sourceIndex = $this->sourceIndex;
$b->selectors = $selectors;
$b->comments = [];
$b->parent = $this->env;
if (! $this->env) {
$b->children = [];
} elseif (empty($this->env->children)) {
$this->env->children = $this->env->comments;
$b->children = [];
$this->env->comments = [];
} else {
$b->children = $this->env->comments;
$this->env->comments = [];
}
$this->env = $b;
return $b;
}
/**
* Push special (named) block onto parse tree
*
* @param string $type
* @param integer $pos
*
* @return \Leafo\ScssPhp\Block
*/
protected function pushSpecialBlock($type, $pos)
{
$block = $this->pushBlock(null, $pos);
$block->type = $type;
return $block;
}
/**
* Pop scope and return last block
*
* @return \Leafo\ScssPhp\Block
*
* @throws \Exception
*/
protected function popBlock()
{
$block = $this->env;
if (empty($block->parent)) {
$this->throwParseError('unexpected }');
}
if ($block->type == Type::T_AT_ROOT) {
// keeps the parent in case of self selector &
$block->selfParent = $block->parent;
}
$this->env = $block->parent;
unset($block->parent);
$comments = $block->comments;
if ($comments) {
$this->env->comments = $comments;
unset($block->comments);
}
return $block;
}
/**
* Peek input stream
*
* @param string $regex
* @param array $out
* @param integer $from
*
* @return integer
*/
protected function peek($regex, &$out, $from = null)
{
if (! isset($from)) {
$from = $this->count;
}
$r = '/' . $regex . '/' .
$this->patternModifiers;
$result = preg_match($r, $this->buffer, $out, null, $from);
return $result;
}
/**
* Seek to position in input stream (or return current position in
input stream)
*
* @param integer $where
*/
protected function seek($where)
{
$this->count = $where;
}
/**
* Match string looking for either ending delim, escape, or string
interpolation
*
* {@internal This is a workaround for preg_match's 250K string
match limit. }}
*
* @param array $m Matches (passed by reference)
* @param string $delim Delimeter
*
* @return boolean True if match; false otherwise
*/
protected function matchString(&$m, $delim)
{
$token = null;
$end = strlen($this->buffer);
// look for either ending delim, escape, or string interpolation
foreach (['#{', '\\', $delim] as $lookahead) {
$pos = strpos($this->buffer, $lookahead, $this->count);
if ($pos !== false && $pos < $end) {
$end = $pos;
$token = $lookahead;
}
}
if (! isset($token)) {
return false;
}
$match = substr($this->buffer, $this->count, $end -
$this->count);
$m = [
$match . $token,
$match,
$token
];
$this->count = $end + strlen($token);
return true;
}
/**
* Try to match something on head of buffer
*
* @param string $regex
* @param array $out
* @param boolean $eatWhitespace
*
* @return boolean
*/
protected function match($regex, &$out, $eatWhitespace = null)
{
$r = '/' . $regex . '/' .
$this->patternModifiers;
if (! preg_match($r, $this->buffer, $out, null,
$this->count)) {
return false;
}
$this->count += strlen($out[0]);
if (! isset($eatWhitespace)) {
$eatWhitespace = $this->eatWhiteDefault;
}
if ($eatWhitespace) {
$this->whitespace();
}
return true;
}
/**
* Match a single string
*
* @param string $char
* @param boolean $eatWhitespace
*
* @return boolean
*/
protected function matchChar($char, $eatWhitespace = null)
{
if (! isset($this->buffer[$this->count]) ||
$this->buffer[$this->count] !== $char) {
return false;
}
$this->count++;
if (! isset($eatWhitespace)) {
$eatWhitespace = $this->eatWhiteDefault;
}
if ($eatWhitespace) {
$this->whitespace();
}
return true;
}
/**
* Match literal string
*
* @param string $what
* @param integer $len
* @param boolean $eatWhitespace
*
* @return boolean
*/
protected function literal($what, $len, $eatWhitespace = null)
{
if (strcasecmp(substr($this->buffer, $this->count, $len),
$what) !== 0) {
return false;
}
$this->count += $len;
if (! isset($eatWhitespace)) {
$eatWhitespace = $this->eatWhiteDefault;
}
if ($eatWhitespace) {
$this->whitespace();
}
return true;
}
/**
* Match some whitespace
*
* @return boolean
*/
protected function whitespace()
{
$gotWhite = false;
while (preg_match(static::$whitePattern, $this->buffer, $m,
null, $this->count)) {
if (isset($m[1]) &&
empty($this->commentsSeen[$this->count])) {
// comment that are kept in the output CSS
$comment = [];
$endCommentCount = $this->count + strlen($m[1]);
// find interpolations in comment
$p = strpos($this->buffer, '#{',
$this->count);
while ($p !== false && $p < $endCommentCount) {
$c = substr($this->buffer, $this->count, $p -
$this->count);
$comment[] = $c;
$this->count = $p;
$out = null;
if ($this->interpolation($out)) {
// keep right spaces in the following string part
if ($out[3]) {
while ($this->buffer[$this->count-1] !==
'}') {
$this->count--;
}
$out[3] = '';
}
$comment[] = $out;
} else {
$comment[] = substr($this->buffer,
$this->count, 2);
$this->count += 2;
}
$p = strpos($this->buffer, '#{',
$this->count);
}
// remaining part
$c = substr($this->buffer, $this->count,
$endCommentCount - $this->count);
if (! $comment) {
// single part static comment
$this->appendComment([Type::T_COMMENT, $c]);
} else {
$comment[] = $c;
$this->appendComment([Type::T_COMMENT,
[Type::T_STRING, '', $comment]]);
}
$this->commentsSeen[$this->count] = true;
$this->count = $endCommentCount;
} else {
// comment that are ignored and not kept in the output css
$this->count += strlen($m[0]);
}
$gotWhite = true;
}
return $gotWhite;
}
/**
* Append comment to current block
*
* @param array $comment
*/
protected function appendComment($comment)
{
if ($comment[0] === Type::T_COMMENT &&
is_string($comment[1])) {
$comment[1] = substr(preg_replace(['/^\s+/m',
'/^(.)/m'], ['', ' \1'], $comment[1]), 1);
}
$this->env->comments[] = $comment;
}
/**
* Append statement to current block
*
* @param array $statement
* @param integer $pos
*/
protected function append($statement, $pos = null)
{
if (! is_null($statement)) {
if ($pos !== null) {
list($line, $column) = $this->getSourcePosition($pos);
$statement[static::SOURCE_LINE] = $line;
$statement[static::SOURCE_COLUMN] = $column;
$statement[static::SOURCE_INDEX] = $this->sourceIndex;
}
$this->env->children[] = $statement;
}
$comments = $this->env->comments;
if ($comments) {
$this->env->children =
array_merge($this->env->children, $comments);
$this->env->comments = [];
}
}
/**
* Returns last child was appended
*
* @return array|null
*/
protected function last()
{
$i = count($this->env->children) - 1;
if (isset($this->env->children[$i])) {
return $this->env->children[$i];
}
}
/**
* Parse media query list
*
* @param array $out
*
* @return boolean
*/
protected function mediaQueryList(&$out)
{
return $this->genericList($out, 'mediaQuery',
',', false);
}
/**
* Parse media query
*
* @param array $out
*
* @return boolean
*/
protected function mediaQuery(&$out)
{
$expressions = null;
$parts = [];
if (($this->literal('only', 4) && ($only =
true) || $this->literal('not', 3) && ($not = true) ||
true) &&
$this->mixedKeyword($mediaType)
) {
$prop = [Type::T_MEDIA_TYPE];
if (isset($only)) {
$prop[] = [Type::T_KEYWORD, 'only'];
}
if (isset($not)) {
$prop[] = [Type::T_KEYWORD, 'not'];
}
$media = [Type::T_LIST, '', []];
foreach ((array) $mediaType as $type) {
if (is_array($type)) {
$media[2][] = $type;
} else {
$media[2][] = [Type::T_KEYWORD, $type];
}
}
$prop[] = $media;
$parts[] = $prop;
}
if (empty($parts) || $this->literal('and', 3)) {
$this->genericList($expressions,
'mediaExpression', 'and', false);
if (is_array($expressions)) {
$parts = array_merge($parts, $expressions[2]);
}
}
$out = $parts;
return true;
}
/**
* Parse media expression
*
* @param array $out
*
* @return boolean
*/
protected function mediaExpression(&$out)
{
$s = $this->count;
$value = null;
if ($this->matchChar('(') &&
$this->expression($feature) &&
($this->matchChar(':') &&
$this->expression($value) || true) &&
$this->matchChar(')')
) {
$out = [Type::T_MEDIA_EXPRESSION, $feature];
if ($value) {
$out[] = $value;
}
return true;
}
$this->seek($s);
return false;
}
/**
* Parse argument values
*
* @param array $out
*
* @return boolean
*/
protected function argValues(&$out)
{
if ($this->genericList($list, 'argValue',
',', false)) {
$out = $list[2];
return true;
}
return false;
}
/**
* Parse argument value
*
* @param array $out
*
* @return boolean
*/
protected function argValue(&$out)
{
$s = $this->count;
$keyword = null;
if (! $this->variable($keyword) || !
$this->matchChar(':')) {
$this->seek($s);
$keyword = null;
}
if ($this->genericList($value, 'expression')) {
$out = [$keyword, $value, false];
$s = $this->count;
if ($this->literal('...', 3)) {
$out[2] = true;
} else {
$this->seek($s);
}
return true;
}
return false;
}
/**
* Parse comma separated value list
*
* @param array $out
*
* @return boolean
*/
protected function valueList(&$out)
{
return $this->genericList($out, 'spaceList',
',');
}
/**
* Parse space separated value list
*
* @param array $out
*
* @return boolean
*/
protected function spaceList(&$out)
{
return $this->genericList($out, 'expression');
}
/**
* Parse generic list
*
* @param array $out
* @param callable $parseItem
* @param string $delim
* @param boolean $flatten
*
* @return boolean
*/
protected function genericList(&$out, $parseItem, $delim =
'', $flatten = true)
{
$s = $this->count;
$items = [];
$value = null;
while ($this->$parseItem($value)) {
$items[] = $value;
if ($delim) {
if (! $this->literal($delim, strlen($delim))) {
break;
}
}
}
if (! $items) {
$this->seek($s);
return false;
}
if ($flatten && count($items) === 1) {
$out = $items[0];
} else {
$out = [Type::T_LIST, $delim, $items];
}
return true;
}
/**
* Parse expression
*
* @param array $out
*
* @return boolean
*/
protected function expression(&$out)
{
$s = $this->count;
if ($this->matchChar('(')) {
if ($this->parenExpression($out, $s, ")")) {
return true;
}
$this->seek($s);
}
if ($this->matchChar('[')) {
if ($this->parenExpression($out, $s, "]",
[Type::T_LIST, Type::T_KEYWORD])) {
if ($out[0] !== Type::T_LIST && $out[0] !==
Type::T_MAP) {
$out = [Type::T_STRING, '', [ '[',
$out, ']' ]];
}
return true;
}
$this->seek($s);
}
if ($this->value($lhs)) {
$out = $this->expHelper($lhs, 0);
return true;
}
return false;
}
/**
* Parse expression specifically checking for lists in parenthesis or
brackets
*
* @param array $out
* @param integer $s
* @param string $closingParen
* @param array $allowedTypes
*
* @return boolean
*/
protected function parenExpression(&$out, $s, $closingParen =
")", $allowedTypes = [Type::T_LIST, Type::T_MAP])
{
if ($this->matchChar($closingParen)) {
$out = [Type::T_LIST, '', []];
return true;
}
if ($this->valueList($out) &&
$this->matchChar($closingParen) && in_array($out[0],
$allowedTypes)) {
return true;
}
$this->seek($s);
if (in_array(Type::T_MAP, $allowedTypes) &&
$this->map($out)) {
return true;
}
return false;
}
/**
* Parse left-hand side of subexpression
*
* @param array $lhs
* @param integer $minP
*
* @return array
*/
protected function expHelper($lhs, $minP)
{
$operators = static::$operatorPattern;
$ss = $this->count;
$whiteBefore = isset($this->buffer[$this->count - 1])
&&
ctype_space($this->buffer[$this->count - 1]);
while ($this->match($operators, $m, false) &&
static::$precedence[$m[1]] >= $minP) {
$whiteAfter = isset($this->buffer[$this->count])
&&
ctype_space($this->buffer[$this->count]);
$varAfter = isset($this->buffer[$this->count]) &&
$this->buffer[$this->count] === '$';
$this->whitespace();
$op = $m[1];
// don't turn negative numbers into expressions
if ($op === '-' && $whiteBefore && !
$whiteAfter && ! $varAfter) {
break;
}
if (! $this->value($rhs)) {
break;
}
// peek and see if rhs belongs to next operator
if ($this->peek($operators, $next) &&
static::$precedence[$next[1]] > static::$precedence[$op]) {
$rhs = $this->expHelper($rhs,
static::$precedence[$next[1]]);
}
$lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs,
$this->inParens, $whiteBefore, $whiteAfter];
$ss = $this->count;
$whiteBefore = isset($this->buffer[$this->count - 1])
&&
ctype_space($this->buffer[$this->count - 1]);
}
$this->seek($ss);
return $lhs;
}
/**
* Parse value
*
* @param array $out
*
* @return boolean
*/
protected function value(&$out)
{
if (! isset($this->buffer[$this->count])) {
return false;
}
$s = $this->count;
$char = $this->buffer[$this->count];
if ($this->literal('url(', 4) &&
$this->match('data:([a-z]+)\/([a-z0-9.+-]+);base64,', $m,
false)) {
$len = strspn(
$this->buffer,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyxz0123456789+/=',
$this->count
);
$this->count += $len;
if ($this->matchChar(')')) {
$content = substr($this->buffer, $s, $this->count -
$s);
$out = [Type::T_KEYWORD, $content];
return true;
}
}
$this->seek($s);
if ($this->literal('url(', 4, false) &&
$this->match('\s*(\/\/\S+)\s*', $m)) {
$content = 'url(' . $m[1];
if ($this->matchChar(')')) {
$content .= ')';
$out = [Type::T_KEYWORD, $content];
return true;
}
}
$this->seek($s);
// not
if ($char === 'n' &&
$this->literal('not', 3, false)) {
if ($this->whitespace() && $this->value($inner))
{
$out = [Type::T_UNARY, 'not', $inner,
$this->inParens];
return true;
}
$this->seek($s);
if ($this->parenValue($inner)) {
$out = [Type::T_UNARY, 'not', $inner,
$this->inParens];
return true;
}
$this->seek($s);
}
// addition
if ($char === '+') {
$this->count++;
if ($this->value($inner)) {
$out = [Type::T_UNARY, '+', $inner,
$this->inParens];
return true;
}
$this->count--;
return false;
}
// negation
if ($char === '-') {
$this->count++;
if ($this->variable($inner) || $this->unit($inner) ||
$this->parenValue($inner)) {
$out = [Type::T_UNARY, '-', $inner,
$this->inParens];
return true;
}
$this->count--;
}
// paren
if ($char === '(' && $this->parenValue($out))
{
return true;
}
if ($char === '#') {
if ($this->interpolation($out) || $this->color($out)) {
return true;
}
}
if ($this->matchChar('&', true)) {
$out = [Type::T_SELF];
return true;
}
if ($char === '$' && $this->variable($out)) {
return true;
}
if ($char === 'p' && $this->progid($out)) {
return true;
}
if (($char === '"' || $char === "'")
&& $this->string($out)) {
return true;
}
if ($this->unit($out)) {
return true;
}
// unicode range with wildcards
if ($this->literal('U+', 2) &&
$this->match('([0-9A-F]+\?*)(-([0-9A-F]+))?', $m, false)) {
$out = [Type::T_KEYWORD, 'U+' . $m[0]];
return true;
}
if ($this->keyword($keyword, false)) {
if ($this->func($keyword, $out)) {
return true;
}
$this->whitespace();
if ($keyword === 'null') {
$out = [Type::T_NULL];
} else {
$out = [Type::T_KEYWORD, $keyword];
}
return true;
}
return false;
}
/**
* Parse parenthesized value
*
* @param array $out
*
* @return boolean
*/
protected function parenValue(&$out)
{
$s = $this->count;
$inParens = $this->inParens;
if ($this->matchChar('(')) {
if ($this->matchChar(')')) {
$out = [Type::T_LIST, '', []];
return true;
}
$this->inParens = true;
if ($this->expression($exp) &&
$this->matchChar(')')) {
$out = $exp;
$this->inParens = $inParens;
return true;
}
}
$this->inParens = $inParens;
$this->seek($s);
return false;
}
/**
* Parse "progid:"
*
* @param array $out
*
* @return boolean
*/
protected function progid(&$out)
{
$s = $this->count;
if ($this->literal('progid:', 7, false) &&
$this->openString('(', $fn) &&
$this->matchChar('(')
) {
$this->openString(')', $args, '(');
if ($this->matchChar(')')) {
$out = [Type::T_STRING, '', [
'progid:', $fn, '(', $args,
')'
]];
return true;
}
}
$this->seek($s);
return false;
}
/**
* Parse function call
*
* @param string $name
* @param array $func
*
* @return boolean
*/
protected function func($name, &$func)
{
$s = $this->count;
if ($this->matchChar('(')) {
if ($name === 'alpha' &&
$this->argumentList($args)) {
$func = [Type::T_FUNCTION, $name, [Type::T_STRING,
'', $args]];
return true;
}
if ($name !== 'expression' && !
preg_match('/^(-[a-z]+-)?calc$/', $name)) {
$ss = $this->count;
if ($this->argValues($args) &&
$this->matchChar(')')) {
$func = [Type::T_FUNCTION_CALL, $name, $args];
return true;
}
$this->seek($ss);
}
if (($this->openString(')', $str, '(')
|| true) &&
$this->matchChar(')')
) {
$args = [];
if (! empty($str)) {
$args[] = [null, [Type::T_STRING, '',
[$str]]];
}
$func = [Type::T_FUNCTION_CALL, $name, $args];
return true;
}
}
$this->seek($s);
return false;
}
/**
* Parse function call argument list
*
* @param array $out
*
* @return boolean
*/
protected function argumentList(&$out)
{
$s = $this->count;
$this->matchChar('(');
$args = [];
while ($this->keyword($var)) {
if ($this->matchChar('=') &&
$this->expression($exp)) {
$args[] = [Type::T_STRING, '', [$var .
'=']];
$arg = $exp;
} else {
break;
}
$args[] = $arg;
if (! $this->matchChar(',')) {
break;
}
$args[] = [Type::T_STRING, '', [', ']];
}
if (! $this->matchChar(')') || ! $args) {
$this->seek($s);
return false;
}
$out = $args;
return true;
}
/**
* Parse mixin/function definition argument list
*
* @param array $out
*
* @return boolean
*/
protected function argumentDef(&$out)
{
$s = $this->count;
$this->matchChar('(');
$args = [];
while ($this->variable($var)) {
$arg = [$var[1], null, false];
$ss = $this->count;
if ($this->matchChar(':') &&
$this->genericList($defaultVal, 'expression')) {
$arg[1] = $defaultVal;
} else {
$this->seek($ss);
}
$ss = $this->count;
if ($this->literal('...', 3)) {
$sss = $this->count;
if (! $this->matchChar(')')) {
$this->throwParseError('... has to be after the
final argument');
}
$arg[2] = true;
$this->seek($sss);
} else {
$this->seek($ss);
}
$args[] = $arg;
if (! $this->matchChar(',')) {
break;
}
}
if (! $this->matchChar(')')) {
$this->seek($s);
return false;
}
$out = $args;
return true;
}
/**
* Parse map
*
* @param array $out
*
* @return boolean
*/
protected function map(&$out)
{
$s = $this->count;
if (! $this->matchChar('(')) {
return false;
}
$keys = [];
$values = [];
while ($this->genericList($key, 'expression')
&& $this->matchChar(':') &&
$this->genericList($value, 'expression')
) {
$keys[] = $key;
$values[] = $value;
if (! $this->matchChar(',')) {
break;
}
}
if (! $keys || ! $this->matchChar(')')) {
$this->seek($s);
return false;
}
$out = [Type::T_MAP, $keys, $values];
return true;
}
/**
* Parse color
*
* @param array $out
*
* @return boolean
*/
protected function color(&$out)
{
$color = [Type::T_COLOR];
$s = $this->count;
if ($this->match('(#([0-9a-f]+))', $m)) {
$nofValues = strlen($m[2]);
$hasAlpha = $nofValues === 4 || $nofValues === 8;
$channels = $hasAlpha ? [4, 3, 2, 1] : [3, 2, 1];
switch ($nofValues) {
case 3:
case 4:
$num = hexdec($m[2]);
foreach ($channels as $i) {
$t = $num & 0xf;
$color[$i] = $t << 4 | $t;
$num >>= 4;
}
break;
case 6:
case 8:
$num = hexdec($m[2]);
foreach ($channels as $i) {
$color[$i] = $num & 0xff;
$num >>= 8;
}
break;
default:
$this->seek($s);
return false;
}
if ($hasAlpha) {
if ($color[4] === 255) {
$color[4] = 1; // fully opaque
} else {
$color[4] = round($color[4] / 255, 3);
}
}
$out = $color;
return true;
}
return false;
}
/**
* Parse number with unit
*
* @param array $unit
*
* @return boolean
*/
protected function unit(&$unit)
{
$s = $this->count;
if ($this->match('([0-9]*(\.)?[0-9]+)([%a-zA-Z]+)?',
$m, false)) {
if (strlen($this->buffer) === $this->count || !
ctype_digit($this->buffer[$this->count])) {
$this->whitespace();
$unit = new Node\Number($m[1], empty($m[3]) ? ''
: $m[3]);
return true;
}
$this->seek($s);
}
return false;
}
/**
* Parse string
*
* @param array $out
*
* @return boolean
*/
protected function string(&$out)
{
$s = $this->count;
if ($this->matchChar('"', false)) {
$delim = '"';
} elseif ($this->matchChar("'", false)) {
$delim = "'";
} else {
return false;
}
$content = [];
$oldWhite = $this->eatWhiteDefault;
$this->eatWhiteDefault = false;
$hasInterpolation = false;
while ($this->matchString($m, $delim)) {
if ($m[1] !== '') {
$content[] = $m[1];
}
if ($m[2] === '#{') {
$this->count -= strlen($m[2]);
if ($this->interpolation($inter, false)) {
$content[] = $inter;
$hasInterpolation = true;
} else {
$this->count += strlen($m[2]);
$content[] = '#{'; // ignore it
}
} elseif ($m[2] === '\\') {
if ($this->matchChar('"', false)) {
$content[] = $m[2] . '"';
} elseif ($this->matchChar("'", false)) {
$content[] = $m[2] . "'";
} elseif ($this->literal("\\", 1, false)) {
$content[] = $m[2] . "\\";
} elseif ($this->literal("\r\n", 2, false)
|| $this->matchChar("\r", false)
|| $this->matchChar("\n", false)
|| $this->matchChar("\f", false)) {
// this is a continuation escaping, to be ignored
} else {
$content[] = $m[2];
}
} else {
$this->count -= strlen($delim);
break; // delim
}
}
$this->eatWhiteDefault = $oldWhite;
if ($this->literal($delim, strlen($delim))) {
if ($hasInterpolation) {
$delim = '"';
foreach ($content as &$string) {
if ($string === "\\\\") {
$string = "\\";
} elseif ($string === "\\'") {
$string = "'";
} elseif ($string === '\\"') {
$string = '"';
}
}
}
$out = [Type::T_STRING, $delim, $content];
return true;
}
$this->seek($s);
return false;
}
/**
* Parse keyword or interpolation
*
* @param array $out
*
* @return boolean
*/
protected function mixedKeyword(&$out)
{
$parts = [];
$oldWhite = $this->eatWhiteDefault;
$this->eatWhiteDefault = false;
for (;;) {
if ($this->keyword($key)) {
$parts[] = $key;
continue;
}
if ($this->interpolation($inter)) {
$parts[] = $inter;
continue;
}
break;
}
$this->eatWhiteDefault = $oldWhite;
if (! $parts) {
return false;
}
if ($this->eatWhiteDefault) {
$this->whitespace();
}
$out = $parts;
return true;
}
/**
* Parse an unbounded string stopped by $end
*
* @param string $end
* @param array $out
* @param string $nestingOpen
*
* @return boolean
*/
protected function openString($end, &$out, $nestingOpen = null)
{
$oldWhite = $this->eatWhiteDefault;
$this->eatWhiteDefault = false;
$patt = '(.*?)([\'"]|#\{|' .
$this->pregQuote($end) . '|' . static::$commentPattern .
')';
$nestingLevel = 0;
$content = [];
while ($this->match($patt, $m, false)) {
if (isset($m[1]) && $m[1] !== '') {
$content[] = $m[1];
if ($nestingOpen) {
$nestingLevel += substr_count($m[1], $nestingOpen);
}
}
$tok = $m[2];
$this->count-= strlen($tok);
if ($tok === $end && ! $nestingLevel--) {
break;
}
if (($tok === "'" || $tok ===
'"') && $this->string($str)) {
$content[] = $str;
continue;
}
if ($tok === '#{' &&
$this->interpolation($inter)) {
$content[] = $inter;
continue;
}
$content[] = $tok;
$this->count+= strlen($tok);
}
$this->eatWhiteDefault = $oldWhite;
if (! $content) {
return false;
}
// trim the end
if (is_string(end($content))) {
$content[count($content) - 1] = rtrim(end($content));
}
$out = [Type::T_STRING, '', $content];
return true;
}
/**
* Parser interpolation
*
* @param array $out
* @param boolean $lookWhite save information about whitespace before
and after
*
* @return boolean
*/
protected function interpolation(&$out, $lookWhite = true)
{
$oldWhite = $this->eatWhiteDefault;
$this->eatWhiteDefault = true;
$s = $this->count;
if ($this->literal('#{', 2) &&
$this->valueList($value) && $this->matchChar('}',
false)) {
if ($value === [Type::T_SELF]) {
$out = $value;
} else {
if ($lookWhite) {
$left = preg_match('/\s/',
$this->buffer[$s - 1]) ? ' ' : '';
$right = preg_match('/\s/',
$this->buffer[$this->count]) ? ' ': '';
} else {
$left = $right = false;
}
$out = [Type::T_INTERPOLATE, $value, $left, $right];
}
$this->eatWhiteDefault = $oldWhite;
if ($this->eatWhiteDefault) {
$this->whitespace();
}
return true;
}
$this->seek($s);
$this->eatWhiteDefault = $oldWhite;
return false;
}
/**
* Parse property name (as an array of parts or a string)
*
* @param array $out
*
* @return boolean
*/
protected function propertyName(&$out)
{
$parts = [];
$oldWhite = $this->eatWhiteDefault;
$this->eatWhiteDefault = false;
for (;;) {
if ($this->interpolation($inter)) {
$parts[] = $inter;
continue;
}
if ($this->keyword($text)) {
$parts[] = $text;
continue;
}
if (! $parts && $this->match('[:.#]', $m,
false)) {
// css hacks
$parts[] = $m[0];
continue;
}
break;
}
$this->eatWhiteDefault = $oldWhite;
if (! $parts) {
return false;
}
// match comment hack
if (preg_match(
static::$whitePattern,
$this->buffer,
$m,
null,
$this->count
)) {
if (! empty($m[0])) {
$parts[] = $m[0];
$this->count += strlen($m[0]);
}
}
$this->whitespace(); // get any extra whitespace
$out = [Type::T_STRING, '', $parts];
return true;
}
/**
* Parse comma separated selector list
*
* @param array $out
*
* @return boolean
*/
protected function selectors(&$out, $subSelector = false)
{
$s = $this->count;
$selectors = [];
while ($this->selector($sel, $subSelector)) {
$selectors[] = $sel;
if (! $this->matchChar(',', true)) {
break;
}
while ($this->matchChar(',', true)) {
; // ignore extra
}
}
if (! $selectors) {
$this->seek($s);
return false;
}
$out = $selectors;
return true;
}
/**
* Parse whitespace separated selector list
*
* @param array $out
*
* @return boolean
*/
protected function selector(&$out, $subSelector = false)
{
$selector = [];
for (;;) {
if ($this->match('[>+~]+', $m, true)) {
$selector[] = [$m[0]];
continue;
}
if ($this->selectorSingle($part, $subSelector)) {
$selector[] = $part;
$this->match('\s+', $m);
continue;
}
if ($this->match('\/[^\/]+\/', $m, true)) {
$selector[] = [$m[0]];
continue;
}
break;
}
if (! $selector) {
return false;
}
$out = $selector;
return true;
}
/**
* Parse the parts that make up a selector
*
* {@internal
* div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder
* }}
*
* @param array $out
*
* @return boolean
*/
protected function selectorSingle(&$out, $subSelector = false)
{
$oldWhite = $this->eatWhiteDefault;
$this->eatWhiteDefault = false;
$parts = [];
if ($this->matchChar('*', false)) {
$parts[] = '*';
}
for (;;) {
if (! isset($this->buffer[$this->count])) {
break;
}
$s = $this->count;
$char = $this->buffer[$this->count];
// see if we can stop early
if ($char === '{' || $char === ',' || $char
=== ';' || $char === '}' || $char === '@') {
break;
}
// parsing a sub selector in () stop with the closing )
if ($subSelector && $char === ')') {
break;
}
//self
switch ($char) {
case '&':
$parts[] = Compiler::$selfSelector;
$this->count++;
continue 2;
case '.':
$parts[] = '.';
$this->count++;
continue 2;
case '|':
$parts[] = '|';
$this->count++;
continue 2;
}
if ($char === '\\' &&
$this->match('\\\\\S', $m)) {
$parts[] = $m[0];
continue;
}
if ($char === '%') {
$this->count++;
if ($this->placeholder($placeholder)) {
$parts[] = '%';
$parts[] = $placeholder;
continue;
}
break;
}
if ($char === '#') {
if ($this->interpolation($inter)) {
$parts[] = $inter;
continue;
}
$parts[] = '#';
$this->count++;
continue;
}
// a pseudo selector
if ($char === ':') {
if ($this->buffer[$this->count + 1] ===
':') {
$this->count += 2;
$part = '::';
} else {
$this->count++;
$part = ':';
}
if ($this->mixedKeyword($nameParts)) {
$parts[] = $part;
foreach ($nameParts as $sub) {
$parts[] = $sub;
}
$ss = $this->count;
if ($nameParts === ['not'] || $nameParts ===
['is'] ||
$nameParts === ['has'] || $nameParts ===
['where']
) {
if ($this->matchChar('(') &&
($this->selectors($subs, true) || true)
&&
$this->matchChar(')')
) {
$parts[] = '(';
while ($sub = array_shift($subs)) {
while ($ps = array_shift($sub)) {
foreach ($ps as &$p) {
$parts[] = $p;
}
if (count($sub) && reset($sub))
{
$parts[] = ' ';
}
}
if (count($subs) && reset($subs)) {
$parts[] = ', ';
}
}
$parts[] = ')';
} else {
$this->seek($ss);
}
} else {
if ($this->matchChar('(') &&
($this->openString(')', $str,
'(') || true) &&
$this->matchChar(')')
) {
$parts[] = '(';
if (! empty($str)) {
$parts[] = $str;
}
$parts[] = ')';
} else {
$this->seek($ss);
}
}
continue;
}
}
$this->seek($s);
// attribute selector
if ($char === '[' &&
$this->matchChar('[') &&
($this->openString(']', $str, '[')
|| true) &&
$this->matchChar(']')
) {
$parts[] = '[';
if (! empty($str)) {
$parts[] = $str;
}
$parts[] = ']';
continue;
}
$this->seek($s);
// for keyframes
if ($this->unit($unit)) {
$parts[] = $unit;
continue;
}
if ($this->keyword($name)) {
$parts[] = $name;
continue;
}
break;
}
$this->eatWhiteDefault = $oldWhite;
if (! $parts) {
return false;
}
$out = $parts;
return true;
}
/**
* Parse a variable
*
* @param array $out
*
* @return boolean
*/
protected function variable(&$out)
{
$s = $this->count;
if ($this->matchChar('$', false) &&
$this->keyword($name)) {
$out = [Type::T_VARIABLE, $name];
return true;
}
$this->seek($s);
return false;
}
/**
* Parse a keyword
*
* @param string $word
* @param boolean $eatWhitespace
*
* @return boolean
*/
protected function keyword(&$word, $eatWhitespace = null)
{
if ($this->match(
$this->utf8
?
'(([\pL\w\x{00A0}-\x{10FFFF}_\-\*!"\']|[\\\\].)([\pL\w\x{00A0}-\x{10FFFF}\-_"\']|[\\\\].)*)'
:
'(([\w_\-\*!"\']|[\\\\].)([\w\-_"\']|[\\\\].)*)',
$m,
$eatWhitespace
)) {
$word = $m[1];
return true;
}
return false;
}
/**
* Parse a placeholder
*
* @param string $placeholder
*
* @return boolean
*/
protected function placeholder(&$placeholder)
{
if ($this->match(
$this->utf8
? '([\pL\w\-_]+)'
: '([\w\-_]+)',
$m
)) {
$placeholder = $m[1];
return true;
}
if ($this->interpolation($placeholder)) {
return true;
}
return false;
}
/**
* Parse a url
*
* @param array $out
*
* @return boolean
*/
protected function url(&$out)
{
if
($this->match('(url\(\s*(["\']?)([^)]+)\2\s*\))',
$m)) {
$out = [Type::T_STRING, '', ['url(' . $m[2]
. $m[3] . $m[2] . ')']];
return true;
}
return false;
}
/**
* Consume an end of statement delimiter
*
* @return boolean
*/
protected function end()
{
if ($this->matchChar(';')) {
return true;
}
if ($this->count === strlen($this->buffer) ||
$this->buffer[$this->count] === '}') {
// if there is end of file or a closing block next then we
don't need a ;
return true;
}
return false;
}
/**
* Strip assignment flag from the list
*
* @param array $value
*
* @return array
*/
protected function stripAssignmentFlags(&$value)
{
$flags = [];
for ($token = &$value; $token[0] === Type::T_LIST &&
($s = count($token[2])); $token = &$lastNode) {
$lastNode = &$token[2][$s - 1];
while ($lastNode[0] === Type::T_KEYWORD &&
in_array($lastNode[1], ['!default', '!global'])) {
array_pop($token[2]);
$node = end($token[2]);
$token = $this->flattenList($token);
$flags[] = $lastNode[1];
$lastNode = $node;
}
}
return $flags;
}
/**
* Strip optional flag from selector list
*
* @param array $selectors
*
* @return string
*/
protected function stripOptionalFlag(&$selectors)
{
$optional = false;
$selector = end($selectors);
$part = end($selector);
if ($part === ['!optional']) {
array_pop($selectors[count($selectors) - 1]);
$optional = true;
}
return $optional;
}
/**
* Turn list of length 1 into value type
*
* @param array $value
*
* @return array
*/
protected function flattenList($value)
{
if ($value[0] === Type::T_LIST && count($value[2]) === 1) {
return $this->flattenList($value[2][0]);
}
return $value;
}
/**
* @deprecated
*
* {@internal
* advance counter to next occurrence of $what
* $until - don't include $what in advance
* $allowNewline, if string, will be used as valid char set
* }}
*/
protected function to($what, &$out, $until = false, $allowNewline =
false)
{
if (is_string($allowNewline)) {
$validChars = $allowNewline;
} else {
$validChars = $allowNewline ? '.' :
"[^\n]";
}
if (! $this->match('(' . $validChars . '*?)'
. $this->pregQuote($what), $m, ! $until)) {
return false;
}
if ($until) {
$this->count -= strlen($what); // give back $what
}
$out = $m[1];
return true;
}
/**
* @deprecated
*/
protected function show()
{
if ($this->peek("(.*?)(\n|$)", $m, $this->count)) {
return $m[1];
}
return '';
}
/**
* Quote regular expression
*
* @param string $what
*
* @return string
*/
private function pregQuote($what)
{
return preg_quote($what, '/');
}
/**
* Extract line numbers from buffer
*
* @param string $buffer
*/
private function extractLineNumbers($buffer)
{
$this->sourcePositions = [0 => 0];
$prev = 0;
while (($pos = strpos($buffer, "\n", $prev)) !== false) {
$this->sourcePositions[] = $pos;
$prev = $pos + 1;
}
$this->sourcePositions[] = strlen($buffer);
if (substr($buffer, -1) !== "\n") {
$this->sourcePositions[] = strlen($buffer) + 1;
}
}
/**
* Get source line number and column (given character position in the
buffer)
*
* @param integer $pos
*
* @return array
*/
private function getSourcePosition($pos)
{
$low = 0;
$high = count($this->sourcePositions);
while ($low < $high) {
$mid = (int) (($high + $low) / 2);
if ($pos < $this->sourcePositions[$mid]) {
$high = $mid - 1;
continue;
}
if ($pos >= $this->sourcePositions[$mid + 1]) {
$low = $mid + 1;
continue;
}
return [$mid + 1, $pos - $this->sourcePositions[$mid]];
}
return [$low + 1, $pos - $this->sourcePositions[$low]];
}
/**
* Save internal encoding
*/
private function saveEncoding()
{
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
return;
}
$iniDirective = 'mbstring' . '.func_overload';
// deprecated in PHP 7.2
if (ini_get($iniDirective) & 2) {
$this->encoding = mb_internal_encoding();
mb_internal_encoding('iso-8859-1');
}
}
/**
* Restore internal encoding
*/
private function restoreEncoding()
{
if ($this->encoding) {
mb_internal_encoding($this->encoding);
}
}
}
PK,d�[P#�=��-vendor/leafo/scssphp/src/SourceMap/Base64.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\SourceMap;
/**
* Base 64 Encode/Decode
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Base64
{
/**
* @var array
*/
private static $encodingMap = [
0 => 'A',
1 => 'B',
2 => 'C',
3 => 'D',
4 => 'E',
5 => 'F',
6 => 'G',
7 => 'H',
8 => 'I',
9 => 'J',
10 => 'K',
11 => 'L',
12 => 'M',
13 => 'N',
14 => 'O',
15 => 'P',
16 => 'Q',
17 => 'R',
18 => 'S',
19 => 'T',
20 => 'U',
21 => 'V',
22 => 'W',
23 => 'X',
24 => 'Y',
25 => 'Z',
26 => 'a',
27 => 'b',
28 => 'c',
29 => 'd',
30 => 'e',
31 => 'f',
32 => 'g',
33 => 'h',
34 => 'i',
35 => 'j',
36 => 'k',
37 => 'l',
38 => 'm',
39 => 'n',
40 => 'o',
41 => 'p',
42 => 'q',
43 => 'r',
44 => 's',
45 => 't',
46 => 'u',
47 => 'v',
48 => 'w',
49 => 'x',
50 => 'y',
51 => 'z',
52 => '0',
53 => '1',
54 => '2',
55 => '3',
56 => '4',
57 => '5',
58 => '6',
59 => '7',
60 => '8',
61 => '9',
62 => '+',
63 => '/',
];
/**
* @var array
*/
private static $decodingMap = [
'A' => 0,
'B' => 1,
'C' => 2,
'D' => 3,
'E' => 4,
'F' => 5,
'G' => 6,
'H' => 7,
'I' => 8,
'J' => 9,
'K' => 10,
'L' => 11,
'M' => 12,
'N' => 13,
'O' => 14,
'P' => 15,
'Q' => 16,
'R' => 17,
'S' => 18,
'T' => 19,
'U' => 20,
'V' => 21,
'W' => 22,
'X' => 23,
'Y' => 24,
'Z' => 25,
'a' => 26,
'b' => 27,
'c' => 28,
'd' => 29,
'e' => 30,
'f' => 31,
'g' => 32,
'h' => 33,
'i' => 34,
'j' => 35,
'k' => 36,
'l' => 37,
'm' => 38,
'n' => 39,
'o' => 40,
'p' => 41,
'q' => 42,
'r' => 43,
's' => 44,
't' => 45,
'u' => 46,
'v' => 47,
'w' => 48,
'x' => 49,
'y' => 50,
'z' => 51,
0 => 52,
1 => 53,
2 => 54,
3 => 55,
4 => 56,
5 => 57,
6 => 58,
7 => 59,
8 => 60,
9 => 61,
'+' => 62,
'/' => 63,
];
/**
* Convert to base64
*
* @param integer $value
*
* @return string
*/
public static function encode($value)
{
return self::$encodingMap[$value];
}
/**
* Convert from base64
*
* @param string $value
*
* @return integer
*/
public static function decode($value)
{
return self::$decodingMap[$value];
}
}
PK,d�[�9�>>0vendor/leafo/scssphp/src/SourceMap/Base64VLQ.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2015 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\SourceMap;
use Leafo\ScssPhp\SourceMap\Base64;
/**
* Base 64 VLQ
*
* Based on the Base 64 VLQ implementation in Closure Compiler:
*
https://github.com/google/closure-compiler/blob/master/src/com/google/debugging/sourcemap/Base64VLQ.java
*
* Copyright 2011 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the
"License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS"
BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author John Lenz <johnlenz@google.com>
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Base64VLQ
{
// A Base64 VLQ digit can represent 5 bits, so it is base-32.
const VLQ_BASE_SHIFT = 5;
// A mask of bits for a VLQ digit (11111), 31 decimal.
const VLQ_BASE_MASK = 31;
// The continuation bit is the 6th bit.
const VLQ_CONTINUATION_BIT = 32;
/**
* Returns the VLQ encoded value.
*
* @param integer $value
*
* @return string
*/
public static function encode($value)
{
$encoded = '';
$vlq = self::toVLQSigned($value);
do {
$digit = $vlq & self::VLQ_BASE_MASK;
$vlq >>= self::VLQ_BASE_SHIFT;
if ($vlq > 0) {
$digit |= self::VLQ_CONTINUATION_BIT;
}
$encoded .= Base64::encode($digit);
} while ($vlq > 0);
return $encoded;
}
/**
* Decodes VLQValue.
*
* @param string $str
* @param integer $index
*
* @return integer
*/
public static function decode($str, &$index)
{
$result = 0;
$shift = 0;
do {
$c = $str[$index++];
$digit = Base64::decode($c);
$continuation = ($digit & self::VLQ_CONTINUATION_BIT) != 0;
$digit &= self::VLQ_BASE_MASK;
$result = $result + ($digit << $shift);
$shift = $shift + self::VLQ_BASE_SHIFT;
} while ($continuation);
return self::fromVLQSigned($result);
}
/**
* Converts from a two-complement value to a value where the sign bit
is
* is placed in the least significant bit. For example, as decimals:
* 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
*
* @param integer $value
*
* @return integer
*/
private static function toVLQSigned($value)
{
if ($value < 0) {
return ((-$value) << 1) + 1;
}
return ($value << 1) + 0;
}
/**
* Converts to a two-complement value from a value where the sign bit
is
* is placed in the least significant bit. For example, as decimals:
* 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
* 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
*
* @param integer $value
*
* @return integer
*/
private static function fromVLQSigned($value)
{
$negate = ($value & 1) === 1;
$value = $value >> 1;
return $negate ? -$value : $value;
}
}
PK,d�[�-�|997vendor/leafo/scssphp/src/SourceMap/Base64VLQEncoder.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\SourceMap;
/**
* Base64 VLQ Encoder
*
* {@internal Derivative of oyejorge/less.php's
lib/SourceMap/Base64VLQ.php, relicensed with permission. }}
*
* @author Josh Schmidt <oyejorge@gmail.com>
* @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com>
*/
class Base64VLQEncoder
{
/**
* Shift
*
* @var integer
*/
private $shift = 5;
/**
* Mask
*
* @var integer
*/
private $mask = 0x1F; // == (1 << shift) == 0b00011111
/**
* Continuation bit
*
* @var integer
*/
private $continuationBit = 0x20; // == (mask - 1 ) == 0b00100000
/**
* Char to integer map
*
* @var array
*/
private $charToIntMap = [
'A' => 0, 'B' => 1, 'C' =>
2, 'D' => 3, 'E' => 4, 'F' => 5,
'G' => 6, 'H' => 7,
'I' => 8, 'J' => 9, 'K' =>
10, 'L' => 11, 'M' => 12, 'N' => 13,
'O' => 14, 'P' => 15,
'Q' => 16, 'R' => 17, 'S' =>
18, 'T' => 19, 'U' => 20, 'V' => 21,
'W' => 22, 'X' => 23,
'Y' => 24, 'Z' => 25, 'a' =>
26, 'b' => 27, 'c' => 28, 'd' => 29,
'e' => 30, 'f' => 31,
'g' => 32, 'h' => 33, 'i' =>
34, 'j' => 35, 'k' => 36, 'l' => 37,
'm' => 38, 'n' => 39,
'o' => 40, 'p' => 41, 'q' =>
42, 'r' => 43, 's' => 44, 't' => 45,
'u' => 46, 'v' => 47,
'w' => 48, 'x' => 49, 'y' =>
50, 'z' => 51, 0 => 52, 1 => 53, 2 => 54, 3
=> 55,
4 => 56, 5 => 57, 6 => 58, 7 => 59, 8 =>
60, 9 => 61, '+' => 62, '/' => 63,
];
/**
* Integer to char map
*
* @var array
*/
private $intToCharMap = [
0 => 'A', 1 => 'B', 2 =>
'C', 3 => 'D', 4 => 'E', 5 =>
'F', 6 => 'G', 7 => 'H',
8 => 'I', 9 => 'J', 10 =>
'K', 11 => 'L', 12 => 'M', 13 =>
'N', 14 => 'O', 15 => 'P',
16 => 'Q', 17 => 'R', 18 =>
'S', 19 => 'T', 20 => 'U', 21 =>
'V', 22 => 'W', 23 => 'X',
24 => 'Y', 25 => 'Z', 26 =>
'a', 27 => 'b', 28 => 'c', 29 =>
'd', 30 => 'e', 31 => 'f',
32 => 'g', 33 => 'h', 34 =>
'i', 35 => 'j', 36 => 'k', 37 =>
'l', 38 => 'm', 39 => 'n',
40 => 'o', 41 => 'p', 42 =>
'q', 43 => 'r', 44 => 's', 45 =>
't', 46 => 'u', 47 => 'v',
48 => 'w', 49 => 'x', 50 =>
'y', 51 => 'z', 52 => '0', 53 =>
'1', 54 => '2', 55 => '3',
56 => '4', 57 => '5', 58 =>
'6', 59 => '7', 60 => '8', 61 =>
'9', 62 => '+', 63 => '/',
];
/**
* Constructor
*/
public function __construct()
{
// I leave it here for future reference
// foreach
(str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')
as $i => $char)
// {
// $this->charToIntMap[$char] = $i;
// $this->intToCharMap[$i] = $char;
// }
}
/**
* Convert from a two-complement value to a value where the sign bit is
* is placed in the least significant bit. For example, as decimals:
* 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
* We generate the value for 32 bit machines, hence -2147483648 becomes
1, not 4294967297,
* even on a 64 bit machine.
*
* @param string $aValue
*/
public function toVLQSigned($aValue)
{
return 0xffffffff & ($aValue < 0 ? ((-$aValue) << 1) +
1 : ($aValue << 1) + 0);
}
/**
* Convert to a two-complement value from a value where the sign bit is
* is placed in the least significant bit. For example, as decimals:
* 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
* 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
* We assume that the value was generated with a 32 bit machine in
mind.
* Hence
* 1 becomes -2147483648
* even on a 64 bit machine.
*
* @param integer $aValue
*/
public function fromVLQSigned($aValue)
{
return $aValue & 1 ? $this->zeroFill(~$aValue + 2, 1) | (-1
- 0x7fffffff) : $this->zeroFill($aValue, 1);
}
/**
* Return the base 64 VLQ encoded value.
*
* @param string $aValue The value to encode
*
* @return string The encoded value
*/
public function encode($aValue)
{
$encoded = '';
$vlq = $this->toVLQSigned($aValue);
do {
$digit = $vlq & $this->mask;
$vlq = $this->zeroFill($vlq, $this->shift);
if ($vlq > 0) {
$digit |= $this->continuationBit;
}
$encoded .= $this->base64Encode($digit);
} while ($vlq > 0);
return $encoded;
}
/**
* Return the value decoded from base 64 VLQ.
*
* @param string $encoded The encoded value to decode
*
* @return integer The decoded value
*/
public function decode($encoded)
{
$vlq = 0;
$i = 0;
do {
$digit = $this->base64Decode($encoded[$i]);
$vlq |= ($digit & $this->mask) << ($i *
$this->shift);
$i++;
} while ($digit & $this->continuationBit);
return $this->fromVLQSigned($vlq);
}
/**
* Right shift with zero fill.
*
* @param integer $a number to shift
* @param integer $b number of bits to shift
*
* @return integer
*/
public function zeroFill($a, $b)
{
return ($a >= 0) ? ($a >> $b) : ($a >> $b) &
(PHP_INT_MAX >> ($b - 1));
}
/**
* Encode single 6-bit digit as base64.
*
* @param integer $number
*
* @return string
*
* @throws \Exception If the number is invalid
*/
public function base64Encode($number)
{
if ($number < 0 || $number > 63) {
throw new \Exception(sprintf('Invalid number
"%s" given. Must be between 0 and 63.', $number));
}
return $this->intToCharMap[$number];
}
/**
* Decode single 6-bit digit from base64
*
* @param string $char
*
* @return integer
*
* @throws \Exception If the number is invalid
*/
public function base64Decode($char)
{
if (! array_key_exists($char, $this->charToIntMap)) {
throw new \Exception(sprintf('Invalid base 64 digit
"%s" given.', $char));
}
return $this->charToIntMap[$char];
}
}
PK,d�[Ky��
'
'9vendor/leafo/scssphp/src/SourceMap/SourceMapGenerator.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp\SourceMap;
use Leafo\ScssPhp\Exception\CompilerException;
/**
* Source Map Generator
*
* {@internal Derivative of oyejorge/less.php's
lib/SourceMap/Generator.php, relicensed with permission. }}
*
* @author Josh Schmidt <oyejorge@gmail.com>
* @author Nicolas FRANÇOIS <nicolas.francois@frog-labs.com>
*/
class SourceMapGenerator
{
/**
* What version of source map does the generator generate?
*/
const VERSION = 3;
/**
* Array of default options
*
* @var array
*/
protected $defaultOptions = [
// an optional source root, useful for relocating source files
// on a server or removing repeated values in the
'sources' entry.
// This value is prepended to the individual entries in the
'source' field.
'sourceRoot' => '',
// an optional name of the generated code that this source map is
associated with.
'sourceMapFilename' => null,
// url of the map
'sourceMapURL' => null,
// absolute path to a file to write the map to
'sourceMapWriteTo' => null,
// output source contents?
'outputSourceFiles' => false,
// base path for filename normalization
'sourceMapRootpath' => '',
// base path for filename normalization
'sourceMapBasepath' => ''
];
/**
* The base64 VLQ encoder
*
* @var \Leafo\ScssPhp\SourceMap\Base64VLQ
*/
protected $encoder;
/**
* Array of mappings
*
* @var array
*/
protected $mappings = [];
/**
* Array of contents map
*
* @var array
*/
protected $contentsMap = [];
/**
* File to content map
*
* @var array
*/
protected $sources = [];
protected $sourceKeys = [];
/**
* @var array
*/
private $options;
public function __construct(array $options = [])
{
$this->options = array_merge($this->defaultOptions,
$options);
$this->encoder = new Base64VLQ();
}
/**
* Adds a mapping
*
* @param integer $generatedLine The line number in generated file
* @param integer $generatedColumn The column number in generated file
* @param integer $originalLine The line number in original file
* @param integer $originalColumn The column number in original file
* @param string $sourceFile The original source file
*/
public function addMapping($generatedLine, $generatedColumn,
$originalLine, $originalColumn, $sourceFile)
{
$this->mappings[] = [
'generated_line' => $generatedLine,
'generated_column' => $generatedColumn,
'original_line' => $originalLine,
'original_column' => $originalColumn,
'source_file' => $sourceFile
];
$this->sources[$sourceFile] = $sourceFile;
}
/**
* Saves the source map to a file
*
* @param string $content The content to write
*
* @return string
*
* @throws \Leafo\ScssPhp\Exception\CompilerException If the file could
not be saved
*/
public function saveMap($content)
{
$file = $this->options['sourceMapWriteTo'];
$dir = dirname($file);
// directory does not exist
if (! is_dir($dir)) {
// FIXME: create the dir automatically?
throw new CompilerException(
sprintf('The directory "%s" does not exist.
Cannot save the source map.', $dir)
);
}
// FIXME: proper saving, with dir write check!
if (file_put_contents($file, $content) === false) {
throw new CompilerException(sprintf('Cannot save the
source map to "%s"', $file));
}
return $this->options['sourceMapURL'];
}
/**
* Generates the JSON source map
*
* @return string
*
* @see
https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#
*/
public function generateJson()
{
$sourceMap = [];
$mappings = $this->generateMappings();
// File version (always the first entry in the object) and must be
a positive integer.
$sourceMap['version'] = self::VERSION;
// An optional name of the generated code that this source map is
associated with.
$file = $this->options['sourceMapFilename'];
if ($file) {
$sourceMap['file'] = $file;
}
// An optional source root, useful for relocating source files on a
server or removing repeated values in the
// 'sources' entry. This value is prepended to the
individual entries in the 'source' field.
$root = $this->options['sourceRoot'];
if ($root) {
$sourceMap['sourceRoot'] = $root;
}
// A list of original sources used by the 'mappings'
entry.
$sourceMap['sources'] = [];
foreach ($this->sources as $sourceUri => $sourceFilename) {
$sourceMap['sources'][] =
$this->normalizeFilename($sourceFilename);
}
// A list of symbol names used by the 'mappings' entry.
$sourceMap['names'] = [];
// A string with the encoded mapping data.
$sourceMap['mappings'] = $mappings;
if ($this->options['outputSourceFiles']) {
// An optional list of source content, useful when the
'source' can't be hosted.
// The contents are listed in the same order as the sources
above.
// 'null' may be used if some original sources should
be retrieved by name.
$sourceMap['sourcesContent'] =
$this->getSourcesContent();
}
// less.js compat fixes
if (count($sourceMap['sources']) &&
empty($sourceMap['sourceRoot'])) {
unset($sourceMap['sourceRoot']);
}
return json_encode($sourceMap, JSON_UNESCAPED_SLASHES);
}
/**
* Returns the sources contents
*
* @return array|null
*/
protected function getSourcesContent()
{
if (empty($this->sources)) {
return null;
}
$content = [];
foreach ($this->sources as $sourceFile) {
$content[] = file_get_contents($sourceFile);
}
return $content;
}
/**
* Generates the mappings string
*
* @return string
*/
public function generateMappings()
{
if (! count($this->mappings)) {
return '';
}
$this->sourceKeys = array_flip(array_keys($this->sources));
// group mappings by generated line number.
$groupedMap = $groupedMapEncoded = [];
foreach ($this->mappings as $m) {
$groupedMap[$m['generated_line']][] = $m;
}
ksort($groupedMap);
$lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine =
$lastOriginalColumn = 0;
foreach ($groupedMap as $lineNumber => $lineMap) {
while (++$lastGeneratedLine < $lineNumber) {
$groupedMapEncoded[] = ';';
}
$lineMapEncoded = [];
$lastGeneratedColumn = 0;
foreach ($lineMap as $m) {
$mapEncoded =
$this->encoder->encode($m['generated_column'] -
$lastGeneratedColumn);
$lastGeneratedColumn = $m['generated_column'];
// find the index
if ($m['source_file']) {
$index =
$this->findFileIndex($m['source_file']);
if ($index !== false) {
$mapEncoded .= $this->encoder->encode($index
- $lastOriginalIndex);
$lastOriginalIndex = $index;
// lines are stored 0-based in SourceMap spec
version 3
$mapEncoded .=
$this->encoder->encode($m['original_line'] - 1 -
$lastOriginalLine);
$lastOriginalLine = $m['original_line'] -
1;
$mapEncoded .=
$this->encoder->encode($m['original_column'] -
$lastOriginalColumn);
$lastOriginalColumn =
$m['original_column'];
}
}
$lineMapEncoded[] = $mapEncoded;
}
$groupedMapEncoded[] = implode(',', $lineMapEncoded)
. ';';
}
return rtrim(implode($groupedMapEncoded), ';');
}
/**
* Finds the index for the filename
*
* @param string $filename
*
* @return integer|false
*/
protected function findFileIndex($filename)
{
return $this->sourceKeys[$filename];
}
/**
* Normalize filename
*
* @param string $filename
*
* @return string
*/
protected function normalizeFilename($filename)
{
$filename = $this->fixWindowsPath($filename);
$rootpath = $this->options['sourceMapRootpath'];
$basePath = $this->options['sourceMapBasepath'];
// "Trim" the 'sourceMapBasepath' from the
output filename.
if (strlen($basePath) && strpos($filename, $basePath) ===
0) {
$filename = substr($filename, strlen($basePath));
}
// Remove extra leading path separators.
if (strpos($filename, '\\') === 0 || strpos($filename,
'/') === 0) {
$filename = substr($filename, 1);
}
return $rootpath . $filename;
}
/**
* Fix windows paths
*
* @param string $path
* @param boolean $addEndSlash
*
* @return string
*/
public function fixWindowsPath($path, $addEndSlash = false)
{
$slash = ($addEndSlash) ? '/' : '';
if (! empty($path)) {
$path = str_replace('\\', '/', $path);
$path = rtrim($path, '/') . $slash;
}
return $path;
}
}
PK,d�[�
'%%!vendor/leafo/scssphp/src/Type.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* Block/node types
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Type
{
const T_ASSIGN = 'assign';
const T_AT_ROOT = 'at-root';
const T_BLOCK = 'block';
const T_BREAK = 'break';
const T_CHARSET = 'charset';
const T_COLOR = 'color';
const T_COMMENT = 'comment';
const T_CONTINUE = 'continue';
const T_CONTROL = 'control';
const T_DEBUG = 'debug';
const T_DIRECTIVE = 'directive';
const T_EACH = 'each';
const T_ELSE = 'else';
const T_ELSEIF = 'elseif';
const T_ERROR = 'error';
const T_EXPRESSION = 'exp';
const T_EXTEND = 'extend';
const T_FOR = 'for';
const T_FUNCTION = 'function';
const T_FUNCTION_CALL = 'fncall';
const T_HSL = 'hsl';
const T_IF = 'if';
const T_IMPORT = 'import';
const T_INCLUDE = 'include';
const T_INTERPOLATE = 'interpolate';
const T_INTERPOLATED = 'interpolated';
const T_KEYWORD = 'keyword';
const T_LIST = 'list';
const T_MAP = 'map';
const T_MEDIA = 'media';
const T_MEDIA_EXPRESSION = 'mediaExp';
const T_MEDIA_TYPE = 'mediaType';
const T_MEDIA_VALUE = 'mediaValue';
const T_MIXIN = 'mixin';
const T_MIXIN_CONTENT = 'mixin_content';
const T_NESTED_PROPERTY = 'nestedprop';
const T_NOT = 'not';
const T_NULL = 'null';
const T_NUMBER = 'number';
const T_RETURN = 'return';
const T_ROOT = 'root';
const T_SCSSPHP_IMPORT_ONCE = 'scssphp-import-once';
const T_SELF = 'self';
const T_STRING = 'string';
const T_UNARY = 'unary';
const T_VARIABLE = 'var';
const T_WARN = 'warn';
const T_WHILE = 'while';
}
PK,d�[jОpBB!vendor/leafo/scssphp/src/Util.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
use Leafo\ScssPhp\Base\Range;
use Leafo\ScssPhp\Exception\RangeException;
/**
* Utilty functions
*
* @author Anthon Pang <anthon.pang@gmail.com>
*/
class Util
{
/**
* Asserts that `value` falls within `range` (inclusive), leaving
* room for slight floating-point errors.
*
* @param string $name The name of the value. Used
in the error message.
* @param \Leafo\ScssPhp\Base\Range $range Range of values.
* @param array $value The value to check.
* @param string $unit The unit of the value. Used
in error reporting.
*
* @return mixed `value` adjusted to fall within range, if it was
outside by a floating-point margin.
*
* @throws \Leafo\ScssPhp\Exception\RangeException
*/
public static function checkRange($name, Range $range, $value, $unit =
'')
{
$val = $value[1];
$grace = new Range(-0.00001, 0.00001);
if ($range->includes($val)) {
return $val;
}
if ($grace->includes($val - $range->first)) {
return $range->first;
}
if ($grace->includes($val - $range->last)) {
return $range->last;
}
throw new RangeException("$name {$val} must be between
{$range->first} and {$range->last}$unit");
}
/**
* Encode URI component
*
* @param string $string
*
* @return string
*/
public static function encodeURIComponent($string)
{
$revert = ['%21' => '!', '%2A'
=> '*', '%27' => "'",
'%28' => '(', '%29' => ')'];
return strtr(rawurlencode($string), $revert);
}
}
PK,d�[Xi�388$vendor/leafo/scssphp/src/Version.phpnu�[���<?php
/**
* SCSSPHP
*
* @copyright 2012-2018 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://leafo.github.io/scssphp
*/
namespace Leafo\ScssPhp;
/**
* SCSSPHP version
*
* @author Leaf Corcoran <leafot@gmail.com>
*/
class Version
{
const VERSION = 'v0.8.4';
}
PK,d�[)?���"vendor/pimple/pimple/composer.jsonnu�[���{
"name": "pimple/pimple",
"type": "library",
"description": "Pimple, a simple Dependency Injection
Container",
"keywords": ["dependency injection",
"container"],
"homepage": "http://pimple.sensiolabs.org",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"require": {
"php": ">=5.3.0",
"psr/container": "^1.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^3.2"
},
"autoload": {
"psr-0": { "Pimple": "src/" }
},
"extra": {
"branch-alias": {
"dev-master": "3.2.x-dev"
}
}
}
PK,d�[{�$$-vendor/pimple/pimple/src/Pimple/Container.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple;
use Pimple\Exception\ExpectedInvokableException;
use Pimple\Exception\FrozenServiceException;
use Pimple\Exception\InvalidServiceIdentifierException;
use Pimple\Exception\UnknownIdentifierException;
/**
* Container main class.
*
* @author Fabien Potencier
*/
class Container implements \ArrayAccess
{
private $values = array();
private $factories;
private $protected;
private $frozen = array();
private $raw = array();
private $keys = array();
/**
* Instantiates the container.
*
* Objects and parameters can be passed as argument to the constructor.
*
* @param array $values The parameters or objects
*/
public function __construct(array $values = array())
{
$this->factories = new \SplObjectStorage();
$this->protected = new \SplObjectStorage();
foreach ($values as $key => $value) {
$this->offsetSet($key, $value);
}
}
/**
* Sets a parameter or an object.
*
* Objects must be defined as Closures.
*
* Allowing any PHP callable leads to difficult to debug problems
* as function names (strings) are callable (creating a function with
* the same name as an existing parameter would break your container).
*
* @param string $id The unique identifier for the parameter or
object
* @param mixed $value The value of the parameter or a closure to
define an object
*
* @throws FrozenServiceException Prevent override of a frozen service
*/
public function offsetSet($id, $value)
{
if (isset($this->frozen[$id])) {
throw new FrozenServiceException($id);
}
$this->values[$id] = $value;
$this->keys[$id] = true;
}
/**
* Gets a parameter or an object.
*
* @param string $id The unique identifier for the parameter or object
*
* @return mixed The value of the parameter or an object
*
* @throws UnknownIdentifierException If the identifier is not defined
*/
public function offsetGet($id)
{
if (!isset($this->keys[$id])) {
throw new UnknownIdentifierException($id);
}
if (
isset($this->raw[$id])
|| !\is_object($this->values[$id])
|| isset($this->protected[$this->values[$id]])
|| !\method_exists($this->values[$id], '__invoke')
) {
return $this->values[$id];
}
if (isset($this->factories[$this->values[$id]])) {
return $this->values[$id]($this);
}
$raw = $this->values[$id];
$val = $this->values[$id] = $raw($this);
$this->raw[$id] = $raw;
$this->frozen[$id] = true;
return $val;
}
/**
* Checks if a parameter or an object is set.
*
* @param string $id The unique identifier for the parameter or object
*
* @return bool
*/
public function offsetExists($id)
{
return isset($this->keys[$id]);
}
/**
* Unsets a parameter or an object.
*
* @param string $id The unique identifier for the parameter or object
*/
public function offsetUnset($id)
{
if (isset($this->keys[$id])) {
if (\is_object($this->values[$id])) {
unset($this->factories[$this->values[$id]],
$this->protected[$this->values[$id]]);
}
unset($this->values[$id], $this->frozen[$id],
$this->raw[$id], $this->keys[$id]);
}
}
/**
* Marks a callable as being a factory service.
*
* @param callable $callable A service definition to be used as a
factory
*
* @return callable The passed callable
*
* @throws ExpectedInvokableException Service definition has to be a
closure or an invokable object
*/
public function factory($callable)
{
if (!\method_exists($callable, '__invoke')) {
throw new ExpectedInvokableException('Service definition
is not a Closure or invokable object.');
}
$this->factories->attach($callable);
return $callable;
}
/**
* Protects a callable from being interpreted as a service.
*
* This is useful when you want to store a callable as a parameter.
*
* @param callable $callable A callable to protect from being evaluated
*
* @return callable The passed callable
*
* @throws ExpectedInvokableException Service definition has to be a
closure or an invokable object
*/
public function protect($callable)
{
if (!\method_exists($callable, '__invoke')) {
throw new ExpectedInvokableException('Callable is not a
Closure or invokable object.');
}
$this->protected->attach($callable);
return $callable;
}
/**
* Gets a parameter or the closure defining an object.
*
* @param string $id The unique identifier for the parameter or object
*
* @return mixed The value of the parameter or the closure defining an
object
*
* @throws UnknownIdentifierException If the identifier is not defined
*/
public function raw($id)
{
if (!isset($this->keys[$id])) {
throw new UnknownIdentifierException($id);
}
if (isset($this->raw[$id])) {
return $this->raw[$id];
}
return $this->values[$id];
}
/**
* Extends an object definition.
*
* Useful when you want to extend an existing object definition,
* without necessarily loading that object.
*
* @param string $id The unique identifier for the object
* @param callable $callable A service definition to extend the
original
*
* @return callable The wrapped callable
*
* @throws UnknownIdentifierException If the identifier is not
defined
* @throws FrozenServiceException If the service is frozen
* @throws InvalidServiceIdentifierException If the identifier belongs
to a parameter
* @throws ExpectedInvokableException If the extension callable
is not a closure or an invokable object
*/
public function extend($id, $callable)
{
if (!isset($this->keys[$id])) {
throw new UnknownIdentifierException($id);
}
if (isset($this->frozen[$id])) {
throw new FrozenServiceException($id);
}
if (!\is_object($this->values[$id]) ||
!\method_exists($this->values[$id], '__invoke')) {
throw new InvalidServiceIdentifierException($id);
}
if (isset($this->protected[$this->values[$id]])) {
@\trigger_error(\sprintf('How Pimple behaves when
extending protected closures will be fixed in Pimple 4. Are you sure
"%s" should be protected?', $id), \E_USER_DEPRECATED);
}
if (!\is_object($callable) || !\method_exists($callable,
'__invoke')) {
throw new ExpectedInvokableException('Extension service
definition is not a Closure or invokable object.');
}
$factory = $this->values[$id];
$extended = function ($c) use ($callable, $factory) {
return $callable($factory($c), $c);
};
if (isset($this->factories[$factory])) {
$this->factories->detach($factory);
$this->factories->attach($extended);
}
return $this[$id] = $extended;
}
/**
* Returns all defined value names.
*
* @return array An array of value names
*/
public function keys()
{
return \array_keys($this->values);
}
/**
* Registers a service provider.
*
* @param ServiceProviderInterface $provider A ServiceProviderInterface
instance
* @param array $values An array of values that
customizes the provider
*
* @return static
*/
public function register(ServiceProviderInterface $provider, array
$values = array())
{
$provider->register($this);
foreach ($values as $key => $value) {
$this[$key] = $value;
}
return $this;
}
}
PK,d�[T�R��Hvendor/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple\Exception;
use Psr\Container\ContainerExceptionInterface;
/**
* A closure or invokable object was expected.
*
* @author Pascal Luna <skalpa@zetareticuli.org>
*/
class ExpectedInvokableException extends \InvalidArgumentException
implements ContainerExceptionInterface
{
}
PK,d�[EKeyyDvendor/pimple/pimple/src/Pimple/Exception/FrozenServiceException.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple\Exception;
use Psr\Container\ContainerExceptionInterface;
/**
* An attempt to modify a frozen service was made.
*
* @author Pascal Luna <skalpa@zetareticuli.org>
*/
class FrozenServiceException extends \RuntimeException implements
ContainerExceptionInterface
{
/**
* @param string $id Identifier of the frozen service
*/
public function __construct($id)
{
parent::__construct(\sprintf('Cannot override frozen service
"%s".', $id));
}
}
PK,d�[�\氲�Ovendor/pimple/pimple/src/Pimple/Exception/InvalidServiceIdentifierException.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple\Exception;
use Psr\Container\NotFoundExceptionInterface;
/**
* An attempt to perform an operation that requires a service identifier
was made.
*
* @author Pascal Luna <skalpa@zetareticuli.org>
*/
class InvalidServiceIdentifierException extends \InvalidArgumentException
implements NotFoundExceptionInterface
{
/**
* @param string $id The invalid identifier
*/
public function __construct($id)
{
parent::__construct(\sprintf('Identifier "%s" does
not contain an object definition.', $id));
}
}
PK,d�[�*s]��Hvendor/pimple/pimple/src/Pimple/Exception/UnknownIdentifierException.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple\Exception;
use Psr\Container\NotFoundExceptionInterface;
/**
* The identifier of a valid service or parameter was expected.
*
* @author Pascal Luna <skalpa@zetareticuli.org>
*/
class UnknownIdentifierException extends \InvalidArgumentException
implements NotFoundExceptionInterface
{
/**
* @param string $id The unknown identifier
*/
public function __construct($id)
{
parent::__construct(\sprintf('Identifier "%s" is not
defined.', $id));
}
}
PK,d�[5�ݢ��3vendor/pimple/pimple/src/Pimple/Psr11/Container.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009-2017 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple\Psr11;
use Pimple\Container as PimpleContainer;
use Psr\Container\ContainerInterface;
/**
* PSR-11 compliant wrapper.
*
* @author Pascal Luna <skalpa@zetareticuli.org>
*/
final class Container implements ContainerInterface
{
private $pimple;
public function __construct(PimpleContainer $pimple)
{
$this->pimple = $pimple;
}
public function get($id)
{
return $this->pimple[$id];
}
public function has($id)
{
return isset($this->pimple[$id]);
}
}
PK,d�[�%��a a 8vendor/pimple/pimple/src/Pimple/Psr11/ServiceLocator.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple\Psr11;
use Pimple\Container as PimpleContainer;
use Pimple\Exception\UnknownIdentifierException;
use Psr\Container\ContainerInterface;
/**
* Pimple PSR-11 service locator.
*
* @author Pascal Luna <skalpa@zetareticuli.org>
*/
class ServiceLocator implements ContainerInterface
{
private $container;
private $aliases = array();
/**
* @param PimpleContainer $container The Container instance used to
locate services
* @param array $ids Array of service ids that can be
located. String keys can be used to define aliases
*/
public function __construct(PimpleContainer $container, array $ids)
{
$this->container = $container;
foreach ($ids as $key => $id) {
$this->aliases[\is_int($key) ? $id : $key] = $id;
}
}
/**
* {@inheritdoc}
*/
public function get($id)
{
if (!isset($this->aliases[$id])) {
throw new UnknownIdentifierException($id);
}
return $this->container[$this->aliases[$id]];
}
/**
* {@inheritdoc}
*/
public function has($id)
{
return isset($this->aliases[$id]) &&
isset($this->container[$this->aliases[$id]]);
}
}
PK-d�[�;1�oo3vendor/pimple/pimple/src/Pimple/ServiceIterator.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple;
/**
* Lazy service iterator.
*
* @author Pascal Luna <skalpa@zetareticuli.org>
*/
final class ServiceIterator implements \Iterator
{
private $container;
private $ids;
public function __construct(Container $container, array $ids)
{
$this->container = $container;
$this->ids = $ids;
}
public function rewind()
{
\reset($this->ids);
}
public function current()
{
return $this->container[\current($this->ids)];
}
public function key()
{
return \current($this->ids);
}
public function next()
{
\next($this->ids);
}
public function valid()
{
return null !== \key($this->ids);
}
}
PK-d�[���SS<vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.phpnu�[���<?php
/*
* This file is part of Pimple.
*
* Copyright (c) 2009 Fabien Potencier
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN
* THE SOFTWARE.
*/
namespace Pimple;
/**
* Pimple service provider interface.
*
* @author Fabien Potencier
* @author Dominik Zogg
*/
interface ServiceProviderInterface
{
/**
* Registers services on the given container.
*
* This method should only be used to configure services and
parameters.
* It should not get services.
*
* @param Container $pimple A container instance
*/
public function register(Container $pimple);
}
PK-d�[U�\��"vendor/psr/container/composer.jsonnu�[���{
"name": "psr/container",
"type": "library",
"description": "Common Container Interface (PHP FIG
PSR-11)",
"keywords": ["psr", "psr-11",
"container", "container-interop",
"container-interface"],
"homepage": "https://github.com/php-fig/container",
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}
PK-d�[N>K���8vendor/psr/container/src/ContainerExceptionInterface.phpnu�[���<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the
LICENSE file)
*/
namespace Psr\Container;
/**
* Base interface representing a generic exception in a container.
*/
interface ContainerExceptionInterface
{
}
PK-d�["x��JJ/vendor/psr/container/src/ContainerInterface.phpnu�[���<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the
LICENSE file)
*/
namespace Psr\Container;
/**
* Describes the interface of a container that exposes methods to read its
entries.
*/
interface ContainerInterface
{
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @throws NotFoundExceptionInterface No entry was found for **this**
identifier.
* @throws ContainerExceptionInterface Error while retrieving the
entry.
*
* @return mixed Entry.
*/
public function get($id);
/**
* Returns true if the container can return an entry for the given
identifier.
* Returns false otherwise.
*
* `has($id)` returning true does not mean that `get($id)` will not
throw an exception.
* It does however mean that `get($id)` will not throw a
`NotFoundExceptionInterface`.
*
* @param string $id Identifier of the entry to look for.
*
* @return bool
*/
public function has($id);
}
PK-d�[�-��7vendor/psr/container/src/NotFoundExceptionInterface.phpnu�[���<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the
LICENSE file)
*/
namespace Psr\Container;
/**
* No entry was found in the container.
*/
interface NotFoundExceptionInterface extends ContainerExceptionInterface
{
}
PK-d�[��11vendor/psr/log/composer.jsonnu�[���{
"name": "psr/log",
"description": "Common interface for logging
libraries",
"keywords": ["psr", "psr-3",
"log"],
"homepage": "https://github.com/php-fig/log",
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
}
}
PK-d�[�Gl)vendor/psr/log/Psr/Log/AbstractLogger.phpnu�[���<?php
namespace Psr\Log;
/**
* This is a simple Logger implementation that other Loggers can inherit
from.
*
* It simply delegates all log-level-specific methods to the `log` method
to
* reduce boilerplate code that a simple Logger that does the same thing
with
* messages regardless of the error level has to implement.
*/
abstract class AbstractLogger implements LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should
typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* 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 $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
}
PK-d�[
�X1``3vendor/psr/log/Psr/Log/InvalidArgumentException.phpnu�[���<?php
namespace Psr\Log;
class InvalidArgumentException extends \InvalidArgumentException
{
}
PK-d�[�j�))/vendor/psr/log/Psr/Log/LoggerAwareInterface.phpnu�[���<?php
namespace Psr\Log;
/**
* Describes a logger-aware instance.
*/
interface LoggerAwareInterface
{
/**
* Sets a logger instance on the object.
*
* @param LoggerInterface $logger
*
* @return void
*/
public function setLogger(LoggerInterface $logger);
}
PK-d�[z%���+vendor/psr/log/Psr/Log/LoggerAwareTrait.phpnu�[���<?php
namespace Psr\Log;
/**
* Basic Implementation of LoggerAwareInterface.
*/
trait LoggerAwareTrait
{
/**
* The logger instance.
*
* @var LoggerInterface
*/
protected $logger;
/**
* Sets a logger.
*
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
PK-d�[1b!q***vendor/psr/log/Psr/Log/LoggerInterface.phpnu�[���<?php
namespace Psr\Log;
/**
* Describes a logger instance.
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data. The only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named
"exception".
*
* See
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
interface LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function emergency($message, array $context = array());
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function alert($message, array $context = array());
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function critical($message, array $context = array());
/**
* Runtime errors that do not require immediate action but should
typically
* be logged and monitored.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function error($message, array $context = array());
/**
* 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 $message
* @param mixed[] $context
*
* @return void
*/
public function warning($message, array $context = array());
/**
* Normal but significant events.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function notice($message, array $context = array());
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function info($message, array $context = array());
/**
* Detailed debug information.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function debug($message, array $context = array());
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param mixed[] $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array());
}
PK-d�[�W�jW
W
&vendor/psr/log/Psr/Log/LoggerTrait.phpnu�[���<?php
namespace Psr\Log;
/**
* This is a simple Logger trait that classes unable to extend
AbstractLogger
* (because they extend another class, etc) can include.
*
* It simply delegates all log-level-specific methods to the `log` method
to
* reduce boilerplate code that a simple Logger that does the same thing
with
* messages regardless of the error level has to implement.
*/
trait LoggerTrait
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should
typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* 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 $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
abstract public function log($level, $message, array $context =
array());
}
PK-d�[��PP#vendor/psr/log/Psr/Log/LogLevel.phpnu�[���<?php
namespace Psr\Log;
/**
* Describes log levels.
*/
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}
PK-d�[���I��%vendor/psr/log/Psr/Log/NullLogger.phpnu�[���<?php
namespace Psr\Log;
/**
* This Logger can be used to avoid conditional log calls.
*
* Logging should always be optional, and if no logger is provided to your
* library creating a NullLogger instance to have something to throw logs
at
* is a good way to avoid littering your code with `if ($this->logger) {
}`
* blocks.
*/
class NullLogger extends AbstractLogger
{
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array())
{
// noop
}
}
PK-d�[HTg��)vendor/psr/log/Psr/Log/Test/DummyTest.phpnu�[���<?php
namespace Psr\Log\Test;
/**
* This class is internal and does not follow the BC promise.
*
* Do NOT use this class in any way.
*
* @internal
*/
class DummyTest
{
public function __toString()
{
return 'DummyTest';
}
}
PK-d�[I\�))3vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.phpnu�[���<?php
namespace Psr\Log\Test;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use PHPUnit\Framework\TestCase;
/**
* Provides a base test class for ensuring compliance with the
LoggerInterface.
*
* Implementors can extend the class and implement abstract methods to run
this
* as part of their test suite.
*/
abstract class LoggerInterfaceTest extends TestCase
{
/**
* @return LoggerInterface
*/
abstract public function getLogger();
/**
* This must return the log messages in order.
*
* The simple formatting of the messages is: "<LOG LEVEL>
<MESSAGE>".
*
* Example ->error('Foo') would yield "error
Foo".
*
* @return string[]
*/
abstract public function getLogs();
public function testImplements()
{
$this->assertInstanceOf('Psr\Log\LoggerInterface',
$this->getLogger());
}
/**
* @dataProvider provideLevelsAndMessages
*/
public function testLogsAtAllLevels($level, $message)
{
$logger = $this->getLogger();
$logger->{$level}($message, array('user' =>
'Bob'));
$logger->log($level, $message, array('user' =>
'Bob'));
$expected = array(
$level.' message of level '.$level.' with
context: Bob',
$level.' message of level '.$level.' with
context: Bob',
);
$this->assertEquals($expected, $this->getLogs());
}
public function provideLevelsAndMessages()
{
return array(
LogLevel::EMERGENCY => array(LogLevel::EMERGENCY,
'message of level emergency with context: {user}'),
LogLevel::ALERT => array(LogLevel::ALERT, 'message of
level alert with context: {user}'),
LogLevel::CRITICAL => array(LogLevel::CRITICAL,
'message of level critical with context: {user}'),
LogLevel::ERROR => array(LogLevel::ERROR, 'message of
level error with context: {user}'),
LogLevel::WARNING => array(LogLevel::WARNING, 'message
of level warning with context: {user}'),
LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of
level notice with context: {user}'),
LogLevel::INFO => array(LogLevel::INFO, 'message of
level info with context: {user}'),
LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of
level debug with context: {user}'),
);
}
/**
* @expectedException \Psr\Log\InvalidArgumentException
*/
public function testThrowsOnInvalidLevel()
{
$logger = $this->getLogger();
$logger->log('invalid level', 'Foo');
}
public function testContextReplacement()
{
$logger = $this->getLogger();
$logger->info('{Message {nothing} {user} {foo.bar}
a}', array('user' => 'Bob', 'foo.bar'
=> 'Bar'));
$expected = array('info {Message {nothing} Bob Bar a}');
$this->assertEquals($expected, $this->getLogs());
}
public function testObjectCastToString()
{
if (method_exists($this, 'createPartialMock')) {
$dummy =
$this->createPartialMock('Psr\Log\Test\DummyTest',
array('__toString'));
} else {
$dummy = $this->getMock('Psr\Log\Test\DummyTest',
array('__toString'));
}
$dummy->expects($this->once())
->method('__toString')
->will($this->returnValue('DUMMY'));
$this->getLogger()->warning($dummy);
$expected = array('warning DUMMY');
$this->assertEquals($expected, $this->getLogs());
}
public function testContextCanContainAnything()
{
$closed = fopen('php://memory', 'r');
fclose($closed);
$context = array(
'bool' => true,
'null' => null,
'string' => 'Foo',
'int' => 0,
'float' => 0.5,
'nested' => array('with object' =>
new DummyTest),
'object' => new \DateTime,
'resource' => fopen('php://memory',
'r'),
'closed' => $closed,
);
$this->getLogger()->warning('Crazy context data',
$context);
$expected = array('warning Crazy context data');
$this->assertEquals($expected, $this->getLogs());
}
public function testContextExceptionKeyCanBeExceptionOrOtherValues()
{
$logger = $this->getLogger();
$logger->warning('Random message',
array('exception' => 'oops'));
$logger->critical('Uncaught Exception!',
array('exception' => new \LogicException('Fail')));
$expected = array(
'warning Random message',
'critical Uncaught Exception!'
);
$this->assertEquals($expected, $this->getLogs());
}
}
PK-d�[�
���*vendor/psr/log/Psr/Log/Test/TestLogger.phpnu�[���<?php
namespace Psr\Log\Test;
use Psr\Log\AbstractLogger;
/**
* Used for testing purposes.
*
* It records all records and gives you access to them for verification.
*
* @method bool hasEmergency($record)
* @method bool hasAlert($record)
* @method bool hasCritical($record)
* @method bool hasError($record)
* @method bool hasWarning($record)
* @method bool hasNotice($record)
* @method bool hasInfo($record)
* @method bool hasDebug($record)
*
* @method bool hasEmergencyRecords()
* @method bool hasAlertRecords()
* @method bool hasCriticalRecords()
* @method bool hasErrorRecords()
* @method bool hasWarningRecords()
* @method bool hasNoticeRecords()
* @method bool hasInfoRecords()
* @method bool hasDebugRecords()
*
* @method bool hasEmergencyThatContains($message)
* @method bool hasAlertThatContains($message)
* @method bool hasCriticalThatContains($message)
* @method bool hasErrorThatContains($message)
* @method bool hasWarningThatContains($message)
* @method bool hasNoticeThatContains($message)
* @method bool hasInfoThatContains($message)
* @method bool hasDebugThatContains($message)
*
* @method bool hasEmergencyThatMatches($message)
* @method bool hasAlertThatMatches($message)
* @method bool hasCriticalThatMatches($message)
* @method bool hasErrorThatMatches($message)
* @method bool hasWarningThatMatches($message)
* @method bool hasNoticeThatMatches($message)
* @method bool hasInfoThatMatches($message)
* @method bool hasDebugThatMatches($message)
*
* @method bool hasEmergencyThatPasses($message)
* @method bool hasAlertThatPasses($message)
* @method bool hasCriticalThatPasses($message)
* @method bool hasErrorThatPasses($message)
* @method bool hasWarningThatPasses($message)
* @method bool hasNoticeThatPasses($message)
* @method bool hasInfoThatPasses($message)
* @method bool hasDebugThatPasses($message)
*/
class TestLogger extends AbstractLogger
{
/**
* @var array
*/
public $records = [];
public $recordsByLevel = [];
/**
* @inheritdoc
*/
public function log($level, $message, array $context = [])
{
$record = [
'level' => $level,
'message' => $message,
'context' => $context,
];
$this->recordsByLevel[$record['level']][] = $record;
$this->records[] = $record;
}
public function hasRecords($level)
{
return isset($this->recordsByLevel[$level]);
}
public function hasRecord($record, $level)
{
if (is_string($record)) {
$record = ['message' => $record];
}
return $this->hasRecordThatPasses(function ($rec) use ($record)
{
if ($rec['message'] !== $record['message'])
{
return false;
}
if (isset($record['context']) &&
$rec['context'] !== $record['context']) {
return false;
}
return true;
}, $level);
}
public function hasRecordThatContains($message, $level)
{
return $this->hasRecordThatPasses(function ($rec) use ($message)
{
return strpos($rec['message'], $message) !== false;
}, $level);
}
public function hasRecordThatMatches($regex, $level)
{
return $this->hasRecordThatPasses(function ($rec) use ($regex) {
return preg_match($regex, $rec['message']) > 0;
}, $level);
}
public function hasRecordThatPasses(callable $predicate, $level)
{
if (!isset($this->recordsByLevel[$level])) {
return false;
}
foreach ($this->recordsByLevel[$level] as $i => $rec) {
if (call_user_func($predicate, $rec, $i)) {
return true;
}
}
return false;
}
public function __call($method, $args)
{
if
(preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/',
$method, $matches) > 0) {
$genericMethod = $matches[1] . ('Records' !==
$matches[3] ? 'Record' : '') . $matches[3];
$level = strtolower($matches[2]);
if (method_exists($this, $genericMethod)) {
$args[] = $level;
return call_user_func_array([$this, $genericMethod],
$args);
}
}
throw new \BadMethodCallException('Call to undefined method
' . get_class($this) . '::' . $method . '()');
}
public function reset()
{
$this->records = [];
$this->recordsByLevel = [];
}
}
PK-d�[�� 88:vendor/rockettheme/toolbox/ArrayTraits/src/ArrayAccess.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements ArrayAccess interface.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*
* @property array $items
*/
trait ArrayAccess
{
/**
* Whether or not an offset exists.
*
* @param mixed $offset An offset to check for.
* @return bool Returns TRUE on success or FALSE on failure.
*/
public function offsetExists($offset)
{
return isset($this->items[$offset]);
}
/**
* Returns the value at specified offset.
*
* @param mixed $offset The offset to retrieve.
* @return mixed Can return all value types.
*/
public function offsetGet($offset)
{
return isset($this->items[$offset]) ? $this->items[$offset] :
null;
}
/**
* Assigns a value to the specified offset.
*
* @param mixed $offset The offset to assign the value to.
* @param mixed $value The value to set.
*/
public function offsetSet($offset, $value)
{
if (null === $offset) {
$this->items[] = $value;
} else {
$this->items[$offset] = $value;
}
}
/**
* Unsets an offset.
*
* @param mixed $offset The offset to unset.
*/
public function offsetUnset($offset)
{
// Hack to make Iterator trait work together with unset.
if (isset($this->iteratorUnset) && $offset ==
key($this->items)) {
$this->iteratorUnset = true;
}
unset($this->items[$offset]);
}
}
PK-d�[�pR��Evendor/rockettheme/toolbox/ArrayTraits/src/ArrayAccessWithGetters.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements getters and setters.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*/
trait ArrayAccessWithGetters
{
use ArrayAccess;
/**
* Magic setter method
*
* @param mixed $offset Asset name value
* @param mixed $value Asset value
*/
public function __set($offset, $value)
{
$this->offsetSet($offset, $value);
}
/**
* Magic getter method
*
* @param mixed $offset Asset name value
* @return mixed Asset value
*/
public function __get($offset)
{
return $this->offsetGet($offset);
}
/**
* Magic method to determine if the attribute is set
*
* @param mixed $offset Asset name value
* @return boolean True if the value is set
*/
public function __isset($offset)
{
return $this->offsetExists($offset);
}
/**
* Magic method to unset the attribute
*
* @param mixed $offset The name value to unset
*/
public function __unset($offset)
{
$this->offsetUnset($offset);
}
}
PK-d�[��-��:vendor/rockettheme/toolbox/ArrayTraits/src/Constructor.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements Constructor for setting items.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*
* @property array $items
*/
trait Constructor
{
/**
* Constructor to initialize array.
*
* @param array $items Initial items inside the iterator.
*/
public function __construct(array $items = array())
{
$this->items = $items;
}
}
PK-d�[�9i���8vendor/rockettheme/toolbox/ArrayTraits/src/Countable.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements \Countable interface.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*
* @property array $items
*/
trait Countable
{
/**
* Implements Countable interface.
*
* @return int
*/
public function count()
{
return \count($this->items);
}
}
PK-d�[�|'�FF5vendor/rockettheme/toolbox/ArrayTraits/src/Export.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
use Symfony\Component\Yaml\Exception\DumpException;
use Symfony\Component\Yaml\Yaml;
/**
* Implements ExportInterface.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*
* @property array $items
*/
trait Export
{
/**
* Convert object into an array.
*
* @return array
*/
public function toArray()
{
return $this->items;
}
/**
* Convert object into YAML string.
*
* @param int $inline The level where you switch to inline YAML.
* @param int $indent The amount of spaces to use for indentation of
nested nodes.
*
* @return string A YAML string representing the object.
* @throws DumpException
*/
public function toYaml($inline = 3, $indent = 2)
{
return Yaml::dump($this->toArray(), $inline, $indent, true,
false);
}
/**
* Convert object into JSON string.
*
* @return string
*/
public function toJson()
{
return json_encode($this->toArray());
}
}
PK-d�[���oo>vendor/rockettheme/toolbox/ArrayTraits/src/ExportInterface.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Defines Export interface.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*/
interface ExportInterface
{
/**
* Convert object into an array.
*
* @return array
*/
public function toArray();
/**
* Convert object into YAML string.
*
* @param int $inline
* @param int $indent
* @return string
*/
public function toYaml($inline = 3, $indent = 2);
/**
* Convert object into JSON string.
*
* @return string
*/
public function toJson();
}
PK-d�[���[[7vendor/rockettheme/toolbox/ArrayTraits/src/Iterator.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements \Iterator interface.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*
* @property array $items
*/
trait Iterator
{
/**
* Hack to make Iterator work together with unset().
*
* @var bool
*/
private $iteratorUnset = false;
/**
* Returns the current element.
*
* @return mixed Can return any type.
*/
public function current()
{
return current($this->items);
}
/**
* Returns the key of the current element.
*
* @return mixed Returns scalar on success, or NULL on failure.
*/
public function key()
{
return key($this->items);
}
/**
* Moves the current position to the next element.
*
* @return void
*/
public function next()
{
if ($this->iteratorUnset) {
// If current item was unset, position is already in the next
element (do nothing).
$this->iteratorUnset = false;
} else {
next($this->items);
}
}
/**
* Rewinds back to the first element of the Iterator.
*
* @return void
*/
public function rewind()
{
$this->iteratorUnset = false;
reset($this->items);
}
/**
* This method is called after Iterator::rewind() and Iterator::next()
to check if the current position is valid.
*
* @return bool Returns TRUE on success or FALSE on failure.
*/
public function valid()
{
return key($this->items) !== null;
}
}
PK-d�[����33@vendor/rockettheme/toolbox/ArrayTraits/src/NestedArrayAccess.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements nested ArrayAccess interface with dot notation.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*
* @property array $items
*/
trait NestedArrayAccess
{
protected $nestedSeparator = '.';
/**
* Get value by using dot notation for nested arrays/objects.
*
* @example $value =
$this->get('this.is.my.nested.variable');
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return mixed Value.
*/
public function get($name, $default = null, $separator = null)
{
$path = explode($separator ?: $this->nestedSeparator, $name);
$current = $this->items;
foreach ($path as $field) {
if (\is_object($current) &&
isset($current->{$field})) {
$current = $current->{$field};
} elseif (\is_array($current) &&
isset($current[$field])) {
$current = $current[$field];
} else {
return $default;
}
}
return $current;
}
/**
* Set value by using dot notation for nested arrays/objects.
*
* @example $data->set('this.is.my.nested.variable',
$value);
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $value New value.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function set($name, $value, $separator = null)
{
$path = explode($separator ?: $this->nestedSeparator, $name);
$current = &$this->items;
foreach ($path as $field) {
if (\is_object($current)) {
// Handle objects.
if (!isset($current->{$field})) {
$current->{$field} = [];
}
$current = &$current->{$field};
} else {
// Handle arrays and scalars.
if (!\is_array($current)) {
$current = [$field => []];
} elseif (!isset($current[$field])) {
$current[$field] = [];
}
$current = &$current[$field];
}
}
$current = $value;
return $this;
}
/**
* Unset value by using dot notation for nested arrays/objects.
*
* @example $data->undef('this.is.my.nested.variable');
*
* @param string $name Dot separated path to the requested
value.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function undef($name, $separator = null)
{
if ($name === '') {
$this->items = [];
return $this;
}
$path = explode($separator ?: $this->nestedSeparator, $name);
$var = array_pop($path);
$current = &$this->items;
foreach ($path as $field) {
if (\is_object($current)) {
// Handle objects.
if (!isset($current->{$field})) {
return $this;
}
$current = &$current->{$field};
} else {
// Handle arrays and scalars.
if (!\is_array($current) || !isset($current[$field])) {
return $this;
}
$current = &$current[$field];
}
}
unset($current[$var]);
return $this;
}
/**
* Set default value by using dot notation for nested arrays/objects.
*
* @example $data->def('this.is.my.nested.variable',
'default');
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function def($name, $default = null, $separator = null)
{
$this->set($name, $this->get($name, $default, $separator),
$separator);
return $this;
}
/**
* Whether or not an offset exists.
*
* @param mixed $offset An offset to check for.
* @return bool Returns TRUE on success or FALSE on failure.
*/
public function offsetExists($offset)
{
return $this->get($offset) !== null;
}
/**
* Returns the value at specified offset.
*
* @param mixed $offset The offset to retrieve.
* @return mixed Can return all value types.
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* Assigns a value to the specified offset.
*
* @param mixed $offset The offset to assign the value to.
* @param mixed $value The value to set.
*/
public function offsetSet($offset, $value)
{
if (null === $offset) {
$this->items[] = $value;
} else {
$this->set($offset, $value);
}
}
/**
* Unsets variable at specified offset.
*
* @param $offset
*/
public function offsetUnset($offset)
{
if (null === $offset) {
$this->items[] = [];
} else {
$this->undef($offset);
}
}
}
PK-d�[H
�Kvendor/rockettheme/toolbox/ArrayTraits/src/NestedArrayAccessWithGetters.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements getters and setters.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*/
trait NestedArrayAccessWithGetters
{
use NestedArrayAccess;
/**
* Magic setter method
*
* @param mixed $offset Asset name value
* @param mixed $value Asset value
*/
public function __set($offset, $value)
{
$this->offsetSet($offset, $value);
}
/**
* Magic getter method
*
* @param mixed $offset Asset name value
* @return mixed Asset value
*/
public function __get($offset)
{
return $this->offsetGet($offset);
}
/**
* Magic method to determine if the attribute is set
*
* @param mixed $offset Asset name value
* @return boolean True if the value is set
*/
public function __isset($offset)
{
return $this->offsetExists($offset);
}
/**
* Magic method to unset the attribute
*
* @param mixed $offset The name value to unset
*/
public function __unset($offset)
{
$this->offsetUnset($offset);
}
}
PK-d�[����;vendor/rockettheme/toolbox/ArrayTraits/src/Serializable.phpnu�[���<?php
namespace RocketTheme\Toolbox\ArrayTraits;
/**
* Implements \Serializable interface.
*
* @package RocketTheme\Toolbox\ArrayTraits
* @author RocketTheme
* @license MIT
*
* @property array $items
*/
trait Serializable
{
/**
* Returns string representation of the object.
*
* @return string Returns the string representation of the object.
*/
public function serialize()
{
return serialize($this->items);
}
/**
* Called during unserialization of the object.
*
* @param string $serialized The string representation of the object.
*/
public function unserialize($serialized)
{
$this->items = unserialize($serialized);
}
}
PK-d�[VVۀ7B7B;vendor/rockettheme/toolbox/Blueprints/src/BlueprintForm.phpnu�[���<?php
namespace RocketTheme\Toolbox\Blueprints;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
use RuntimeException;
/**
* The Config class contains configuration information.
*
* @author RocketTheme
*/
abstract class BlueprintForm implements \ArrayAccess, ExportInterface
{
use NestedArrayAccessWithGetters;
use Export;
/** @var array */
protected $items;
/** @var string */
protected $filename;
/** @var string */
protected $context;
/** @var array */
protected $overrides = [];
/** @var array */
protected $dynamic = [];
/**
* Load file and return its contents.
*
* @param string $filename
* @return array
*/
abstract protected function loadFile($filename);
/**
* Get list of blueprint form files (file and its parents for
overrides).
*
* @param string|array $path
* @param string $context
* @return array
*/
abstract protected function getFiles($path, $context = null);
/**
* Constructor.
*
* @param string|array $filename
* @param array $items
*/
public function __construct($filename = null, array $items = [])
{
$this->nestedSeparator = '/';
$this->filename = $filename;
$this->items = $items;
}
/**
* Set filename for the blueprint. Can also be array of files for
parent lookup.
*
* @param string|array $filename
* @return $this
*/
public function setFilename($filename)
{
$this->filename = $filename;
return $this;
}
/**
* Get the filename of the blueprint.
*
* @return array|null|string
*/
public function getFilename()
{
return $this->filename;
}
/**
* Set context for import@ and extend@.
*
* @param $context
* @return $this
*/
public function setContext($context)
{
$this->context = $context;
return $this;
}
/**
* Set custom overrides for import@ and extend@.
*
* @param array $overrides
* @return $this
*/
public function setOverrides($overrides)
{
$this->overrides = $overrides;
return $this;
}
/**
* Load blueprint.
*
* @return $this
*/
public function load($extends = null)
{
// Only load and extend blueprint if it has not yet been loaded.
if (empty($this->items) && $this->filename) {
// Get list of files.
$files = $this->getFiles($this->filename);
// Load and extend blueprints.
$data = $this->doLoad($files, $extends);
$this->items = (array) array_shift($data);
foreach ($data as $content) {
$this->extend($content, true);
}
}
// Import blueprints.
$this->deepInit($this->items);
return $this;
}
/**
* Initialize blueprints with its dynamic fields.
*
* @return $this
*/
public function init()
{
foreach ($this->dynamic as $key => $data) {
// Locate field.
$path = explode('/', $key);
$current = &$this->items;
foreach ($path as $field) {
if (\is_object($current)) {
// Handle objects.
if (!isset($current->{$field})) {
$current->{$field} = [];
}
$current = &$current->{$field};
} else {
// Handle arrays and scalars.
if (!\is_array($current)) {
$current = [$field => []];
} elseif (!isset($current[$field])) {
$current[$field] = [];
}
$current = &$current[$field];
}
}
// Set dynamic property.
foreach ($data as $property => $call) {
$action = 'dynamic' .
ucfirst($call['action']);
if (method_exists($this, $action)) {
$this->{$action}($current, $property, $call);
}
}
}
return $this;
}
/**
* Get form.
*
* @return array
*/
public function form()
{
return (array) $this->get('form');
}
/**
* Get form fields.
*
* @return array
*/
public function fields()
{
$fields = $this->get('form/fields');
if ($fields === null) {
$field = $this->get('form/field');
$fields = $field !== null ? ['' => (array) $field]
: $fields;
}
return (array) $fields;
}
/**
* Extend blueprint with another blueprint.
*
* @param BlueprintForm|array $extends
* @param bool $append
* @return $this
*/
public function extend($extends, $append = false)
{
if ($extends instanceof self) {
$extends = $extends->toArray();
}
if ($append) {
$a = $this->items;
$b = $extends;
} else {
$a = $extends;
$b = $this->items;
}
$this->items = $this->deepMerge($a, $b);
return $this;
}
/**
* @param string $name
* @param mixed $value
* @param string $separator
* @param bool $append
* @return $this
*/
public function embed($name, $value, $separator = '/',
$append = false)
{
$oldValue = $this->get($name, null, $separator);
if (\is_array($oldValue) && \is_array($value)) {
if ($append) {
$a = $oldValue;
$b = $value;
} else {
$a = $value;
$b = $oldValue;
}
$value = $this->deepMerge($a, $b);
}
$this->set($name, $value, $separator);
return $this;
}
/**
* Get blueprints by using slash notation for nested arrays/objects.
*
* @example $value =
$this->resolve('this/is/my/nested/variable');
* returns ['this/is/my', 'nested/variable']
*
* @param array $path
* @param string $separator
* @return array
*/
public function resolve(array $path, $separator = '/')
{
$fields = false;
$parts = [];
$current = $this['form/fields'];
$result = [null, null, null];
while (($field = current($path)) !== null) {
if (!$fields && isset($current['fields'])) {
if (!empty($current['array'])) {
$result = [$current, $parts, $path ?
implode($separator, $path) : null];
// Skip item offset.
$parts[] = array_shift($path);
}
$current = $current['fields'];
$fields = true;
} elseif (isset($current[$field])) {
$parts[] = array_shift($path);
$current = $current[$field];
$fields = false;
} elseif (isset($current[$index = '.' . $field])) {
$parts[] = array_shift($path);
$current = $current[$index];
$fields = false;
} else {
break;
}
}
return $result;
}
/**
* Deep merge two arrays together.
*
* @param array $a
* @param array $b
* @return array
*/
protected function deepMerge(array $a, array $b)
{
$bref_stack = [&$a];
$head_stack = [$b];
do {
end($bref_stack);
$bref = &$bref_stack[key($bref_stack)];
$head = array_pop($head_stack);
unset($bref_stack[key($bref_stack)]);
foreach ($head as $key => $value) {
if (strpos($key, '@') !== false) {
// Remove @ from the start and the end. Key syntax
`import@2` is supported to allow multiple operations of the same type.
$list = explode('-',
preg_replace('/^(@*)?([^@]+)(@\d*)?$/', '\2', $key),
2);
$action = array_shift($list);
$property = array_shift($list);
switch ($action) {
case 'unset':
case 'replace':
if (!$property) {
$bref = ['unset@' => true];
} else {
unset($bref[$property]);
}
continue 2;
}
}
if (isset($key, $bref[$key]) &&
\is_array($bref[$key]) && \is_array($head[$key])) {
$bref_stack[] = &$bref[$key];
$head_stack[] = $head[$key];
} else {
$bref = array_merge($bref, [$key => $head[$key]]);
}
}
} while (\count($head_stack));
return $a;
}
/**
* @param array $items
* @param array $path
* @return string
*/
protected function deepInit(array &$items, $path = [])
{
$ordering = '';
$order = [];
$field = end($path) === 'fields';
foreach ($items as $key => &$item) {
// Set name for nested field.
if ($field && isset($item['type'])) {
$item['name'] = $key;
}
// Handle special instructions in the form.
if (strpos($key, '@') !== false) {
// Remove @ from the start and the end. Key syntax
`import@2` is supported to allow multiple operations of the same type.
$list = explode('-',
preg_replace('/^(@*)?([^@]+)(@\d*)?$/', '\2', $key),
2);
$action = array_shift($list);
$property = array_shift($list);
switch ($action) {
case 'unset':
unset($items[$key]);
if (empty($items)) {
return null;
}
break;
case 'import':
unset($items[$key]);
$this->doImport($item, $path);
break;
case 'ordering':
$ordering = $item;
unset($items[$key]);
break;
default:
$this->dynamic[implode('/',
$path)][$property] = ['action' => $action, 'params'
=> $item];
}
} elseif (\is_array($item)) {
// Recursively initialize form.
$newPath = array_merge($path, [$key]);
$location = $this->deepInit($item, $newPath);
if ($location) {
$order[$key] = $location;
} elseif ($location === null) {
unset($items[$key]);
}
}
}
unset($item);
if ($order) {
// Reorder fields if needed.
$items = $this->doReorder($items, $order);
}
return $ordering;
}
/**
* @param array|string $value
* @return array|null
*/
protected function loadImport($value)
{
$type = !\is_string($value) ? (!isset($value['type']) ?
null : $value['type']) : $value;
$field = 'form';
if ($type && strpos($type, ':') !== false) {
list ($type, $field) = explode(':', $type, 2);
}
if (!$type && !$field) {
return null;
}
if ($type) {
$files = $this->getFiles($type,
isset($value['context']) ? $value['context'] : null);
if (!$files) {
return null;
}
/** @var BlueprintForm $blueprint */
$blueprint = new static($files);
$blueprint->setContext($this->context)->setOverrides($this->overrides)->load();
} else {
$blueprint = $this;
}
$import = $blueprint->get($field);
return \is_array($import) ? $import : null;
}
/**
* @param array|string $value
* @param array $path
*/
protected function doImport($value, array &$path)
{
$imported = $this->loadImport($value);
if ($imported) {
$this->deepInit($imported, $path);
$name = implode('/', $path);
$this->embed($name, $imported, '/', false);
}
}
/**
* Internal function that handles loading extended blueprints.
*
* @param array $files
* @param string|array|null $extends
* @return array
*/
protected function doLoad(array $files, $extends = null)
{
$filename = array_shift($files);
$content = $this->loadFile($filename);
$key = '';
if (isset($content['extends@'])) {
$key = 'extends@';
} elseif (isset($content['@extends'])) {
$key = '@extends';
} elseif (isset($content['@extends@'])) {
$key = '@extends@';
}
$override = (bool)$extends;
$extends = (array)($key && !$extends ? $content[$key] :
$extends);
unset($content['extends@'],
$content['@extends'], $content['@extends@']);
$data = $extends ? $this->doExtend($filename, $files, $extends,
$override) : [];
$data[] = $content;
return $data;
}
/**
* Internal function to recursively load extended blueprints.
*
* @param string $filename
* @param array $parents
* @param array $extends
* @return array
*/
protected function doExtend($filename, array $parents, array $extends,
$override = false)
{
if (\is_string(key($extends))) {
$extends = [$extends];
}
$data = [[]];
foreach ($extends as $value) {
// Accept array of type and context or a string.
$type = !\is_string($value) ? (!isset($value['type'])
? null : $value['type']) : $value;
if (!$type) {
continue;
}
if ($type === '@parent' || $type ===
'parent@') {
if (!$parents) {
throw new RuntimeException("Parent blueprint
missing for '{$filename}'");
}
$files = $parents;
} else {
$files = $this->getFiles($type,
isset($value['context']) ? $value['context'] : null);
if ($override && !$files) {
throw new RuntimeException("Blueprint
'{$type}' missing for '{$filename}'");
}
// Detect extend loops.
if ($files && array_intersect($files, $parents)) {
// Let's check if user really meant extends@:
parent@.
$index = \array_search($filename, $files, true);
if ($index !== false) {
// We want to grab only the parents of the file
which is currently being loaded.
$files = \array_slice($files, $index + 1);
}
if ($files !== $parents) {
throw new RuntimeException("Loop detected
while extending blueprint file '{$filename}'");
}
if (!$parents) {
throw new RuntimeException("Parent blueprint
missing for '{$filename}'");
}
}
}
if ($files) {
$data[] = $this->doLoad($files);
}
}
// TODO: In PHP 5.6+ use array_merge(...$data);
return call_user_func_array('array_merge', $data);
}
/**
* Internal function to reorder items.
*
* @param array $items
* @param array $keys
* @return array
*/
protected function doReorder(array $items, array $keys)
{
$reordered = array_keys($items);
foreach ($keys as $item => $ordering) {
if ((string)(int) $ordering === (string) $ordering) {
$location = array_search($item, $reordered, true);
$rel = array_splice($reordered, $location, 1);
array_splice($reordered, $ordering, 0, $rel);
} elseif (isset($items[$ordering])) {
$location = array_search($item, $reordered, true);
$rel = array_splice($reordered, $location, 1);
$location = array_search($ordering, $reordered, true);
array_splice($reordered, $location + 1, 0, $rel);
}
}
return array_merge(array_flip($reordered), $items);
}
}
PK-d�[�-��8vendor/rockettheme/toolbox/Blueprints/src/Blueprints.phpnu�[���<?php
namespace RocketTheme\Toolbox\Blueprints;
/**
* Deprecated class, use BlueprintSchema instead.
*
* @package RocketTheme\Toolbox\Blueprints
* @author RocketTheme
* @license MIT
* @deprecated
*/
class Blueprints extends BlueprintSchema {}
PK-d�[xJ��P�P=vendor/rockettheme/toolbox/Blueprints/src/BlueprintSchema.phpnu�[���<?php
namespace RocketTheme\Toolbox\Blueprints;
/**
* BlueprintSchema is used to define a data structure.
*
* @package RocketTheme\Toolbox\Blueprints
* @author RocketTheme
* @license MIT
*/
class BlueprintSchema
{
/** @var array */
protected $items = [];
/** @var array */
protected $rules = [];
/** @var array */
protected $nested = [];
/** @var array */
protected $dynamic = [];
/** @var array */
protected $filter = ['validation' => true];
/** @var array */
protected $ignoreFormKeys = ['fields' => 1];
/** @var array */
protected $types = [];
/**
* Constructor.
*
* @param array $serialized Serialized content if available.
*/
public function __construct($serialized = null)
{
if (\is_array($serialized) && !empty($serialized)) {
$this->items = (array) $serialized['items'];
$this->rules = (array) $serialized['rules'];
$this->nested = (array) $serialized['nested'];
$this->dynamic = (array) $serialized['dynamic'];
$this->filter = (array) $serialized['filter'];
}
}
/**
* @param array $types
* @return $this
*/
public function setTypes(array $types)
{
$this->types = $types;
return $this;
}
/**
* Restore Blueprints object.
*
* @param array $serialized
* @return static
*/
public static function restore(array $serialized)
{
return new static($serialized);
}
/**
* Initialize blueprints with its dynamic fields.
*
* @return $this
*/
public function init()
{
foreach ($this->dynamic as $key => $data) {
$field = &$this->items[$key];
foreach ($data as $property => $call) {
$action = 'dynamic' .
ucfirst($call['action']);
if (method_exists($this, $action)) {
$this->{$action}($field, $property, $call);
}
}
}
return $this;
}
/**
* Set filter for inherited properties.
*
* @param array $filter List of field names to be inherited.
*/
public function setFilter(array $filter)
{
$this->filter = array_flip($filter);
}
/**
* Get value by using dot notation for nested arrays/objects.
*
* @example $value =
$data->get('this.is.my.nested.variable');
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
*
* @return mixed Value.
*/
public function get($name, $default = null, $separator = '.')
{
$name = $separator !== '.' ? str_replace($separator,
'.', $name) : $name;
return isset($this->items[$name]) ? $this->items[$name] :
$default;
}
/**
* Set value by using dot notation for nested arrays/objects.
*
* @example $value =
$data->set('this.is.my.nested.variable', $newField);
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $value New value.
* @param string $separator Separator, defaults to '.'
*/
public function set($name, $value, $separator = '.')
{
$name = $separator !== '.' ? str_replace($separator,
'.', $name) : $name;
$this->items[$name] = $value;
$this->addProperty($name);
}
/**
* Define value by using dot notation for nested arrays/objects.
*
* @example $value =
$data->set('this.is.my.nested.variable', true);
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $value New value.
* @param string $separator Separator, defaults to '.'
*/
public function def($name, $value, $separator = '.')
{
$this->set($name, $this->get($name, $value, $separator),
$separator);
}
/**
* @return array
* @deprecated
*/
public function toArray()
{
return $this->getState();
}
/**
* Convert object into an array.
*
* @return array
*/
public function getState()
{
return [
'items' => $this->items,
'rules' => $this->rules,
'nested' => $this->nested,
'dynamic' => $this->dynamic,
'filter' => $this->filter
];
}
/**
* Get nested structure containing default values defined in the
blueprints.
*
* Fields without default value are ignored in the list.
*
* @return array
*/
public function getDefaults()
{
return $this->buildDefaults($this->nested);
}
/**
* Embed an array to the blueprint.
*
* @param $name
* @param array $value
* @param string $separator
* @param bool $merge Merge fields instead replacing them.
* @return $this
*/
public function embed($name, array $value, $separator = '.',
$merge = false)
{
if (isset($value['rules'])) {
$this->rules = array_merge($this->rules,
$value['rules']);
}
$name = $separator !== '.' ? str_replace($separator,
'.', $name) : $name;
if (isset($value['form'])) {
$form = array_diff_key($value['form'],
['fields' => 1, 'field' => 1]);
} else {
$form = [];
}
$items = isset($this->items[$name]) ? $this->items[$name] :
['type' => '_root', 'form_field' =>
false];
$this->items[$name] = $items;
$this->addProperty($name);
$prefix = $name ? $name . '.' : '';
$params = array_intersect_key($form, $this->filter);
$location = [$name];
if (isset($value['form']['field'])) {
$this->parseFormField($name,
$value['form']['field'], $params, $prefix,
'', $merge, $location);
} elseif (isset($value['form']['fields'])) {
$this->parseFormFields($value['form']['fields'],
$params, $prefix, '', $merge, $location);
}
$this->items[$name] += ['form' => $form];
return $this;
}
/**
* Merge two arrays by using blueprints.
*
* @param array $data1
* @param array $data2
* @param string $name Optional
* @param string $separator Optional
* @return array
*/
public function mergeData(array $data1, array $data2, $name = null,
$separator = '.')
{
$nested = $this->getNested($name, $separator);
if (!\is_array($nested)) {
$nested = [];
}
return $this->mergeArrays($data1, $data2, $nested);
}
/**
* Get the property with given path.
*
* @param string $path
* @param string $separator
* @return mixed
*/
public function getProperty($path = null, $separator = '.')
{
$name = $this->getPropertyName($path, $separator);
$property = $this->get($name);
$nested = $this->getNested($name);
return $this->getPropertyRecursion($property, $nested);
}
/**
* Returns name of the property with given path.
*
* @param string $path
* @param string $separator
* @return string
*/
public function getPropertyName($path = null, $separator =
'.')
{
$parts = explode($separator, $path);
$nested = $this->nested;
$result = [];
while (($part = array_shift($parts)) !== null) {
if (!isset($nested[$part])) {
if (isset($nested['*'])) {
$part = '*';
} else {
return implode($separator, array_merge($result,
[$part], $parts));
}
}
$result[] = $part;
$nested = $nested[$part];
}
return implode('.', $result);
}
/**
* Return data fields that do not exist in blueprints.
*
* @param array $data
* @param string $prefix
* @return array
*/
public function extra(array $data, $prefix = '')
{
$rules = $this->nested;
// Drill down to prefix level
if (!empty($prefix)) {
$parts = explode('.', trim($prefix, '.'));
foreach ($parts as $part) {
$rules = isset($rules[$part]) ? $rules[$part] : [];
}
}
// Check if the form cannot have extra fields.
if (isset($rules[''])) {
$rule = $this->items[''];
if (isset($rule['type']) &&
$rule['type'] !== '_root') {
return [];
}
}
return $this->extraArray($data, $rules, $prefix);
}
/**
* Get the property with given path.
*
* @param $property
* @param $nested
* @return mixed
*/
protected function getPropertyRecursion($property, $nested)
{
if (empty($nested) || !\is_array($nested) ||
!isset($property['type'])) {
return $property;
}
if ($property['type'] === '_root') {
foreach ($nested as $key => $value) {
if ($key === '') {
continue;
}
$name = \is_array($value) ? $key : $value;
$property['fields'][$key] =
$this->getPropertyRecursion($this->get($name), $value);
}
} elseif ($property['type'] === '_parent' ||
!empty($property['array'])) {
foreach ($nested as $key => $value) {
$name = \is_array($value) ?
"{$property['name']}.{$key}" : $value;
$property['fields'][$key] =
$this->getPropertyRecursion($this->get($name), $value);
}
}
return $property;
}
/**
* Get property from the definition.
*
* @param string $path Comma separated path to the property.
* @param string $separator
* @return array|string|null
* @internal
*/
protected function getNested($path = null, $separator = '.')
{
if (!$path) {
return $this->nested;
}
$parts = explode($separator, $path);
$item = array_pop($parts);
$nested = $this->nested;
foreach ($parts as $part) {
if (!isset($nested[$part])) {
$part = '*';
if (!isset($nested[$part])) {
return [];
}
}
$nested = $nested[$part];
}
return isset($nested[$item]) ? $nested[$item] :
(isset($nested['*']) ? $nested['*'] : null);
}
/**
* @param array $nested
* @return array
*/
protected function buildDefaults(array $nested)
{
$defaults = [];
foreach ($nested as $key => $value) {
if ($key === '*') {
// TODO: Add support for adding defaults to collections.
continue;
}
if (\is_array($value)) {
// Recursively fetch the items.
$list = $this->buildDefaults($value);
// Only return defaults if there are any.
if (!empty($list)) {
$defaults[$key] = $list;
}
} else {
// We hit a field; get default from it if it exists.
$item = $this->get($value);
// Only return default value if it exists.
if (isset($item['default'])) {
$defaults[$key] = $item['default'];
}
}
}
return $defaults;
}
/**
* @param array $data1
* @param array $data2
* @param array $rules
* @return array
* @internal
*/
protected function mergeArrays(array $data1, array $data2, array
$rules)
{
foreach ($data2 as $key => $field) {
$val = isset($rules[$key]) ? $rules[$key] : null;
$rule = \is_string($val) ? $this->items[$val] : null;
if ((array_key_exists($key, $data1) &&
\is_array($data1[$key]) && \is_array($field) &&
\is_array($val) && !isset($val['*']))
|| (!empty($rule['type']) &&
strpos($rule['type'], '_') === 0)) {
// Array has been defined in blueprints and is not a
collection of items.
$data1[$key] = $this->mergeArrays($data1[$key], $field,
$val);
} else {
// Otherwise just take value from the data2.
$data1[$key] = $field;
}
}
return $data1;
}
/**
* Gets all field definitions from the blueprints.
*
* @param array $fields Fields to parse.
* @param array $params Property parameters.
* @param string $prefix Property prefix.
* @param string $parent Parent property.
* @param bool $merge Merge fields instead replacing them.
* @param array $formPath
*/
protected function parseFormFields(array $fields, array $params,
$prefix = '', $parent = '', $merge = false, array
$formPath = [])
{
if (isset($fields['type']) &&
!\is_array($fields['type'])) {
return;
}
// Go though all the fields in current level.
foreach ($fields as $key => $field) {
$this->parseFormField($key, $field, $params, $prefix,
$parent, $merge, $formPath);
}
}
/**
* @param string $key
* @param array $field
* @param array $params
* @param string $prefix
* @param string $parent
* @param bool $merge
* @param array $formPath
*/
protected function parseFormField($key, array $field, array $params,
$prefix = '', $parent = '', $merge = false, array
$formPath = [])
{
// Skip illegal field (needs to be an array).
if (!\is_array($field)) {
return;
}
$key = $this->getFieldKey($key, $prefix, $parent);
$newPath = array_merge($formPath, [$key]);
$properties = array_diff_key($field, $this->ignoreFormKeys) +
$params;
$properties['name'] = $key;
// Set default properties for the field type.
$type = isset($properties['type']) ?
$properties['type'] : '';
if (isset($this->types[$type])) {
$properties += $this->types[$type];
}
// Merge properties with existing ones.
if ($merge && isset($this->items[$key])) {
$properties += $this->items[$key];
}
$isInputField = !isset($properties['input@']) ||
$properties['input@'];
$propertyExists = isset($this->items[$key]);
if (!$isInputField) {
// Remove property if it exists.
if ($propertyExists) {
$this->removeProperty($key);
}
} elseif (!$propertyExists) {
// Add missing property.
$this->addProperty($key);
}
if (isset($field['fields'])) {
// Recursively get all the nested fields.
$isArray = !empty($properties['array']);
$newParams = array_intersect_key($properties,
$this->filter);
$this->parseFormFields($field['fields'],
$newParams, $prefix, $key . ($isArray ? '.*': ''),
$merge, $newPath);
} else {
if (!isset($this->items[$key])) {
// Add parent rules.
$path = explode('.', $key);
array_pop($path);
$parent = '';
foreach ($path as $part) {
$parent .= ($parent ? '.' : '') .
$part;
if (!isset($this->items[$parent])) {
$this->items[$parent] = ['type' =>
'_parent', 'name' => $parent, 'form_field'
=> false];
}
}
}
if ($isInputField) {
$this->parseProperties($key, $properties);
}
}
if ($isInputField) {
$this->items[$key] = $properties;
}
}
protected function getFieldKey($key, $prefix, $parent)
{
// Set name from the array key.
if (strpos($key[0], '.') === 0) {
return ($parent ?: rtrim($prefix, '.')) . $key;
}
return $prefix . $key;
}
protected function parseProperties($key, array &$properties)
{
$key = ltrim($key, '.');
if (!empty($properties['data'])) {
$this->dynamic[$key] = $properties['data'];
}
foreach ($properties as $name => $value) {
if (strpos($name[0], '@') !== false) {
$list = explode('-', trim($name, '@'),
2);
$action = array_shift($list);
$property = array_shift($list);
$this->dynamic[$key][$property] = ['action'
=> $action, 'params' => $value];
}
}
// Initialize predefined validation rule.
if (isset($properties['validate']['rule'])) {
$properties['validate'] +=
$this->getRule($properties['validate']['rule']);
}
}
/**
* Add property to the definition.
*
* @param string $path Comma separated path to the property.
* @internal
*/
protected function addProperty($path)
{
$parts = explode('.', $path);
$item = array_pop($parts);
$nested = &$this->nested;
foreach ($parts as $part) {
if (!isset($nested[$part]) || !\is_array($nested[$part])) {
$nested[$part] = [];
}
$nested = &$nested[$part];
}
if (!isset($nested[$item])) {
$nested[$item] = $path;
}
}
/**
* Remove property to the definition.
*
* @param string $path Comma separated path to the property.
* @internal
*/
protected function removeProperty($path)
{
$parts = explode('.', $path);
$item = array_pop($parts);
$nested = &$this->nested;
foreach ($parts as $part) {
if (!isset($nested[$part]) || !\is_array($nested[$part])) {
return;
}
$nested = &$nested[$part];
}
if (isset($nested[$item])) {
unset($nested[$item]);
}
}
/**
* @param $rule
* @return array
* @internal
*/
protected function getRule($rule)
{
if (isset($this->rules[$rule]) &&
\is_array($this->rules[$rule])) {
return $this->rules[$rule];
}
return [];
}
/**
* @param array $data
* @param array $rules
* @param string $prefix
* @return array
* @internal
*/
protected function extraArray(array $data, array $rules, $prefix)
{
$array = [];
foreach ($data as $key => $field) {
$val = isset($rules[$key]) ? $rules[$key] :
(isset($rules['*']) ? $rules['*'] : null);
$rule = \is_string($val) ? $this->items[$val] : null;
if ($rule || isset($val['*'])) {
// Item has been defined in blueprints.
} elseif (\is_array($field) && \is_array($val)) {
// Array has been defined in blueprints.
$array += $this->extraArray($field, $val, $prefix . $key
. '.');
} else {
// Undefined/extra item.
$array[$prefix.$key] = $field;
}
}
return $array;
}
/**
* @param array $field
* @param string $property
* @param array $call
*/
protected function dynamicData(array &$field, $property, array
$call)
{
$params = $call['params'];
if (\is_array($params)) {
$function = array_shift($params);
} else {
$function = $params;
$params = [];
}
$list = explode('::', $function, 2);
$f = array_pop($list);
$o = array_pop($list);
if (!$o) {
if (\function_exists($f)) {
$data = \call_user_func_array($f, $params);
}
} else {
if (method_exists($o, $f)) {
$data = \call_user_func_array(array($o, $f), $params);
}
}
// If function returns a value,
if (isset($data)) {
if (\is_array($data) && isset($field[$property])
&& \is_array($field[$property])) {
// Combine field and @data-field together.
$field[$property] += $data;
} else {
// Or create/replace field with @data-field.
$field[$property] = $data;
}
}
}
}
PK-d�[T�����Kvendor/rockettheme/toolbox/Compat/src/Yaml/Exception/ExceptionInterface.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RocketTheme\Toolbox\Compat\Yaml\Exception;
/**
* Exception interface for all exceptions thrown by the component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ExceptionInterface
{
}
PK-d�[��Gvendor/rockettheme/toolbox/Compat/src/Yaml/Exception/ParseException.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RocketTheme\Toolbox\Compat\Yaml\Exception;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ParseException extends RuntimeException
{
private $parsedFile;
private $parsedLine;
private $snippet;
private $rawMessage;
/**
* @param string $message The error message
* @param int $parsedLine The line where the error occurred
* @param string|null $snippet The snippet of code near the
problem
* @param string|null $parsedFile The file name where the error
occurred
* @param \Exception|null $previous The previous exception
*/
public function __construct($message, $parsedLine = -1, $snippet =
null, $parsedFile = null, \Exception $previous = null)
{
$this->parsedFile = $parsedFile;
$this->parsedLine = $parsedLine;
$this->snippet = $snippet;
$this->rawMessage = $message;
$this->updateRepr();
parent::__construct($this->message, 0, $previous);
}
/**
* Gets the snippet of code near the error.
*
* @return string The snippet of code
*/
public function getSnippet()
{
return $this->snippet;
}
/**
* Sets the snippet of code near the error.
*
* @param string $snippet The code snippet
*/
public function setSnippet($snippet)
{
$this->snippet = $snippet;
$this->updateRepr();
}
/**
* Gets the filename where the error occurred.
*
* This method returns null if a string is parsed.
*
* @return string The filename
*/
public function getParsedFile()
{
return $this->parsedFile;
}
/**
* Sets the filename where the error occurred.
*
* @param string $parsedFile The filename
*/
public function setParsedFile($parsedFile)
{
$this->parsedFile = $parsedFile;
$this->updateRepr();
}
/**
* Gets the line where the error occurred.
*
* @return int The file line
*/
public function getParsedLine()
{
return $this->parsedLine;
}
/**
* Sets the line where the error occurred.
*
* @param int $parsedLine The file line
*/
public function setParsedLine($parsedLine)
{
$this->parsedLine = $parsedLine;
$this->updateRepr();
}
private function updateRepr()
{
$this->message = $this->rawMessage;
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
if (null !== $this->parsedFile) {
if (\PHP_VERSION_ID >= 50400) {
$jsonOptions = JSON_UNESCAPED_SLASHES |
JSON_UNESCAPED_UNICODE;
} else {
$jsonOptions = 0;
}
$this->message .= sprintf(' in %s',
json_encode($this->parsedFile, $jsonOptions));
}
if ($this->parsedLine >= 0) {
$this->message .= sprintf(' at line %d',
$this->parsedLine);
}
if ($this->snippet) {
$this->message .= sprintf(' (near
"%s")', $this->snippet);
}
if ($dot) {
$this->message .= '.';
}
}
}
PK-d�[y����Ivendor/rockettheme/toolbox/Compat/src/Yaml/Exception/RuntimeException.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RocketTheme\Toolbox\Compat\Yaml\Exception;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Romain Neutron <imprec@gmail.com>
*/
class RuntimeException extends \RuntimeException implements
ExceptionInterface
{
}
PK-d�[�:9;FF5vendor/rockettheme/toolbox/Compat/src/Yaml/Inline.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RocketTheme\Toolbox\Compat\Yaml;
use RocketTheme\Toolbox\Compat\Yaml\Exception\ParseException;
/**
* Inline implements a YAML parser/dumper for the YAML inline syntax.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Inline
{
const REGEX_QUOTED_STRING =
'(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
private static $exceptionOnInvalidType = false;
private static $objectSupport = false;
private static $objectForMap = false;
/**
* Converts a YAML string to a PHP value.
*
* @param string $value A YAML string
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
* @param array $references Mapping of variable names to
values
*
* @return mixed A PHP value
*
* @throws ParseException
*/
public static function parse($value, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false, $references = array())
{
self::$exceptionOnInvalidType = $exceptionOnInvalidType;
self::$objectSupport = $objectSupport;
self::$objectForMap = $objectForMap;
$value = trim($value);
if ('' === $value) {
return '';
}
if (2 /* MB_OVERLOAD_STRING */ & (int)
ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
$i = 0;
switch ($value[0]) {
case '[':
$result = self::parseSequence($value, $i, $references);
++$i;
break;
case '{':
$result = self::parseMapping($value, $i, $references);
++$i;
break;
default:
$result = self::parseScalar($value, null,
array('"', "'"), $i, true, $references);
}
// some comments are allowed at the end
if (preg_replace('/\s+#.*$/A', '',
substr($value, $i))) {
throw new ParseException(sprintf('Unexpected characters
near "%s".', substr($value, $i)));
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return $result;
}
/**
* Check if given array is hash or just normal indexed array.
*
* @internal
*
* @param array $value The PHP array to check
*
* @return bool true if value is hash array, false otherwise
*/
public static function isHash(array $value)
{
$expectedKey = 0;
foreach ($value as $key => $val) {
if ($key !== $expectedKey++) {
return true;
}
}
return false;
}
/**
* Parses a YAML scalar.
*
* @param string $scalar
* @param string[] $delimiters
* @param string[] $stringDelimiters
* @param int &$i
* @param bool $evaluate
* @param array $references
*
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*
* @internal
*/
public static function parseScalar($scalar, $delimiters = null,
$stringDelimiters = array('"', "'"), &$i
= 0, $evaluate = true, $references = array())
{
if (in_array($scalar[$i], $stringDelimiters)) {
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), ' ');
if (!in_array($tmp[0], $delimiters)) {
throw new ParseException(sprintf('Unexpected
characters (%s).', substr($scalar, $i)));
}
}
} else {
// "normal" string
if (!$delimiters) {
$output = substr($scalar, $i);
$i += strlen($output);
// remove comments
if (Parser::preg_match('/[ \t]+#/', $output,
$match, PREG_OFFSET_CAPTURE)) {
$output = substr($output, 0, $match[0][1]);
}
} elseif
(Parser::preg_match('/^(.+?)('.implode('|',
$delimiters).')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += strlen($output);
} else {
throw new ParseException(sprintf('Malformed inline
YAML string: %s.', $scalar));
}
// a non-quoted string cannot start with @ or ` (reserved) nor
with a scalar indicator (| or >)
if ($output && ('@' === $output[0] ||
'`' === $output[0] || '|' === $output[0] ||
'>' === $output[0])) {
@trigger_error(sprintf('Not quoting the scalar
"%s" starting with "%s" is deprecated since Symfony 2.8
and will throw a ParseException in 3.0.', $output, $output[0]),
E_USER_DEPRECATED);
// to be thrown in 3.0
// throw new ParseException(sprintf('The reserved
indicator "%s" cannot start a plain scalar; you need to quote the
scalar.', $output[0]));
}
if ($evaluate) {
$output = self::evaluateScalar($output, $references);
}
}
return $output;
}
/**
* Parses a YAML quoted scalar.
*
* @param string $scalar
* @param int &$i
*
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseQuotedScalar($scalar, &$i)
{
if
(!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au',
substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML
string: %s.', substr($scalar, $i)));
}
$output = substr($match[0], 1, strlen($match[0]) - 2);
$unescaper = new Unescaper();
if ('"' == $scalar[$i]) {
$output = $unescaper->unescapeDoubleQuotedString($output);
} else {
$output = $unescaper->unescapeSingleQuotedString($output);
}
$i += strlen($match[0]);
return $output;
}
/**
* Parses a YAML sequence.
*
* @param string $sequence
* @param int &$i
* @param array $references
*
* @return array
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseSequence($sequence, &$i = 0,
$references = array())
{
$output = array();
$len = strlen($sequence);
++$i;
// [foo, bar, ...]
while ($i < $len) {
switch ($sequence[$i]) {
case '[':
// nested sequence
$output[] = self::parseSequence($sequence, $i,
$references);
break;
case '{':
// nested mapping
$output[] = self::parseMapping($sequence, $i,
$references);
break;
case ']':
return $output;
case ',':
case ' ':
break;
default:
$isQuoted = in_array($sequence[$i],
array('"', "'"));
$value = self::parseScalar($sequence,
array(',', ']'), array('"',
"'"), $i, true, $references);
// the value can be an array if a reference has been
resolved to an array var
if (!is_array($value) && !$isQuoted &&
false !== strpos($value, ': ')) {
// embedded mapping?
try {
$pos = 0;
$value =
self::parseMapping('{'.$value.'}', $pos, $references);
} catch (\InvalidArgumentException $e) {
// no, it's not
}
}
$output[] = $value;
--$i;
}
++$i;
}
throw new ParseException(sprintf('Malformed inline YAML
string: %s.', $sequence));
}
/**
* Parses a YAML mapping.
*
* @param string $mapping
* @param int &$i
* @param array $references
*
* @return array|\stdClass
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseMapping($mapping, &$i = 0, $references
= array())
{
$output = array();
$len = strlen($mapping);
++$i;
$allowOverwrite = false;
// {foo: bar, bar:foo, ...}
while ($i < $len) {
switch ($mapping[$i]) {
case ' ':
case ',':
++$i;
continue 2;
case '}':
if (self::$objectForMap) {
return (object) $output;
}
return $output;
}
// key
$key = self::parseScalar($mapping, array(':', '
'), array('"', "'"), $i, false);
if ('<<' === $key) {
$allowOverwrite = true;
}
// value
$done = false;
while ($i < $len) {
switch ($mapping[$i]) {
case '[':
// nested sequence
$value = self::parseSequence($mapping, $i,
$references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since
lines
// are processed sequentially.
// But overwriting is allowed when a merge node is
used in current block.
if ('<<' === $key) {
foreach ($value as $parsedValue) {
$output += $parsedValue;
}
} elseif ($allowOverwrite || !isset($output[$key]))
{
$output[$key] = $value;
}
$done = true;
break;
case '{':
// nested mapping
$value = self::parseMapping($mapping, $i,
$references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since
lines
// are processed sequentially.
// But overwriting is allowed when a merge node is
used in current block.
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key]))
{
$output[$key] = $value;
}
$done = true;
break;
case ':':
case ' ':
break;
default:
$value = self::parseScalar($mapping,
array(',', '}'), array('"',
"'"), $i, true, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since
lines
// are processed sequentially.
// But overwriting is allowed when a merge node is
used in current block.
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key]))
{
$output[$key] = $value;
}
$done = true;
--$i;
}
++$i;
if ($done) {
continue 2;
}
}
}
throw new ParseException(sprintf('Malformed inline YAML
string: %s.', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
* @param array $references
*
* @return mixed The evaluated YAML string
*
* @throws ParseException when object parsing support was disabled and
the parser detected a PHP object or when a reference could not be resolved
*/
private static function evaluateScalar($scalar, $references = array())
{
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);
if (0 === strpos($scalar, '*')) {
if (false !== $pos = strpos($scalar, '#')) {
$value = substr($scalar, 1, $pos - 2);
} else {
$value = substr($scalar, 1);
}
// an unquoted *
if (false === $value || '' === $value) {
throw new ParseException('A reference must contain at
least one character.');
}
if (!array_key_exists($value, $references)) {
throw new ParseException(sprintf('Reference
"%s" does not exist.', $value));
}
return $references[$value];
}
switch (true) {
case 'null' === $scalarLower:
case '' === $scalar:
case '~' === $scalar:
return;
case 'true' === $scalarLower:
return true;
case 'false' === $scalarLower:
return false;
// Optimise for returning strings.
case '+' === $scalar[0] || '-' ===
$scalar[0] || '.' === $scalar[0] || '!' === $scalar[0]
|| is_numeric($scalar[0]):
switch (true) {
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return (int) self::parseScalar(substr($scalar, 2));
case 0 === strpos($scalar, '!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 12));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support
when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 13));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support
when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
case ctype_digit($scalar):
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[0] ?
octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case '-' === $scalar[0] &&
ctype_digit(substr($scalar, 1)):
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[1] ?
octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
case Parser::preg_match(self::getHexRegex(), $scalar):
return '0x' === $scalar[0].$scalar[1] ?
hexdec($scalar) : (float) $scalar;
case '.inf' === $scalarLower:
case '.nan' === $scalarLower:
return -log(0);
case '-.inf' === $scalarLower:
return log(0);
case
Parser::preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return (float) str_replace(',',
'', $scalar);
case Parser::preg_match(self::getTimestampRegex(),
$scalar):
$timeZone = date_default_timezone_get();
date_default_timezone_set('UTC');
$time = strtotime($scalar);
date_default_timezone_set($timeZone);
return $time;
}
// no break
default:
return (string) $scalar;
}
}
/**
* Gets a regex that matches a YAML date.
*
* @return string The regular expression
*
* @see http://www.yaml.org/spec/1.2/spec.html#id2761573
*/
private static function getTimestampRegex()
{
return <<<EOF
~^
(?P<year>[0-9][0-9][0-9][0-9])
-(?P<month>[0-9][0-9]?)
-(?P<day>[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P<hour>[0-9][0-9]?)
:(?P<minute>[0-9][0-9])
:(?P<second>[0-9][0-9])
(?:\.(?P<fraction>[0-9]*))?
(?:[
\t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
$~x
EOF;
}
/**
* Gets a regex that matches a YAML number in hexadecimal notation.
*
* @return string
*/
private static function getHexRegex()
{
return '~^0x[0-9a-f]++$~i';
}
}
PK-d�[
SE�:�:�5vendor/rockettheme/toolbox/Compat/src/Yaml/Parser.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RocketTheme\Toolbox\Compat\Yaml;
use RocketTheme\Toolbox\Compat\Yaml\Exception\ParseException;
/**
* Parser parses YAML strings to convert them to PHP arrays.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Parser
{
const BLOCK_SCALAR_HEADER_PATTERN =
'(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments>
+#.*)?';
// BC - wrongly named
const FOLDED_SCALAR_PATTERN = self::BLOCK_SCALAR_HEADER_PATTERN;
private $offset = 0;
private $totalNumberOfLines;
private $lines = array();
private $currentLineNb = -1;
private $currentLine = '';
private $refs = array();
private $skippedLineNumbers = array();
private $locallySkippedLineNumbers = array();
/**
* @param int $offset The offset of YAML document
(used for line numbers in error messages)
* @param int|null $totalNumberOfLines The overall number of lines
being parsed
* @param int[] $skippedLineNumbers Number of comment lines that
have been skipped by the parser
*/
public function __construct($offset = 0, $totalNumberOfLines = null,
array $skippedLineNumbers = array())
{
$this->offset = $offset;
$this->totalNumberOfLines = $totalNumberOfLines;
$this->skippedLineNumbers = $skippedLineNumbers;
}
/**
* Parses a YAML string to a PHP value.
*
* @param string $value A YAML string
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
*
* @return mixed A PHP value
*
* @throws ParseException If the YAML is not valid
*/
public function parse($value, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false)
{
if (false === preg_match('//u', $value)) {
throw new ParseException('The YAML value does not appear
to be valid UTF-8.');
}
$this->refs = array();
$mbEncoding = null;
$e = null;
$data = null;
if (2 /* MB_OVERLOAD_STRING */ & (int)
ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}
try {
$data = $this->doParse($value, $exceptionOnInvalidType,
$objectSupport, $objectForMap);
} catch (\Exception $e) {
} catch (\Throwable $e) {
}
if (null !== $mbEncoding) {
mb_internal_encoding($mbEncoding);
}
$this->lines = array();
$this->currentLine = '';
$this->refs = array();
$this->skippedLineNumbers = array();
$this->locallySkippedLineNumbers = array();
if (null !== $e) {
throw $e;
}
return $data;
}
private function doParse($value, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false)
{
$this->currentLineNb = -1;
$this->currentLine = '';
$value = $this->cleanup($value);
$this->lines = explode("\n", $value);
$this->locallySkippedLineNumbers = array();
if (null === $this->totalNumberOfLines) {
$this->totalNumberOfLines = count($this->lines);
}
$data = array();
$context = null;
$allowOverwrite = false;
while ($this->moveToNextLine()) {
if ($this->isCurrentLineEmpty()) {
continue;
}
// tab?
if ("\t" === $this->currentLine[0]) {
throw new ParseException('A YAML file cannot contain
tabs as indentation.', $this->getRealCurrentLineNb() + 1,
$this->currentLine);
}
$isRef = $mergeNode = false;
if
(self::preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+))?$#u',
rtrim($this->currentLine), $values)) {
if ($context && 'mapping' == $context) {
throw new ParseException('You cannot define a
sequence item when in a mapping', $this->getRealCurrentLineNb() +
1, $this->currentLine);
}
$context = 'sequence';
if (isset($values['value']) &&
self::preg_match('#^&(?P<ref>[^ ]+)
*(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] =
$matches['value'];
}
// array
if (!isset($values['value']) || '' ==
trim($values['value'], ' ') || 0 ===
strpos(ltrim($values['value'], ' '), '#')) {
$data[] =
$this->parseBlock($this->getRealCurrentLineNb() + 1,
$this->getNextEmbedBlock(null, true), $exceptionOnInvalidType,
$objectSupport, $objectForMap);
} else {
if (isset($values['leadspaces'])
&&
self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^
\'"\{\[].*?) *\:(\s+(?P<value>.+))?$#u',
rtrim($values['value']), $matches)
) {
// this is a compact notation element, add to next
block and parse
$block = $values['value'];
if ($this->isNextLineIndented()) {
$block .=
"\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation()
+ strlen($values['leadspaces']) + 1);
}
$data[] =
$this->parseBlock($this->getRealCurrentLineNb(), $block,
$exceptionOnInvalidType, $objectSupport, $objectForMap);
} else {
$data[] =
$this->parseValue($values['value'], $exceptionOnInvalidType,
$objectSupport, $objectForMap, $context);
}
}
if ($isRef) {
$this->refs[$isRef] = end($data);
}
} elseif (
self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^
\'"\[\{].*?) *\:(\s+(?P<value>.+))?$#u',
rtrim($this->currentLine), $values)
&& (false === strpos($values['key'],
' #') || in_array($values['key'][0],
array('"', "'")))
) {
if ($context && 'sequence' == $context) {
throw new ParseException('You cannot define a
mapping item when in a sequence', $this->currentLineNb + 1,
$this->currentLine);
}
$context = 'mapping';
// force correct settings
Inline::parse(null, $exceptionOnInvalidType,
$objectSupport, $objectForMap, $this->refs);
try {
$key = Inline::parseScalar($values['key']);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() +
1);
$e->setSnippet($this->currentLine);
throw $e;
}
// Convert float keys to strings, to avoid being converted
to integers by PHP
if (is_float($key)) {
$key = (string) $key;
}
if ('<<' === $key &&
(!isset($values['value']) ||
!self::preg_match('#^&(?P<ref>[^ ]+)#u',
$values['value'], $refMatches))) {
$mergeNode = true;
$allowOverwrite = true;
if (isset($values['value']) && 0 ===
strpos($values['value'], '*')) {
$refName = substr($values['value'], 1);
if (!array_key_exists($refName, $this->refs)) {
throw new
ParseException(sprintf('Reference "%s" does not
exist.', $refName), $this->getRealCurrentLineNb() + 1,
$this->currentLine);
}
$refValue = $this->refs[$refName];
if (!is_array($refValue)) {
throw new ParseException('YAML merge keys
used with a scalar value instead of an array.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
$data += $refValue; // array union
} else {
if (isset($values['value']) &&
'' !== $values['value']) {
$value = $values['value'];
} else {
$value = $this->getNextEmbedBlock();
}
$parsed =
$this->parseBlock($this->getRealCurrentLineNb() + 1, $value,
$exceptionOnInvalidType, $objectSupport, $objectForMap);
if (!is_array($parsed)) {
throw new ParseException('YAML merge keys
used with a scalar value instead of an array.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
if (isset($parsed[0])) {
// If the value associated with the merge key
is a sequence, then this sequence is expected to contain mapping nodes
// and each of these nodes is merged in turn
according to its order in the sequence. Keys in mapping nodes earlier
// in the sequence override keys specified in
later mapping nodes.
foreach ($parsed as $parsedItem) {
if (!is_array($parsedItem)) {
throw new ParseException('Merge
items must be arrays.', $this->getRealCurrentLineNb() + 1,
$parsedItem);
}
$data += $parsedItem; // array union
}
} else {
// If the value associated with the key is a
single mapping node, each of its key/value pairs is inserted into the
// current mapping, unless the key already
exists in it.
$data += $parsed; // array union
}
}
} elseif ('<<' !== $key &&
isset($values['value']) &&
self::preg_match('#^&(?P<ref>[^ ]+)
*(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] =
$matches['value'];
}
if ($mergeNode) {
// Merge keys
} elseif (!isset($values['value']) ||
'' == trim($values['value'], ' ') || 0 ===
strpos(ltrim($values['value'], ' '), '#') ||
'<<' === $key) {
// hash
// if next line is less indented or equal, then it
means that the current value is null
if (!$this->isNextLineIndented() &&
!$this->isNextLineUnIndentedCollection()) {
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node is
used in current block.
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = null;
}
} else {
$value =
$this->parseBlock($this->getRealCurrentLineNb() + 1,
$this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport,
$objectForMap);
if ('<<' === $key) {
$this->refs[$refMatches['ref']] =
$value;
$data += $value;
} elseif ($allowOverwrite || !isset($data[$key])) {
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node
is used in current block.
$data[$key] = $value;
}
}
} else {
$value =
$this->parseValue($values['value'], $exceptionOnInvalidType,
$objectSupport, $objectForMap, $context);
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node is used
in current block.
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
}
}
if ($isRef) {
$this->refs[$isRef] = $data[$key];
}
} else {
// multiple documents are not supported
if ('---' === $this->currentLine) {
throw new ParseException('Multiple documents are
not supported.', $this->currentLineNb + 1, $this->currentLine);
}
// 1-liner optionally followed by newline(s)
if (is_string($value) && $this->lines[0] ===
trim($value)) {
try {
$value = Inline::parse($this->lines[0],
$exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
return $value;
}
throw new ParseException('Unable to parse.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}
if ($objectForMap && !is_object($data) &&
'mapping' === $context) {
$object = new \stdClass();
foreach ($data as $key => $value) {
$object->$key = $value;
}
$data = $object;
}
return empty($data) ? null : $data;
}
private function parseBlock($offset, $yaml, $exceptionOnInvalidType,
$objectSupport, $objectForMap)
{
$skippedLineNumbers = $this->skippedLineNumbers;
foreach ($this->locallySkippedLineNumbers as $lineNumber) {
if ($lineNumber < $offset) {
continue;
}
$skippedLineNumbers[] = $lineNumber;
}
$parser = new self($offset, $this->totalNumberOfLines,
$skippedLineNumbers);
$parser->refs = &$this->refs;
return $parser->doParse($yaml, $exceptionOnInvalidType,
$objectSupport, $objectForMap);
}
/**
* Returns the current line number (takes the offset into account).
*
* @return int The current line number
*/
private function getRealCurrentLineNb()
{
$realCurrentLineNumber = $this->currentLineNb +
$this->offset;
foreach ($this->skippedLineNumbers as $skippedLineNumber) {
if ($skippedLineNumber > $realCurrentLineNumber) {
break;
}
++$realCurrentLineNumber;
}
return $realCurrentLineNumber;
}
/**
* Returns the current line indentation.
*
* @return int The current line indentation
*/
private function getCurrentLineIndentation()
{
return strlen($this->currentLine) -
strlen(ltrim($this->currentLine, ' '));
}
/**
* Returns the next embed block of YAML.
*
* @param int $indentation The indent level at which the block is to
be read, or null for default
* @param bool $inSequence True if the enclosing data structure is a
sequence
*
* @return string A YAML string
*
* @throws ParseException When indentation problem are detected
*/
private function getNextEmbedBlock($indentation = null, $inSequence =
false)
{
$oldLineIndentation = $this->getCurrentLineIndentation();
$blockScalarIndentations = array();
if ($this->isBlockScalarHeader()) {
$blockScalarIndentations[] =
$this->getCurrentLineIndentation();
}
if (!$this->moveToNextLine()) {
return;
}
if (null === $indentation) {
$newIndent = $this->getCurrentLineIndentation();
$unindentedEmbedBlock =
$this->isStringUnIndentedCollectionItem();
if (!$this->isCurrentLineEmpty() && 0 === $newIndent
&& !$unindentedEmbedBlock) {
throw new ParseException('Indentation problem.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
} else {
$newIndent = $indentation;
}
$data = array();
if ($this->getCurrentLineIndentation() >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} else {
$this->moveToPreviousLine();
return;
}
if ($inSequence && $oldLineIndentation === $newIndent
&& isset($data[0][0]) && '-' === $data[0][0]) {
// the previous line contained a dash but no item content, this
line is a sequence item with the same indentation
// and therefore no nested list or mapping
$this->moveToPreviousLine();
return;
}
$isItUnindentedCollection =
$this->isStringUnIndentedCollectionItem();
if (empty($blockScalarIndentations) &&
$this->isBlockScalarHeader()) {
$blockScalarIndentations[] =
$this->getCurrentLineIndentation();
}
$previousLineIndentation = $this->getCurrentLineIndentation();
while ($this->moveToNextLine()) {
$indent = $this->getCurrentLineIndentation();
// terminate all block scalars that are more indented than the
current line
if (!empty($blockScalarIndentations) && $indent <
$previousLineIndentation && '' !==
trim($this->currentLine)) {
foreach ($blockScalarIndentations as $key =>
$blockScalarIndentation) {
if ($blockScalarIndentation >=
$this->getCurrentLineIndentation()) {
unset($blockScalarIndentations[$key]);
}
}
}
if (empty($blockScalarIndentations) &&
!$this->isCurrentLineComment() &&
$this->isBlockScalarHeader()) {
$blockScalarIndentations[] =
$this->getCurrentLineIndentation();
}
$previousLineIndentation = $indent;
if ($isItUnindentedCollection &&
!$this->isCurrentLineEmpty() &&
!$this->isStringUnIndentedCollectionItem() && $newIndent ===
$indent) {
$this->moveToPreviousLine();
break;
}
if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
continue;
}
// we ignore "comment" lines only when we are not
inside a scalar block
if (empty($blockScalarIndentations) &&
$this->isCurrentLineComment()) {
// remember ignored comment lines (they are used later in
nested
// parser calls to determine real line numbers)
//
// CAUTION: beware to not populate the global property here
as it
// will otherwise influence the getRealCurrentLineNb() call
here
// for consecutive comment lines and subsequent embedded
blocks
$this->locallySkippedLineNumbers[] =
$this->getRealCurrentLineNb();
continue;
}
if ($indent >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} elseif (0 == $indent) {
$this->moveToPreviousLine();
break;
} else {
throw new ParseException('Indentation problem.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}
return implode("\n", $data);
}
/**
* Moves the parser to the next line.
*
* @return bool
*/
private function moveToNextLine()
{
if ($this->currentLineNb >= count($this->lines) - 1) {
return false;
}
$this->currentLine = $this->lines[++$this->currentLineNb];
return true;
}
/**
* Moves the parser to the previous line.
*
* @return bool
*/
private function moveToPreviousLine()
{
if ($this->currentLineNb < 1) {
return false;
}
$this->currentLine = $this->lines[--$this->currentLineNb];
return true;
}
/**
* Parses a YAML value.
*
* @param string $value A YAML value
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
* @param string $context The parser context (either
sequence or mapping)
*
* @return mixed A PHP value
*
* @throws ParseException When reference does not exist
*/
private function parseValue($value, $exceptionOnInvalidType,
$objectSupport, $objectForMap, $context)
{
if (0 === strpos($value, '*')) {
if (false !== $pos = strpos($value, '#')) {
$value = substr($value, 1, $pos - 2);
} else {
$value = substr($value, 1);
}
if (!array_key_exists($value, $this->refs)) {
throw new ParseException(sprintf('Reference
"%s" does not exist.', $value), $this->currentLineNb + 1,
$this->currentLine);
}
return $this->refs[$value];
}
if
(self::preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/',
$value, $matches)) {
$modifiers = isset($matches['modifiers']) ?
$matches['modifiers'] : '';
return
$this->parseBlockScalar($matches['separator'],
preg_replace('#\d+#', '', $modifiers), (int)
abs($modifiers));
}
try {
$parsedValue = Inline::parse($value, $exceptionOnInvalidType,
$objectSupport, $objectForMap, $this->refs);
if ('mapping' === $context &&
'"' !== $value[0] && "'" !==
$value[0] && '[' !== $value[0] && '{'
!== $value[0] && '!' !== $value[0] && false !==
strpos($parsedValue, ': ')) {
@trigger_error(sprintf('Using a colon in the unquoted
mapping value "%s" in line %d is deprecated since Symfony 2.8 and
will throw a ParseException in 3.0.', $value,
$this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED);
// to be thrown in 3.0
// throw new ParseException('A colon cannot be used in
an unquoted mapping value.');
}
return $parsedValue;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
}
/**
* Parses a block scalar.
*
* @param string $style The style indicator that was used to
begin this block scalar (| or >)
* @param string $chomping The chomping indicator that was used to
begin this block scalar (+ or -)
* @param int $indentation The indentation indicator that was used
to begin this block scalar
*
* @return string The text value
*/
private function parseBlockScalar($style, $chomping = '',
$indentation = 0)
{
$notEOF = $this->moveToNextLine();
if (!$notEOF) {
return '';
}
$isCurrentLineBlank = $this->isCurrentLineBlank();
$blockLines = array();
// leading blank lines are consumed before determining indentation
while ($notEOF && $isCurrentLineBlank) {
// newline only if not EOF
if ($notEOF = $this->moveToNextLine()) {
$blockLines[] = '';
$isCurrentLineBlank = $this->isCurrentLineBlank();
}
}
// determine indentation if not specified
if (0 === $indentation) {
if (self::preg_match('/^ +/', $this->currentLine,
$matches)) {
$indentation = strlen($matches[0]);
}
}
if ($indentation > 0) {
$pattern = sprintf('/^ {%d}(.*)$/', $indentation);
while (
$notEOF && (
$isCurrentLineBlank ||
self::preg_match($pattern, $this->currentLine,
$matches)
)
) {
if ($isCurrentLineBlank &&
strlen($this->currentLine) > $indentation) {
$blockLines[] = substr($this->currentLine,
$indentation);
} elseif ($isCurrentLineBlank) {
$blockLines[] = '';
} else {
$blockLines[] = $matches[1];
}
// newline only if not EOF
if ($notEOF = $this->moveToNextLine()) {
$isCurrentLineBlank = $this->isCurrentLineBlank();
}
}
} elseif ($notEOF) {
$blockLines[] = '';
}
if ($notEOF) {
$blockLines[] = '';
$this->moveToPreviousLine();
} elseif (!$notEOF &&
!$this->isCurrentLineLastLineInDocument()) {
$blockLines[] = '';
}
// folded style
if ('>' === $style) {
$text = '';
$previousLineIndented = false;
$previousLineBlank = false;
for ($i = 0, $blockLinesCount = count($blockLines); $i <
$blockLinesCount; ++$i) {
if ('' === $blockLines[$i]) {
$text .= "\n";
$previousLineIndented = false;
$previousLineBlank = true;
} elseif (' ' === $blockLines[$i][0]) {
$text .= "\n".$blockLines[$i];
$previousLineIndented = true;
$previousLineBlank = false;
} elseif ($previousLineIndented) {
$text .= "\n".$blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
} elseif ($previousLineBlank || 0 === $i) {
$text .= $blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
} else {
$text .= ' '.$blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
}
}
} else {
$text = implode("\n", $blockLines);
}
// deal with trailing newlines
if ('' === $chomping) {
$text = preg_replace('/\n+$/', "\n",
$text);
} elseif ('-' === $chomping) {
$text = preg_replace('/\n+$/', '', $text);
}
return $text;
}
/**
* Returns true if the next line is indented.
*
* @return bool Returns true if the next line is indented, false
otherwise
*/
private function isNextLineIndented()
{
$currentIndentation = $this->getCurrentLineIndentation();
$EOF = !$this->moveToNextLine();
while (!$EOF && $this->isCurrentLineEmpty()) {
$EOF = !$this->moveToNextLine();
}
if ($EOF) {
return false;
}
$ret = $this->getCurrentLineIndentation() >
$currentIndentation;
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the current line is blank or if it is a comment
line.
*
* @return bool Returns true if the current line is empty or if it is a
comment line, false otherwise
*/
private function isCurrentLineEmpty()
{
return $this->isCurrentLineBlank() ||
$this->isCurrentLineComment();
}
/**
* Returns true if the current line is blank.
*
* @return bool Returns true if the current line is blank, false
otherwise
*/
private function isCurrentLineBlank()
{
return '' == trim($this->currentLine, ' ');
}
/**
* Returns true if the current line is a comment line.
*
* @return bool Returns true if the current line is a comment line,
false otherwise
*/
private function isCurrentLineComment()
{
//checking explicitly the first char of the trim is faster than
loops or strpos
$ltrimmedLine = ltrim($this->currentLine, ' ');
return '' !== $ltrimmedLine && '#' ===
$ltrimmedLine[0];
}
private function isCurrentLineLastLineInDocument()
{
return ($this->offset + $this->currentLineNb) >=
($this->totalNumberOfLines - 1);
}
/**
* Cleanups a YAML string to be parsed.
*
* @param string $value The input YAML string
*
* @return string A cleaned up YAML string
*/
private function cleanup($value)
{
$value = str_replace(array("\r\n", "\r"),
"\n", $value);
// strip YAML header
$count = 0;
$value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u',
'', $value, -1, $count);
$this->offset += $count;
// remove leading comments
$trimmedValue = preg_replace('#^(\#.*?\n)+#s',
'', $value, -1, $count);
if (1 == $count) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") -
substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}
// remove start of the document marker (---)
$trimmedValue = preg_replace('#^\-\-\-.*?\n#s',
'', $value, -1, $count);
if (1 == $count) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") -
substr_count($trimmedValue, "\n");
$value = $trimmedValue;
// remove end of the document marker (...)
$value = preg_replace('#\.\.\.\s*$#', '',
$value);
}
return $value;
}
/**
* Returns true if the next line starts unindented collection.
*
* @return bool Returns true if the next line starts unindented
collection, false otherwise
*/
private function isNextLineUnIndentedCollection()
{
$currentIndentation = $this->getCurrentLineIndentation();
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineEmpty()) {
$notEOF = $this->moveToNextLine();
}
if (false === $notEOF) {
return false;
}
$ret = $this->getCurrentLineIndentation() ===
$currentIndentation &&
$this->isStringUnIndentedCollectionItem();
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the string is un-indented collection item.
*
* @return bool Returns true if the string is un-indented collection
item, false otherwise
*/
private function isStringUnIndentedCollectionItem()
{
return '-' === rtrim($this->currentLine) || 0 ===
strpos($this->currentLine, '- ');
}
/**
* Tests whether or not the current line is the header of a block
scalar.
*
* @return bool
*/
private function isBlockScalarHeader()
{
return (bool)
self::preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~',
$this->currentLine);
}
/**
* A local wrapper for `preg_match` which will throw a ParseException
if there
* is an internal error in the PCRE engine.
*
* This avoids us needing to check for "false" every time
PCRE is used
* in the YAML engine
*
* @throws ParseException on a PCRE internal error
*
* @see preg_last_error()
*
* @internal
*/
public static function preg_match($pattern, $subject, &$matches =
null, $flags = 0, $offset = 0)
{
if (false === $ret = preg_match($pattern, $subject, $matches,
$flags, $offset)) {
switch (preg_last_error()) {
case PREG_INTERNAL_ERROR:
$error = 'Internal PCRE error.';
break;
case PREG_BACKTRACK_LIMIT_ERROR:
$error = 'pcre.backtrack_limit reached.';
break;
case PREG_RECURSION_LIMIT_ERROR:
$error = 'pcre.recursion_limit reached.';
break;
case PREG_BAD_UTF8_ERROR:
$error = 'Malformed UTF-8 data.';
break;
case PREG_BAD_UTF8_OFFSET_ERROR:
$error = 'Offset doesn\'t correspond to the
begin of a valid UTF-8 code point.';
break;
default:
$error = 'Error.';
}
throw new ParseException($error);
}
return $ret;
}
}
PK-d�[gA�sMM8vendor/rockettheme/toolbox/Compat/src/Yaml/Unescaper.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RocketTheme\Toolbox\Compat\Yaml;
/**
* Unescaper encapsulates unescaping rules for single and double-quoted
* YAML strings.
*
* @author Matthew Lewinski <matthew@lewinski.org>
*
* @internal
*/
class Unescaper
{
/**
* Parser and Inline assume UTF-8 encoding, so escaped Unicode
characters
* must be converted to that encoding.
*
* @deprecated since version 2.5, to be removed in 3.0
*
* @internal
*/
const ENCODING = 'UTF-8';
/**
* Regex fragment that matches an escaped character in a double quoted
string.
*/
const REGEX_ESCAPED_CHARACTER =
'\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)';
/**
* Unescapes a single quoted string.
*
* @param string $value A single quoted string
*
* @return string The unescaped string
*/
public function unescapeSingleQuotedString($value)
{
return str_replace('\'\'', '\'',
$value);
}
/**
* Unescapes a double quoted string.
*
* @param string $value A double quoted string
*
* @return string The unescaped string
*/
public function unescapeDoubleQuotedString($value)
{
$self = $this;
$callback = function ($match) use ($self) {
return $self->unescapeCharacter($match[0]);
};
// evaluate the string
return
preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u',
$callback, $value);
}
/**
* Unescapes a character that was found in a double-quoted string.
*
* @param string $value An escaped character
*
* @return string The unescaped character
*
* @internal This method is public to be usable as callback. It should
not
* be used in user code. Should be changed in 3.0.
*/
public function unescapeCharacter($value)
{
switch ($value[1]) {
case '0':
return "\x0";
case 'a':
return "\x7";
case 'b':
return "\x8";
case 't':
return "\t";
case "\t":
return "\t";
case 'n':
return "\n";
case 'v':
return "\xB";
case 'f':
return "\xC";
case 'r':
return "\r";
case 'e':
return "\x1B";
case ' ':
return ' ';
case '"':
return '"';
case '/':
return '/';
case '\\':
return '\\';
case 'N':
// U+0085 NEXT LINE
return "\xC2\x85";
case '_':
// U+00A0 NO-BREAK SPACE
return "\xC2\xA0";
case 'L':
// U+2028 LINE SEPARATOR
return "\xE2\x80\xA8";
case 'P':
// U+2029 PARAGRAPH SEPARATOR
return "\xE2\x80\xA9";
case 'x':
return self::utf8chr(hexdec(substr($value, 2, 2)));
case 'u':
return self::utf8chr(hexdec(substr($value, 2, 4)));
case 'U':
return self::utf8chr(hexdec(substr($value, 2, 8)));
default:
@trigger_error('Not escaping a backslash in a
double-quoted string is deprecated since Symfony 2.8 and will throw a
ParseException in 3.0.', E_USER_DEPRECATED);
return $value;
}
}
/**
* Get the UTF-8 character for the given code point.
*
* @param int $c The unicode code point
*
* @return string The corresponding UTF-8 character
*/
private static function utf8chr($c)
{
if (0x80 > $c %= 0x200000) {
return chr($c);
}
if (0x800 > $c) {
return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
}
if (0x10000 > $c) {
return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6
& 0x3F).chr(0x80 | $c & 0x3F);
}
return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 &
0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
}
}
PK-d�[l��_
_
3vendor/rockettheme/toolbox/Compat/src/Yaml/Yaml.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RocketTheme\Toolbox\Compat\Yaml;
use RocketTheme\Toolbox\Compat\Yaml\Exception\ParseException;
/**
* Yaml offers convenience methods to load and dump YAML.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Yaml
{
/**
* Parses YAML into a PHP value.
*
* Usage:
* <code>
* $array = Yaml::parse(file_get_contents('config.yml'));
* print_r($array);
* </code>
*
* As this method accepts both plain strings and file names as an
input,
* you must validate the input before calling this method. Passing a
file
* as an input is a deprecated feature and will be removed in 3.0.
*
* Note: the ability to pass file names to the Yaml::parse method is
deprecated since version 2.2 and will be removed in 3.0. Pass the YAML
contents of the file instead.
*
* @param string $input Path to a YAML file or a
string containing YAML
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
*
* @return mixed The YAML converted to a PHP value
*
* @throws ParseException If the YAML is not valid
*/
public static function parse($input, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false)
{
// if input is a file, process it
$file = '';
if (false === strpos($input, "\n") &&
is_file($input)) {
@trigger_error('The ability to pass file names to the
'.__METHOD__.' method is deprecated since version 2.2 and will be
removed in 3.0. Pass the YAML contents of the file instead.',
E_USER_DEPRECATED);
if (false === is_readable($input)) {
throw new ParseException(sprintf('Unable to parse
"%s" as the file is not readable.', $input));
}
$file = $input;
$input = file_get_contents($file);
}
$yaml = new Parser();
try {
return $yaml->parse($input, $exceptionOnInvalidType,
$objectSupport, $objectForMap);
} catch (ParseException $e) {
if ($file) {
$e->setParsedFile($file);
}
throw $e;
}
}
}
PK-d�[�����(vendor/rockettheme/toolbox/composer.jsonnu�[���{
"name": "rockettheme/toolbox",
"type": "library",
"description": "RocketTheme Toolbox Library",
"keywords": ["rockettheme", "php"],
"homepage": "http://www.rockettheme.com",
"license": "MIT",
"require": {
"php": ">=5.4.0",
"ext-json": "*",
"pimple/pimple": "~3.0",
"symfony/yaml": ">2.5",
"symfony/event-dispatcher": ">2.5"
},
"require-dev": {
"phpunit/phpunit": "~6"
},
"autoload": {
"psr-4": {
"RocketTheme\\Toolbox\\ArrayTraits\\":
"ArrayTraits/src",
"RocketTheme\\Toolbox\\Blueprints\\":
"Blueprints/src",
"RocketTheme\\Toolbox\\Compat\\":
"Compat/src",
"RocketTheme\\Toolbox\\DI\\": "DI/src",
"RocketTheme\\Toolbox\\Event\\":
"Event/src",
"RocketTheme\\Toolbox\\File\\": "File/src",
"RocketTheme\\Toolbox\\ResourceLocator\\":
"ResourceLocator/src",
"RocketTheme\\Toolbox\\Session\\":
"Session/src",
"RocketTheme\\Toolbox\\StreamWrapper\\":
"StreamWrapper/src"
}
},
"scripts": {
"test": "vendor/bin/phpunit run unit",
"test-windows": "vendor\\bin\\phpunit run unit"
}
}
PK-d�[���/vendor/rockettheme/toolbox/DI/src/Container.phpnu�[���<?php
namespace RocketTheme\Toolbox\DI;
use Pimple\Container as BaseContainer;
/**
* Implements Dependency Injection Container.
*
* @package RocketTheme\Toolbox\DI
* @author RocketTheme
* @license MIT
*/
class Container extends BaseContainer
{
}
PK-d�[l��66>vendor/rockettheme/toolbox/DI/src/ServiceProviderInterface.phpnu�[���<?php
namespace RocketTheme\Toolbox\DI;
use \Pimple\ServiceProviderInterface as BaseServiceProviderInterface;
/**
* Defines ServiceProviderInterface.
*
* @package RocketTheme\Toolbox\DI
* @author RocketTheme
* @license MIT
*/
interface ServiceProviderInterface extends BaseServiceProviderInterface
{
}
PK-d�[ ݅�.vendor/rockettheme/toolbox/Event/src/Event.phpnu�[���<?php
namespace RocketTheme\Toolbox\Event;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
use RocketTheme\Toolbox\ArrayTraits\Constructor;
use RocketTheme\Toolbox\ArrayTraits\Export;
use Symfony\Component\EventDispatcher\Event as BaseEvent;
/**
* Implements Symfony Event interface.
*
* @package RocketTheme\Toolbox\Event
* @author RocketTheme
* @license MIT
*/
class Event extends BaseEvent implements \ArrayAccess
{
use ArrayAccess, Constructor, Export;
/**
* @var array
*/
protected $items = [];
}
PK-d�[A�g��8vendor/rockettheme/toolbox/Event/src/EventDispatcher.phpnu�[���<?php
namespace RocketTheme\Toolbox\Event;
use Symfony\Component\EventDispatcher\Event as BaseEvent;
use Symfony\Component\EventDispatcher\EventDispatcher as
BaseEventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Implements Symfony EventDispatcher interface.
*
* @package RocketTheme\Toolbox\Event
* @author RocketTheme
* @license MIT
*/
class EventDispatcher extends BaseEventDispatcher implements
EventDispatcherInterface
{
public function dispatch($eventName, BaseEvent $event = null)
{
if (null === $event) {
$event = new Event();
}
return parent::dispatch($eventName, $event);
}
}
PK-d�[�ҧ�VVAvendor/rockettheme/toolbox/Event/src/EventSubscriberInterface.phpnu�[���<?php
namespace RocketTheme\Toolbox\Event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface as
BaseEventSubscriberInterface;
/**
* Defines EventSubscriberInterface.
*
* @package RocketTheme\Toolbox\Event
* @author RocketTheme
* @license MIT
*/
interface EventSubscriberInterface extends BaseEventSubscriberInterface
{
}
PK-d�[$M�)*)*,vendor/rockettheme/toolbox/File/src/File.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
/**
* Implements Universal File Reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class File implements FileInterface
{
/**
* @var string
*/
protected $filename;
/**
* @var resource
*/
protected $handle;
/**
* @var bool|null
*/
protected $locked;
/**
* @var string
*/
protected $extension;
/**
* @var string Raw file contents.
*/
protected $raw;
/**
* @var array Parsed file contents.
*/
protected $content;
/**
* @var array
*/
protected $settings = [];
/**
* @var array|File[]
*/
static protected $instances = [];
/**
* Get file instance.
*
* @param string $filename
* @return static
*/
public static function instance($filename)
{
if (!\is_string($filename) && $filename) {
throw new \InvalidArgumentException('Filename should be
non-empty string');
}
if (!isset(static::$instances[$filename])) {
static::$instances[$filename] = new static;
static::$instances[$filename]->init($filename);
}
return static::$instances[$filename];
}
/**
* Set/get settings.
*
* @param array $settings
* @return array
*/
public function settings(array $settings = null)
{
if ($settings !== null) {
$this->settings = $settings;
}
return $this->settings;
}
/**
* Get setting.
*
* @param string $setting
* @param mixed $default
* @return mixed
*/
public function setting($setting, $default = null)
{
return isset($this->settings[$setting]) ?
$this->settings[$setting] : $default;
}
/**
* Prevent constructor from being used.
*/
protected function __construct()
{
}
/**
* Prevent cloning.
*/
protected function __clone()
{
//Me not like clones! Me smash clones!
}
/**
* Set filename.
*
* @param $filename
*/
protected function init($filename)
{
$this->filename = $filename;
}
/**
* Free the file instance.
*/
public function free()
{
if ($this->locked) {
$this->unlock();
}
$this->content = null;
$this->raw = null;
unset(static::$instances[$this->filename]);
}
/**
* Get/set the file location.
*
* @param string $var
* @return string
*/
public function filename($var = null)
{
if ($var !== null) {
$this->filename = $var;
}
return $this->filename;
}
/**
* Return basename of the file.
*
* @return string
*/
public function basename()
{
return basename($this->filename, $this->extension);
}
/**
* Check if file exits.
*
* @return bool
*/
public function exists()
{
return is_file($this->filename);
}
/**
* Return file modification time.
*
* @return int|bool Timestamp or false if file doesn't exist.
*/
public function modified()
{
return is_file($this->filename) ? filemtime($this->filename)
: false;
}
/**
* Lock file for writing. You need to manually unlock().
*
* @param bool $block For non-blocking lock, set the parameter to
false.
* @return bool
* @throws \RuntimeException
*/
public function lock($block = true)
{
if (!$this->handle) {
if (!$this->mkdir(\dirname($this->filename))) {
throw new \RuntimeException('Creating directory failed
for ' . $this->filename);
}
$this->handle = @fopen($this->filename, 'cb+');
if (!$this->handle) {
$error = error_get_last();
throw new \RuntimeException("Opening file for writing
failed on error {$error['message']}");
}
}
$lock = $block ? LOCK_EX : LOCK_EX | LOCK_NB;
// Some filesystems do not support file locks, only fail if another
process holds the lock.
$this->locked = flock($this->handle, $lock, $wouldblock) ||
!$wouldblock;
return $this->locked;
}
/**
* Returns true if file has been locked for writing.
*
* @return bool|null True = locked, false = failed, null = not locked.
*/
public function locked()
{
return $this->locked;
}
/**
* Unlock file.
*
* @return bool
*/
public function unlock()
{
if (!$this->handle) {
return false;
}
if ($this->locked) {
flock($this->handle, LOCK_UN);
$this->locked = null;
}
fclose($this->handle);
$this->handle = null;
return true;
}
/**
* Check if file can be written.
*
* @return bool
*/
public function writable()
{
return file_exists($this->filename) ?
is_writable($this->filename) && is_file($this->filename) :
$this->writableDir(\dirname($this->filename));
}
/**
* (Re)Load a file and return RAW file contents.
*
* @return string
*/
public function load()
{
$this->raw = $this->exists() ? (string)
file_get_contents($this->filename) : '';
$this->content = null;
return $this->raw;
}
/**
* Get/set raw file contents.
*
* @param string $var
* @return string
*/
public function raw($var = null)
{
if ($var !== null) {
$this->raw = (string) $var;
$this->content = null;
}
if (!\is_string($this->raw)) {
$this->raw = $this->load();
}
return $this->raw;
}
/**
* Get/set parsed file contents.
*
* @param mixed $var
* @return string|array
* @throws \RuntimeException
*/
public function content($var = null)
{
if ($var !== null) {
$this->content = $this->check($var);
// Update RAW, too.
$this->raw = $this->encode($this->content);
} elseif ($this->content === null) {
// Decode RAW file.
try {
$this->content = $this->decode($this->raw());
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Failed to read
%s: %s', $this->filename, $e->getMessage()), 500, $e);
}
}
return $this->content;
}
/**
* Save file.
*
* @param mixed $data Optional data to be saved, usually array.
* @throws \RuntimeException
*/
public function save($data = null)
{
if ($data !== null) {
$this->content($data);
}
$filename = $this->filename;
$dir = \dirname($filename);
if (!$this->mkdir($dir)) {
throw new \RuntimeException('Creating directory failed for
' . $filename);
}
try {
if ($this->handle) {
$tmp = true;
// As we are using non-truncating locking, make sure that
the file is empty before writing.
if (@ftruncate($this->handle, 0) === false ||
@fwrite($this->handle, $this->raw()) === false) {
// Writing file failed, throw an error.
$tmp = false;
}
} else {
// Create file with a temporary name and rename it to make
the save action atomic.
$tmp = $this->tempname($filename);
if (file_put_contents($tmp, $this->raw()) === false) {
$tmp = false;
} elseif (@rename($tmp, $filename) === false) {
@unlink($tmp);
$tmp = false;
}
}
} catch (\Exception $e) {
$tmp = false;
}
if ($tmp === false) {
throw new \RuntimeException('Failed to save file ' .
$filename);
}
// Touch the directory as well, thus marking it modified.
@touch($dir);
}
/**
* Rename file in the filesystem if it exists.
*
* @param $filename
* @return bool
*/
public function rename($filename)
{
if ($this->exists() && !@rename($this->filename,
$filename)) {
return false;
}
unset(static::$instances[$this->filename]);
static::$instances[$filename] = $this;
$this->filename = $filename;
return true;
}
/**
* Delete file from filesystem.
*
* @return bool
*/
public function delete()
{
return unlink($this->filename);
}
/**
* Check contents and make sure it is in correct format.
*
* Override in derived class.
*
* @param string $var
* @return string
*/
protected function check($var)
{
return (string) $var;
}
/**
* Encode contents into RAW string.
*
* Override in derived class.
*
* @param string $var
* @return string
*/
protected function encode($var)
{
return (string) $var;
}
/**
* Decode RAW string into contents.
*
* Override in derived class.
*
* @param string $var
* @return string mixed
*/
protected function decode($var)
{
return (string) $var;
}
/**
* @param string $dir
*/
private function mkdir($dir)
{
// Silence error for open_basedir; should fail in mkdir instead.
if (@is_dir($dir)) {
return true;
}
$success = @mkdir($dir, 0777, true);
if (!$success) {
// Take yet another look, make sure that the folder
doesn't exist.
clearstatcache(true, $dir);
if (!@is_dir($dir)) {
return false;
}
}
return true;
}
/**
* @param string $dir
* @return bool
* @internal
*/
protected function writableDir($dir)
{
if ($dir && !file_exists($dir)) {
return $this->writableDir(\dirname($dir));
}
return $dir && is_dir($dir) && is_writable($dir);
}
/**
* @param string $filename
* @param int $length
* @return string
*/
protected function tempname($filename, $length = 5)
{
do {
$test = $filename .
substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'),
0, $length);
} while (file_exists($test));
return $test;
}
}
PK-d�[����5vendor/rockettheme/toolbox/File/src/FileInterface.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
/**
* Defines FileInterface.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
interface FileInterface
{
/**
* Get file instance.
*
* @param string $filename
* @return static
*/
public static function instance($filename);
/**
* Free the file instance.
*/
public function free();
/**
* Check if file exits.
*
* @return bool
*/
public function exists();
/**
* Return file modification time.
*
* @return int Timestamp
*/
public function modified();
/**
* Lock file for writing.
*
* @param bool $block For non-blocking lock, set the parameter to
false.
* @return bool
*/
public function lock($block = true);
/**
* Returns true if file has been locked for writing.
*
* @return bool|null True = locked, false = failed, null = not locked.
*/
public function locked();
/**
* Unlock file.
*
* @return bool
*/
public function unlock();
/**
* Check if file can be written.
*
* @return bool
*/
public function writable();
/**
* (Re)Load a file and return its contents.
*
* @return string
*/
public function load();
/**
* Get/set raw file contents.
*
* @param string $var
* @return string
*/
public function raw($var = null);
/**
* Get/set parsed file contents.
*
* @param string $var
* @return string
*/
public function content($var = null);
/**
* Save file.
*
* @param string $data Optional data to be saved.
* @throws \RuntimeException
*/
public function save($data = null);
/**
* Delete file from filesystem.
*
* @return bool
*/
public function delete();
}
PK-d�[\�(��/vendor/rockettheme/toolbox/File/src/IniFile.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
/**
* Implements INI File reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class IniFile extends File
{
/**
* @var string
*/
protected $extension = '.ini';
/**
* @var array|File[]
*/
static protected $instances = [];
/**
* Check contents and make sure it is in correct format.
*
* @param array $var
* @return array
* @throws \RuntimeException
*/
protected function check($var)
{
if (!\is_array($var)) {
throw new \RuntimeException('Provided data is not an
array');
}
return $var;
}
/**
* Encode configuration object into RAW string (INI).
*
* @param array $var
* @return string
* @throws \RuntimeException
*/
protected function encode($var)
{
$string = '';
foreach ($var as $key => $value) {
$string .= $key . '="' . preg_replace(
['/"/', '/\\\/',
"/\t/", "/\n/", "/\r/"],
['\"', '\\\\',
'\t', '\n', '\r'],
$value
) . "\"\n";
}
return $string;
}
/**
* Decode INI file into contents.
*
* @param string $var
* @return array
* @throws \RuntimeException
*/
protected function decode($var)
{
$decoded = file_exists($this->filename) ?
@parse_ini_file($this->filename) : [];
if ($decoded === false) {
throw new \RuntimeException("Decoding file
'{$this->filename}' failed'");
}
return $decoded;
}
}
PK-d�[��p''0vendor/rockettheme/toolbox/File/src/JsonFile.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
/**
* Implements Json File reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class JsonFile extends File
{
/**
* @var string
*/
protected $extension = '.json';
/**
* @var array|File[]
*/
static protected $instances = [];
/**
* Check contents and make sure it is in correct format.
*
* @param array $var
* @return array
*/
protected function check($var)
{
return (array) $var;
}
/**
* Encode contents into RAW string.
*
* @param string $var
* @param int $options
* @return string
*/
protected function encode($var, $options = 0)
{
return (string) json_encode($var, $options);
}
/**
* Decode RAW string into contents.
*
* @param string $var
* @param bool $assoc
* @return array mixed
*/
protected function decode($var, $assoc = false)
{
return (array) json_decode($var, $assoc);
}
}
PK-d�[-(A��/vendor/rockettheme/toolbox/File/src/LogFile.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
/**
* Implements Log File reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class LogFile extends File
{
/**
* @var array|File[]
*/
static protected $instances = [];
/**
* Constructor.
*/
protected function __construct()
{
parent::__construct();
$this->extension = '.log';
}
/**
* Check contents and make sure it is in correct format.
*
* @param array $var
* @return array
*/
protected function check($var)
{
return (array) $var;
}
/**
* Encode contents into RAW string (unsupported).
*
* @param string $var
* @return string|void
* @throws \BadMethodCallException
*/
protected function encode($var)
{
throw new \BadMethodCallException('Saving log file is
forbidden.');
}
/**
* Decode RAW string into contents.
*
* @param string $var
* @return array mixed
*/
protected function decode($var)
{
$lines = (array) preg_split('#(\r\n|\n|\r)#', $var);
$results = array();
foreach ($lines as $line) {
preg_match('#^\[(.*)\] (.*) @ (.*) @@ (.*)$#',
$line, $matches);
if ($matches) {
$results[] = ['date' => $matches[1],
'message' => $matches[2], 'url' => $matches[3],
'file' => $matches[4]];
}
}
return $results;
}
}
PK-d�[���%4vendor/rockettheme/toolbox/File/src/MarkdownFile.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml as YamlParser;
use RocketTheme\Toolbox\Compat\Yaml\Yaml as FallbackYamlParser;
/**
* Implements Markdown File reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class MarkdownFile extends File
{
/**
* @var string
*/
protected $extension = '.md';
/**
* @var array|File[]
*/
static protected $instances = [];
/**
* Get/set file header.
*
* @param array $var
*
* @return array
*/
public function header(array $var = null)
{
$content = $this->content();
if ($var !== null) {
$content['header'] = $var;
$this->content($content);
}
return $content['header'];
}
/**
* Get/set markdown content.
*
* @param string $var
*
* @return string
*/
public function markdown($var = null)
{
$content = $this->content();
if ($var !== null) {
$content['markdown'] = (string) $var;
$this->content($content);
}
return $content['markdown'];
}
/**
* Get/set frontmatter content.
*
* @param string $var
*
* @return string
*/
public function frontmatter($var = null)
{
$content = $this->content();
if ($var !== null) {
$content['frontmatter'] = (string) $var;
$this->content($content);
}
return $content['frontmatter'];
}
/**
* Check contents and make sure it is in correct format.
*
* @param array $var
* @return array
*/
protected function check($var)
{
$var = (array) $var;
if (!isset($var['header']) ||
!\is_array($var['header'])) {
$var['header'] = array();
}
if (!isset($var['markdown']) ||
!\is_string($var['markdown'])) {
$var['markdown'] = '';
}
return $var;
}
/**
* Encode contents into RAW string.
*
* @param array $var
* @return string
*/
protected function encode($var)
{
// Create Markdown file with YAML header.
$o = (!empty($var['header']) ? "---\n" .
trim(YamlParser::dump($var['header'], 20)) .
"\n---\n\n" : '') . $var['markdown'];
// Normalize line endings to Unix style.
$o = preg_replace("/(\r\n|\r)/", "\n", $o);
return $o;
}
/**
* Decode RAW string into contents.
*
* @param string $var
* @return array mixed
*/
protected function decode($var)
{
$content = [
'header' => false,
'frontmatter' => ''
];
$frontmatter_regex = "/^---\n(.+?)\n---\n{0,}(.*)$/uis";
// Normalize line endings to Unix style.
$var = preg_replace("/(\r\n|\r)/", "\n", $var);
// Parse header.
preg_match($frontmatter_regex, ltrim($var), $m);
if(!empty($m)) {
// Normalize frontmatter.
$content['frontmatter'] = $frontmatter =
preg_replace("/\n\t/", "\n ", $m[1]);
// Try native PECL YAML PHP extension first if available.
if (\function_exists('yaml_parse') &&
$this->setting('native')) {
// Safely decode YAML.
$saved = @ini_get('yaml.decode_php');
@ini_set('yaml.decode_php', 0);
$content['header'] =
@yaml_parse("---\n" . $frontmatter . "\n...");
@ini_set('yaml.decode_php', $saved);
}
if ($content['header'] === false) {
// YAML hasn't been parsed yet (error or extension
isn't available). Fall back to Symfony parser.
try {
$content['header'] = (array)
YamlParser::parse($frontmatter);
} catch (ParseException $e) {
if (!$this->setting('compat', true)) {
throw $e;
}
$content['header'] = (array)
FallbackYamlParser::parse($frontmatter);
}
}
$content['markdown'] = $m[2];
} else {
$content['header'] = [];
$content['markdown'] = $var;
}
return $content;
}
}
PK-d�[��Ǥ__.vendor/rockettheme/toolbox/File/src/MoFile.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
/**
* Implements Gettext Mo File reader (readonly).
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class MoFile extends File
{
/**
* @var string
*/
protected $extension = '.mo';
protected $pos = 0;
protected $str;
protected $len;
protected $endian;
/**
* @var array|File[]
*/
static protected $instances = [];
/**
* File can never be written.
*
* @return bool
*/
public function writable()
{
return false;
}
/**
* Prevent saving file.
*
* @throws \BadMethodCallException
*/
public function save($data = null)
{
throw new \BadMethodCallException('save() not supported for
.mo files.');
}
/**
* Prevent deleting file from filesystem.
*
* @return bool
*/
public function delete()
{
return false;
}
/**
* @param $var
* @return array
* @throws \RuntimeException
*/
public function decode($var)
{
$this->endian = 'V';
$this->str = $var;
$this->len = \strlen($var);
$magic = $this->readInt() & 0xffffffff;
if ($magic === 0x950412de) {
// Low endian.
$this->endian = 'V';
} elseif ($magic === 0xde120495) {
// Big endian.
$this->endian = 'N';
} else {
throw new \RuntimeException('Not a Gettext file
(.mo).');
}
// Skip revision number.
$rev = $this->readInt();
// Total count.
$total = $this->readInt();
// Offset of original table.
$originals = $this->readInt();
// Offset of translation table.
$translations = $this->readInt();
// Each table consists of string length and offset of the string.
$this->seek($originals);
$table_originals = $this->readIntArray($total * 2);
$this->seek($translations);
$table_translations = $this->readIntArray($total * 2);
$items = [];
for ($i = 0; $i < $total; $i++) {
$this->seek($table_originals[$i * 2 + 2]);
// TODO: Original string can have context concatenated on it.
We do not yet support that.
$original = $this->read($table_originals[$i * 2 + 1]);
if ($original) {
$this->seek($table_translations[$i * 2 + 2]);
// TODO: Plural forms are stored by letting the plural of
the original string follow the singular of the original string, separated
through a NUL byte.
$translated = $this->read($table_translations[$i * 2 +
1]);
$items[$original] = $translated;
}
}
return $items;
}
/**
* @return int
*/
protected function readInt()
{
$read = $this->read(4);
if ($read === false) {
return false;
}
$read = unpack($this->endian, $read);
return array_shift($read);
}
/**
* @param $count
* @return array
*/
protected function readIntArray($count)
{
return unpack($this->endian . $count, $this->read(4 *
$count));
}
/**
* @param $bytes
* @return string
*/
private function read($bytes)
{
$data = substr($this->str, $this->pos, $bytes);
$this->seek($this->pos + $bytes);
return $data;
}
/**
* @param $pos
* @return mixed
*/
private function seek($pos)
{
$this->pos = $pos < $this->len ? $pos : $this->len;
return $this->pos;
}
}
PK-d�[��?�
/vendor/rockettheme/toolbox/File/src/PhpFile.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
/**
* Implements PHP File reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class PhpFile extends File
{
/**
* @var string
*/
protected $extension = '.php';
/**
* @var array|File[]
*/
static protected $instances = [];
/**
* Saves PHP file and invalidates opcache.
*
* @param mixed $data Optional data to be saved, usually array.
* @throws \RuntimeException
*/
public function save($data = null)
{
parent::save($data);
// Invalidate configuration file from the opcache.
if (\function_exists('opcache_invalidate')) {
// PHP 5.5.5+
@opcache_invalidate($this->filename, true);
} elseif (\function_exists('apc_invalidate')) {
// APC
@apc_invalidate($this->filename);
}
}
/**
* Check contents and make sure it is in correct format.
*
* @param array|object $var
* @return array
* @throws \RuntimeException
*/
protected function check($var)
{
if (!(\is_array($var) || \is_object($var))) {
throw new \RuntimeException('Provided data is not an
array');
}
return $var;
}
/**
* Encode configuration object into RAW string (PHP class).
*
* @param array $var
* @return string
* @throws \RuntimeException
*/
protected function encode($var)
{
// Build the object variables string
return "<?php\nreturn {$this->encodeArray((array)
$var)};\n";
}
/**
* Method to get an array as an exported string.
*
* @param array $a The array to get as a string.
* @param int $level Used internally to indent rows.
*
* @return string
*/
protected function encodeArray(array $a, $level = 0)
{
$r = [];
foreach ($a as $k => $v) {
if (\is_array($v) || \is_object($v)) {
$r[] = var_export($k, true) . ' => ' .
$this->encodeArray((array) $v, $level + 1);
} else {
$r[] = var_export($k, true) . ' => ' .
var_export($v, true);
}
}
$space = str_repeat(' ', $level);
return "[\n {$space}" . implode(",\n
{$space}", $r) . "\n{$space}]";
}
/**
* Decode PHP file into contents.
*
* @param string $var
* @return array
*/
protected function decode($var)
{
return (array) include $this->filename;
}
}
PK-d�[<�lj��0vendor/rockettheme/toolbox/File/src/YamlFile.phpnu�[���<?php
namespace RocketTheme\Toolbox\File;
use Symfony\Component\Yaml\Exception\DumpException;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml as YamlParser;
use RocketTheme\Toolbox\Compat\Yaml\Yaml as FallbackYamlParser;
/**
* Implements YAML File reader.
*
* @package RocketTheme\Toolbox\File
* @author RocketTheme
* @license MIT
*/
class YamlFile extends File
{
/**
* @var array|File[]
*/
static protected $instances = [];
static protected $globalSettings = [
'compat' => true,
'native' => true
];
/**
* Set/get settings.
*
* @param array $settings
* @return array
*/
public static function globalSettings(array $settings = null)
{
if ($settings !== null) {
static::$globalSettings = $settings;
}
return static::$globalSettings;
}
/**
* Constructor.
*/
protected function __construct()
{
parent::__construct();
$this->extension = '.yaml';
}
/**
* Set/get settings.
*
* @param array $settings
* @return array
*/
public function settings(array $settings = null)
{
if ($settings !== null) {
$this->settings = $settings;
}
return $this->settings + static::$globalSettings;
}
/**
* Get setting.
*
* @param string $setting
* @param mixed $default
* @return mixed
*/
public function setting($setting, $default = null)
{
$value = parent::setting($setting);
if (null === $value) {
$value = isset(static::$globalSettings[$setting]) ?
static::$globalSettings[$setting] : $default;
}
return $value;
}
/**
* Check contents and make sure it is in correct format.
*
* @param array $var
* @return array
*/
protected function check($var)
{
return (array) $var;
}
/**
* Encode contents into RAW string.
*
* @param array $var
* @return string
* @throws DumpException
*/
protected function encode($var)
{
return (string) YamlParser::dump($var,
$this->setting('inline', 5),
$this->setting('indent', 2), true, false);
}
/**
* Decode RAW string into contents.
*
* @param string $var
* @return array mixed
* @throws ParseException
*/
protected function decode($var)
{
// Try native PECL YAML PHP extension first if available.
if (\function_exists('yaml_parse') &&
$this->setting('native', true)) {
// Safely decode YAML.
$saved = @ini_get('yaml.decode_php');
@ini_set('yaml.decode_php', 0);
$data = @yaml_parse($var);
@ini_set('yaml.decode_php', $saved);
if ($data !== false) {
return (array) $data;
}
}
try {
return (array) YamlParser::parse($var);
} catch (ParseException $e) {
if ($this->setting('compat', true)) {
return (array) FallbackYamlParser::parse($var);
}
throw $e;
}
}
}
PK-d�[����Svendor/rockettheme/toolbox/ResourceLocator/src/RecursiveUniformResourceIterator.phpnu�[���<?php
namespace RocketTheme\Toolbox\ResourceLocator;
/**
* Implements recursive iterator over filesystem.
*
* @package RocketTheme\Toolbox\ResourceLocator
* @author RocketTheme
* @license MIT
*/
class RecursiveUniformResourceIterator extends UniformResourceIterator
implements \SeekableIterator, \RecursiveIterator
{
protected $subPath;
public function getChildren()
{
$subPath = $this->getSubPathName();
return (new static($this->getUrl(), $this->flags,
$this->locator))->setSubPath($subPath);
}
public function hasChildren($allow_links = null)
{
$allow_links = (bool) ($allow_links !== null ? $allow_links :
$this->flags & \FilesystemIterator::FOLLOW_SYMLINKS);
return $this->iterator && $this->isDir() &&
!$this->isDot() && ($allow_links || !$this->isLink());
}
public function getSubPath()
{
return $this->subPath;
}
public function getSubPathName()
{
return ($this->subPath ? $this->subPath . '/' :
'') . $this->getFilename();
}
/**
* @param $path
* @return $this
* @internal
*/
public function setSubPath($path)
{
$this->subPath = $path;
return $this;
}
}
PK-d�[{�&N��Kvendor/rockettheme/toolbox/ResourceLocator/src/ResourceLocatorInterface.phpnu�[���<?php
namespace RocketTheme\Toolbox\ResourceLocator;
/**
* Defines ResourceLocatorInterface.
*
* @package RocketTheme\Toolbox\ResourceLocator
* @author RocketTheme
* @license MIT
*/
interface ResourceLocatorInterface
{
/**
* Alias for findResource()
*
* @param $uri
* @return string|bool
*/
public function __invoke($uri);
/**
* Returns true if uri is resolvable by using locator.
*
* @param string $uri
* @return bool
*/
public function isStream($uri);
/**
* @param string $uri
* @param bool $absolute
* @param bool $first
* @return string|bool
*/
public function findResource($uri, $absolute = true, $first = false);
/**
* @param string $uri
* @param bool $absolute
* @param bool $all
* @return array
*/
public function findResources($uri, $absolute = true, $all = false);
}
PK-d�[ժ��iiJvendor/rockettheme/toolbox/ResourceLocator/src/UniformResourceIterator.phpnu�[���<?php
namespace RocketTheme\Toolbox\ResourceLocator;
use FilesystemIterator;
/**
* Implements FilesystemIterator for uniform resource locator.
*
* @package RocketTheme\Toolbox\ResourceLocator
* @author RocketTheme
* @license MIT
*/
class UniformResourceIterator extends FilesystemIterator
{
/**
* @var FilesystemIterator
*/
protected $iterator;
/**
* @var array
*/
protected $found;
/**
* @var array
*/
protected $stack;
/**
* @var string
*/
protected $path;
/**
* @var int
*/
protected $flags;
/**
* @var UniformResourceLocator
*/
protected $locator;
public function __construct($path, $flags = null,
UniformResourceLocator $locator = null)
{
if (!$locator) {
throw new \BadMethodCallException('Use
$locator->getIterator() instead');
}
$this->path = $path;
$this->setFlags($flags);
$this->locator = $locator;
$this->rewind();
}
public function current()
{
if ($this->flags & static::CURRENT_AS_SELF) {
return $this;
}
return $this->iterator->current();
}
public function key()
{
return $this->iterator->key();
}
public function next()
{
do {
$found = $this->findNext();
} while ($found && !empty($this->found[$found]));
if ($found) {
// Mark the file as found.
$this->found[$found] = true;
}
}
public function valid()
{
return $this->iterator &&
$this->iterator->valid();
}
public function rewind()
{
$this->found = [];
$this->stack =
$this->locator->findResources($this->path);
$this->next();
}
public function getUrl()
{
$path = $this->path . (substr($this->path, -1, 1) ===
'/' ? '' : '/');
return $path . $this->iterator->getFilename();
}
public function seek($position)
{
throw new \RuntimeException('Seek not implemented');
}
public function getATime()
{
return $this->iterator->getATime();
}
public function getBasename($suffix = null)
{
return $this->iterator->getBasename($suffix);
}
public function getCTime()
{
return $this->iterator->getCTime();
}
public function getExtension()
{
return $this->iterator->getExtension();
}
public function getFilename()
{
return $this->iterator->getFilename();
}
public function getGroup()
{
return $this->iterator->getGroup();
}
public function getInode()
{
return $this->iterator->getInode();
}
public function getMTime()
{
return $this->iterator->getMTime();
}
public function getOwner()
{
return $this->iterator->getOwner();
}
public function getPath()
{
return $this->iterator->getPath();
}
public function getPathname()
{
return $this->iterator->getPathname();
}
public function getPerms()
{
return $this->iterator->getPerms();
}
public function getSize()
{
return $this->iterator->getSize();
}
public function getType()
{
return $this->iterator->getType();
}
public function isDir()
{
return $this->iterator->isDir();
}
public function isDot()
{
return $this->iterator->isDot();
}
public function isExecutable()
{
return $this->iterator->isExecutable();
}
public function isFile()
{
return $this->iterator->isFile();
}
public function isLink()
{
return $this->iterator->isLink();
}
public function isReadable()
{
return $this->iterator->isReadable();
}
public function isWritable()
{
return $this->iterator->isWritable();
}
public function __toString()
{
return $this->iterator->__toString();
}
public function getFlags()
{
return $this->flags;
}
public function setFlags($flags = null)
{
$this->flags = $flags === null ? static::KEY_AS_PATHNAME |
static::CURRENT_AS_SELF | static::SKIP_DOTS : $flags;
if ($this->iterator) {
$this->iterator->setFlags($this->flags);
}
}
protected function findNext()
{
if ($this->iterator) {
$this->iterator->next();
}
if (!$this->valid()) {
do {
// Move to the next iterator if it exists.
$path = array_shift($this->stack);
if (!isset($path)) {
return null;
}
$this->iterator = new \FilesystemIterator($path,
$this->getFlags());
} while (!$this->iterator->valid());
}
return $this->getFilename();
}
}
PK-d�[��|J9J9Ivendor/rockettheme/toolbox/ResourceLocator/src/UniformResourceLocator.phpnu�[���<?php
namespace RocketTheme\Toolbox\ResourceLocator;
/**
* Implements Uniform Resource Location.
*
* @package RocketTheme\Toolbox\ResourceLocator
* @author RocketTheme
* @license MIT
*
* @link
http://webmozarts.com/2013/06/19/the-power-of-uniform-resource-location-in-php/
*/
class UniformResourceLocator implements ResourceLocatorInterface
{
/**
* @var string Base URL for all the streams.
*/
public $base;
/**
* @var array[]
*/
protected $schemes = [];
/**
* @var array
*/
protected $cache = [];
public function __construct($base = null)
{
// Normalize base path.
$this->base = rtrim(str_replace('\\', '/',
$base ?: getcwd()), '/');
}
/**
* Return iterator for the resource URI.
*
* @param string $uri
* @param int $flags See constants from FilesystemIterator
class.
* @return UniformResourceIterator
*/
public function getIterator($uri, $flags = null)
{
return new UniformResourceIterator($uri, $flags, $this);
}
/**
* Return recursive iterator for the resource URI.
*
* @param string $uri
* @param int $flags See constants from FilesystemIterator
class.
* @return RecursiveUniformResourceIterator
*/
public function getRecursiveIterator($uri, $flags = null)
{
return new RecursiveUniformResourceIterator($uri, $flags, $this);
}
/**
* Reset locator by removing all the schemes.
*
* @return $this
*/
public function reset()
{
$this->schemes = [];
$this->cache = [];
return $this;
}
/**
* Reset a locator scheme
*
* @param string $scheme The scheme to reset
*
* @return $this
*/
public function resetScheme($scheme)
{
$this->schemes[$scheme] = [];
$this->cache = [];
return $this;
}
/**
* Add new paths to the scheme.
*
* @param string $scheme
* @param string $prefix
* @param string|array $paths
* @param bool|string $override True to add path as override, string
* @param bool $force True to add paths even if them do not exist.
* @throws \BadMethodCallException
*/
public function addPath($scheme, $prefix, $paths, $override = false,
$force = false)
{
$list = [];
foreach((array) $paths as $path) {
if (\is_array($path)) {
// Support stream lookup in ['theme',
'path/to'] format.
if (\count($path) !== 2 || !\is_string($path[0]) ||
!\is_string($path[1])) {
throw new \BadMethodCallException('Invalid stream
path given.');
}
$list[] = $path;
} elseif (false !== strpos($path, '://')) {
// Support stream lookup in 'theme://path/to'
format.
$stream = explode('://', $path, 2);
$stream[1] = trim($stream[1], '/');
$list[] = $stream;
} else {
// Normalize path.
$path = rtrim(str_replace('\\', '/',
$path), '/');
if ($force ||
@file_exists("{$this->base}/{$path}") || @file_exists($path))
{
// Support for absolute and relative paths.
$list[] = $path;
}
}
}
if (isset($this->schemes[$scheme][$prefix])) {
$paths = $this->schemes[$scheme][$prefix];
if (!$override || $override == 1) {
$list = $override ? array_merge($paths, $list) :
array_merge($list, $paths);
} else {
$location = array_search($override, $paths, true) ?:
\count($paths);
array_splice($paths, $location, 0, $list);
$list = $paths;
}
}
$this->schemes[$scheme][$prefix] = $list;
// Sort in reverse order to get longer prefixes to be matched
first.
krsort($this->schemes[$scheme]);
$this->cache = [];
}
/**
* Return base directory.
*
* @return string
*/
public function getBase()
{
return $this->base;
}
/**
* Return true if scheme has been defined.
*
* @param string $name
* @return bool
*/
public function schemeExists($name)
{
return isset($this->schemes[$name]);
}
/**
* Return defined schemes.
*
* @return array
*/
public function getSchemes()
{
return array_keys($this->schemes);
}
/**
* Return all scheme lookup paths.
*
* @param string $scheme
* @return array
*/
public function getPaths($scheme = null)
{
return !$scheme ? $this->schemes :
(isset($this->schemes[$scheme]) ? $this->schemes[$scheme] : []);
}
/**
* @param string $uri
* @return string|bool
* @throws \BadMethodCallException
*/
public function __invoke($uri)
{
if (!\is_string($uri)) {
throw new \BadMethodCallException('Invalid parameter
$uri.');
}
return $this->findCached($uri, false, true, false);
}
/**
* Returns true if uri is resolvable by using locator.
*
* @param string $uri
* @return bool
*/
public function isStream($uri)
{
try {
list ($scheme,) = $this->normalize($uri, true, true);
} catch (\Exception $e) {
return false;
}
return $this->schemeExists($scheme);
}
/**
* Returns the canonicalized URI on success. The resulting path will
have no '/./' or '/../' components.
* Trailing delimiter `/` is kept.
*
* By default (if $throwException parameter is not set to true) returns
false on failure.
*
* @param string $uri
* @param bool $throwException
* @param bool $splitStream
* @return string|array|bool
* @throws \BadMethodCallException
*/
public function normalize($uri, $throwException = false, $splitStream =
false)
{
if (!\is_string($uri)) {
if ($throwException) {
throw new \BadMethodCallException('Invalid parameter
$uri.');
}
return false;
}
$uri = preg_replace('|\\\|u', '/', $uri);
$segments = explode('://', $uri, 2);
$path = array_pop($segments);
$scheme = array_pop($segments) ?: 'file';
if ($path) {
$path = preg_replace('|\\\|u', '/', $path);
$parts = explode('/', $path);
$list = [];
foreach ($parts as $i => $part) {
if ($part === '..') {
$part = array_pop($list);
if ($part === null || $part === '' || (!$list
&& strpos($part, ':'))) {
if ($throwException) {
throw new \BadMethodCallException('Invalid
parameter $uri.');
}
return false;
}
} elseif (($i && $part === '') || $part
=== '.') {
continue;
} else {
$list[] = $part;
}
}
if (($l = end($parts)) === '' || $l === '.'
|| $l === '..') {
$list[] = '';
}
$path = implode('/', $list);
}
return $splitStream ? [$scheme, $path] : ($scheme !==
'file' ? "{$scheme}://{$path}" : $path);
}
/**
* Find highest priority instance from a resource.
*
* @param string $uri Input URI to be searched.
* @param bool $absolute Whether to return absolute path.
* @param bool $first Whether to return first path even if it
doesn't exist.
* @throws \BadMethodCallException
* @return string|bool
*/
public function findResource($uri, $absolute = true, $first = false)
{
if (!\is_string($uri)) {
throw new \BadMethodCallException('Invalid parameter
$uri.');
}
return $this->findCached($uri, false, $absolute, $first);
}
/**
* Find all instances from a resource.
*
* @param string $uri Input URI to be searched.
* @param bool $absolute Whether to return absolute path.
* @param bool $all Whether to return all paths even if they
don't exist.
* @throws \BadMethodCallException
* @return array
*/
public function findResources($uri, $absolute = true, $all = false)
{
if (!\is_string($uri)) {
throw new \BadMethodCallException('Invalid parameter
$uri.');
}
return $this->findCached($uri, true, $absolute, $all);
}
/**
* Find all instances from a list of resources.
*
* @param array $uris Input URIs to be searched.
* @param bool $absolute Whether to return absolute path.
* @param bool $all Whether to return all paths even if they
don't exist.
* @throws \BadMethodCallException
* @return array
*/
public function mergeResources(array $uris, $absolute = true, $all =
false)
{
$uris = array_unique($uris);
$lists = [[]];
foreach ($uris as $uri) {
$lists[] = $this->findResources($uri, $absolute, $all);
}
// TODO: In PHP 5.6+ use array_merge(...$list);
return call_user_func_array('array_merge', $lists);
}
/**
* Pre-fill cache by a stream.
*
* @param string $uri
* @return $this
*/
public function fillCache($uri)
{
$cacheKey = $uri . '@cache';
if (!isset($this->cache[$cacheKey])) {
$this->cache[$cacheKey] = true;
$iterator = new
\RecursiveIteratorIterator($this->getRecursiveIterator($uri),
\RecursiveIteratorIterator::SELF_FIRST);
/** @var UniformResourceIterator $uri */
foreach ($iterator as $item) {
$key = $item->getUrl() . '@010';
$this->cache[$key] = $item->getPathname();
}
}
return $this;
}
/**
* Reset locator cache.
*
* @param string $uri
* @return $this
*/
public function clearCache($uri = null)
{
if ($uri) {
$this->clearCached($uri, true, true, true);
$this->clearCached($uri, true, true, false);
$this->clearCached($uri, true, false, true);
$this->clearCached($uri, true, false, false);
$this->clearCached($uri, false, true, true);
$this->clearCached($uri, false, true, false);
$this->clearCached($uri, false, false, true);
$this->clearCached($uri, false, false, false);
} else {
$this->cache = [];
}
return $this;
}
/**
* @param string $uri
* @param bool $array
* @param bool $absolute
* @param bool $all
* @return array|string|bool
* @throws \BadMethodCallException
*/
protected function findCached($uri, $array, $absolute, $all)
{
// Local caching: make sure that the function gets only called at
once for each file.
$key = $uri .'@'. (int) $array . (int) $absolute . (int)
$all;
if (!isset($this->cache[$key])) {
try {
list ($scheme, $file) = $this->normalize($uri, true,
true);
if (!$file && $scheme === 'file') {
$file = $this->base;
}
$this->cache[$key] = $this->find($scheme, $file,
$array, $absolute, $all);
} catch (\BadMethodCallException $e) {
$this->cache[$key] = $array ? [] : false;
}
}
return $this->cache[$key];
}
protected function clearCached($uri, $array, $absolute, $all)
{
// Local caching: make sure that the function gets only called at
once for each file.
$key = $uri .'@'. (int) $array . (int) $absolute . (int)
$all;
unset($this->cache[$key]);
}
/**
* @param string $scheme
* @param string $file
* @param bool $array
* @param bool $absolute
* @param bool $all
*
* @throws \InvalidArgumentException
* @return array|string|bool
* @internal
*/
protected function find($scheme, $file, $array, $absolute, $all)
{
if (!isset($this->schemes[$scheme])) {
throw new \InvalidArgumentException("Invalid resource
{$scheme}://");
}
$results = $array ? [] : false;
foreach ($this->schemes[$scheme] as $prefix => $paths) {
if ($prefix && strpos($file, $prefix) !== 0) {
continue;
}
// Remove prefix from filename.
$filename = '/' . trim(substr($file,
\strlen($prefix)), '\/');
foreach ($paths as $path) {
if (\is_array($path)) {
// Handle scheme lookup.
$relPath = trim($path[1] . $filename, '/');
$found = $this->find($path[0], $relPath, $array,
$absolute, $all);
if ($found) {
if (!$array) {
return $found;
}
$results = array_merge($results, $found);
}
} else {
// TODO: We could provide some extra information about
the path to remove preg_match().
// Check absolute paths for both unix and windows
if (!$path || !preg_match('`^/|\w+:`',
$path)) {
// Handle relative path lookup.
$relPath = trim($path . $filename, '/');
$fullPath = $this->base . '/' .
$relPath;
} else {
// Handle absolute path lookup.
$fullPath = rtrim($path . $filename,
'/');
if (!$absolute) {
throw new
\RuntimeException("UniformResourceLocator: Absolute stream path with
relative lookup not allowed ({$prefix})", 500);
}
}
if ($all || file_exists($fullPath)) {
$current = $absolute ? $fullPath : $relPath;
if (!$array) {
return $current;
}
$results[] = $current;
}
}
}
}
return $results;
}
}
PK-d�[k�2{{2vendor/rockettheme/toolbox/Session/src/Message.phpnu�[���<?php
namespace RocketTheme\Toolbox\Session;
/**
* Implements session messages.
*
* @package RocketTheme\Toolbox\Session
* @author RocketTheme
* @license MIT
*/
class Message
{
/**
* @var array|string[]
*/
protected $messages = [];
/**
* Add message to the queue.
*
* @param string $message
* @param string $scope
* @return $this
*/
public function add($message, $scope = 'default')
{
$key = md5($scope.'~'.$message);
$item = ['message' => $message, 'scope'
=> $scope];
// don't add duplicates
if (!array_key_exists($key, $this->messages)) {
$this->messages[$key] = $item;
}
return $this;
}
/**
* Clear message queue.
*
* @param string $scope
* @return $this
*/
public function clear($scope = null)
{
if ($scope === null) {
$this->messages = array();
} else {
foreach ($this->messages as $key => $message) {
if ($message['scope'] === $scope) {
unset($this->messages[$key]);
}
}
}
return $this;
}
/**
* Fetch all messages.
*
* @param string $scope
* @return array
*/
public function all($scope = null)
{
if ($scope === null) {
return array_values($this->messages);
}
$messages = array();
foreach ($this->messages as $message) {
if ($message['scope'] === $scope) {
$messages[] = $message;
}
}
return $messages;
}
/**
* Fetch and clear message queue.
*
* @param string $scope
* @return array
*/
public function fetch($scope = null)
{
$messages = $this->all($scope);
$this->clear($scope);
return $messages;
}
}
PK-d�[�}%�>>2vendor/rockettheme/toolbox/Session/src/Session.phpnu�[���<?php
namespace RocketTheme\Toolbox\Session;
/**
* Implements Session handling.
*
* @package RocketTheme\Toolbox\Session
* @author RocketTheme
* @license MIT
*/
class Session implements \IteratorAggregate
{
/**
* @var bool
*/
protected $started = false;
/**
* @var Session
*/
protected static $instance;
/**
* @param int $lifetime Defaults to 1800 seconds.
* @param string $path Cookie path.
* @param string $domain Optional, domain for the session
* @throws \RuntimeException
*/
public function __construct($lifetime, $path, $domain = null)
{
// Session is a singleton.
if (null !== self::$instance) {
throw new \RuntimeException('Session has already been
initialized.', 500);
}
// Destroy any existing sessions started with session.auto_start
if ($this->isSessionStarted()) {
session_unset();
session_destroy();
}
// Disable transparent sid support
ini_set('session.use_trans_sid', 0);
// Only allow cookies
ini_set('session.use_cookies', 1);
session_name('msF9kJcW');
session_set_cookie_params($lifetime, $path, $domain);
register_shutdown_function([$this, 'close']);
session_cache_limiter('nocache');
self::$instance = $this;
}
/**
* Get current session instance.
*
* @return Session
* @throws \RuntimeException
*/
public function instance()
{
if (null === self::$instance) {
throw new \RuntimeException("Session hasn't been
initialized.", 500);
}
return self::$instance;
}
/**
* Starts the session storage
*
* @return $this
* @throws \RuntimeException
*/
public function start()
{
// Protection against invalid session cookie names throwing
exception: http://php.net/manual/en/function.session-id.php#116836
if (isset($_COOKIE[session_name()]) &&
!preg_match('/^[-,a-zA-Z0-9]{1,128}$/',
$_COOKIE[session_name()])) {
unset($_COOKIE[session_name()]);
}
if (!session_start()) {
throw new \RuntimeException('Failed to start
session.', 500);
}
$this->started = true;
return $this;
}
/**
* Get session ID
*
* @return string|null Session ID
*/
public function getId()
{
return session_id();
}
/**
* Set session Id
*
* @param string $id Session ID
*
* @return $this
*/
public function setId($id)
{
session_id($id);
return $this;
}
/**
* Get session name
*
* @return string|null
*/
public function getName()
{
return session_name();
}
/**
* Set session name
*
* @param string $name
*
* @return $this
*/
public function setName($name)
{
session_name($name);
return $this;
}
/**
* Invalidates the current session.
*
* @return $this
*/
public function invalidate()
{
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params['path'], $params['domain'],
$params['secure'], $params['httponly']
);
session_unset();
session_destroy();
$this->started = false;
return $this;
}
/**
* Force the session to be saved and closed
*
* @return $this
*/
public function close()
{
if ($this->started) {
session_write_close();
}
$this->started = false;
return $this;
}
/**
* Checks if an attribute is defined.
*
* @param string $name The attribute name
*
* @return bool True if the attribute is defined, false otherwise
*/
public function __isset($name)
{
return isset($_SESSION[$name]);
}
/**
* Returns an attribute.
*
* @param string $name The attribute name
*
* @return mixed
*/
public function __get($name)
{
return isset($_SESSION[$name]) ? $_SESSION[$name] : null;
}
/**
* Sets an attribute.
*
* @param string $name
* @param mixed $value
*/
public function __set($name, $value)
{
$_SESSION[$name] = $value;
}
/**
* Removes an attribute.
*
* @param string $name
*/
public function __unset($name)
{
unset($_SESSION[$name]);
}
/**
* Returns attributes.
*
* @return array Attributes
*/
public function all()
{
return $_SESSION;
}
/**
* Retrieve an external iterator
*
* @return \ArrayIterator Return an ArrayIterator of $_SESSION
*/
public function getIterator()
{
return new \ArrayIterator($_SESSION);
}
/**
* Checks if the session was started.
*
* @return Boolean
*/
public function started()
{
return $this->started;
}
/**
* http://php.net/manual/en/function.session-status.php#113468
* Check if session is started nicely.
* @return bool
*/
protected function isSessionStarted()
{
return php_sapi_name() !== 'cli' ? session_id() !==
'' : false;
}
}
PK-d�[�9�&}
}
?vendor/rockettheme/toolbox/StreamWrapper/src/ReadOnlyStream.phpnu�[���<?php
namespace RocketTheme\Toolbox\StreamWrapper;
use RocketTheme\Toolbox\ResourceLocator\ResourceLocatorInterface;
/**
* Implements Read Only Streams.
*
* @package RocketTheme\Toolbox\StreamWrapper
* @author RocketTheme
* @license MIT
*/
class ReadOnlyStream extends Stream implements StreamInterface
{
/**
* @var ResourceLocatorInterface
*/
protected static $locator;
public function stream_open($uri, $mode, $options, &$opened_url)
{
if (!\in_array($mode, ['r', 'rb',
'rt'], true)) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('stream_open() write modes not
allowed for %s', $uri), E_USER_WARNING);
}
return false;
}
$path = $this->getPath($uri);
if (!$path) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('stream_open(): path for %s does
not exist', $uri), E_USER_WARNING);
}
return false;
}
$this->uri = $uri;
$this->handle = ($options & STREAM_REPORT_ERRORS) ?
fopen($path, $mode) : @fopen($path, $mode);
return (bool) $this->handle;
}
public function stream_lock($operation)
{
// Disallow exclusive lock or non-blocking lock requests
if (!\in_array($operation, [LOCK_SH, LOCK_UN, LOCK_SH | LOCK_NB],
true)) {
trigger_error(
sprintf('stream_lock() exclusive lock operations not
allowed for %s', $this->uri),
E_USER_WARNING
);
return false;
}
return flock($this->handle, $operation);
}
public function stream_metadata($uri, $option, $value)
{
if ($option !== STREAM_META_TOUCH) {
throw new
\BadMethodCallException(sprintf('stream_metadata() not allowed for
%s', $uri));
}
return parent::stream_metadata($uri, $option, $value);
}
public function stream_write($data)
{
throw new \BadMethodCallException(sprintf('stream_write() not
allowed for %s', $this->uri));
}
public function unlink($uri)
{
throw new \BadMethodCallException(sprintf('unlink() not
allowed for %s', $uri));
}
public function rename($from_uri, $to_uri)
{
throw new \BadMethodCallException(sprintf('rename() not
allowed for %s', $from_uri));
}
public function mkdir($uri, $mode, $options)
{
throw new \BadMethodCallException(sprintf('mkdir() not allowed
for %s', $uri));
}
public function rmdir($uri, $options)
{
throw new \BadMethodCallException(sprintf('rmdir() not allowed
for %s', $uri));
}
}
PK-d�[f�//7vendor/rockettheme/toolbox/StreamWrapper/src/Stream.phpnu�[���<?php
namespace RocketTheme\Toolbox\StreamWrapper;
use RocketTheme\Toolbox\ResourceLocator\ResourceLocatorInterface;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Implements Read/Write Streams.
*
* @package RocketTheme\Toolbox\StreamWrapper
* @author RocketTheme
* @license MIT
*/
class Stream implements StreamInterface
{
/**
* @var string
*/
protected $uri;
/**
* A generic resource handle.
*
* @var Resource
*/
protected $handle = null;
/**
* @var ResourceLocatorInterface|UniformResourceLocator
*/
protected static $locator;
/**
* @param ResourceLocatorInterface $locator
*/
public static function setLocator(ResourceLocatorInterface $locator)
{
static::$locator = $locator;
}
public function stream_open($uri, $mode, $options, &$opened_url)
{
$path = $this->getPath($uri, $mode);
if (!$path) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('stream_open(): path for %s does
not exist', $uri), E_USER_WARNING);
}
return false;
}
$this->uri = $uri;
$this->handle = ($options & STREAM_REPORT_ERRORS) ?
fopen($path, $mode) : @fopen($path, $mode);
if (static::$locator instanceof UniformResourceLocator &&
!\in_array($mode, ['r', 'rb', 'rt'], true)) {
static::$locator->clearCache($this->uri);
}
return (bool) $this->handle;
}
public function stream_close()
{
return fclose($this->handle);
}
public function stream_lock($operation)
{
if (\in_array($operation, [LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB],
true)) {
return flock($this->handle, $operation);
}
return false;
}
public function stream_metadata($uri, $option, $value)
{
$path = $this->findPath($uri);
if ($path) {
switch ($option) {
case STREAM_META_TOUCH:
list($time, $atime) = $value;
return touch($path, $time, $atime);
case STREAM_META_OWNER_NAME:
case STREAM_META_OWNER:
return chown($path, $value);
case STREAM_META_GROUP_NAME:
case STREAM_META_GROUP:
return chgrp($path, $value);
case STREAM_META_ACCESS:
return chmod($path, $value);
}
}
return false;
}
public function stream_read($count)
{
return fread($this->handle, $count);
}
public function stream_write($data)
{
return fwrite($this->handle, $data);
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_seek($offset, $whence)
{
// fseek returns 0 on success and -1 on a failure.
return !fseek($this->handle, $offset, $whence);
}
public function stream_flush()
{
return fflush($this->handle);
}
public function stream_tell()
{
return ftell($this->handle);
}
public function stream_stat()
{
return fstat($this->handle);
}
/**
* @return bool
*/
public function stream_set_option($option, $arg1, $arg2)
{
switch ((int)$option) {
case STREAM_OPTION_BLOCKING:
return stream_set_blocking($this->handle, (int)$arg1);
case STREAM_OPTION_READ_TIMEOUT:
return stream_set_timeout($this->handle, (int)$arg1,
(int)$arg2);
case STREAM_OPTION_WRITE_BUFFER:
return stream_set_write_buffer($this->handle,
(int)$arg2);
default:
return false;
}
}
/**
* @param string $uri
* @return bool
*/
public function unlink($uri)
{
$path = $this->getPath($uri);
if (!$path) {
return false;
}
return unlink($path);
}
public function rename($fromUri, $toUri)
{
$fromPath = $this->getPath($fromUri);
$toPath = $this->getPath($toUri, 'w');
if (!$fromPath || !$toPath) {
return false;
}
if (static::$locator instanceof UniformResourceLocator) {
static::$locator->clearCache($fromUri);
static::$locator->clearCache($toUri);
}
return rename($fromPath, $toPath);
}
public function mkdir($uri, $mode, $options)
{
$recursive = (bool) ($options & STREAM_MKDIR_RECURSIVE);
$path = $this->getPath($uri, $recursive ? 'd' :
'w');
if (!$path) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('mkdir(): Could not create
directory for %s', $uri), E_USER_WARNING);
}
return false;
}
if (static::$locator instanceof UniformResourceLocator) {
static::$locator->clearCache($uri);
}
return ($options & STREAM_REPORT_ERRORS) ? mkdir($path, $mode,
$recursive) : @mkdir($path, $mode, $recursive);
}
public function rmdir($uri, $options)
{
$path = $this->getPath($uri);
if (!$path) {
if ($options & STREAM_REPORT_ERRORS) {
trigger_error(sprintf('rmdir(): Directory not found
for %s', $uri), E_USER_WARNING);
}
return false;
}
if (static::$locator instanceof UniformResourceLocator) {
static::$locator->clearCache($uri);
}
return ($options & STREAM_REPORT_ERRORS) ? rmdir($path) :
@rmdir($path);
}
public function url_stat($uri, $flags)
{
$path = $this->getPath($uri);
if (!$path) {
return false;
}
// Suppress warnings if requested or if the file or directory does
not
// exist. This is consistent with PHPs plain filesystem stream
wrapper.
return ($flags & STREAM_URL_STAT_QUIET || !file_exists($path))
? @stat($path) : stat($path);
}
public function dir_opendir($uri, $options)
{
$path = $this->getPath($uri);
if (!$path) {
return false;
}
$this->uri = $uri;
$this->handle = opendir($path);
return (bool) $this->handle;
}
public function dir_readdir()
{
return readdir($this->handle);
}
public function dir_rewinddir()
{
rewinddir($this->handle);
return true;
}
public function dir_closedir()
{
closedir($this->handle);
return true;
}
protected function getPath($uri, $mode = null)
{
if ($mode === null) {
$mode = 'r';
}
$path = $this->findPath($uri);
if ($path && file_exists($path)) {
return $path;
}
if (strpos($mode[0], 'r') === 0) {
return false;
}
// We are either opening a file or creating directory.
list($scheme, $target) = explode('://', $uri, 2);
if ($target === '') {
return false;
}
$target = explode('/', $target);
$filename = [];
do {
$filename[] = array_pop($target);
$path = $this->findPath($scheme . '://' .
implode('/', $target));
} while ($target && !$path);
if (!$path) {
return false;
}
return $path . '/' . implode('/',
array_reverse($filename));
}
protected function findPath($uri)
{
return static::$locator &&
static::$locator->isStream($uri) ?
static::$locator->findResource($uri) : false;
}
}
PK-d�[��}}>vendor/rockettheme/toolbox/StreamWrapper/src/StreamBuilder.phpnu�[���<?php
namespace RocketTheme\Toolbox\StreamWrapper;
/**
* Class StreamBuilder
* @package RocketTheme\Toolbox\StreamWrapper
*/
class StreamBuilder
{
/**
* @var array
*/
protected $items = [];
/**
* StreamBuilder constructor.
* @param StreamInterface[] $items
* @throws \InvalidArgumentException
*/
public function __construct(array $items = [])
{
foreach ($items as $scheme => $handler) {
$this->add($scheme, $handler);
}
}
/**
* @param string $scheme
* @param StreamInterface $handler
* @return $this
* @throws \InvalidArgumentException
*/
public function add($scheme, $handler)
{
if (isset($this->items[$scheme])) {
if ($handler === $this->items[$scheme]) {
return $this;
}
throw new \InvalidArgumentException("Stream
'{$scheme}' has already been initialized.");
}
if (!is_subclass_of($handler,
'RocketTheme\Toolbox\StreamWrapper\StreamInterface')) {
throw new \InvalidArgumentException("Stream
'{$scheme}' has unknown or invalid type.");
}
if (!@stream_wrapper_register($scheme, $handler)) {
throw new \InvalidArgumentException("Stream
'{$scheme}' could not be initialized.");
}
$this->items[$scheme] = $handler;
return $this;
}
/**
* @param string $scheme
* @return $this
*/
public function remove($scheme)
{
if (isset($this->items[$scheme])) {
stream_wrapper_unregister($scheme);
unset($this->items[$scheme]);
}
return $this;
}
/**
* @return array
*/
public function getStreams()
{
return $this->items;
}
/**
* @param string $scheme
* @return bool
*/
public function isStream($scheme)
{
return isset($this->items[$scheme]);
}
/**
* @param string $scheme
* @return StreamInterface|null
*/
public function getStreamType($scheme)
{
return isset($this->items[$scheme]) ? $this->items[$scheme] :
null;
}
}
PK-d�[ɠ4�� �
@vendor/rockettheme/toolbox/StreamWrapper/src/StreamInterface.phpnu�[���<?php
namespace RocketTheme\Toolbox\StreamWrapper;
/**
* Defines Generic PHP stream wrapper interface.
*
* @package RocketTheme\Toolbox\StreamWrapper
* @author RocketTheme
* @license MIT
*
* @see http://www.php.net/manual/class.streamwrapper.php
*/
interface StreamInterface
{
/**
* Support for fopen(), file_get_contents(), file_put_contents() etc.
*
* @param string $uri A string containing the URI to the file to
open.
* @param string $mode The file mode ("r",
"wb" etc.).
* @param int $options A bit mask of STREAM_USE_PATH and
STREAM_REPORT_ERRORS.
* @param string $opened_url A string containing the path actually
opened.
*
* @return bool Returns TRUE if file was opened successfully.
* @see http://php.net/manual/streamwrapper.stream-open.php
*/
public function stream_open($uri, $mode, $options, &$opened_url);
/**
* Support for fclose().
*
* @return bool TRUE if stream was successfully closed.
* @see http://php.net/manual/streamwrapper.stream-close.php
*/
public function stream_close();
/**
* Support for flock().
*
* @param $operation
* One of the following:
* - LOCK_SH to acquire a shared lock (reader).
* - LOCK_EX to acquire an exclusive lock (writer).
* - LOCK_UN to release a lock (shared or exclusive).
* - LOCK_NB if you don't want flock() to block while locking
(not
* supported on Windows).
*
* @return bool Always returns TRUE at the present time.
* @see http://php.net/manual/streamwrapper.stream-lock.php
*/
public function stream_lock($operation);
/**
* Support for touch(), chmod(), chown(), chgrp().
*
* @param $path
* The file path or URL to set metadata. Note that in the case of a
URL, it must be a :// delimited URL.
* Other URL forms are not supported.
*
* @param $option
* One of:
* - STREAM_META_TOUCH The method was called in response to
touch()
* - STREAM_META_OWNER_NAME The method was called in response to
chown() with string parameter
* - STREAM_META_OWNER The method was called in response to
chown()
* - STREAM_META_GROUP_NAME The method was called in response to
chgrp()
* - STREAM_META_GROUP The method was called in response to
chgrp()
* - STREAM_META_ACCESS The method was called in response to
chmod()
*
* @param $value
* If option is
* - STREAM_META_TOUCH: Array consisting of two arguments
of the touch() function.
* - STREAM_META_OWNER_NAME or
* STREAM_META_GROUP_NAME: The name of the owner user/group as
string.
* - STREAM_META_OWNER or
* STREAM_META_GROUP: The value owner user/group argument
as integer.
* - STREAM_META_ACCESS: The argument of the chmod() as
integer.
*
* @return bool
* @see http://php.net/manual/en/streamwrapper.stream-metadata.php
*/
public function stream_metadata($path, $option, $value);
/**
* Support for fread(), file_get_contents() etc.
*
* @param $count
* Maximum number of bytes to be read.
*
* @return string|bool The string that was read, or FALSE in case of an
error.
* @see http://php.net/manual/streamwrapper.stream-read.php
*/
public function stream_read($count);
/**
* Support for fwrite(), file_put_contents() etc.
*
* @param $data
* The string to be written.
*
* @return int The number of bytes written (integer).
* @see http://php.net/manual/streamwrapper.stream-write.php
*/
public function stream_write($data);
/**
* Support for feof().
*
* @return bool TRUE if end-of-file has been reached.
* @see http://php.net/manual/streamwrapper.stream-eof.php
*/
public function stream_eof();
/**
* Support for fseek().
*
* @param $offset
* The byte offset to got to.
* @param $whence
* SEEK_SET, SEEK_CUR, or SEEK_END.
*
* @return bool TRUE on success.
* @see http://php.net/manual/streamwrapper.stream-seek.php
*/
public function stream_seek($offset, $whence);
/**
* Support for fflush().
*
* @return bool TRUE if data was successfully stored (or there was no
data to store).
* @see http://php.net/manual/streamwrapper.stream-flush.php
*/
public function stream_flush();
/**
* Support for ftell().
*
* @return int The current offset in bytes from the beginning of file.
* @see http://php.net/manual/streamwrapper.stream-tell.php
*/
public function stream_tell();
/**
* Support for fstat().
*
* @return array An array with file status, or FALSE in case of an
error - see fstat()
* @see http://php.net/manual/streamwrapper.stream-stat.php
*/
public function stream_stat();
/**
* Support for stream_set_option
* - stream_set_blocking()
* - stream_set_timeout()
* - stream_set_write_buffer()
*
* @param int $option
* @param int $arg1
* @param int $arg2
* @return bool
*
* @see http://php.net/manual/streamwrapper.stream-set-option.php
*/
public function stream_set_option($option, $arg1, $arg2);
/**
* Support for unlink().
*
* @param $uri
* A string containing the URI to the resource to delete.
*
* @return
* TRUE if resource was successfully deleted.
* @see http://php.net/manual/streamwrapper.unlink.php
*/
public function unlink($uri);
/**
* Support for rename().
*
* @param $from_uri ,
* The URI to the file to rename.
* @param $to_uri
* The new URI for file.
*
* @return bool TRUE if file was successfully renamed.
* @see http://php.net/manual/streamwrapper.rename.php
*/
public function rename($from_uri, $to_uri);
/**
* Support for mkdir().
*
* @param $uri
* A string containing the URI to the directory to create.
* @param $mode
* Permission flags - see mkdir().
* @param $options
* A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE.
*
* @return bool TRUE if directory was successfully created.
* @see http://php.net/manual/streamwrapper.mkdir.php
*/
public function mkdir($uri, $mode, $options);
/**
* Support for rmdir().
*
* @param $uri
* A string containing the URI to the directory to delete.
* @param $options
* A bit mask of STREAM_REPORT_ERRORS.
*
* @return
* TRUE if directory was successfully removed.
*
* @see http://php.net/manual/streamwrapper.rmdir.php
*/
public function rmdir($uri, $options);
/**
* Support for stat().
*
* @param $uri
* A string containing the URI to get information about.
* @param $flags
* A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
*
* @return array An array with file status, or FALSE in case of an
error - see fstat()
* @see http://php.net/manual/streamwrapper.url-stat.php
*/
public function url_stat($uri, $flags);
/**
* Support for opendir().
*
* @param $uri
* A string containing the URI to the directory to open.
* @param $options
* Unknown (parameter is not documented in PHP Manual).
*
* @return bool TRUE on success.
* @see http://php.net/manual/streamwrapper.dir-opendir.php
*/
public function dir_opendir($uri, $options);
/**
* Support for readdir().
*
* @return string The next filename, or FALSE if there are no more
files in the directory.
* @see http://php.net/manual/streamwrapper.dir-readdir.php
*/
public function dir_readdir();
/**
* Support for rewinddir().
*
* @return bool TRUE on success.
* @see http://php.net/manual/streamwrapper.dir-rewinddir.php
*/
public function dir_rewinddir();
/**
* Support for closedir().
*
* @return bool TRUE on success.
* @see http://php.net/manual/streamwrapper.dir-closedir.php
*/
public function dir_closedir();
}
PK-d�[[��~oo-vendor/symfony/event-dispatcher/composer.jsonnu�[���{
"name": "symfony/event-dispatcher",
"type": "library",
"description": "Symfony EventDispatcher Component",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/config": "^2.0.5|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0",
"psr/log": "~1.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
}
}
PK-d�[�N��Avendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Lazily loads listeners and subscribers from the dependency injection
* container.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Jordan Alliot <jordan.alliot@gmail.com>
*/
class ContainerAwareEventDispatcher extends EventDispatcher
{
private $container;
/**
* The service IDs of the event listeners and subscribers.
*/
private $listenerIds = array();
/**
* The services registered as listeners.
*/
private $listeners = array();
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Adds a service as event listener.
*
* @param string $eventName Event for which the listener is added
* @param array $callback The service ID of the listener service
& the method
* name that has to be called
* @param int $priority The higher this value, the earlier an event
listener
* will be triggered in the chain.
* Defaults to 0.
*
* @throws \InvalidArgumentException
*/
public function addListenerService($eventName, $callback, $priority =
0)
{
if (!\is_array($callback) || 2 !== \count($callback)) {
throw new \InvalidArgumentException('Expected an
array("service", "method") argument');
}
$this->listenerIds[$eventName][] = array($callback[0],
$callback[1], $priority);
}
public function removeListener($eventName, $listener)
{
$this->lazyLoad($eventName);
if (isset($this->listenerIds[$eventName])) {
foreach ($this->listenerIds[$eventName] as $i => $args) {
list($serviceId, $method) = $args;
$key = $serviceId.'.'.$method;
if (isset($this->listeners[$eventName][$key]) &&
$listener === array($this->listeners[$eventName][$key], $method)) {
unset($this->listeners[$eventName][$key]);
if (empty($this->listeners[$eventName])) {
unset($this->listeners[$eventName]);
}
unset($this->listenerIds[$eventName][$i]);
if (empty($this->listenerIds[$eventName])) {
unset($this->listenerIds[$eventName]);
}
}
}
}
parent::removeListener($eventName, $listener);
}
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null)
{
if (null === $eventName) {
return $this->listenerIds || $this->listeners ||
parent::hasListeners();
}
if (isset($this->listenerIds[$eventName])) {
return true;
}
return parent::hasListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null)
{
if (null === $eventName) {
foreach ($this->listenerIds as $serviceEventName =>
$args) {
$this->lazyLoad($serviceEventName);
}
} else {
$this->lazyLoad($eventName);
}
return parent::getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
{
$this->lazyLoad($eventName);
return parent::getListenerPriority($eventName, $listener);
}
/**
* Adds a service as event subscriber.
*
* @param string $serviceId The service ID of the subscriber service
* @param string $class The service's class name (which must
implement EventSubscriberInterface)
*/
public function addSubscriberService($serviceId, $class)
{
foreach ($class::getSubscribedEvents() as $eventName => $params)
{
if (\is_string($params)) {
$this->listenerIds[$eventName][] = array($serviceId,
$params, 0);
} elseif (\is_string($params[0])) {
$this->listenerIds[$eventName][] = array($serviceId,
$params[0], isset($params[1]) ? $params[1] : 0);
} else {
foreach ($params as $listener) {
$this->listenerIds[$eventName][] = array($serviceId,
$listener[0], isset($listener[1]) ? $listener[1] : 0);
}
}
}
}
public function getContainer()
{
return $this->container;
}
/**
* Lazily loads listeners for this event from the dependency injection
* container.
*
* @param string $eventName The name of the event to dispatch. The name
of
* the event is the name of the method that is
* invoked on listeners.
*/
protected function lazyLoad($eventName)
{
if (isset($this->listenerIds[$eventName])) {
foreach ($this->listenerIds[$eventName] as $args) {
list($serviceId, $method, $priority) = $args;
$listener = $this->container->get($serviceId);
$key = $serviceId.'.'.$method;
if (!isset($this->listeners[$eventName][$key])) {
$this->addListener($eventName, array($listener,
$method), $priority);
} elseif ($this->listeners[$eventName][$key] !==
$listener) {
parent::removeListener($eventName,
array($this->listeners[$eventName][$key], $method));
$this->addListener($eventName, array($listener,
$method), $priority);
}
$this->listeners[$eventName][$key] = $listener;
}
}
}
}
PK-d�[O�S�I,I,Bvendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher\Debug;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* Collects some data about event listeners.
*
* This event dispatcher delegates the dispatching to another one.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TraceableEventDispatcher implements TraceableEventDispatcherInterface
{
protected $logger;
protected $stopwatch;
private $called;
private $dispatcher;
private $wrappedListeners;
public function __construct(EventDispatcherInterface $dispatcher,
Stopwatch $stopwatch, LoggerInterface $logger = null)
{
$this->dispatcher = $dispatcher;
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->called = array();
$this->wrappedListeners = array();
}
/**
* {@inheritdoc}
*/
public function addListener($eventName, $listener, $priority = 0)
{
$this->dispatcher->addListener($eventName, $listener,
$priority);
}
/**
* {@inheritdoc}
*/
public function addSubscriber(EventSubscriberInterface $subscriber)
{
$this->dispatcher->addSubscriber($subscriber);
}
/**
* {@inheritdoc}
*/
public function removeListener($eventName, $listener)
{
if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index =>
$wrappedListener) {
if ($wrappedListener->getWrappedListener() ===
$listener) {
$listener = $wrappedListener;
unset($this->wrappedListeners[$eventName][$index]);
break;
}
}
}
return $this->dispatcher->removeListener($eventName,
$listener);
}
/**
* {@inheritdoc}
*/
public function removeSubscriber(EventSubscriberInterface $subscriber)
{
return $this->dispatcher->removeSubscriber($subscriber);
}
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
{
if (!method_exists($this->dispatcher,
'getListenerPriority')) {
return 0;
}
return $this->dispatcher->getListenerPriority($eventName,
$listener);
}
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function dispatch($eventName, Event $event = null)
{
if (null === $event) {
$event = new Event();
}
if (null !== $this->logger &&
$event->isPropagationStopped()) {
$this->logger->debug(sprintf('The "%s"
event is already stopped. No listeners have been called.',
$eventName));
}
$this->preProcess($eventName);
$this->preDispatch($eventName, $event);
$e = $this->stopwatch->start($eventName,
'section');
$this->dispatcher->dispatch($eventName, $event);
if ($e->isStarted()) {
$e->stop();
}
$this->postDispatch($eventName, $event);
$this->postProcess($eventName);
return $event;
}
/**
* {@inheritdoc}
*/
public function getCalledListeners()
{
$called = array();
foreach ($this->called as $eventName => $listeners) {
foreach ($listeners as $listener) {
$info =
$this->getListenerInfo($listener->getWrappedListener(), $eventName);
$called[$eventName.'.'.$info['pretty']]
= $info;
}
}
return $called;
}
/**
* {@inheritdoc}
*/
public function getNotCalledListeners()
{
try {
$allListeners = $this->getListeners();
} catch (\Exception $e) {
if (null !== $this->logger) {
$this->logger->info('An exception was thrown
while getting the uncalled listeners.', array('exception'
=> $e));
}
// unable to retrieve the uncalled listeners
return array();
}
$notCalled = array();
foreach ($allListeners as $eventName => $listeners) {
foreach ($listeners as $listener) {
$called = false;
if (isset($this->called[$eventName])) {
foreach ($this->called[$eventName] as $l) {
if ($l->getWrappedListener() === $listener) {
$called = true;
break;
}
}
}
if (!$called) {
$info = $this->getListenerInfo($listener,
$eventName);
$notCalled[$eventName.'.'.$info['pretty']] = $info;
}
}
}
uasort($notCalled, array($this,
'sortListenersByPriority'));
return $notCalled;
}
/**
* Proxies all method calls to the original event dispatcher.
*
* @param string $method The method name
* @param array $arguments The method arguments
*
* @return mixed
*/
public function __call($method, $arguments)
{
return \call_user_func_array(array($this->dispatcher, $method),
$arguments);
}
/**
* Called before dispatching the event.
*
* @param string $eventName The event name
* @param Event $event The event
*/
protected function preDispatch($eventName, Event $event)
{
}
/**
* Called after dispatching the event.
*
* @param string $eventName The event name
* @param Event $event The event
*/
protected function postDispatch($eventName, Event $event)
{
}
private function preProcess($eventName)
{
foreach ($this->dispatcher->getListeners($eventName) as
$listener) {
$info = $this->getListenerInfo($listener, $eventName);
$name = isset($info['class']) ?
$info['class'] : $info['type'];
$wrappedListener = new WrappedListener($listener, $name,
$this->stopwatch, $this);
$this->wrappedListeners[$eventName][] = $wrappedListener;
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName,
$wrappedListener, $info['priority']);
}
}
private function postProcess($eventName)
{
unset($this->wrappedListeners[$eventName]);
$skipped = false;
foreach ($this->dispatcher->getListeners($eventName) as
$listener) {
if (!$listener instanceof WrappedListener) { // #12845: a new
listener was added during dispatch.
continue;
}
// Unwrap listener
$priority = $this->getListenerPriority($eventName,
$listener);
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName,
$listener->getWrappedListener(), $priority);
$info =
$this->getListenerInfo($listener->getWrappedListener(), $eventName);
if ($listener->wasCalled()) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Notified event
"%s" to listener "%s".', $eventName,
$info['pretty']));
}
if (!isset($this->called[$eventName])) {
$this->called[$eventName] = new \SplObjectStorage();
}
$this->called[$eventName]->attach($listener);
}
if (null !== $this->logger && $skipped) {
$this->logger->debug(sprintf('Listener
"%s" was not called for event "%s".',
$info['pretty'], $eventName));
}
if ($listener->stoppedPropagation()) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Listener
"%s" stopped propagation of the event "%s".',
$info['pretty'], $eventName));
}
$skipped = true;
}
}
}
/**
* Returns information about the listener.
*
* @param object $listener The listener
* @param string $eventName The event name
*
* @return array Information about the listener
*/
private function getListenerInfo($listener, $eventName)
{
$info = array(
'event' => $eventName,
'priority' =>
$this->getListenerPriority($eventName, $listener),
);
// unwrap for correct listener info
if ($listener instanceof WrappedListener) {
$listener = $listener->getWrappedListener();
}
if ($listener instanceof \Closure) {
$info += array(
'type' => 'Closure',
'pretty' => 'closure',
);
} elseif (\is_string($listener)) {
try {
$r = new \ReflectionFunction($listener);
$file = $r->getFileName();
$line = $r->getStartLine();
} catch (\ReflectionException $e) {
$file = null;
$line = null;
}
$info += array(
'type' => 'Function',
'function' => $listener,
'file' => $file,
'line' => $line,
'pretty' => $listener,
);
} elseif (\is_array($listener) || (\is_object($listener) &&
\is_callable($listener))) {
if (!\is_array($listener)) {
$listener = array($listener, '__invoke');
}
$class = \is_object($listener[0]) ? \get_class($listener[0]) :
$listener[0];
try {
$r = new \ReflectionMethod($class, $listener[1]);
$file = $r->getFileName();
$line = $r->getStartLine();
} catch (\ReflectionException $e) {
$file = null;
$line = null;
}
$info += array(
'type' => 'Method',
'class' => $class,
'method' => $listener[1],
'file' => $file,
'line' => $line,
'pretty' =>
$class.'::'.$listener[1],
);
}
return $info;
}
private function sortListenersByPriority($a, $b)
{
if (\is_int($a['priority']) &&
!\is_int($b['priority'])) {
return 1;
}
if (!\is_int($a['priority']) &&
\is_int($b['priority'])) {
return -1;
}
if ($a['priority'] === $b['priority']) {
return 0;
}
if ($a['priority'] > $b['priority']) {
return -1;
}
return 1;
}
}
PK-d�[�Ӗc##Kvendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher\Debug;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
interface TraceableEventDispatcherInterface extends
EventDispatcherInterface
{
/**
* Gets the called listeners.
*
* @return array An array of called listeners
*/
public function getCalledListeners();
/**
* Gets the not called listeners.
*
* @return array An array of not called listeners
*/
public function getNotCalledListeners();
}
PK-d�[�4���9vendor/symfony/event-dispatcher/Debug/WrappedListener.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher\Debug;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class WrappedListener
{
private $listener;
private $name;
private $called;
private $stoppedPropagation;
private $stopwatch;
private $dispatcher;
public function __construct($listener, $name, Stopwatch $stopwatch,
EventDispatcherInterface $dispatcher = null)
{
$this->listener = $listener;
$this->name = $name;
$this->stopwatch = $stopwatch;
$this->dispatcher = $dispatcher;
$this->called = false;
$this->stoppedPropagation = false;
}
public function getWrappedListener()
{
return $this->listener;
}
public function wasCalled()
{
return $this->called;
}
public function stoppedPropagation()
{
return $this->stoppedPropagation;
}
public function __invoke(Event $event, $eventName,
EventDispatcherInterface $dispatcher)
{
$this->called = true;
$e = $this->stopwatch->start($this->name,
'event_listener');
\call_user_func($this->listener, $event, $eventName,
$this->dispatcher ?: $dispatcher);
if ($e->isStarted()) {
$e->stop();
}
if ($event->isPropagationStopped()) {
$this->stoppedPropagation = true;
}
}
}
PK-d�[q$z��Mvendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Compiler pass to register tagged services for an event dispatcher.
*/
class RegisterListenersPass implements CompilerPassInterface
{
protected $dispatcherService;
protected $listenerTag;
protected $subscriberTag;
/**
* @param string $dispatcherService Service name of the event
dispatcher in processed container
* @param string $listenerTag Tag name used for listener
* @param string $subscriberTag Tag name used for subscribers
*/
public function __construct($dispatcherService =
'event_dispatcher', $listenerTag =
'kernel.event_listener', $subscriberTag =
'kernel.event_subscriber')
{
$this->dispatcherService = $dispatcherService;
$this->listenerTag = $listenerTag;
$this->subscriberTag = $subscriberTag;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->dispatcherService)
&& !$container->hasAlias($this->dispatcherService)) {
return;
}
$definition =
$container->findDefinition($this->dispatcherService);
foreach ($container->findTaggedServiceIds($this->listenerTag)
as $id => $events) {
$def = $container->getDefinition($id);
if (!$def->isPublic()) {
throw new \InvalidArgumentException(sprintf('The
service "%s" must be public as event listeners are
lazy-loaded.', $id));
}
if ($def->isAbstract()) {
throw new \InvalidArgumentException(sprintf('The
service "%s" must not be abstract as event listeners are
lazy-loaded.', $id));
}
foreach ($events as $event) {
$priority = isset($event['priority']) ?
$event['priority'] : 0;
if (!isset($event['event'])) {
throw new
\InvalidArgumentException(sprintf('Service "%s" must define
the "event" attribute on "%s" tags.', $id,
$this->listenerTag));
}
if (!isset($event['method'])) {
$event['method'] =
'on'.preg_replace_callback(array(
'/(?<=\b)[a-z]/i',
'/[^a-z0-9]/i',
), function ($matches) { return
strtoupper($matches[0]); }, $event['event']);
$event['method'] =
preg_replace('/[^a-z0-9]/i', '',
$event['method']);
}
$definition->addMethodCall('addListenerService',
array($event['event'], array($id, $event['method']),
$priority));
}
}
foreach
($container->findTaggedServiceIds($this->subscriberTag) as $id =>
$attributes) {
$def = $container->getDefinition($id);
if (!$def->isPublic()) {
throw new \InvalidArgumentException(sprintf('The
service "%s" must be public as event subscribers are
lazy-loaded.', $id));
}
if ($def->isAbstract()) {
throw new \InvalidArgumentException(sprintf('The
service "%s" must not be abstract as event subscribers are
lazy-loaded.', $id));
}
// We must assume that the class value has been correctly
filled, even if the service is created by a factory
$class =
$container->getParameterBag()->resolveValue($def->getClass());
$interface =
'Symfony\Component\EventDispatcher\EventSubscriberInterface';
if (!is_subclass_of($class, $interface)) {
if (!class_exists($class, false)) {
throw new \InvalidArgumentException(sprintf('Class
"%s" used for service "%s" cannot be found.',
$class, $id));
}
throw new \InvalidArgumentException(sprintf('Service
"%s" must implement interface "%s".', $id,
$interface));
}
$definition->addMethodCall('addSubscriberService',
array($id, $class));
}
}
}
PK-d�[�P��
�
)vendor/symfony/event-dispatcher/Event.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* Event is the base class for classes containing event data.
*
* This class contains no event data. It is used by events that do not pass
* state information to an event handler when an event is raised.
*
* You can call the method stopPropagation() to abort the execution of
* further listeners in your event listener.
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class Event
{
/**
* @var bool Whether no further event listeners should be triggered
*/
private $propagationStopped = false;
/**
* @var EventDispatcherInterface Dispatcher that dispatched this event
*/
private $dispatcher;
/**
* @var string This event's name
*/
private $name;
/**
* Returns whether further event listeners should be triggered.
*
* @see Event::stopPropagation()
*
* @return bool Whether propagation was already stopped for this event
*/
public function isPropagationStopped()
{
return $this->propagationStopped;
}
/**
* Stops the propagation of the event to further event listeners.
*
* If multiple event listeners are connected to the same event, no
* further event listener will be triggered once any trigger calls
* stopPropagation().
*/
public function stopPropagation()
{
$this->propagationStopped = true;
}
/**
* Stores the EventDispatcher that dispatches this Event.
*
* @param EventDispatcherInterface $dispatcher
*
* @deprecated since version 2.4, to be removed in 3.0. The event
dispatcher is passed to the listener call.
*/
public function setDispatcher(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* Returns the EventDispatcher that dispatches this Event.
*
* @return EventDispatcherInterface
*
* @deprecated since version 2.4, to be removed in 3.0. The event
dispatcher is passed to the listener call.
*/
public function getDispatcher()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since Symfony 2.4 and will be removed in 3.0. The event
dispatcher instance can be received in the listener call instead.',
E_USER_DEPRECATED);
return $this->dispatcher;
}
/**
* Gets the event's name.
*
* @return string
*
* @deprecated since version 2.4, to be removed in 3.0. The event name
is passed to the listener call.
*/
public function getName()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since Symfony 2.4 and will be removed in 3.0. The event name can
be received in the listener call instead.', E_USER_DEPRECATED);
return $this->name;
}
/**
* Sets the event's name property.
*
* @param string $name The event name
*
* @deprecated since version 2.4, to be removed in 3.0. The event name
is passed to the listener call.
*/
public function setName($name)
{
$this->name = $name;
}
}
PK-d�[�93vendor/symfony/event-dispatcher/EventDispatcher.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* The EventDispatcherInterface is the central point of Symfony's
event listener system.
*
* Listeners are registered on the manager and events are dispatched
through the
* manager.
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Jordan Alliot <jordan.alliot@gmail.com>
*/
class EventDispatcher implements EventDispatcherInterface
{
private $listeners = array();
private $sorted = array();
/**
* {@inheritdoc}
*/
public function dispatch($eventName, Event $event = null)
{
if (null === $event) {
$event = new Event();
}
$event->setDispatcher($this);
$event->setName($eventName);
if ($listeners = $this->getListeners($eventName)) {
$this->doDispatch($listeners, $eventName, $event);
}
return $event;
}
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null)
{
if (null !== $eventName) {
if (!isset($this->listeners[$eventName])) {
return array();
}
if (!isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}
return $this->sorted[$eventName];
}
foreach ($this->listeners as $eventName => $eventListeners) {
if (!isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}
}
return array_filter($this->sorted);
}
/**
* Gets the listener priority for a specific event.
*
* Returns null if the event or the listener does not exist.
*
* @param string $eventName The name of the event
* @param callable $listener The listener
*
* @return int|null The event listener priority
*/
public function getListenerPriority($eventName, $listener)
{
if (!isset($this->listeners[$eventName])) {
return;
}
foreach ($this->listeners[$eventName] as $priority =>
$listeners) {
if (false !== \in_array($listener, $listeners, true)) {
return $priority;
}
}
}
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null)
{
return (bool) $this->getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function addListener($eventName, $listener, $priority = 0)
{
$this->listeners[$eventName][$priority][] = $listener;
unset($this->sorted[$eventName]);
}
/**
* {@inheritdoc}
*/
public function removeListener($eventName, $listener)
{
if (!isset($this->listeners[$eventName])) {
return;
}
foreach ($this->listeners[$eventName] as $priority =>
$listeners) {
if (false !== ($key = array_search($listener, $listeners,
true))) {
unset($this->listeners[$eventName][$priority][$key],
$this->sorted[$eventName]);
}
}
}
/**
* {@inheritdoc}
*/
public function addSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName =>
$params) {
if (\is_string($params)) {
$this->addListener($eventName, array($subscriber,
$params));
} elseif (\is_string($params[0])) {
$this->addListener($eventName, array($subscriber,
$params[0]), isset($params[1]) ? $params[1] : 0);
} else {
foreach ($params as $listener) {
$this->addListener($eventName, array($subscriber,
$listener[0]), isset($listener[1]) ? $listener[1] : 0);
}
}
}
}
/**
* {@inheritdoc}
*/
public function removeSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName =>
$params) {
if (\is_array($params) && \is_array($params[0])) {
foreach ($params as $listener) {
$this->removeListener($eventName, array($subscriber,
$listener[0]));
}
} else {
$this->removeListener($eventName, array($subscriber,
\is_string($params) ? $params : $params[0]));
}
}
}
/**
* Triggers the listeners of an event.
*
* This method can be overridden to add functionality that is executed
* for each listener.
*
* @param callable[] $listeners The event listeners
* @param string $eventName The name of the event to dispatch
* @param Event $event The event object to pass to the event
handlers/listeners
*/
protected function doDispatch($listeners, $eventName, Event $event)
{
foreach ($listeners as $listener) {
if ($event->isPropagationStopped()) {
break;
}
\call_user_func($listener, $event, $eventName, $this);
}
}
/**
* Sorts the internal list of listeners for the given event by
priority.
*
* @param string $eventName The name of the event
*/
private function sortListeners($eventName)
{
krsort($this->listeners[$eventName]);
$this->sorted[$eventName] =
\call_user_func_array('array_merge',
$this->listeners[$eventName]);
}
}
PK-d�[WHC��
�
<vendor/symfony/event-dispatcher/EventDispatcherInterface.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* The EventDispatcherInterface is the central point of Symfony's
event listener system.
* Listeners are registered on the manager and events are dispatched
through the
* manager.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface EventDispatcherInterface
{
/**
* Dispatches an event to all registered listeners.
*
* @param string $eventName The name of the event to dispatch. The name
of
* the event is the name of the method that is
* invoked on listeners.
* @param Event $event The event to pass to the event
handlers/listeners
* If not supplied, an empty Event instance is
created
*
* @return Event
*/
public function dispatch($eventName, Event $event = null);
/**
* Adds an event listener that listens on the specified events.
*
* @param string $eventName The event to listen on
* @param callable $listener The listener
* @param int $priority The higher this value, the earlier an
event
* listener will be triggered in the chain
(defaults to 0)
*/
public function addListener($eventName, $listener, $priority = 0);
/**
* Adds an event subscriber.
*
* The subscriber is asked for all the events he is
* interested in and added as a listener for these events.
*/
public function addSubscriber(EventSubscriberInterface $subscriber);
/**
* Removes an event listener from the specified events.
*
* @param string $eventName The event to remove a listener from
* @param callable $listener The listener to remove
*/
public function removeListener($eventName, $listener);
public function removeSubscriber(EventSubscriberInterface $subscriber);
/**
* Gets the listeners of a specific event or all listeners sorted by
descending priority.
*
* @param string $eventName The name of the event
*
* @return array The event listeners for the specified event, or all
event listeners by event name
*/
public function getListeners($eventName = null);
/**
* Checks whether an event has any registered listeners.
*
* @param string $eventName The name of the event
*
* @return bool true if the specified event has any listeners, false
otherwise
*/
public function hasListeners($eventName = null);
}
PK-d�[���<vendor/symfony/event-dispatcher/EventSubscriberInterface.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* An EventSubscriber knows himself what events he is interested in.
* If an EventSubscriber is added to an EventDispatcherInterface, the
manager invokes
* {@link getSubscribedEvents} and registers the subscriber as a listener
for all
* returned events.
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface EventSubscriberInterface
{
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and
respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName',
$priority))
* * array('eventName' =>
array(array('methodName1', $priority),
array('methodName2')))
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents();
}
PK-d�[��d�{{0vendor/symfony/event-dispatcher/GenericEvent.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* Event encapsulation class.
*
* Encapsulates events thus decoupling the observer from the subject they
encapsulate.
*
* @author Drak <drak@zikula.org>
*/
class GenericEvent extends Event implements \ArrayAccess,
\IteratorAggregate
{
protected $subject;
protected $arguments;
/**
* Encapsulate an event with $subject and $args.
*
* @param mixed $subject The subject of the event, usually an object
or a callable
* @param array $arguments Arguments to store in the event
*/
public function __construct($subject = null, array $arguments =
array())
{
$this->subject = $subject;
$this->arguments = $arguments;
}
/**
* Getter for subject property.
*
* @return mixed The observer subject
*/
public function getSubject()
{
return $this->subject;
}
/**
* Get argument by key.
*
* @param string $key Key
*
* @return mixed Contents of array key
*
* @throws \InvalidArgumentException if key is not found
*/
public function getArgument($key)
{
if ($this->hasArgument($key)) {
return $this->arguments[$key];
}
throw new \InvalidArgumentException(sprintf('Argument
"%s" not found.', $key));
}
/**
* Add argument to event.
*
* @param string $key Argument name
* @param mixed $value Value
*
* @return $this
*/
public function setArgument($key, $value)
{
$this->arguments[$key] = $value;
return $this;
}
/**
* Getter for all arguments.
*
* @return array
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Set args property.
*
* @param array $args Arguments
*
* @return $this
*/
public function setArguments(array $args = array())
{
$this->arguments = $args;
return $this;
}
/**
* Has argument.
*
* @param string $key Key of arguments array
*
* @return bool
*/
public function hasArgument($key)
{
return array_key_exists($key, $this->arguments);
}
/**
* ArrayAccess for argument getter.
*
* @param string $key Array key
*
* @return mixed
*
* @throws \InvalidArgumentException if key does not exist in
$this->args
*/
public function offsetGet($key)
{
return $this->getArgument($key);
}
/**
* ArrayAccess for argument setter.
*
* @param string $key Array key to set
* @param mixed $value Value
*/
public function offsetSet($key, $value)
{
$this->setArgument($key, $value);
}
/**
* ArrayAccess for unset argument.
*
* @param string $key Array key
*/
public function offsetUnset($key)
{
if ($this->hasArgument($key)) {
unset($this->arguments[$key]);
}
}
/**
* ArrayAccess has argument.
*
* @param string $key Array key
*
* @return bool
*/
public function offsetExists($key)
{
return $this->hasArgument($key);
}
/**
* IteratorAggregate for iterating over the object like an array.
*
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->arguments);
}
}
PK-d�[�_~~<vendor/symfony/event-dispatcher/ImmutableEventDispatcher.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* A read-only proxy for an event dispatcher.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ImmutableEventDispatcher implements EventDispatcherInterface
{
private $dispatcher;
public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* {@inheritdoc}
*/
public function dispatch($eventName, Event $event = null)
{
return $this->dispatcher->dispatch($eventName, $event);
}
/**
* {@inheritdoc}
*/
public function addListener($eventName, $listener, $priority = 0)
{
throw new \BadMethodCallException('Unmodifiable event
dispatchers must not be modified.');
}
/**
* {@inheritdoc}
*/
public function addSubscriber(EventSubscriberInterface $subscriber)
{
throw new \BadMethodCallException('Unmodifiable event
dispatchers must not be modified.');
}
/**
* {@inheritdoc}
*/
public function removeListener($eventName, $listener)
{
throw new \BadMethodCallException('Unmodifiable event
dispatchers must not be modified.');
}
/**
* {@inheritdoc}
*/
public function removeSubscriber(EventSubscriberInterface $subscriber)
{
throw new \BadMethodCallException('Unmodifiable event
dispatchers must not be modified.');
}
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
{
return $this->dispatcher->getListenerPriority($eventName,
$listener);
}
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}
}
PK-d�[�01�+vendor/symfony/polyfill-ctype/bootstrap.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Polyfill\Ctype as p;
if (!function_exists('ctype_alnum')) {
function ctype_alnum($input) { return p\Ctype::ctype_alnum($input); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha($input) { return p\Ctype::ctype_alpha($input); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl($input) { return p\Ctype::ctype_cntrl($input); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit($input) { return p\Ctype::ctype_digit($input); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph($input) { return p\Ctype::ctype_graph($input); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower($input) { return p\Ctype::ctype_lower($input); }
}
if (!function_exists('ctype_print')) {
function ctype_print($input) { return p\Ctype::ctype_print($input); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct($input) { return p\Ctype::ctype_punct($input); }
}
if (!function_exists('ctype_space')) {
function ctype_space($input) { return p\Ctype::ctype_space($input); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper($input) { return p\Ctype::ctype_upper($input); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit($input) { return p\Ctype::ctype_xdigit($input); }
}
PK-d�[��-���+vendor/symfony/polyfill-ctype/composer.jsonnu�[���{
"name": "symfony/polyfill-ctype",
"type": "library",
"description": "Symfony polyfill for ctype
functions",
"keywords": ["polyfill", "compatibility",
"portable", "ctype"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.3"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Ctype\\":
"" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-ctype": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.19-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url":
"https://github.com/symfony/polyfill"
}
}
}
PK-d�[\��}}'vendor/symfony/polyfill-ctype/Ctype.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Polyfill\Ctype;
/**
* Ctype implementation through regex.
*
* @internal
*
* @author Gert de Pagter <BackEndTea@gmail.com>
*/
final class Ctype
{
/**
* Returns TRUE if every character in text is either a letter or a
digit, FALSE otherwise.
*
* @see https://php.net/ctype-alnum
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_alnum($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^A-Za-z0-9]/', $text);
}
/**
* Returns TRUE if every character in text is a letter, FALSE
otherwise.
*
* @see https://php.net/ctype-alpha
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_alpha($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^A-Za-z]/', $text);
}
/**
* Returns TRUE if every character in text is a control character from
the current locale, FALSE otherwise.
*
* @see https://php.net/ctype-cntrl
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_cntrl($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^\x00-\x1f\x7f]/', $text);
}
/**
* Returns TRUE if every character in the string text is a decimal
digit, FALSE otherwise.
*
* @see https://php.net/ctype-digit
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_digit($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^0-9]/', $text);
}
/**
* Returns TRUE if every character in text is printable and actually
creates visible output (no white space), FALSE otherwise.
*
* @see https://php.net/ctype-graph
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_graph($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^!-~]/', $text);
}
/**
* Returns TRUE if every character in text is a lowercase letter.
*
* @see https://php.net/ctype-lower
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_lower($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^a-z]/', $text);
}
/**
* Returns TRUE if every character in text will actually create output
(including blanks). Returns FALSE if text contains control characters or
characters that do not have any output or control function at all.
*
* @see https://php.net/ctype-print
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_print($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^ -~]/', $text);
}
/**
* Returns TRUE if every character in text is printable, but neither
letter, digit or blank, FALSE otherwise.
*
* @see https://php.net/ctype-punct
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_punct($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
}
/**
* Returns TRUE if every character in text creates some sort of white
space, FALSE otherwise. Besides the blank character this also includes tab,
vertical tab, line feed, carriage return and form feed characters.
*
* @see https://php.net/ctype-space
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_space($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^\s]/', $text);
}
/**
* Returns TRUE if every character in text is an uppercase letter.
*
* @see https://php.net/ctype-upper
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_upper($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^A-Z]/', $text);
}
/**
* Returns TRUE if every character in text is a hexadecimal
'digit', that is a decimal digit or a character from [A-Fa-f] ,
FALSE otherwise.
*
* @see https://php.net/ctype-xdigit
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_xdigit($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text
&& !preg_match('/[^A-Fa-f0-9]/', $text);
}
/**
* Converts integers to their char versions according to normal ctype
behaviour, if needed.
*
* If an integer between -128 and 255 inclusive is provided,
* it is interpreted as the ASCII value of a single character
* (negative values have 256 added in order to allow characters in the
Extended ASCII range).
* Any other integer is interpreted as a string containing the decimal
digits of the integer.
*
* @param string|int $int
*
* @return mixed
*/
private static function convert_int_to_char_for_ctype($int)
{
if (!\is_int($int)) {
return $int;
}
if ($int < -128 || $int > 255) {
return (string) $int;
}
if ($int < 0) {
$int += 256;
}
return \chr($int);
}
}
PK-d�[�!vendor/symfony/yaml/composer.jsonnu�[���{
"name": "symfony/yaml",
"type": "library",
"description": "Symfony Yaml Component",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage":
"https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.9",
"symfony/polyfill-ctype": "~1.8"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Yaml\\":
"" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
}
}
PK-d�[&�� � vendor/symfony/yaml/Dumper.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
/**
* Dumper dumps PHP variables to YAML strings.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Dumper
{
/**
* The amount of spaces to use for indentation of nested nodes.
*
* @var int
*/
protected $indentation = 4;
/**
* Sets the indentation.
*
* @param int $num The amount of spaces to use for indentation of
nested nodes
*/
public function setIndentation($num)
{
if ($num < 1) {
throw new \InvalidArgumentException('The indentation must
be greater than zero.');
}
$this->indentation = (int) $num;
}
/**
* Dumps a PHP value to YAML.
*
* @param mixed $input The PHP value
* @param int $inline The level where you switch to
inline YAML
* @param int $indent The level of indentation (used
internally)
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
*
* @return string The YAML representation of the PHP value
*/
public function dump($input, $inline = 0, $indent = 0,
$exceptionOnInvalidType = false, $objectSupport = false)
{
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) :
'';
if ($inline <= 0 || !\is_array($input) || empty($input)) {
$output .= $prefix.Inline::dump($input,
$exceptionOnInvalidType, $objectSupport);
} else {
$isAHash = Inline::isHash($input);
foreach ($input as $key => $value) {
$willBeInlined = $inline - 1 <= 0 || !\is_array($value)
|| empty($value);
$output .= sprintf('%s%s%s%s',
$prefix,
$isAHash ? Inline::dump($key, $exceptionOnInvalidType,
$objectSupport).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0
: $indent + $this->indentation, $exceptionOnInvalidType, $objectSupport)
).($willBeInlined ? "\n" : '');
}
}
return $output;
}
}
PK-d�[�hhvendor/symfony/yaml/Escaper.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
/**
* Escaper encapsulates escaping rules for single and double-quoted
* YAML strings.
*
* @author Matthew Lewinski <matthew@lewinski.org>
*
* @internal
*/
class Escaper
{
// Characters that would cause a dumped string to require double
quoting.
const REGEX_CHARACTER_TO_ESCAPE =
"[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";
// Mapping arrays for escaping a double quoted string. The backslash is
// first to ensure proper escaping because str_replace operates
iteratively
// on the input arrays. This ordering of the characters avoids the use
of strtr,
// which performs more slowly.
private static $escapees = array('\\', '\\\\',
'\\"', '"',
"\x00", "\x01",
"\x02", "\x03", "\x04", "\x05",
"\x06", "\x07",
"\x08", "\x09",
"\x0a", "\x0b", "\x0c", "\x0d",
"\x0e", "\x0f",
"\x10", "\x11",
"\x12", "\x13", "\x14", "\x15",
"\x16", "\x17",
"\x18", "\x19",
"\x1a", "\x1b", "\x1c", "\x1d",
"\x1e", "\x1f",
"\xc2\x85",
"\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9",
);
private static $escaped = array('\\\\', '\\"',
'\\\\', '\\"',
'\\0', '\\x01',
'\\x02', '\\x03', '\\x04', '\\x05',
'\\x06', '\\a',
'\\b', '\\t',
'\\n', '\\v', '\\f', '\\r',
'\\x0e', '\\x0f',
'\\x10', '\\x11',
'\\x12', '\\x13', '\\x14', '\\x15',
'\\x16', '\\x17',
'\\x18', '\\x19',
'\\x1a', '\\e', '\\x1c', '\\x1d',
'\\x1e', '\\x1f',
'\\N', '\\_',
'\\L', '\\P',
);
/**
* Determines if a PHP value would require double quoting in YAML.
*
* @param string $value A PHP value
*
* @return bool True if the value would require double quotes
*/
public static function requiresDoubleQuoting($value)
{
return 0 <
preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u',
$value);
}
/**
* Escapes and surrounds a PHP value with double quotes.
*
* @param string $value A PHP value
*
* @return string The quoted, escaped string
*/
public static function escapeWithDoubleQuotes($value)
{
return sprintf('"%s"',
str_replace(self::$escapees, self::$escaped, $value));
}
/**
* Determines if a PHP value would require single quoting in YAML.
*
* @param string $value A PHP value
*
* @return bool True if the value would require single quotes
*/
public static function requiresSingleQuoting($value)
{
// Determines if a PHP value is entirely composed of a value that
would
// require single quoting in YAML.
if (\in_array(strtolower($value), array('null',
'~', 'true', 'false', 'y',
'n', 'yes', 'no', 'on',
'off'))) {
return true;
}
// Determines if the PHP value contains any single characters that
would
// cause it to require single quoting in YAML.
return 0 < preg_match('/[ \s \' " \: \{ \} \[ \]
, & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value);
}
/**
* Escapes and surrounds a PHP value with single quotes.
*
* @param string $value A PHP value
*
* @return string The quoted, escaped string
*/
public static function escapeWithSingleQuotes($value)
{
return sprintf("'%s'",
str_replace('\'', '\'\'', $value));
}
}
PK-d�[���/vendor/symfony/yaml/Exception/DumpException.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml\Exception;
/**
* Exception class thrown when an error occurs during dumping.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DumpException extends RuntimeException
{
}
PK-d�[�^KA��4vendor/symfony/yaml/Exception/ExceptionInterface.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml\Exception;
/**
* Exception interface for all exceptions thrown by the component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ExceptionInterface
{
}
PK-d�[�c��
�
0vendor/symfony/yaml/Exception/ParseException.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml\Exception;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ParseException extends RuntimeException
{
private $parsedFile;
private $parsedLine;
private $snippet;
private $rawMessage;
/**
* @param string $message The error message
* @param int $parsedLine The line where the error occurred
* @param string|null $snippet The snippet of code near the
problem
* @param string|null $parsedFile The file name where the error
occurred
* @param \Exception|null $previous The previous exception
*/
public function __construct($message, $parsedLine = -1, $snippet =
null, $parsedFile = null, \Exception $previous = null)
{
$this->parsedFile = $parsedFile;
$this->parsedLine = $parsedLine;
$this->snippet = $snippet;
$this->rawMessage = $message;
$this->updateRepr();
parent::__construct($this->message, 0, $previous);
}
/**
* Gets the snippet of code near the error.
*
* @return string The snippet of code
*/
public function getSnippet()
{
return $this->snippet;
}
/**
* Sets the snippet of code near the error.
*
* @param string $snippet The code snippet
*/
public function setSnippet($snippet)
{
$this->snippet = $snippet;
$this->updateRepr();
}
/**
* Gets the filename where the error occurred.
*
* This method returns null if a string is parsed.
*
* @return string The filename
*/
public function getParsedFile()
{
return $this->parsedFile;
}
/**
* Sets the filename where the error occurred.
*
* @param string $parsedFile The filename
*/
public function setParsedFile($parsedFile)
{
$this->parsedFile = $parsedFile;
$this->updateRepr();
}
/**
* Gets the line where the error occurred.
*
* @return int The file line
*/
public function getParsedLine()
{
return $this->parsedLine;
}
/**
* Sets the line where the error occurred.
*
* @param int $parsedLine The file line
*/
public function setParsedLine($parsedLine)
{
$this->parsedLine = $parsedLine;
$this->updateRepr();
}
private function updateRepr()
{
$this->message = $this->rawMessage;
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
if (null !== $this->parsedFile) {
if (\PHP_VERSION_ID >= 50400) {
$jsonOptions = JSON_UNESCAPED_SLASHES |
JSON_UNESCAPED_UNICODE;
} else {
$jsonOptions = 0;
}
$this->message .= sprintf(' in %s',
json_encode($this->parsedFile, $jsonOptions));
}
if ($this->parsedLine >= 0) {
$this->message .= sprintf(' at line %d',
$this->parsedLine);
}
if ($this->snippet) {
$this->message .= sprintf(' (near
"%s")', $this->snippet);
}
if ($dot) {
$this->message .= '.';
}
}
}
PK-d�[�_q���2vendor/symfony/yaml/Exception/RuntimeException.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml\Exception;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Romain Neutron <imprec@gmail.com>
*/
class RuntimeException extends \RuntimeException implements
ExceptionInterface
{
}
PK-d�[}�S]�W�Wvendor/symfony/yaml/Inline.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Exception\DumpException;
use Symfony\Component\Yaml\Exception\ParseException;
/**
* Inline implements a YAML parser/dumper for the YAML inline syntax.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Inline
{
const REGEX_QUOTED_STRING =
'(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
private static $exceptionOnInvalidType = false;
private static $objectSupport = false;
private static $objectForMap = false;
/**
* Converts a YAML string to a PHP value.
*
* @param string $value A YAML string
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
* @param array $references Mapping of variable names to
values
*
* @return mixed A PHP value
*
* @throws ParseException
*/
public static function parse($value, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false, $references = array())
{
self::$exceptionOnInvalidType = $exceptionOnInvalidType;
self::$objectSupport = $objectSupport;
self::$objectForMap = $objectForMap;
$value = trim($value);
if ('' === $value) {
return '';
}
if (2 /* MB_OVERLOAD_STRING */ & (int)
ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
$i = 0;
switch ($value[0]) {
case '[':
$result = self::parseSequence($value, $i, $references);
++$i;
break;
case '{':
$result = self::parseMapping($value, $i, $references);
++$i;
break;
default:
$result = self::parseScalar($value, null,
array('"', "'"), $i, true, $references);
}
// some comments are allowed at the end
if (preg_replace('/\s+#.*$/A', '',
substr($value, $i))) {
throw new ParseException(sprintf('Unexpected characters
near "%s".', substr($value, $i)));
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return $result;
}
/**
* Dumps a given PHP variable to a YAML string.
*
* @param mixed $value The PHP variable to convert
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
*
* @return string The YAML string representing the PHP value
*
* @throws DumpException When trying to dump PHP resource
*/
public static function dump($value, $exceptionOnInvalidType = false,
$objectSupport = false)
{
switch (true) {
case \is_resource($value):
if ($exceptionOnInvalidType) {
throw new DumpException(sprintf('Unable to dump
PHP resources in a YAML file ("%s").',
get_resource_type($value)));
}
return 'null';
case \is_object($value):
if ($objectSupport) {
return '!php/object:'.serialize($value);
}
if ($exceptionOnInvalidType) {
throw new DumpException('Object support when
dumping a YAML file has been disabled.');
}
return 'null';
case \is_array($value):
return self::dumpArray($value, $exceptionOnInvalidType,
$objectSupport);
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case ctype_digit($value):
return \is_string($value) ? "'$value'"
: (int) $value;
case is_numeric($value):
$locale = setlocale(LC_NUMERIC, 0);
if (false !== $locale) {
setlocale(LC_NUMERIC, 'C');
}
if (\is_float($value)) {
$repr = (string) $value;
if (is_infinite($value)) {
$repr = str_ireplace('INF',
'.Inf', $repr);
} elseif (floor($value) == $value && $repr ==
$value) {
// Preserve float data type since storing a whole
number will result in integer value.
$repr = '!!float '.$repr;
}
} else {
$repr = \is_string($value) ?
"'$value'" : (string) $value;
}
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
return $repr;
case '' == $value:
return "''";
case Escaper::requiresDoubleQuoting($value):
return Escaper::escapeWithDoubleQuotes($value);
case Escaper::requiresSingleQuoting($value):
case Parser::preg_match(self::getHexRegex(), $value):
case Parser::preg_match(self::getTimestampRegex(), $value):
return Escaper::escapeWithSingleQuotes($value);
default:
return $value;
}
}
/**
* Check if given array is hash or just normal indexed array.
*
* @internal
*
* @param array $value The PHP array to check
*
* @return bool true if value is hash array, false otherwise
*/
public static function isHash(array $value)
{
$expectedKey = 0;
foreach ($value as $key => $val) {
if ($key !== $expectedKey++) {
return true;
}
}
return false;
}
/**
* Dumps a PHP array to a YAML string.
*
* @param array $value The PHP array to dump
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
*
* @return string The YAML string representing the PHP array
*/
private static function dumpArray($value, $exceptionOnInvalidType,
$objectSupport)
{
// array
if ($value && !self::isHash($value)) {
$output = array();
foreach ($value as $val) {
$output[] = self::dump($val, $exceptionOnInvalidType,
$objectSupport);
}
return sprintf('[%s]', implode(', ',
$output));
}
// hash
$output = array();
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key,
$exceptionOnInvalidType, $objectSupport), self::dump($val,
$exceptionOnInvalidType, $objectSupport));
}
return sprintf('{ %s }', implode(', ',
$output));
}
/**
* Parses a YAML scalar.
*
* @param string $scalar
* @param string[] $delimiters
* @param string[] $stringDelimiters
* @param int &$i
* @param bool $evaluate
* @param array $references
*
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*
* @internal
*/
public static function parseScalar($scalar, $delimiters = null,
$stringDelimiters = array('"', "'"), &$i
= 0, $evaluate = true, $references = array())
{
if (\in_array($scalar[$i], $stringDelimiters)) {
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), ' ');
if ('' === $tmp) {
throw new ParseException(sprintf('Unexpected end
of line, expected one of "%s".', implode('',
$delimiters)));
}
if (!\in_array($tmp[0], $delimiters)) {
throw new ParseException(sprintf('Unexpected
characters (%s).', substr($scalar, $i)));
}
}
} else {
// "normal" string
if (!$delimiters) {
$output = substr($scalar, $i);
$i += \strlen($output);
// remove comments
if (Parser::preg_match('/[ \t]+#/', $output,
$match, PREG_OFFSET_CAPTURE)) {
$output = substr($output, 0, $match[0][1]);
}
} elseif
(Parser::preg_match('/^(.+?)('.implode('|',
$delimiters).')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += \strlen($output);
} else {
throw new ParseException(sprintf('Malformed inline
YAML string: %s.', $scalar));
}
// a non-quoted string cannot start with @ or ` (reserved) nor
with a scalar indicator (| or >)
if ($output && ('@' === $output[0] ||
'`' === $output[0] || '|' === $output[0] ||
'>' === $output[0])) {
@trigger_error(sprintf('Not quoting the scalar
"%s" starting with "%s" is deprecated since Symfony 2.8
and will throw a ParseException in 3.0.', $output, $output[0]),
E_USER_DEPRECATED);
// to be thrown in 3.0
// throw new ParseException(sprintf('The reserved
indicator "%s" cannot start a plain scalar; you need to quote the
scalar.', $output[0]));
}
if ($evaluate) {
$output = self::evaluateScalar($output, $references);
}
}
return $output;
}
/**
* Parses a YAML quoted scalar.
*
* @param string $scalar
* @param int &$i
*
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseQuotedScalar($scalar, &$i)
{
if
(!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au',
substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML
string: %s.', substr($scalar, $i)));
}
$output = substr($match[0], 1, \strlen($match[0]) - 2);
$unescaper = new Unescaper();
if ('"' == $scalar[$i]) {
$output = $unescaper->unescapeDoubleQuotedString($output);
} else {
$output = $unescaper->unescapeSingleQuotedString($output);
}
$i += \strlen($match[0]);
return $output;
}
/**
* Parses a YAML sequence.
*
* @param string $sequence
* @param int &$i
* @param array $references
*
* @return array
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseSequence($sequence, &$i = 0,
$references = array())
{
$output = array();
$len = \strlen($sequence);
++$i;
// [foo, bar, ...]
while ($i < $len) {
switch ($sequence[$i]) {
case '[':
// nested sequence
$output[] = self::parseSequence($sequence, $i,
$references);
break;
case '{':
// nested mapping
$output[] = self::parseMapping($sequence, $i,
$references);
break;
case ']':
return $output;
case ',':
case ' ':
break;
default:
$isQuoted = \in_array($sequence[$i],
array('"', "'"));
$value = self::parseScalar($sequence,
array(',', ']'), array('"',
"'"), $i, true, $references);
// the value can be an array if a reference has been
resolved to an array var
if (!\is_array($value) && !$isQuoted &&
false !== strpos($value, ': ')) {
// embedded mapping?
try {
$pos = 0;
$value =
self::parseMapping('{'.$value.'}', $pos, $references);
} catch (\InvalidArgumentException $e) {
// no, it's not
}
}
$output[] = $value;
--$i;
}
++$i;
}
throw new ParseException(sprintf('Malformed inline YAML
string: %s.', $sequence));
}
/**
* Parses a YAML mapping.
*
* @param string $mapping
* @param int &$i
* @param array $references
*
* @return array|\stdClass
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseMapping($mapping, &$i = 0, $references
= array())
{
$output = array();
$len = \strlen($mapping);
++$i;
$allowOverwrite = false;
// {foo: bar, bar:foo, ...}
while ($i < $len) {
switch ($mapping[$i]) {
case ' ':
case ',':
++$i;
continue 2;
case '}':
if (self::$objectForMap) {
return (object) $output;
}
return $output;
}
// key
$key = self::parseScalar($mapping, array(':', '
'), array('"', "'"), $i, false);
if ('<<' === $key) {
$allowOverwrite = true;
}
// value
$done = false;
while ($i < $len) {
switch ($mapping[$i]) {
case '[':
// nested sequence
$value = self::parseSequence($mapping, $i,
$references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since
lines
// are processed sequentially.
// But overwriting is allowed when a merge node is
used in current block.
if ('<<' === $key) {
foreach ($value as $parsedValue) {
$output += $parsedValue;
}
} elseif ($allowOverwrite || !isset($output[$key]))
{
$output[$key] = $value;
}
$done = true;
break;
case '{':
// nested mapping
$value = self::parseMapping($mapping, $i,
$references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since
lines
// are processed sequentially.
// But overwriting is allowed when a merge node is
used in current block.
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key]))
{
$output[$key] = $value;
}
$done = true;
break;
case ':':
case ' ':
break;
default:
$value = self::parseScalar($mapping,
array(',', '}'), array('"',
"'"), $i, true, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since
lines
// are processed sequentially.
// But overwriting is allowed when a merge node is
used in current block.
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key]))
{
$output[$key] = $value;
}
$done = true;
--$i;
}
++$i;
if ($done) {
continue 2;
}
}
}
throw new ParseException(sprintf('Malformed inline YAML
string: %s.', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
* @param array $references
*
* @return mixed The evaluated YAML string
*
* @throws ParseException when object parsing support was disabled and
the parser detected a PHP object or when a reference could not be resolved
*/
private static function evaluateScalar($scalar, $references = array())
{
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);
if (0 === strpos($scalar, '*')) {
if (false !== $pos = strpos($scalar, '#')) {
$value = substr($scalar, 1, $pos - 2);
} else {
$value = substr($scalar, 1);
}
// an unquoted *
if (false === $value || '' === $value) {
throw new ParseException('A reference must contain at
least one character.');
}
if (!array_key_exists($value, $references)) {
throw new ParseException(sprintf('Reference
"%s" does not exist.', $value));
}
return $references[$value];
}
switch (true) {
case 'null' === $scalarLower:
case '' === $scalar:
case '~' === $scalar:
return;
case 'true' === $scalarLower:
return true;
case 'false' === $scalarLower:
return false;
// Optimise for returning strings.
case '+' === $scalar[0] || '-' ===
$scalar[0] || '.' === $scalar[0] || '!' === $scalar[0]
|| is_numeric($scalar[0]):
switch (true) {
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return (int) self::parseScalar(substr($scalar, 2));
case 0 === strpos($scalar, '!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 12));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support
when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 13));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support
when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
case ctype_digit($scalar):
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[0] ?
octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case '-' === $scalar[0] &&
ctype_digit(substr($scalar, 1)):
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[1] ?
octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
case Parser::preg_match(self::getHexRegex(), $scalar):
return '0x' === $scalar[0].$scalar[1] ?
hexdec($scalar) : (float) $scalar;
case '.inf' === $scalarLower:
case '.nan' === $scalarLower:
return -log(0);
case '-.inf' === $scalarLower:
return log(0);
case
Parser::preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return (float) str_replace(',',
'', $scalar);
case Parser::preg_match(self::getTimestampRegex(),
$scalar):
$timeZone = date_default_timezone_get();
date_default_timezone_set('UTC');
$time = strtotime($scalar);
date_default_timezone_set($timeZone);
return $time;
}
// no break
default:
return (string) $scalar;
}
}
/**
* Gets a regex that matches a YAML date.
*
* @return string The regular expression
*
* @see http://www.yaml.org/spec/1.2/spec.html#id2761573
*/
private static function getTimestampRegex()
{
return <<<EOF
~^
(?P<year>[0-9][0-9][0-9][0-9])
-(?P<month>[0-9][0-9]?)
-(?P<day>[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P<hour>[0-9][0-9]?)
:(?P<minute>[0-9][0-9])
:(?P<second>[0-9][0-9])
(?:\.(?P<fraction>[0-9]*))?
(?:[
\t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
$~x
EOF;
}
/**
* Gets a regex that matches a YAML number in hexadecimal notation.
*
* @return string
*/
private static function getHexRegex()
{
return '~^0x[0-9a-f]++$~i';
}
}
PK-d�[�B^(7�7�vendor/symfony/yaml/Parser.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;
/**
* Parser parses YAML strings to convert them to PHP arrays.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Parser
{
const BLOCK_SCALAR_HEADER_PATTERN =
'(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments>
+#.*)?';
// BC - wrongly named
const FOLDED_SCALAR_PATTERN = self::BLOCK_SCALAR_HEADER_PATTERN;
private $offset = 0;
private $totalNumberOfLines;
private $lines = array();
private $currentLineNb = -1;
private $currentLine = '';
private $refs = array();
private $skippedLineNumbers = array();
private $locallySkippedLineNumbers = array();
/**
* @param int $offset The offset of YAML document
(used for line numbers in error messages)
* @param int|null $totalNumberOfLines The overall number of lines
being parsed
* @param int[] $skippedLineNumbers Number of comment lines that
have been skipped by the parser
*/
public function __construct($offset = 0, $totalNumberOfLines = null,
array $skippedLineNumbers = array())
{
$this->offset = $offset;
$this->totalNumberOfLines = $totalNumberOfLines;
$this->skippedLineNumbers = $skippedLineNumbers;
}
/**
* Parses a YAML string to a PHP value.
*
* @param string $value A YAML string
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
*
* @return mixed A PHP value
*
* @throws ParseException If the YAML is not valid
*/
public function parse($value, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false)
{
if (false === preg_match('//u', $value)) {
throw new ParseException('The YAML value does not appear
to be valid UTF-8.');
}
$this->refs = array();
$mbEncoding = null;
$e = null;
$data = null;
if (2 /* MB_OVERLOAD_STRING */ & (int)
ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}
try {
$data = $this->doParse($value, $exceptionOnInvalidType,
$objectSupport, $objectForMap);
} catch (\Exception $e) {
} catch (\Throwable $e) {
}
if (null !== $mbEncoding) {
mb_internal_encoding($mbEncoding);
}
$this->lines = array();
$this->currentLine = '';
$this->refs = array();
$this->skippedLineNumbers = array();
$this->locallySkippedLineNumbers = array();
if (null !== $e) {
throw $e;
}
return $data;
}
private function doParse($value, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false)
{
$this->currentLineNb = -1;
$this->currentLine = '';
$value = $this->cleanup($value);
$this->lines = explode("\n", $value);
$this->locallySkippedLineNumbers = array();
if (null === $this->totalNumberOfLines) {
$this->totalNumberOfLines = \count($this->lines);
}
$data = array();
$context = null;
$allowOverwrite = false;
while ($this->moveToNextLine()) {
if ($this->isCurrentLineEmpty()) {
continue;
}
// tab?
if ("\t" === $this->currentLine[0]) {
throw new ParseException('A YAML file cannot contain
tabs as indentation.', $this->getRealCurrentLineNb() + 1,
$this->currentLine);
}
$isRef = $mergeNode = false;
if
(self::preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+))?$#u',
rtrim($this->currentLine), $values)) {
if ($context && 'mapping' == $context) {
throw new ParseException('You cannot define a
sequence item when in a mapping', $this->getRealCurrentLineNb() +
1, $this->currentLine);
}
$context = 'sequence';
if (isset($values['value']) &&
self::preg_match('#^&(?P<ref>[^ ]+)
*(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] =
$matches['value'];
}
// array
if (!isset($values['value']) || '' ==
trim($values['value'], ' ') || 0 ===
strpos(ltrim($values['value'], ' '), '#')) {
$data[] =
$this->parseBlock($this->getRealCurrentLineNb() + 1,
$this->getNextEmbedBlock(null, true), $exceptionOnInvalidType,
$objectSupport, $objectForMap);
} else {
if (isset($values['leadspaces'])
&&
self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^
\'"\{\[].*?) *\:(\s+(?P<value>.+))?$#u',
rtrim($values['value']), $matches)
) {
// this is a compact notation element, add to next
block and parse
$block = $values['value'];
if ($this->isNextLineIndented()) {
$block .=
"\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation()
+ \strlen($values['leadspaces']) + 1);
}
$data[] =
$this->parseBlock($this->getRealCurrentLineNb(), $block,
$exceptionOnInvalidType, $objectSupport, $objectForMap);
} else {
$data[] =
$this->parseValue($values['value'], $exceptionOnInvalidType,
$objectSupport, $objectForMap, $context);
}
}
if ($isRef) {
$this->refs[$isRef] = end($data);
}
} elseif (
self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^
\'"\[\{].*?) *\:(\s+(?P<value>.+))?$#u',
rtrim($this->currentLine), $values)
&& (false === strpos($values['key'],
' #') || \in_array($values['key'][0],
array('"', "'")))
) {
if ($context && 'sequence' == $context) {
throw new ParseException('You cannot define a
mapping item when in a sequence', $this->currentLineNb + 1,
$this->currentLine);
}
$context = 'mapping';
// force correct settings
Inline::parse(null, $exceptionOnInvalidType,
$objectSupport, $objectForMap, $this->refs);
try {
$key = Inline::parseScalar($values['key']);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() +
1);
$e->setSnippet($this->currentLine);
throw $e;
}
// Convert float keys to strings, to avoid being converted
to integers by PHP
if (\is_float($key)) {
$key = (string) $key;
}
if ('<<' === $key &&
(!isset($values['value']) ||
!self::preg_match('#^&(?P<ref>[^ ]+)#u',
$values['value'], $refMatches))) {
$mergeNode = true;
$allowOverwrite = true;
if (isset($values['value']) && 0 ===
strpos($values['value'], '*')) {
$refName = substr($values['value'], 1);
if (!array_key_exists($refName, $this->refs)) {
throw new
ParseException(sprintf('Reference "%s" does not
exist.', $refName), $this->getRealCurrentLineNb() + 1,
$this->currentLine);
}
$refValue = $this->refs[$refName];
if (!\is_array($refValue)) {
throw new ParseException('YAML merge keys
used with a scalar value instead of an array.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
$data += $refValue; // array union
} else {
if (isset($values['value']) &&
'' !== $values['value']) {
$value = $values['value'];
} else {
$value = $this->getNextEmbedBlock();
}
$parsed =
$this->parseBlock($this->getRealCurrentLineNb() + 1, $value,
$exceptionOnInvalidType, $objectSupport, $objectForMap);
if (!\is_array($parsed)) {
throw new ParseException('YAML merge keys
used with a scalar value instead of an array.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
if (isset($parsed[0])) {
// If the value associated with the merge key
is a sequence, then this sequence is expected to contain mapping nodes
// and each of these nodes is merged in turn
according to its order in the sequence. Keys in mapping nodes earlier
// in the sequence override keys specified in
later mapping nodes.
foreach ($parsed as $parsedItem) {
if (!\is_array($parsedItem)) {
throw new ParseException('Merge
items must be arrays.', $this->getRealCurrentLineNb() + 1,
$parsedItem);
}
$data += $parsedItem; // array union
}
} else {
// If the value associated with the key is a
single mapping node, each of its key/value pairs is inserted into the
// current mapping, unless the key already
exists in it.
$data += $parsed; // array union
}
}
} elseif ('<<' !== $key &&
isset($values['value']) &&
self::preg_match('#^&(?P<ref>[^ ]+)
*(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] =
$matches['value'];
}
if ($mergeNode) {
// Merge keys
} elseif (!isset($values['value']) ||
'' == trim($values['value'], ' ') || 0 ===
strpos(ltrim($values['value'], ' '), '#') ||
'<<' === $key) {
// hash
// if next line is less indented or equal, then it
means that the current value is null
if (!$this->isNextLineIndented() &&
!$this->isNextLineUnIndentedCollection()) {
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node is
used in current block.
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = null;
}
} else {
$value =
$this->parseBlock($this->getRealCurrentLineNb() + 1,
$this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport,
$objectForMap);
if ('<<' === $key) {
$this->refs[$refMatches['ref']] =
$value;
$data += $value;
} elseif ($allowOverwrite || !isset($data[$key])) {
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node
is used in current block.
$data[$key] = $value;
}
}
} else {
$value =
$this->parseValue($values['value'], $exceptionOnInvalidType,
$objectSupport, $objectForMap, $context);
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node is used
in current block.
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
}
}
if ($isRef) {
$this->refs[$isRef] = $data[$key];
}
} else {
// multiple documents are not supported
if ('---' === $this->currentLine) {
throw new ParseException('Multiple documents are
not supported.', $this->currentLineNb + 1, $this->currentLine);
}
// 1-liner optionally followed by newline(s)
if (\is_string($value) && $this->lines[0] ===
trim($value)) {
try {
$value = Inline::parse($this->lines[0],
$exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
return $value;
}
throw new ParseException('Unable to parse.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}
if ($objectForMap && !\is_object($data) &&
'mapping' === $context) {
$object = new \stdClass();
foreach ($data as $key => $value) {
$object->$key = $value;
}
$data = $object;
}
return empty($data) ? null : $data;
}
private function parseBlock($offset, $yaml, $exceptionOnInvalidType,
$objectSupport, $objectForMap)
{
$skippedLineNumbers = $this->skippedLineNumbers;
foreach ($this->locallySkippedLineNumbers as $lineNumber) {
if ($lineNumber < $offset) {
continue;
}
$skippedLineNumbers[] = $lineNumber;
}
$parser = new self($offset, $this->totalNumberOfLines,
$skippedLineNumbers);
$parser->refs = &$this->refs;
return $parser->doParse($yaml, $exceptionOnInvalidType,
$objectSupport, $objectForMap);
}
/**
* Returns the current line number (takes the offset into account).
*
* @return int The current line number
*/
private function getRealCurrentLineNb()
{
$realCurrentLineNumber = $this->currentLineNb +
$this->offset;
foreach ($this->skippedLineNumbers as $skippedLineNumber) {
if ($skippedLineNumber > $realCurrentLineNumber) {
break;
}
++$realCurrentLineNumber;
}
return $realCurrentLineNumber;
}
/**
* Returns the current line indentation.
*
* @return int The current line indentation
*/
private function getCurrentLineIndentation()
{
return \strlen($this->currentLine) -
\strlen(ltrim($this->currentLine, ' '));
}
/**
* Returns the next embed block of YAML.
*
* @param int $indentation The indent level at which the block is to
be read, or null for default
* @param bool $inSequence True if the enclosing data structure is a
sequence
*
* @return string A YAML string
*
* @throws ParseException When indentation problem are detected
*/
private function getNextEmbedBlock($indentation = null, $inSequence =
false)
{
$oldLineIndentation = $this->getCurrentLineIndentation();
$blockScalarIndentations = array();
if ($this->isBlockScalarHeader()) {
$blockScalarIndentations[] =
$this->getCurrentLineIndentation();
}
if (!$this->moveToNextLine()) {
return;
}
if (null === $indentation) {
$newIndent = $this->getCurrentLineIndentation();
$unindentedEmbedBlock =
$this->isStringUnIndentedCollectionItem();
if (!$this->isCurrentLineEmpty() && 0 === $newIndent
&& !$unindentedEmbedBlock) {
throw new ParseException('Indentation problem.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
} else {
$newIndent = $indentation;
}
$data = array();
if ($this->getCurrentLineIndentation() >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} else {
$this->moveToPreviousLine();
return;
}
if ($inSequence && $oldLineIndentation === $newIndent
&& isset($data[0][0]) && '-' === $data[0][0]) {
// the previous line contained a dash but no item content, this
line is a sequence item with the same indentation
// and therefore no nested list or mapping
$this->moveToPreviousLine();
return;
}
$isItUnindentedCollection =
$this->isStringUnIndentedCollectionItem();
if (empty($blockScalarIndentations) &&
$this->isBlockScalarHeader()) {
$blockScalarIndentations[] =
$this->getCurrentLineIndentation();
}
$previousLineIndentation = $this->getCurrentLineIndentation();
while ($this->moveToNextLine()) {
$indent = $this->getCurrentLineIndentation();
// terminate all block scalars that are more indented than the
current line
if (!empty($blockScalarIndentations) && $indent <
$previousLineIndentation && '' !==
trim($this->currentLine)) {
foreach ($blockScalarIndentations as $key =>
$blockScalarIndentation) {
if ($blockScalarIndentation >=
$this->getCurrentLineIndentation()) {
unset($blockScalarIndentations[$key]);
}
}
}
if (empty($blockScalarIndentations) &&
!$this->isCurrentLineComment() &&
$this->isBlockScalarHeader()) {
$blockScalarIndentations[] =
$this->getCurrentLineIndentation();
}
$previousLineIndentation = $indent;
if ($isItUnindentedCollection &&
!$this->isCurrentLineEmpty() &&
!$this->isStringUnIndentedCollectionItem() && $newIndent ===
$indent) {
$this->moveToPreviousLine();
break;
}
if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
continue;
}
// we ignore "comment" lines only when we are not
inside a scalar block
if (empty($blockScalarIndentations) &&
$this->isCurrentLineComment()) {
// remember ignored comment lines (they are used later in
nested
// parser calls to determine real line numbers)
//
// CAUTION: beware to not populate the global property here
as it
// will otherwise influence the getRealCurrentLineNb() call
here
// for consecutive comment lines and subsequent embedded
blocks
$this->locallySkippedLineNumbers[] =
$this->getRealCurrentLineNb();
continue;
}
if ($indent >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} elseif (0 == $indent) {
$this->moveToPreviousLine();
break;
} else {
throw new ParseException('Indentation problem.',
$this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}
return implode("\n", $data);
}
/**
* Moves the parser to the next line.
*
* @return bool
*/
private function moveToNextLine()
{
if ($this->currentLineNb >= \count($this->lines) - 1) {
return false;
}
$this->currentLine = $this->lines[++$this->currentLineNb];
return true;
}
/**
* Moves the parser to the previous line.
*
* @return bool
*/
private function moveToPreviousLine()
{
if ($this->currentLineNb < 1) {
return false;
}
$this->currentLine = $this->lines[--$this->currentLineNb];
return true;
}
/**
* Parses a YAML value.
*
* @param string $value A YAML value
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
* @param string $context The parser context (either
sequence or mapping)
*
* @return mixed A PHP value
*
* @throws ParseException When reference does not exist
*/
private function parseValue($value, $exceptionOnInvalidType,
$objectSupport, $objectForMap, $context)
{
if (0 === strpos($value, '*')) {
if (false !== $pos = strpos($value, '#')) {
$value = substr($value, 1, $pos - 2);
} else {
$value = substr($value, 1);
}
if (!array_key_exists($value, $this->refs)) {
throw new ParseException(sprintf('Reference
"%s" does not exist.', $value), $this->currentLineNb + 1,
$this->currentLine);
}
return $this->refs[$value];
}
if
(self::preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/',
$value, $matches)) {
$modifiers = isset($matches['modifiers']) ?
$matches['modifiers'] : '';
return
$this->parseBlockScalar($matches['separator'],
preg_replace('#\d+#', '', $modifiers), (int)
abs($modifiers));
}
try {
$parsedValue = Inline::parse($value, $exceptionOnInvalidType,
$objectSupport, $objectForMap, $this->refs);
if ('mapping' === $context &&
'"' !== $value[0] && "'" !==
$value[0] && '[' !== $value[0] && '{'
!== $value[0] && '!' !== $value[0] && false !==
strpos($parsedValue, ': ')) {
@trigger_error(sprintf('Using a colon in the unquoted
mapping value "%s" in line %d is deprecated since Symfony 2.8 and
will throw a ParseException in 3.0.', $value,
$this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED);
// to be thrown in 3.0
// throw new ParseException('A colon cannot be used in
an unquoted mapping value.');
}
return $parsedValue;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
}
/**
* Parses a block scalar.
*
* @param string $style The style indicator that was used to
begin this block scalar (| or >)
* @param string $chomping The chomping indicator that was used to
begin this block scalar (+ or -)
* @param int $indentation The indentation indicator that was used
to begin this block scalar
*
* @return string The text value
*/
private function parseBlockScalar($style, $chomping = '',
$indentation = 0)
{
$notEOF = $this->moveToNextLine();
if (!$notEOF) {
return '';
}
$isCurrentLineBlank = $this->isCurrentLineBlank();
$blockLines = array();
// leading blank lines are consumed before determining indentation
while ($notEOF && $isCurrentLineBlank) {
// newline only if not EOF
if ($notEOF = $this->moveToNextLine()) {
$blockLines[] = '';
$isCurrentLineBlank = $this->isCurrentLineBlank();
}
}
// determine indentation if not specified
if (0 === $indentation) {
if (self::preg_match('/^ +/', $this->currentLine,
$matches)) {
$indentation = \strlen($matches[0]);
}
}
if ($indentation > 0) {
$pattern = sprintf('/^ {%d}(.*)$/', $indentation);
while (
$notEOF && (
$isCurrentLineBlank ||
self::preg_match($pattern, $this->currentLine,
$matches)
)
) {
if ($isCurrentLineBlank &&
\strlen($this->currentLine) > $indentation) {
$blockLines[] = substr($this->currentLine,
$indentation);
} elseif ($isCurrentLineBlank) {
$blockLines[] = '';
} else {
$blockLines[] = $matches[1];
}
// newline only if not EOF
if ($notEOF = $this->moveToNextLine()) {
$isCurrentLineBlank = $this->isCurrentLineBlank();
}
}
} elseif ($notEOF) {
$blockLines[] = '';
}
if ($notEOF) {
$blockLines[] = '';
$this->moveToPreviousLine();
} elseif (!$notEOF &&
!$this->isCurrentLineLastLineInDocument()) {
$blockLines[] = '';
}
// folded style
if ('>' === $style) {
$text = '';
$previousLineIndented = false;
$previousLineBlank = false;
for ($i = 0, $blockLinesCount = \count($blockLines); $i <
$blockLinesCount; ++$i) {
if ('' === $blockLines[$i]) {
$text .= "\n";
$previousLineIndented = false;
$previousLineBlank = true;
} elseif (' ' === $blockLines[$i][0]) {
$text .= "\n".$blockLines[$i];
$previousLineIndented = true;
$previousLineBlank = false;
} elseif ($previousLineIndented) {
$text .= "\n".$blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
} elseif ($previousLineBlank || 0 === $i) {
$text .= $blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
} else {
$text .= ' '.$blockLines[$i];
$previousLineIndented = false;
$previousLineBlank = false;
}
}
} else {
$text = implode("\n", $blockLines);
}
// deal with trailing newlines
if ('' === $chomping) {
$text = preg_replace('/\n+$/', "\n",
$text);
} elseif ('-' === $chomping) {
$text = preg_replace('/\n+$/', '', $text);
}
return $text;
}
/**
* Returns true if the next line is indented.
*
* @return bool Returns true if the next line is indented, false
otherwise
*/
private function isNextLineIndented()
{
$currentIndentation = $this->getCurrentLineIndentation();
$EOF = !$this->moveToNextLine();
while (!$EOF && $this->isCurrentLineEmpty()) {
$EOF = !$this->moveToNextLine();
}
if ($EOF) {
return false;
}
$ret = $this->getCurrentLineIndentation() >
$currentIndentation;
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the current line is blank or if it is a comment
line.
*
* @return bool Returns true if the current line is empty or if it is a
comment line, false otherwise
*/
private function isCurrentLineEmpty()
{
return $this->isCurrentLineBlank() ||
$this->isCurrentLineComment();
}
/**
* Returns true if the current line is blank.
*
* @return bool Returns true if the current line is blank, false
otherwise
*/
private function isCurrentLineBlank()
{
return '' == trim($this->currentLine, ' ');
}
/**
* Returns true if the current line is a comment line.
*
* @return bool Returns true if the current line is a comment line,
false otherwise
*/
private function isCurrentLineComment()
{
//checking explicitly the first char of the trim is faster than
loops or strpos
$ltrimmedLine = ltrim($this->currentLine, ' ');
return '' !== $ltrimmedLine && '#' ===
$ltrimmedLine[0];
}
private function isCurrentLineLastLineInDocument()
{
return ($this->offset + $this->currentLineNb) >=
($this->totalNumberOfLines - 1);
}
/**
* Cleanups a YAML string to be parsed.
*
* @param string $value The input YAML string
*
* @return string A cleaned up YAML string
*/
private function cleanup($value)
{
$value = str_replace(array("\r\n", "\r"),
"\n", $value);
// strip YAML header
$count = 0;
$value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u',
'', $value, -1, $count);
$this->offset += $count;
// remove leading comments
$trimmedValue = preg_replace('#^(\#.*?\n)+#s',
'', $value, -1, $count);
if (1 == $count) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") -
substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}
// remove start of the document marker (---)
$trimmedValue = preg_replace('#^\-\-\-.*?\n#s',
'', $value, -1, $count);
if (1 == $count) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") -
substr_count($trimmedValue, "\n");
$value = $trimmedValue;
// remove end of the document marker (...)
$value = preg_replace('#\.\.\.\s*$#', '',
$value);
}
return $value;
}
/**
* Returns true if the next line starts unindented collection.
*
* @return bool Returns true if the next line starts unindented
collection, false otherwise
*/
private function isNextLineUnIndentedCollection()
{
$currentIndentation = $this->getCurrentLineIndentation();
$notEOF = $this->moveToNextLine();
while ($notEOF && $this->isCurrentLineEmpty()) {
$notEOF = $this->moveToNextLine();
}
if (false === $notEOF) {
return false;
}
$ret = $this->getCurrentLineIndentation() ===
$currentIndentation &&
$this->isStringUnIndentedCollectionItem();
$this->moveToPreviousLine();
return $ret;
}
/**
* Returns true if the string is un-indented collection item.
*
* @return bool Returns true if the string is un-indented collection
item, false otherwise
*/
private function isStringUnIndentedCollectionItem()
{
return '-' === rtrim($this->currentLine) || 0 ===
strpos($this->currentLine, '- ');
}
/**
* Tests whether or not the current line is the header of a block
scalar.
*
* @return bool
*/
private function isBlockScalarHeader()
{
return (bool)
self::preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~',
$this->currentLine);
}
/**
* A local wrapper for `preg_match` which will throw a ParseException
if there
* is an internal error in the PCRE engine.
*
* This avoids us needing to check for "false" every time
PCRE is used
* in the YAML engine
*
* @throws ParseException on a PCRE internal error
*
* @see preg_last_error()
*
* @internal
*/
public static function preg_match($pattern, $subject, &$matches =
null, $flags = 0, $offset = 0)
{
if (false === $ret = preg_match($pattern, $subject, $matches,
$flags, $offset)) {
switch (preg_last_error()) {
case PREG_INTERNAL_ERROR:
$error = 'Internal PCRE error.';
break;
case PREG_BACKTRACK_LIMIT_ERROR:
$error = 'pcre.backtrack_limit reached.';
break;
case PREG_RECURSION_LIMIT_ERROR:
$error = 'pcre.recursion_limit reached.';
break;
case PREG_BAD_UTF8_ERROR:
$error = 'Malformed UTF-8 data.';
break;
case PREG_BAD_UTF8_OFFSET_ERROR:
$error = 'Offset doesn\'t correspond to the
begin of a valid UTF-8 code point.';
break;
default:
$error = 'Error.';
}
throw new ParseException($error);
}
return $ret;
}
}
PK-d�["~uNN!vendor/symfony/yaml/Unescaper.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
/**
* Unescaper encapsulates unescaping rules for single and double-quoted
* YAML strings.
*
* @author Matthew Lewinski <matthew@lewinski.org>
*
* @internal
*/
class Unescaper
{
/**
* Parser and Inline assume UTF-8 encoding, so escaped Unicode
characters
* must be converted to that encoding.
*
* @deprecated since version 2.5, to be removed in 3.0
*
* @internal
*/
const ENCODING = 'UTF-8';
/**
* Regex fragment that matches an escaped character in a double quoted
string.
*/
const REGEX_ESCAPED_CHARACTER =
'\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)';
/**
* Unescapes a single quoted string.
*
* @param string $value A single quoted string
*
* @return string The unescaped string
*/
public function unescapeSingleQuotedString($value)
{
return str_replace('\'\'', '\'',
$value);
}
/**
* Unescapes a double quoted string.
*
* @param string $value A double quoted string
*
* @return string The unescaped string
*/
public function unescapeDoubleQuotedString($value)
{
$self = $this;
$callback = function ($match) use ($self) {
return $self->unescapeCharacter($match[0]);
};
// evaluate the string
return
preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u',
$callback, $value);
}
/**
* Unescapes a character that was found in a double-quoted string.
*
* @param string $value An escaped character
*
* @return string The unescaped character
*
* @internal This method is public to be usable as callback. It should
not
* be used in user code. Should be changed in 3.0.
*/
public function unescapeCharacter($value)
{
switch ($value[1]) {
case '0':
return "\x0";
case 'a':
return "\x7";
case 'b':
return "\x8";
case 't':
return "\t";
case "\t":
return "\t";
case 'n':
return "\n";
case 'v':
return "\xB";
case 'f':
return "\xC";
case 'r':
return "\r";
case 'e':
return "\x1B";
case ' ':
return ' ';
case '"':
return '"';
case '/':
return '/';
case '\\':
return '\\';
case 'N':
// U+0085 NEXT LINE
return "\xC2\x85";
case '_':
// U+00A0 NO-BREAK SPACE
return "\xC2\xA0";
case 'L':
// U+2028 LINE SEPARATOR
return "\xE2\x80\xA8";
case 'P':
// U+2029 PARAGRAPH SEPARATOR
return "\xE2\x80\xA9";
case 'x':
return self::utf8chr(hexdec(substr($value, 2, 2)));
case 'u':
return self::utf8chr(hexdec(substr($value, 2, 4)));
case 'U':
return self::utf8chr(hexdec(substr($value, 2, 8)));
default:
@trigger_error('Not escaping a backslash in a
double-quoted string is deprecated since Symfony 2.8 and will throw a
ParseException in 3.0.', E_USER_DEPRECATED);
return $value;
}
}
/**
* Get the UTF-8 character for the given code point.
*
* @param int $c The unicode code point
*
* @return string The corresponding UTF-8 character
*/
private static function utf8chr($c)
{
if (0x80 > $c %= 0x200000) {
return \chr($c);
}
if (0x800 > $c) {
return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
}
if (0x10000 > $c) {
return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6
& 0x3F).\chr(0x80 | $c & 0x3F);
}
return \chr(0xF0 | $c >> 18).\chr(0x80 | $c >> 12 &
0x3F).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
}
}
PK-d�[�l���vendor/symfony/yaml/Yaml.phpnu�[���<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;
/**
* Yaml offers convenience methods to load and dump YAML.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Yaml
{
/**
* Parses YAML into a PHP value.
*
* Usage:
*
* $array = Yaml::parse(file_get_contents('config.yml'));
* print_r($array);
*
* As this method accepts both plain strings and file names as an
input,
* you must validate the input before calling this method. Passing a
file
* as an input is a deprecated feature and will be removed in 3.0.
*
* Note: the ability to pass file names to the Yaml::parse method is
deprecated since Symfony 2.2 and will be removed in 3.0. Pass the YAML
contents of the file instead.
*
* @param string $input Path to a YAML file or a
string containing YAML
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
* @param bool $objectForMap True if maps should return a
stdClass instead of array()
*
* @return mixed The YAML converted to a PHP value
*
* @throws ParseException If the YAML is not valid
*/
public static function parse($input, $exceptionOnInvalidType = false,
$objectSupport = false, $objectForMap = false)
{
// if input is a file, process it
$file = '';
if (false === strpos($input, "\n") &&
is_file($input)) {
@trigger_error('The ability to pass file names to the
'.__METHOD__.' method is deprecated since Symfony 2.2 and will be
removed in 3.0. Pass the YAML contents of the file instead.',
E_USER_DEPRECATED);
if (false === is_readable($input)) {
throw new ParseException(sprintf('Unable to parse
"%s" as the file is not readable.', $input));
}
$file = $input;
$input = file_get_contents($file);
}
$yaml = new Parser();
try {
return $yaml->parse($input, $exceptionOnInvalidType,
$objectSupport, $objectForMap);
} catch (ParseException $e) {
if ($file) {
$e->setParsedFile($file);
}
throw $e;
}
}
/**
* Dumps a PHP value to a YAML string.
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML.
*
* @param mixed $input The PHP value
* @param int $inline The level where you switch to
inline YAML
* @param int $indent The amount of spaces to use for
indentation of nested nodes
* @param bool $exceptionOnInvalidType True if an exception must be
thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport True if object support is
enabled, false otherwise
*
* @return string A YAML string representing the original PHP value
*/
public static function dump($input, $inline = 2, $indent = 4,
$exceptionOnInvalidType = false, $objectSupport = false)
{
if ($indent < 1) {
throw new \InvalidArgumentException('The indentation must
be greater than zero.');
}
$yaml = new Dumper();
$yaml->setIndentation($indent);
return $yaml->dump($input, $inline, 0, $exceptionOnInvalidType,
$objectSupport);
}
}
PK-d�[�ʺ9vendor/twig/twig/.php_cs.distnu�[���<?php
return PhpCsFixer\Config::create()
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'@PHPUnit75Migration:risky' => true,
'php_unit_dedicate_assert' => ['target'
=> '5.6'],
'array_syntax' => ['syntax' =>
'short'],
'php_unit_fqcn_annotation' => true,
'no_unreachable_default_argument_value' => false,
'braces' => ['allow_single_line_closure'
=> true],
'heredoc_to_nowdoc' => false,
'ordered_imports' => true,
'phpdoc_types_order' => ['null_adjustment'
=> 'always_last', 'sort_algorithm' =>
'none'],
'native_function_invocation' => ['include'
=> ['@compiler_optimized'], 'scope' =>
'all'],
])
->setRiskyAllowed(true)
->setFinder(PhpCsFixer\Finder::create()->in(__DIR__))
;
PK-d�[_P?>��vendor/twig/twig/composer.jsonnu�[���{
"name": "twig/twig",
"type": "library",
"description": "Twig, the flexible, fast, and secure
template language for PHP",
"keywords": ["templating"],
"homepage": "https://twig.symfony.com",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"require": {
"php": ">=5.5.0",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"symfony/phpunit-bridge": "^4.4|^5.0",
"psr/container": "^1.0"
},
"autoload": {
"psr-0" : {
"Twig_" : "lib/"
},
"psr-4" : {
"Twig\\" : "src/"
}
},
"autoload-dev": {
"psr-4" : {
"Twig\\Tests\\" : "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.42-dev"
}
}
}
PK-d�[�g���(vendor/twig/twig/lib/Twig/Autoloader.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Autoloader class is deprecated since version
1.21 and will be removed in 2.0. Use Composer instead.',
E_USER_DEPRECATED);
/**
* Autoloads Twig classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.21 and will be removed in 2.0. Use Composer instead.
2.0.
*/
class Twig_Autoloader
{
/**
* Registers Twig_Autoloader as an SPL autoloader.
*
* @param bool $prepend whether to prepend the autoloader or not
*/
public static function register($prepend = false)
{
@trigger_error('Using Twig_Autoloader is deprecated since
version 1.21. Use Composer instead.', E_USER_DEPRECATED);
spl_autoload_register([__CLASS__, 'autoload'], true,
$prepend);
}
/**
* Handles autoloading of classes.
*
* @param string $class a class name
*/
public static function autoload($class)
{
if (0 !== strpos($class, 'Twig')) {
return;
}
if (is_file($file =
__DIR__.'/../'.str_replace(['_', "\0"],
['/', ''], $class).'.php')) {
require $file;
} elseif (is_file($file =
__DIR__.'/../../src/'.str_replace(['Twig\\',
'\\', "\0"], ['', '/',
''], $class).'.php')) {
require $file;
}
}
}
PK-d�[&����-vendor/twig/twig/lib/Twig/BaseNodeVisitor.phpnu�[���<?php
use Twig\NodeVisitor\AbstractNodeVisitor;
class_exists('Twig\NodeVisitor\AbstractNodeVisitor');
if (\false) {
class Twig_BaseNodeVisitor extends AbstractNodeVisitor
{
}
}
PK-d�[Q�����.vendor/twig/twig/lib/Twig/Cache/Filesystem.phpnu�[���<?php
use Twig\Cache\FilesystemCache;
class_exists('Twig\Cache\FilesystemCache');
if (\false) {
class Twig_Cache_Filesystem extends FilesystemCache
{
}
}
PK-d�[ ��ʑ�(vendor/twig/twig/lib/Twig/Cache/Null.phpnu�[���<?php
use Twig\Cache\NullCache;
class_exists('Twig\Cache\NullCache');
if (\false) {
class Twig_Cache_Null extends NullCache
{
}
}
PK-d�[�=����,vendor/twig/twig/lib/Twig/CacheInterface.phpnu�[���<?php
use Twig\Cache\CacheInterface;
class_exists('Twig\Cache\CacheInterface');
if (\false) {
class Twig_CacheInterface extends CacheInterface
{
}
}
PK-d�[�Vv3��&vendor/twig/twig/lib/Twig/Compiler.phpnu�[���<?php
use Twig\Compiler;
class_exists('Twig\Compiler');
if (\false) {
class Twig_Compiler extends Compiler
{
}
}
PK-d�[��R��/vendor/twig/twig/lib/Twig/CompilerInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by compiler classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_CompilerInterface
{
/**
* Compiles a node.
*
* @return $this
*/
public function compile(Twig_NodeInterface $node);
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource();
}
PK-d�[ɻ�T��4vendor/twig/twig/lib/Twig/ContainerRuntimeLoader.phpnu�[���<?php
use Twig\RuntimeLoader\ContainerRuntimeLoader;
class_exists('Twig\RuntimeLoader\ContainerRuntimeLoader');
if (\false) {
class Twig_ContainerRuntimeLoader extends ContainerRuntimeLoader
{
}
}
PK-d�[��9���)vendor/twig/twig/lib/Twig/Environment.phpnu�[���<?php
use Twig\Environment;
class_exists('Twig\Environment');
if (\false) {
class Twig_Environment extends Environment
{
}
}
PK-d�[�
ei��*vendor/twig/twig/lib/Twig/Error/Loader.phpnu�[���<?php
use Twig\Error\LoaderError;
class_exists('Twig\Error\LoaderError');
if (\false) {
class Twig_Error_Loader extends LoaderError
{
}
}
PK-d�[�#ڝ�+vendor/twig/twig/lib/Twig/Error/Runtime.phpnu�[���<?php
use Twig\Error\RuntimeError;
class_exists('Twig\Error\RuntimeError');
if (\false) {
class Twig_Error_Runtime extends RuntimeError
{
}
}
PK-d�[d�˃��*vendor/twig/twig/lib/Twig/Error/Syntax.phpnu�[���<?php
use Twig\Error\SyntaxError;
class_exists('Twig\Error\SyntaxError');
if (\false) {
class Twig_Error_Syntax extends SyntaxError
{
}
}
PK-d�[�Bڨ��#vendor/twig/twig/lib/Twig/Error.phpnu�[���<?php
use Twig\Error\Error;
class_exists('Twig\Error\Error');
if (\false) {
class Twig_Error extends Error
{
}
}
PK-d�[ð�=��3vendor/twig/twig/lib/Twig/ExistsLoaderInterface.phpnu�[���<?php
use Twig\Loader\ExistsLoaderInterface;
class_exists('Twig\Loader\ExistsLoaderInterface');
if (\false) {
class Twig_ExistsLoaderInterface extends ExistsLoaderInterface
{
}
}
PK-d�[D;��.vendor/twig/twig/lib/Twig/ExpressionParser.phpnu�[���<?php
use Twig\ExpressionParser;
class_exists('Twig\ExpressionParser');
if (\false) {
class Twig_ExpressionParser extends ExpressionParser
{
}
}
PK-d�["G���,vendor/twig/twig/lib/Twig/Extension/Core.phpnu�[���<?php
use Twig\Extension\CoreExtension;
class_exists('Twig\Extension\CoreExtension');
if (\false) {
class Twig_Extension_Core extends CoreExtension
{
}
}
PK-d�[:��e��-vendor/twig/twig/lib/Twig/Extension/Debug.phpnu�[���<?php
use Twig\Extension\DebugExtension;
class_exists('Twig\Extension\DebugExtension');
if (\false) {
class Twig_Extension_Debug extends DebugExtension
{
}
}
PK-d�[��Aٵ�/vendor/twig/twig/lib/Twig/Extension/Escaper.phpnu�[���<?php
use Twig\Extension\EscaperExtension;
class_exists('Twig\Extension\EscaperExtension');
if (\false) {
class Twig_Extension_Escaper extends EscaperExtension
{
}
}
PK-d�[��I��8vendor/twig/twig/lib/Twig/Extension/GlobalsInterface.phpnu�[���<?php
use Twig\Extension\GlobalsInterface;
class_exists('Twig\Extension\GlobalsInterface');
if (\false) {
class Twig_Extension_GlobalsInterface extends GlobalsInterface
{
}
}
PK-d�[�����<vendor/twig/twig/lib/Twig/Extension/InitRuntimeInterface.phpnu�[���<?php
use Twig\Extension\InitRuntimeInterface;
class_exists('Twig\Extension\InitRuntimeInterface');
if (\false) {
class Twig_Extension_InitRuntimeInterface extends InitRuntimeInterface
{
}
}
PK-d�[n���1vendor/twig/twig/lib/Twig/Extension/Optimizer.phpnu�[���<?php
use Twig\Extension\OptimizerExtension;
class_exists('Twig\Extension\OptimizerExtension');
if (\false) {
class Twig_Extension_Optimizer extends OptimizerExtension
{
}
}
PK-d�[ѕu��0vendor/twig/twig/lib/Twig/Extension/Profiler.phpnu�[���<?php
use Twig\Extension\ProfilerExtension;
class_exists('Twig\Extension\ProfilerExtension');
if (\false) {
class Twig_Extension_Profiler extends ProfilerExtension
{
}
}
PK-d�[��3���/vendor/twig/twig/lib/Twig/Extension/Sandbox.phpnu�[���<?php
use Twig\Extension\SandboxExtension;
class_exists('Twig\Extension\SandboxExtension');
if (\false) {
class Twig_Extension_Sandbox extends SandboxExtension
{
}
}
PK-d�[P�El��/vendor/twig/twig/lib/Twig/Extension/Staging.phpnu�[���<?php
use Twig\Extension\StagingExtension;
class_exists('Twig\Extension\StagingExtension');
if (\false) {
class Twig_Extension_Staging extends StagingExtension
{
}
}
PK-d�[��"���4vendor/twig/twig/lib/Twig/Extension/StringLoader.phpnu�[���<?php
use Twig\Extension\StringLoaderExtension;
class_exists('Twig\Extension\StringLoaderExtension');
if (\false) {
class Twig_Extension_StringLoader extends StringLoaderExtension
{
}
}
PK-d�[����'vendor/twig/twig/lib/Twig/Extension.phpnu�[���<?php
use Twig\Extension\AbstractExtension;
class_exists('Twig\Extension\AbstractExtension');
if (\false) {
class Twig_Extension extends AbstractExtension
{
}
}
PK-d�[�3���0vendor/twig/twig/lib/Twig/ExtensionInterface.phpnu�[���<?php
use Twig\Extension\ExtensionInterface;
class_exists('Twig\Extension\ExtensionInterface');
if (\false) {
class Twig_ExtensionInterface extends ExtensionInterface
{
}
}
PK-d�[�<���2vendor/twig/twig/lib/Twig/FactoryRuntimeLoader.phpnu�[���<?php
use Twig\RuntimeLoader\FactoryRuntimeLoader;
class_exists('Twig\RuntimeLoader\FactoryRuntimeLoader');
if (\false) {
class Twig_FactoryRuntimeLoader extends FactoryRuntimeLoader
{
}
}
PK-d�[�,L���;vendor/twig/twig/lib/Twig/FileExtensionEscapingStrategy.phpnu�[���<?php
use Twig\FileExtensionEscapingStrategy;
class_exists('Twig\FileExtensionEscapingStrategy');
if (\false) {
class Twig_FileExtensionEscapingStrategy extends
FileExtensionEscapingStrategy
{
}
}
PK-d�[�R��-vendor/twig/twig/lib/Twig/Filter/Function.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Filter_Function class is deprecated since
version 1.12 and will be removed in 2.0. Use \Twig\TwigFilter
instead.', E_USER_DEPRECATED);
/**
* Represents a function template filter.
*
* Use \Twig\TwigFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Function extends Twig_Filter
{
protected $function;
public function __construct($function, array $options = [])
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}
PK-d�[�M�MXX+vendor/twig/twig/lib/Twig/Filter/Method.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Extension\ExtensionInterface;
@trigger_error('The Twig_Filter_Method class is deprecated since
version 1.12 and will be removed in 2.0. Use \Twig\TwigFilter
instead.', E_USER_DEPRECATED);
/**
* Represents a method template filter.
*
* Use \Twig\TwigFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Method extends Twig_Filter
{
protected $extension;
protected $method;
public function __construct(ExtensionInterface $extension, $method,
array $options = [])
{
$options['callable'] = [$extension, $method];
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return
sprintf('$this->env->getExtension(\'%s\')->%s',
\get_class($this->extension), $this->method);
}
}
PK-d�[��`pp)vendor/twig/twig/lib/Twig/Filter/Node.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Filter_Node class is deprecated since version
1.12 and will be removed in 2.0. Use \Twig\TwigFilter instead.',
E_USER_DEPRECATED);
/**
* Represents a template filter as a node.
*
* Use \Twig\TwigFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Node extends Twig_Filter
{
protected $class;
public function __construct($class, array $options = [])
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}
PK-d�[��k���$vendor/twig/twig/lib/Twig/Filter.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Node\Node;
@trigger_error('The Twig_Filter class is deprecated since version 1.12
and will be removed in 2.0. Use \Twig\TwigFilter instead.',
E_USER_DEPRECATED);
/**
* Represents a template filter.
*
* Use \Twig\TwigFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Filter implements Twig_FilterInterface,
Twig_FilterCallableInterface
{
protected $options;
protected $arguments = [];
public function __construct(array $options = [])
{
$this->options = array_merge([
'needs_environment' => false,
'needs_context' => false,
'pre_escape' => null,
'preserves_safety' => null,
'callable' => null,
], $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Node $filterArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return
\call_user_func($this->options['is_safe_callback'],
$filterArgs);
}
}
public function getPreservesSafety()
{
return $this->options['preserves_safety'];
}
public function getPreEscape()
{
return $this->options['pre_escape'];
}
public function getCallable()
{
return $this->options['callable'];
}
}
PK-d�[,ı+��5vendor/twig/twig/lib/Twig/FilterCallableInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a callable template filter.
*
* Use \Twig\TwigFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterCallableInterface
{
public function getCallable();
}
PK-d�[� �?[[-vendor/twig/twig/lib/Twig/FilterInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Node\Node;
/**
* Represents a template filter.
*
* Use \Twig\TwigFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterInterface
{
/**
* Compiles a filter.
*
* @return string The PHP code for the filter
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Node $filterArgs);
public function getPreservesSafety();
public function getPreEscape();
public function setArguments($arguments);
public function getArguments();
}
PK-d�[�Ὢ��/vendor/twig/twig/lib/Twig/Function/Function.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Function_Function class is deprecated since
version 1.12 and will be removed in 2.0. Use \Twig\TwigFunction
instead.', E_USER_DEPRECATED);
/**
* Represents a function template function.
*
* Use \Twig\TwigFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Function extends Twig_Function
{
protected $function;
public function __construct($function, array $options = [])
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}
PK-d�[�a��{{-vendor/twig/twig/lib/Twig/Function/Method.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Extension\ExtensionInterface;
@trigger_error('The Twig_Function_Method class is deprecated since
version 1.12 and will be removed in 2.0. Use \Twig\TwigFunction
instead.', E_USER_DEPRECATED);
/**
* Represents a method template function.
*
* Use \Twig\TwigFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Method extends Twig_Function
{
protected $extension;
protected $method;
public function __construct(ExtensionInterface $extension, $method,
array $options = [])
{
$options['callable'] = [$extension, $method];
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return
sprintf('$this->env->getExtension(\'%s\')->%s',
\get_class($this->extension), $this->method);
}
}
PK-d�[ �|||+vendor/twig/twig/lib/Twig/Function/Node.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Function_Node class is deprecated since
version 1.12 and will be removed in 2.0. Use \Twig\TwigFunction
instead.', E_USER_DEPRECATED);
/**
* Represents a template function as a node.
*
* Use \Twig\TwigFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Node extends Twig_Function
{
protected $class;
public function __construct($class, array $options = [])
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}
PK-d�[So�)��&vendor/twig/twig/lib/Twig/Function.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Node\Node;
@trigger_error('The Twig_Function class is deprecated since version
1.12 and will be removed in 2.0. Use \Twig\TwigFunction instead.',
E_USER_DEPRECATED);
/**
* Represents a template function.
*
* Use \Twig\TwigFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Function implements Twig_FunctionInterface,
Twig_FunctionCallableInterface
{
protected $options;
protected $arguments = [];
public function __construct(array $options = [])
{
$this->options = array_merge([
'needs_environment' => false,
'needs_context' => false,
'callable' => null,
], $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Node $functionArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return
\call_user_func($this->options['is_safe_callback'],
$functionArgs);
}
return [];
}
public function getCallable()
{
return $this->options['callable'];
}
}
PK-d�[d����7vendor/twig/twig/lib/Twig/FunctionCallableInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a callable template function.
*
* Use \Twig\TwigFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionCallableInterface
{
public function getCallable();
}
PK-d�[9t/,,/vendor/twig/twig/lib/Twig/FunctionInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Node\Node;
/**
* Represents a template function.
*
* Use \Twig\TwigFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionInterface
{
/**
* Compiles a function.
*
* @return string The PHP code for the function
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Node $filterArgs);
public function setArguments($arguments);
public function getArguments();
}
PK-d�[��t�tt#vendor/twig/twig/lib/Twig/Lexer.phpnu�[���<?php
use Twig\Lexer;
class_exists('Twig\Lexer');
if (\false) {
class Twig_Lexer extends Lexer
{
}
}
PK-d�[�Y�,vendor/twig/twig/lib/Twig/LexerInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Error\SyntaxError;
use Twig\Source;
use Twig\TokenStream;
/**
* Interface implemented by lexer classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_LexerInterface
{
/**
* Tokenizes a source code.
*
* @param string|Source $code The source code
* @param string $name A unique identifier for the source code
*
* @return TokenStream
*
* @throws SyntaxError When the code is syntactically wrong
*/
public function tokenize($code, $name = null);
}
PK-d�[�) ��*vendor/twig/twig/lib/Twig/Loader/Array.phpnu�[���<?php
use Twig\Loader\ArrayLoader;
class_exists('Twig\Loader\ArrayLoader');
if (\false) {
class Twig_Loader_Array extends ArrayLoader
{
}
}
PK-d�[�#�ʛ�*vendor/twig/twig/lib/Twig/Loader/Chain.phpnu�[���<?php
use Twig\Loader\ChainLoader;
class_exists('Twig\Loader\ChainLoader');
if (\false) {
class Twig_Loader_Chain extends ChainLoader
{
}
}
PK-d�[4`v˯�/vendor/twig/twig/lib/Twig/Loader/Filesystem.phpnu�[���<?php
use Twig\Loader\FilesystemLoader;
class_exists('Twig\Loader\FilesystemLoader');
if (\false) {
class Twig_Loader_Filesystem extends FilesystemLoader
{
}
}
PK-d�[T����+vendor/twig/twig/lib/Twig/Loader/String.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Loader\ExistsLoaderInterface;
use Twig\Loader\LoaderInterface;
use Twig\Loader\SourceContextLoaderInterface;
use Twig\Source;
@trigger_error('The Twig_Loader_String class is deprecated since
version 1.18.1 and will be removed in 2.0. Use
"Twig\Loader\ArrayLoader" instead or
"Twig\Environment::createTemplate()".', E_USER_DEPRECATED);
/**
* Loads a template from a string.
*
* This loader should NEVER be used. It only exists for Twig internal
purposes.
*
* When using this loader with a cache mechanism, you should know that a
new cache
* key is generated each time a template content "changes" (the
cache key being the
* source code of the template). If you don't want to see your cache
grows out of
* control, you need to take care of clearing the old cache file by
yourself.
*
* @deprecated since 1.18.1 (to be removed in 2.0)
*
* @internal
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_String implements LoaderInterface, ExistsLoaderInterface,
SourceContextLoaderInterface
{
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on
"%s" is deprecated since 1.27. Use getSourceContext()
instead.', \get_class($this)), E_USER_DEPRECATED);
return $name;
}
public function getSourceContext($name)
{
return new Source($name, $name);
}
public function exists($name)
{
return true;
}
public function getCacheKey($name)
{
return $name;
}
public function isFresh($name, $time)
{
return true;
}
}
PK-d�[7b����-vendor/twig/twig/lib/Twig/LoaderInterface.phpnu�[���<?php
use Twig\Loader\LoaderInterface;
class_exists('Twig\Loader\LoaderInterface');
if (\false) {
class Twig_LoaderInterface extends LoaderInterface
{
}
}
PK-d�[^�<�xx$vendor/twig/twig/lib/Twig/Markup.phpnu�[���<?php
use Twig\Markup;
class_exists('Twig\Markup');
if (\false) {
class Twig_Markup extends Markup
{
}
}
PK-d�[���-vendor/twig/twig/lib/Twig/Node/AutoEscape.phpnu�[���<?php
use Twig\Node\AutoEscapeNode;
class_exists('Twig\Node\AutoEscapeNode');
if (\false) {
class Twig_Node_AutoEscape extends AutoEscapeNode
{
}
}
PK-d�[V��~��(vendor/twig/twig/lib/Twig/Node/Block.phpnu�[���<?php
use Twig\Node\BlockNode;
class_exists('Twig\Node\BlockNode');
if (\false) {
class Twig_Node_Block extends BlockNode
{
}
}
PK-d�[<B�G��1vendor/twig/twig/lib/Twig/Node/BlockReference.phpnu�[���<?php
use Twig\Node\BlockReferenceNode;
class_exists('Twig\Node\BlockReferenceNode');
if (\false) {
class Twig_Node_BlockReference extends BlockReferenceNode
{
}
}
PK-d�[�Z�
��'vendor/twig/twig/lib/Twig/Node/Body.phpnu�[���<?php
use Twig\Node\BodyNode;
class_exists('Twig\Node\BodyNode');
if (\false) {
class Twig_Node_Body extends BodyNode
{
}
}
PK-d�[m8�2��0vendor/twig/twig/lib/Twig/Node/CheckSecurity.phpnu�[���<?php
use Twig\Node\CheckSecurityNode;
class_exists('Twig\Node\CheckSecurityNode');
if (\false) {
class Twig_Node_CheckSecurity extends CheckSecurityNode
{
}
}
PK-d�[c��ţ�-vendor/twig/twig/lib/Twig/Node/Deprecated.phpnu�[���<?php
use Twig\Node\DeprecatedNode;
class_exists('Twig\Node\DeprecatedNode');
if (\false) {
class Twig_Node_Deprecated extends DeprecatedNode
{
}
}
PK-d�[�a���%vendor/twig/twig/lib/Twig/Node/Do.phpnu�[���<?php
use Twig\Node\DoNode;
class_exists('Twig\Node\DoNode');
if (\false) {
class Twig_Node_Do extends DoNode
{
}
}
PK-d�[C��ԏ�(vendor/twig/twig/lib/Twig/Node/Embed.phpnu�[���<?php
use Twig\Node\EmbedNode;
class_exists('Twig\Node\EmbedNode');
if (\false) {
class Twig_Node_Embed extends EmbedNode
{
}
}
PK-d�[����3vendor/twig/twig/lib/Twig/Node/Expression/Array.phpnu�[���<?php
use Twig\Node\Expression\ArrayExpression;
class_exists('Twig\Node\Expression\ArrayExpression');
if (\false) {
class Twig_Node_Expression_Array extends ArrayExpression
{
}
}
PK-d�[B&���8vendor/twig/twig/lib/Twig/Node/Expression/AssignName.phpnu�[���<?php
use Twig\Node\Expression\AssignNameExpression;
class_exists('Twig\Node\Expression\AssignNameExpression');
if (\false) {
class Twig_Node_Expression_AssignName extends AssignNameExpression
{
}
}
PK-d�[2K����8vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.phpnu�[���<?php
use Twig\Node\Expression\Binary\AddBinary;
class_exists('Twig\Node\Expression\Binary\AddBinary');
if (\false) {
class Twig_Node_Expression_Binary_Add extends AddBinary
{
}
}
PK-d�[�~����8vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.phpnu�[���<?php
use Twig\Node\Expression\Binary\AndBinary;
class_exists('Twig\Node\Expression\Binary\AndBinary');
if (\false) {
class Twig_Node_Expression_Binary_And extends AndBinary
{
}
}
PK-d�[S
���?vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.phpnu�[���<?php
use Twig\Node\Expression\Binary\BitwiseAndBinary;
class_exists('Twig\Node\Expression\Binary\BitwiseAndBinary');
if (\false) {
class Twig_Node_Expression_Binary_BitwiseAnd extends BitwiseAndBinary
{
}
}
PK-d�[�ѣ���>vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.phpnu�[���<?php
use Twig\Node\Expression\Binary\BitwiseOrBinary;
class_exists('Twig\Node\Expression\Binary\BitwiseOrBinary');
if (\false) {
class Twig_Node_Expression_Binary_BitwiseOr extends BitwiseOrBinary
{
}
}
PK-d�[���?vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.phpnu�[���<?php
use Twig\Node\Expression\Binary\BitwiseXorBinary;
class_exists('Twig\Node\Expression\Binary\BitwiseXorBinary');
if (\false) {
class Twig_Node_Expression_Binary_BitwiseXor extends BitwiseXorBinary
{
}
}
PK-d�[������;vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.phpnu�[���<?php
use Twig\Node\Expression\Binary\ConcatBinary;
class_exists('Twig\Node\Expression\Binary\ConcatBinary');
if (\false) {
class Twig_Node_Expression_Binary_Concat extends ConcatBinary
{
}
}
PK-d�[(�B���8vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.phpnu�[���<?php
use Twig\Node\Expression\Binary\DivBinary;
class_exists('Twig\Node\Expression\Binary\DivBinary');
if (\false) {
class Twig_Node_Expression_Binary_Div extends DivBinary
{
}
}
PK-d�[W��G��=vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.phpnu�[���<?php
use Twig\Node\Expression\Binary\EndsWithBinary;
class_exists('Twig\Node\Expression\Binary\EndsWithBinary');
if (\false) {
class Twig_Node_Expression_Binary_EndsWith extends EndsWithBinary
{
}
}
PK-d�[}�n2��:vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.phpnu�[���<?php
use Twig\Node\Expression\Binary\EqualBinary;
class_exists('Twig\Node\Expression\Binary\EqualBinary');
if (\false) {
class Twig_Node_Expression_Binary_Equal extends EqualBinary
{
}
}
PK-d�[�*�/��=vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.phpnu�[���<?php
use Twig\Node\Expression\Binary\FloorDivBinary;
class_exists('Twig\Node\Expression\Binary\FloorDivBinary');
if (\false) {
class Twig_Node_Expression_Binary_FloorDiv extends FloorDivBinary
{
}
}
PK-d�[-�Z��<vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.phpnu�[���<?php
use Twig\Node\Expression\Binary\GreaterBinary;
class_exists('Twig\Node\Expression\Binary\GreaterBinary');
if (\false) {
class Twig_Node_Expression_Binary_Greater extends GreaterBinary
{
}
}
PK-d�[ߞ����Avendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.phpnu�[���<?php
use Twig\Node\Expression\Binary\GreaterEqualBinary;
class_exists('Twig\Node\Expression\Binary\GreaterEqualBinary');
if (\false) {
class Twig_Node_Expression_Binary_GreaterEqual extends
GreaterEqualBinary
{
}
}
PK-d�[K�n���7vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.phpnu�[���<?php
use Twig\Node\Expression\Binary\InBinary;
class_exists('Twig\Node\Expression\Binary\InBinary');
if (\false) {
class Twig_Node_Expression_Binary_In extends InBinary
{
}
}
PK-d�[�w�~��9vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.phpnu�[���<?php
use Twig\Node\Expression\Binary\LessBinary;
class_exists('Twig\Node\Expression\Binary\LessBinary');
if (\false) {
class Twig_Node_Expression_Binary_Less extends LessBinary
{
}
}
PK-d�[�[�%��>vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.phpnu�[���<?php
use Twig\Node\Expression\Binary\LessEqualBinary;
class_exists('Twig\Node\Expression\Binary\LessEqualBinary');
if (\false) {
class Twig_Node_Expression_Binary_LessEqual extends LessEqualBinary
{
}
}
PK-d�[�y����<vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.phpnu�[���<?php
use Twig\Node\Expression\Binary\MatchesBinary;
class_exists('Twig\Node\Expression\Binary\MatchesBinary');
if (\false) {
class Twig_Node_Expression_Binary_Matches extends MatchesBinary
{
}
}
PK-d�[�aL���8vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.phpnu�[���<?php
use Twig\Node\Expression\Binary\ModBinary;
class_exists('Twig\Node\Expression\Binary\ModBinary');
if (\false) {
class Twig_Node_Expression_Binary_Mod extends ModBinary
{
}
}
PK-d�[8Vd'��8vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.phpnu�[���<?php
use Twig\Node\Expression\Binary\MulBinary;
class_exists('Twig\Node\Expression\Binary\MulBinary');
if (\false) {
class Twig_Node_Expression_Binary_Mul extends MulBinary
{
}
}
PK-d�[DCO��=vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.phpnu�[���<?php
use Twig\Node\Expression\Binary\NotEqualBinary;
class_exists('Twig\Node\Expression\Binary\NotEqualBinary');
if (\false) {
class Twig_Node_Expression_Binary_NotEqual extends NotEqualBinary
{
}
}
PK-d�[�ސB��:vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.phpnu�[���<?php
use Twig\Node\Expression\Binary\NotInBinary;
class_exists('Twig\Node\Expression\Binary\NotInBinary');
if (\false) {
class Twig_Node_Expression_Binary_NotIn extends NotInBinary
{
}
}
PK-d�[�����7vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.phpnu�[���<?php
use Twig\Node\Expression\Binary\OrBinary;
class_exists('Twig\Node\Expression\Binary\OrBinary');
if (\false) {
class Twig_Node_Expression_Binary_Or extends OrBinary
{
}
}
PK-d�[�~u@��:vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.phpnu�[���<?php
use Twig\Node\Expression\Binary\PowerBinary;
class_exists('Twig\Node\Expression\Binary\PowerBinary');
if (\false) {
class Twig_Node_Expression_Binary_Power extends PowerBinary
{
}
}
PK-d�[ٰ�w��:vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.phpnu�[���<?php
use Twig\Node\Expression\Binary\RangeBinary;
class_exists('Twig\Node\Expression\Binary\RangeBinary');
if (\false) {
class Twig_Node_Expression_Binary_Range extends RangeBinary
{
}
}
PK-d�[��s��?vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.phpnu�[���<?php
use Twig\Node\Expression\Binary\StartsWithBinary;
class_exists('Twig\Node\Expression\Binary\StartsWithBinary');
if (\false) {
class Twig_Node_Expression_Binary_StartsWith extends StartsWithBinary
{
}
}
PK-d�[�nڸ��8vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.phpnu�[���<?php
use Twig\Node\Expression\Binary\SubBinary;
class_exists('Twig\Node\Expression\Binary\SubBinary');
if (\false) {
class Twig_Node_Expression_Binary_Sub extends SubBinary
{
}
}
PK-d�[��q5��4vendor/twig/twig/lib/Twig/Node/Expression/Binary.phpnu�[���<?php
use Twig\Node\Expression\Binary\AbstractBinary;
class_exists('Twig\Node\Expression\Binary\AbstractBinary');
if (\false) {
class Twig_Node_Expression_Binary extends AbstractBinary
{
}
}
PK-d�[(d���<vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.phpnu�[���<?php
use Twig\Node\Expression\BlockReferenceExpression;
class_exists('Twig\Node\Expression\BlockReferenceExpression');
if (\false) {
class Twig_Node_Expression_BlockReference extends
BlockReferenceExpression
{
}
}
PK-d�[p��,��2vendor/twig/twig/lib/Twig/Node/Expression/Call.phpnu�[���<?php
use Twig\Node\Expression\CallExpression;
class_exists('Twig\Node\Expression\CallExpression');
if (\false) {
class Twig_Node_Expression_Call extends CallExpression
{
}
}
PK-d�[�R�!��9vendor/twig/twig/lib/Twig/Node/Expression/Conditional.phpnu�[���<?php
use Twig\Node\Expression\ConditionalExpression;
class_exists('Twig\Node\Expression\ConditionalExpression');
if (\false) {
class Twig_Node_Expression_Conditional extends ConditionalExpression
{
}
}
PK-d�[���T��6vendor/twig/twig/lib/Twig/Node/Expression/Constant.phpnu�[���<?php
use Twig\Node\Expression\ConstantExpression;
class_exists('Twig\Node\Expression\ConstantExpression');
if (\false) {
class Twig_Node_Expression_Constant extends ConstantExpression
{
}
}
PK-d�[����@vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
@trigger_error('The Twig_Node_Expression_ExtensionReference class is
deprecated since version 1.23 and will be removed in 2.0.',
E_USER_DEPRECATED);
/**
* Represents an extension call node.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.23 and will be removed in 2.0.
*/
class Twig_Node_Expression_ExtensionReference extends AbstractExpression
{
public function __construct($name, $lineno, $tag = null)
{
parent::__construct([], ['name' => $name], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
$compiler->raw(sprintf("\$this->env->getExtension('%s')",
$this->getAttribute('name')));
}
}
PK-d�[#�"0��<vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.phpnu�[���<?php
use Twig\Node\Expression\Filter\DefaultFilter;
class_exists('Twig\Node\Expression\Filter\DefaultFilter');
if (\false) {
class Twig_Node_Expression_Filter_Default extends DefaultFilter
{
}
}
PK-d�[f��4vendor/twig/twig/lib/Twig/Node/Expression/Filter.phpnu�[���<?php
use Twig\Node\Expression\FilterExpression;
class_exists('Twig\Node\Expression\FilterExpression');
if (\false) {
class Twig_Node_Expression_Filter extends FilterExpression
{
}
}
PK-d�[��j!��6vendor/twig/twig/lib/Twig/Node/Expression/Function.phpnu�[���<?php
use Twig\Node\Expression\FunctionExpression;
class_exists('Twig\Node\Expression\FunctionExpression');
if (\false) {
class Twig_Node_Expression_Function extends FunctionExpression
{
}
}
PK-d�[����5vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.phpnu�[���<?php
use Twig\Node\Expression\GetAttrExpression;
class_exists('Twig\Node\Expression\GetAttrExpression');
if (\false) {
class Twig_Node_Expression_GetAttr extends GetAttrExpression
{
}
}
PK-d�[�����8vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.phpnu�[���<?php
use Twig\Node\Expression\MethodCallExpression;
class_exists('Twig\Node\Expression\MethodCallExpression');
if (\false) {
class Twig_Node_Expression_MethodCall extends MethodCallExpression
{
}
}
PK-d�[�c�Ѿ�2vendor/twig/twig/lib/Twig/Node/Expression/Name.phpnu�[���<?php
use Twig\Node\Expression\NameExpression;
class_exists('Twig\Node\Expression\NameExpression');
if (\false) {
class Twig_Node_Expression_Name extends NameExpression
{
}
}
PK-d�[�=߲��:vendor/twig/twig/lib/Twig/Node/Expression/NullCoalesce.phpnu�[���<?php
use Twig\Node\Expression\NullCoalesceExpression;
class_exists('Twig\Node\Expression\NullCoalesceExpression');
if (\false) {
class Twig_Node_Expression_NullCoalesce extends NullCoalesceExpression
{
}
}
PK-d�[4\3���4vendor/twig/twig/lib/Twig/Node/Expression/Parent.phpnu�[���<?php
use Twig\Node\Expression\ParentExpression;
class_exists('Twig\Node\Expression\ParentExpression');
if (\false) {
class Twig_Node_Expression_Parent extends ParentExpression
{
}
}
PK-d�[�U��6vendor/twig/twig/lib/Twig/Node/Expression/TempName.phpnu�[���<?php
use Twig\Node\Expression\TempNameExpression;
class_exists('Twig\Node\Expression\TempNameExpression');
if (\false) {
class Twig_Node_Expression_TempName extends TempNameExpression
{
}
}
PK-d�[�7o��;vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.phpnu�[���<?php
use Twig\Node\Expression\Test\ConstantTest;
class_exists('Twig\Node\Expression\Test\ConstantTest');
if (\false) {
class Twig_Node_Expression_Test_Constant extends ConstantTest
{
}
}
PK-d�[��!%��:vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.phpnu�[���<?php
use Twig\Node\Expression\Test\DefinedTest;
class_exists('Twig\Node\Expression\Test\DefinedTest');
if (\false) {
class Twig_Node_Expression_Test_Defined extends DefinedTest
{
}
}
PK-d�[�h�n��>vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.phpnu�[���<?php
use Twig\Node\Expression\Test\DivisiblebyTest;
class_exists('Twig\Node\Expression\Test\DivisiblebyTest');
if (\false) {
class Twig_Node_Expression_Test_Divisibleby extends DivisiblebyTest
{
}
}
PK-d�[�DLc��7vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.phpnu�[���<?php
use Twig\Node\Expression\Test\EvenTest;
class_exists('Twig\Node\Expression\Test\EvenTest');
if (\false) {
class Twig_Node_Expression_Test_Even extends EvenTest
{
}
}
PK-d�[���7vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.phpnu�[���<?php
use Twig\Node\Expression\Test\NullTest;
class_exists('Twig\Node\Expression\Test\NullTest');
if (\false) {
class Twig_Node_Expression_Test_Null extends NullTest
{
}
}
PK-d�[��H��6vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.phpnu�[���<?php
use Twig\Node\Expression\Test\OddTest;
class_exists('Twig\Node\Expression\Test\OddTest');
if (\false) {
class Twig_Node_Expression_Test_Odd extends OddTest
{
}
}
PK-d�[b@R���9vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.phpnu�[���<?php
use Twig\Node\Expression\Test\SameasTest;
class_exists('Twig\Node\Expression\Test\SameasTest');
if (\false) {
class Twig_Node_Expression_Test_Sameas extends SameasTest
{
}
}
PK-d�[��C��2vendor/twig/twig/lib/Twig/Node/Expression/Test.phpnu�[���<?php
use Twig\Node\Expression\TestExpression;
class_exists('Twig\Node\Expression\TestExpression');
if (\false) {
class Twig_Node_Expression_Test extends TestExpression
{
}
}
PK-d�[��\C��7vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.phpnu�[���<?php
use Twig\Node\Expression\Unary\NegUnary;
class_exists('Twig\Node\Expression\Unary\NegUnary');
if (\false) {
class Twig_Node_Expression_Unary_Neg extends NegUnary
{
}
}
PK-d�[V�I��7vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.phpnu�[���<?php
use Twig\Node\Expression\Unary\NotUnary;
class_exists('Twig\Node\Expression\Unary\NotUnary');
if (\false) {
class Twig_Node_Expression_Unary_Not extends NotUnary
{
}
}
PK-d�[�P����7vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.phpnu�[���<?php
use Twig\Node\Expression\Unary\PosUnary;
class_exists('Twig\Node\Expression\Unary\PosUnary');
if (\false) {
class Twig_Node_Expression_Unary_Pos extends PosUnary
{
}
}
PK-d�[=��y��3vendor/twig/twig/lib/Twig/Node/Expression/Unary.phpnu�[���<?php
use Twig\Node\Expression\Unary\AbstractUnary;
class_exists('Twig\Node\Expression\Unary\AbstractUnary');
if (\false) {
class Twig_Node_Expression_Unary extends AbstractUnary
{
}
}
PK-d�[b��d��-vendor/twig/twig/lib/Twig/Node/Expression.phpnu�[���<?php
use Twig\Node\Expression\AbstractExpression;
class_exists('Twig\Node\Expression\AbstractExpression');
if (\false) {
class Twig_Node_Expression extends AbstractExpression
{
}
}
PK-d�[FzP��(vendor/twig/twig/lib/Twig/Node/Flush.phpnu�[���<?php
use Twig\Node\FlushNode;
class_exists('Twig\Node\FlushNode');
if (\false) {
class Twig_Node_Flush extends FlushNode
{
}
}
PK-d�[*�b��&vendor/twig/twig/lib/Twig/Node/For.phpnu�[���<?php
use Twig\Node\ForNode;
class_exists('Twig\Node\ForNode');
if (\false) {
class Twig_Node_For extends ForNode
{
}
}
PK-d�[�Nח�*vendor/twig/twig/lib/Twig/Node/ForLoop.phpnu�[���<?php
use Twig\Node\ForLoopNode;
class_exists('Twig\Node\ForLoopNode');
if (\false) {
class Twig_Node_ForLoop extends ForLoopNode
{
}
}
PK-d�[w=����%vendor/twig/twig/lib/Twig/Node/If.phpnu�[���<?php
use Twig\Node\IfNode;
class_exists('Twig\Node\IfNode');
if (\false) {
class Twig_Node_If extends IfNode
{
}
}
PK-d�[��n��)vendor/twig/twig/lib/Twig/Node/Import.phpnu�[���<?php
use Twig\Node\ImportNode;
class_exists('Twig\Node\ImportNode');
if (\false) {
class Twig_Node_Import extends ImportNode
{
}
}
PK-d�[�0��*vendor/twig/twig/lib/Twig/Node/Include.phpnu�[���<?php
use Twig\Node\IncludeNode;
class_exists('Twig\Node\IncludeNode');
if (\false) {
class Twig_Node_Include extends IncludeNode
{
}
}
PK-d�[��<A��(vendor/twig/twig/lib/Twig/Node/Macro.phpnu�[���<?php
use Twig\Node\MacroNode;
class_exists('Twig\Node\MacroNode');
if (\false) {
class Twig_Node_Macro extends MacroNode
{
}
}
PK-d�[��禎�)vendor/twig/twig/lib/Twig/Node/Module.phpnu�[���<?php
use Twig\Node\ModuleNode;
class_exists('Twig\Node\ModuleNode');
if (\false) {
class Twig_Node_Module extends ModuleNode
{
}
}
PK-d�[ԡ�Ï�(vendor/twig/twig/lib/Twig/Node/Print.phpnu�[���<?php
use Twig\Node\PrintNode;
class_exists('Twig\Node\PrintNode');
if (\false) {
class Twig_Node_Print extends PrintNode
{
}
}
PK-d�[�~���*vendor/twig/twig/lib/Twig/Node/Sandbox.phpnu�[���<?php
use Twig\Node\SandboxNode;
class_exists('Twig\Node\SandboxNode');
if (\false) {
class Twig_Node_Sandbox extends SandboxNode
{
}
}
PK-d�[�y�@��1vendor/twig/twig/lib/Twig/Node/SandboxedPrint.phpnu�[���<?php
use Twig\Node\SandboxedPrintNode;
class_exists('Twig\Node\SandboxedPrintNode');
if (\false) {
class Twig_Node_SandboxedPrint extends SandboxedPrintNode
{
}
}
PK-d�[絡߇�&vendor/twig/twig/lib/Twig/Node/Set.phpnu�[���<?php
use Twig\Node\SetNode;
class_exists('Twig\Node\SetNode');
if (\false) {
class Twig_Node_Set extends SetNode
{
}
}
PK-d�[0�f��*vendor/twig/twig/lib/Twig/Node/SetTemp.phpnu�[���<?php
use Twig\Node\SetTempNode;
class_exists('Twig\Node\SetTempNode');
if (\false) {
class Twig_Node_SetTemp extends SetTempNode
{
}
}
PK-d�[��͟�,vendor/twig/twig/lib/Twig/Node/Spaceless.phpnu�[���<?php
use Twig\Node\SpacelessNode;
class_exists('Twig\Node\SpacelessNode');
if (\false) {
class Twig_Node_Spaceless extends SpacelessNode
{
}
}
PK-d�[5c�x��'vendor/twig/twig/lib/Twig/Node/Text.phpnu�[���<?php
use Twig\Node\TextNode;
class_exists('Twig\Node\TextNode');
if (\false) {
class Twig_Node_Text extends TextNode
{
}
}
PK-d�[@3�&��'vendor/twig/twig/lib/Twig/Node/With.phpnu�[���<?php
use Twig\Node\WithNode;
class_exists('Twig\Node\WithNode');
if (\false) {
class Twig_Node_With extends WithNode
{
}
}
PK-d�[~ң�zz"vendor/twig/twig/lib/Twig/Node.phpnu�[���<?php
use Twig\Node\Node;
class_exists('Twig\Node\Node');
if (\false) {
class Twig_Node extends Node
{
}
}
PK-d�[��N��2vendor/twig/twig/lib/Twig/NodeCaptureInterface.phpnu�[���<?php
use Twig\Node\NodeCaptureInterface;
class_exists('Twig\Node\NodeCaptureInterface');
if (\false) {
class Twig_NodeCaptureInterface extends NodeCaptureInterface
{
}
}
PK-d�[br����+vendor/twig/twig/lib/Twig/NodeInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Compiler;
/**
* Represents a node in the AST.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_NodeInterface extends \Countable, \IteratorAggregate
{
/**
* Compiles the node to PHP.
*/
public function compile(Compiler $compiler);
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getLine();
public function getNodeTag();
}
PK-d�[O�8��1vendor/twig/twig/lib/Twig/NodeOutputInterface.phpnu�[���<?php
use Twig\Node\NodeOutputInterface;
class_exists('Twig\Node\NodeOutputInterface');
if (\false) {
class Twig_NodeOutputInterface extends NodeOutputInterface
{
}
}
PK-d�[��퓔�+vendor/twig/twig/lib/Twig/NodeTraverser.phpnu�[���<?php
use Twig\NodeTraverser;
class_exists('Twig\NodeTraverser');
if (\false) {
class Twig_NodeTraverser extends NodeTraverser
{
}
}
PK-d�[h��1vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.phpnu�[���<?php
use Twig\NodeVisitor\EscaperNodeVisitor;
class_exists('Twig\NodeVisitor\EscaperNodeVisitor');
if (\false) {
class Twig_NodeVisitor_Escaper extends EscaperNodeVisitor
{
}
}
PK-d�[$�����3vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.phpnu�[���<?php
use Twig\NodeVisitor\OptimizerNodeVisitor;
class_exists('Twig\NodeVisitor\OptimizerNodeVisitor');
if (\false) {
class Twig_NodeVisitor_Optimizer extends OptimizerNodeVisitor
{
}
}
PK-d�[�����6vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.phpnu�[���<?php
use Twig\NodeVisitor\SafeAnalysisNodeVisitor;
class_exists('Twig\NodeVisitor\SafeAnalysisNodeVisitor');
if (\false) {
class Twig_NodeVisitor_SafeAnalysis extends SafeAnalysisNodeVisitor
{
}
}
PK-d�[�����1vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.phpnu�[���<?php
use Twig\NodeVisitor\SandboxNodeVisitor;
class_exists('Twig\NodeVisitor\SandboxNodeVisitor');
if (\false) {
class Twig_NodeVisitor_Sandbox extends SandboxNodeVisitor
{
}
}
PK-d�[�N@��2vendor/twig/twig/lib/Twig/NodeVisitorInterface.phpnu�[���<?php
use Twig\NodeVisitor\NodeVisitorInterface;
class_exists('Twig\NodeVisitor\NodeVisitorInterface');
if (\false) {
class Twig_NodeVisitorInterface extends NodeVisitorInterface
{
}
}
PK-d�[�(%xx$vendor/twig/twig/lib/Twig/Parser.phpnu�[���<?php
use Twig\Parser;
class_exists('Twig\Parser');
if (\false) {
class Twig_Parser extends Parser
{
}
}
PK-d�[L�E���-vendor/twig/twig/lib/Twig/ParserInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Error\SyntaxError;
use Twig\Node\ModuleNode;
use Twig\TokenStream;
/**
* Interface implemented by parser classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_ParserInterface
{
/**
* Converts a token stream to a node tree.
*
* @return ModuleNode
*
* @throws SyntaxError When the token stream is syntactically or
semantically wrong
*/
public function parse(TokenStream $stream);
}
PK-d�[
��2vendor/twig/twig/lib/Twig/Profiler/Dumper/Base.phpnu�[���<?php
use Twig\Profiler\Dumper\BaseDumper;
class_exists('Twig\Profiler\Dumper\BaseDumper');
if (\false) {
class Twig_Profiler_Dumper_Base extends BaseDumper
{
}
}
PK-d�[w���7vendor/twig/twig/lib/Twig/Profiler/Dumper/Blackfire.phpnu�[���<?php
use Twig\Profiler\Dumper\BlackfireDumper;
class_exists('Twig\Profiler\Dumper\BlackfireDumper');
if (\false) {
class Twig_Profiler_Dumper_Blackfire extends BlackfireDumper
{
}
}
PK-d�[X�f���2vendor/twig/twig/lib/Twig/Profiler/Dumper/Html.phpnu�[���<?php
use Twig\Profiler\Dumper\HtmlDumper;
class_exists('Twig\Profiler\Dumper\HtmlDumper');
if (\false) {
class Twig_Profiler_Dumper_Html extends HtmlDumper
{
}
}
PK-d�[�����2vendor/twig/twig/lib/Twig/Profiler/Dumper/Text.phpnu�[���<?php
use Twig\Profiler\Dumper\TextDumper;
class_exists('Twig\Profiler\Dumper\TextDumper');
if (\false) {
class Twig_Profiler_Dumper_Text extends TextDumper
{
}
}
PK-d�[d����8vendor/twig/twig/lib/Twig/Profiler/Node/EnterProfile.phpnu�[���<?php
use Twig\Profiler\Node\EnterProfileNode;
class_exists('Twig\Profiler\Node\EnterProfileNode');
if (\false) {
class Twig_Profiler_Node_EnterProfile extends EnterProfileNode
{
}
}
PK-d�[�����8vendor/twig/twig/lib/Twig/Profiler/Node/LeaveProfile.phpnu�[���<?php
use Twig\Profiler\Node\LeaveProfileNode;
class_exists('Twig\Profiler\Node\LeaveProfileNode');
if (\false) {
class Twig_Profiler_Node_LeaveProfile extends LeaveProfileNode
{
}
}
PK-d�[~�~��;vendor/twig/twig/lib/Twig/Profiler/NodeVisitor/Profiler.phpnu�[���<?php
use Twig\Profiler\NodeVisitor\ProfilerNodeVisitor;
class_exists('Twig\Profiler\NodeVisitor\ProfilerNodeVisitor');
if (\false) {
class Twig_Profiler_NodeVisitor_Profiler extends ProfilerNodeVisitor
{
}
}
PK-d�[%V��.vendor/twig/twig/lib/Twig/Profiler/Profile.phpnu�[���<?php
use Twig\Profiler\Profile;
class_exists('Twig\Profiler\Profile');
if (\false) {
class Twig_Profiler_Profile extends Profile
{
}
}
PK-d�[Stʼ��4vendor/twig/twig/lib/Twig/RuntimeLoaderInterface.phpnu�[���<?php
use Twig\RuntimeLoader\RuntimeLoaderInterface;
class_exists('Twig\RuntimeLoader\RuntimeLoaderInterface');
if (\false) {
class Twig_RuntimeLoaderInterface extends RuntimeLoaderInterface
{
}
}
PK-d�[
����3vendor/twig/twig/lib/Twig/Sandbox/SecurityError.phpnu�[���<?php
use Twig\Sandbox\SecurityError;
class_exists('Twig\Sandbox\SecurityError');
if (\false) {
class Twig_Sandbox_SecurityError extends SecurityError
{
}
}
PK-d�[�����Cvendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.phpnu�[���<?php
use Twig\Sandbox\SecurityNotAllowedFilterError;
class_exists('Twig\Sandbox\SecurityNotAllowedFilterError');
if (\false) {
class Twig_Sandbox_SecurityNotAllowedFilterError extends
SecurityNotAllowedFilterError
{
}
}
PK-d�[����Evendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.phpnu�[���<?php
use Twig\Sandbox\SecurityNotAllowedFunctionError;
class_exists('Twig\Sandbox\SecurityNotAllowedFunctionError');
if (\false) {
class Twig_Sandbox_SecurityNotAllowedFunctionError extends
SecurityNotAllowedFunctionError
{
}
}
PK-d�[y,����Cvendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedMethodError.phpnu�[���<?php
use Twig\Sandbox\SecurityNotAllowedMethodError;
class_exists('Twig\Sandbox\SecurityNotAllowedMethodError');
if (\false) {
class Twig_Sandbox_SecurityNotAllowedMethodError extends
SecurityNotAllowedMethodError
{
}
}
PK-d�[PMQ��Evendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.phpnu�[���<?php
use Twig\Sandbox\SecurityNotAllowedPropertyError;
class_exists('Twig\Sandbox\SecurityNotAllowedPropertyError');
if (\false) {
class Twig_Sandbox_SecurityNotAllowedPropertyError extends
SecurityNotAllowedPropertyError
{
}
}
PK-d�[�M����@vendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.phpnu�[���<?php
use Twig\Sandbox\SecurityNotAllowedTagError;
class_exists('Twig\Sandbox\SecurityNotAllowedTagError');
if (\false) {
class Twig_Sandbox_SecurityNotAllowedTagError extends
SecurityNotAllowedTagError
{
}
}
PK-d�[�}@���4vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.phpnu�[���<?php
use Twig\Sandbox\SecurityPolicy;
class_exists('Twig\Sandbox\SecurityPolicy');
if (\false) {
class Twig_Sandbox_SecurityPolicy extends SecurityPolicy
{
}
}
PK-d�[��W���=vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.phpnu�[���<?php
use Twig\Sandbox\SecurityPolicyInterface;
class_exists('Twig\Sandbox\SecurityPolicyInterface');
if (\false) {
class Twig_Sandbox_SecurityPolicyInterface extends
SecurityPolicyInterface
{
}
}
PK-d�[�S�*vendor/twig/twig/lib/Twig/SimpleFilter.phpnu�[���<?php
use Twig\TwigFilter;
class_exists('Twig\TwigFilter');
if (\false) {
class Twig_SimpleFilter extends TwigFilter
{
}
}
PK-d�[�\��,vendor/twig/twig/lib/Twig/SimpleFunction.phpnu�[���<?php
use Twig\TwigFunction;
class_exists('Twig\TwigFunction');
if (\false) {
class Twig_SimpleFunction extends TwigFunction
{
}
}
PK-d�[���m��(vendor/twig/twig/lib/Twig/SimpleTest.phpnu�[���<?php
use Twig\TwigTest;
class_exists('Twig\TwigTest');
if (\false) {
class Twig_SimpleTest extends TwigTest
{
}
}
PK-d�[��vxx$vendor/twig/twig/lib/Twig/Source.phpnu�[���<?php
use Twig\Source;
class_exists('Twig\Source');
if (\false) {
class Twig_Source extends Source
{
}
}
PK-d�[�����:vendor/twig/twig/lib/Twig/SourceContextLoaderInterface.phpnu�[���<?php
use Twig\Loader\SourceContextLoaderInterface;
class_exists('Twig\Loader\SourceContextLoaderInterface');
if (\false) {
class Twig_SourceContextLoaderInterface extends
SourceContextLoaderInterface
{
}
}
PK-d�[ֹ鈀�&vendor/twig/twig/lib/Twig/Template.phpnu�[���<?php
use Twig\Template;
class_exists('Twig\Template');
if (\false) {
class Twig_Template extends Template
{
}
}
PK-d�[�yv���/vendor/twig/twig/lib/Twig/TemplateInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Environment;
/**
* Interface implemented by all compiled templates.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_TemplateInterface
{
const ANY_CALL = 'any';
const ARRAY_CALL = 'array';
const METHOD_CALL = 'method';
/**
* Renders the template with the given context and returns it as
string.
*
* @param array $context An array of parameters to pass to the template
*
* @return string The rendered template
*/
public function render(array $context);
/**
* Displays the template with the given context.
*
* @param array $context An array of parameters to pass to the template
* @param array $blocks An array of blocks to pass to the template
*/
public function display(array $context, array $blocks = []);
/**
* Returns the bound environment for this template.
*
* @return Environment
*/
public function getEnvironment();
}
PK-d�[�����-vendor/twig/twig/lib/Twig/TemplateWrapper.phpnu�[���<?php
use Twig\TemplateWrapper;
class_exists('Twig\TemplateWrapper');
if (\false) {
class Twig_TemplateWrapper extends TemplateWrapper
{
}
}
PK-d�[i��WW+vendor/twig/twig/lib/Twig/Test/Function.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Test_Function class is deprecated since
version 1.12 and will be removed in 2.0. Use \Twig\TwigTest instead.',
E_USER_DEPRECATED);
/**
* Represents a function template test.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Test_Function extends Twig_Test
{
protected $function;
public function __construct($function, array $options = [])
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}
PK-d�[��U��6vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.phpnu�[���<?php
use Twig\Test\IntegrationTestCase;
class_exists('Twig\Test\IntegrationTestCase');
if (\false) {
class Twig_Test_IntegrationTestCase extends IntegrationTestCase
{
}
}
PK-d�[_�<**)vendor/twig/twig/lib/Twig/Test/Method.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\Extension\ExtensionInterface;
@trigger_error('The Twig_Test_Method class is deprecated since version
1.12 and will be removed in 2.0. Use \Twig\TwigTest instead.',
E_USER_DEPRECATED);
/**
* Represents a method template test.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Test_Method extends Twig_Test
{
protected $extension;
protected $method;
public function __construct(ExtensionInterface $extension, $method,
array $options = [])
{
$options['callable'] = [$extension, $method];
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return
sprintf('$this->env->getExtension(\'%s\')->%s',
\get_class($this->extension), $this->method);
}
}
PK-d�[�r�\&&'vendor/twig/twig/lib/Twig/Test/Node.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Test_Node class is deprecated since version
1.12 and will be removed in 2.0.', E_USER_DEPRECATED);
/**
* Represents a template test as a Node.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Test_Node extends Twig_Test
{
protected $class;
public function __construct($class, array $options = [])
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}
PK-d�[��P^��/vendor/twig/twig/lib/Twig/Test/NodeTestCase.phpnu�[���<?php
use Twig\Test\NodeTestCase;
class_exists('Twig\Test\NodeTestCase');
if (\false) {
class Twig_Test_NodeTestCase extends NodeTestCase
{
}
}
PK-d�[�@'tt"vendor/twig/twig/lib/Twig/Test.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@trigger_error('The Twig_Test class is deprecated since version 1.12
and will be removed in 2.0. Use \Twig\TwigTest instead.',
E_USER_DEPRECATED);
/**
* Represents a template test.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Test implements Twig_TestInterface,
Twig_TestCallableInterface
{
protected $options;
protected $arguments = [];
public function __construct(array $options = [])
{
$this->options = array_merge([
'callable' => null,
], $options);
}
public function getCallable()
{
return $this->options['callable'];
}
}
PK-d�[�5}��3vendor/twig/twig/lib/Twig/TestCallableInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a callable template test.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_TestCallableInterface
{
public function getCallable();
}
PK-d�[�J3��+vendor/twig/twig/lib/Twig/TestInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template test.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_TestInterface
{
/**
* Compiles a test.
*
* @return string The PHP code for the test
*/
public function compile();
}
PK-d�[�tt#vendor/twig/twig/lib/Twig/Token.phpnu�[���<?php
use Twig\Token;
class_exists('Twig\Token');
if (\false) {
class Twig_Token extends Token
{
}
}
PK-d�[ ��R��4vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.phpnu�[���<?php
use Twig\TokenParser\AutoEscapeTokenParser;
class_exists('Twig\TokenParser\AutoEscapeTokenParser');
if (\false) {
class Twig_TokenParser_AutoEscape extends AutoEscapeTokenParser
{
}
}
PK-d�[���/vendor/twig/twig/lib/Twig/TokenParser/Block.phpnu�[���<?php
use Twig\TokenParser\BlockTokenParser;
class_exists('Twig\TokenParser\BlockTokenParser');
if (\false) {
class Twig_TokenParser_Block extends BlockTokenParser
{
}
}
PK-d�[�+�b��4vendor/twig/twig/lib/Twig/TokenParser/Deprecated.phpnu�[���<?php
use Twig\TokenParser\DeprecatedTokenParser;
class_exists('Twig\TokenParser\DeprecatedTokenParser');
if (\false) {
class Twig_TokenParser_Deprecated extends DeprecatedTokenParser
{
}
}
PK-d�[:IA[��,vendor/twig/twig/lib/Twig/TokenParser/Do.phpnu�[���<?php
use Twig\TokenParser\DoTokenParser;
class_exists('Twig\TokenParser\DoTokenParser');
if (\false) {
class Twig_TokenParser_Do extends DoTokenParser
{
}
}
PK-d�[�!'�/vendor/twig/twig/lib/Twig/TokenParser/Embed.phpnu�[���<?php
use Twig\TokenParser\EmbedTokenParser;
class_exists('Twig\TokenParser\EmbedTokenParser');
if (\false) {
class Twig_TokenParser_Embed extends EmbedTokenParser
{
}
}
PK-d�[�z���1vendor/twig/twig/lib/Twig/TokenParser/Extends.phpnu�[���<?php
use Twig\TokenParser\ExtendsTokenParser;
class_exists('Twig\TokenParser\ExtendsTokenParser');
if (\false) {
class Twig_TokenParser_Extends extends ExtendsTokenParser
{
}
}
PK-d�[�UTK��0vendor/twig/twig/lib/Twig/TokenParser/Filter.phpnu�[���<?php
use Twig\TokenParser\FilterTokenParser;
class_exists('Twig\TokenParser\FilterTokenParser');
if (\false) {
class Twig_TokenParser_Filter extends FilterTokenParser
{
}
}
PK-d�[�����/vendor/twig/twig/lib/Twig/TokenParser/Flush.phpnu�[���<?php
use Twig\TokenParser\FlushTokenParser;
class_exists('Twig\TokenParser\FlushTokenParser');
if (\false) {
class Twig_TokenParser_Flush extends FlushTokenParser
{
}
}
PK-d�[N
���-vendor/twig/twig/lib/Twig/TokenParser/For.phpnu�[���<?php
use Twig\TokenParser\ForTokenParser;
class_exists('Twig\TokenParser\ForTokenParser');
if (\false) {
class Twig_TokenParser_For extends ForTokenParser
{
}
}
PK-d�[e�mU��.vendor/twig/twig/lib/Twig/TokenParser/From.phpnu�[���<?php
use Twig\TokenParser\FromTokenParser;
class_exists('Twig\TokenParser\FromTokenParser');
if (\false) {
class Twig_TokenParser_From extends FromTokenParser
{
}
}
PK-d�[?_d`��,vendor/twig/twig/lib/Twig/TokenParser/If.phpnu�[���<?php
use Twig\TokenParser\IfTokenParser;
class_exists('Twig\TokenParser\IfTokenParser');
if (\false) {
class Twig_TokenParser_If extends IfTokenParser
{
}
}
PK-d�[�1 ��0vendor/twig/twig/lib/Twig/TokenParser/Import.phpnu�[���<?php
use Twig\TokenParser\ImportTokenParser;
class_exists('Twig\TokenParser\ImportTokenParser');
if (\false) {
class Twig_TokenParser_Import extends ImportTokenParser
{
}
}
PK-d�[�@�|��1vendor/twig/twig/lib/Twig/TokenParser/Include.phpnu�[���<?php
use Twig\TokenParser\IncludeTokenParser;
class_exists('Twig\TokenParser\IncludeTokenParser');
if (\false) {
class Twig_TokenParser_Include extends IncludeTokenParser
{
}
}
PK-d�[Bl�
��/vendor/twig/twig/lib/Twig/TokenParser/Macro.phpnu�[���<?php
use Twig\TokenParser\MacroTokenParser;
class_exists('Twig\TokenParser\MacroTokenParser');
if (\false) {
class Twig_TokenParser_Macro extends MacroTokenParser
{
}
}
PK-d�[�V̐��1vendor/twig/twig/lib/Twig/TokenParser/Sandbox.phpnu�[���<?php
use Twig\TokenParser\SandboxTokenParser;
class_exists('Twig\TokenParser\SandboxTokenParser');
if (\false) {
class Twig_TokenParser_Sandbox extends SandboxTokenParser
{
}
}
PK-d�[g����-vendor/twig/twig/lib/Twig/TokenParser/Set.phpnu�[���<?php
use Twig\TokenParser\SetTokenParser;
class_exists('Twig\TokenParser\SetTokenParser');
if (\false) {
class Twig_TokenParser_Set extends SetTokenParser
{
}
}
PK-d�[������3vendor/twig/twig/lib/Twig/TokenParser/Spaceless.phpnu�[���<?php
use Twig\TokenParser\SpacelessTokenParser;
class_exists('Twig\TokenParser\SpacelessTokenParser');
if (\false) {
class Twig_TokenParser_Spaceless extends SpacelessTokenParser
{
}
}
PK-d�[A�[��-vendor/twig/twig/lib/Twig/TokenParser/Use.phpnu�[���<?php
use Twig\TokenParser\UseTokenParser;
class_exists('Twig\TokenParser\UseTokenParser');
if (\false) {
class Twig_TokenParser_Use extends UseTokenParser
{
}
}
PK-d�[�ou��.vendor/twig/twig/lib/Twig/TokenParser/With.phpnu�[���<?php
use Twig\TokenParser\WithTokenParser;
class_exists('Twig\TokenParser\WithTokenParser');
if (\false) {
class Twig_TokenParser_With extends WithTokenParser
{
}
}
PK-d�[/u�:��)vendor/twig/twig/lib/Twig/TokenParser.phpnu�[���<?php
use Twig\TokenParser\AbstractTokenParser;
class_exists('Twig\TokenParser\AbstractTokenParser');
if (\false) {
class Twig_TokenParser extends AbstractTokenParser
{
}
}
PK-d�[��Z�/vendor/twig/twig/lib/Twig/TokenParserBroker.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\TokenParser\TokenParserInterface;
/**
* Default implementation of a token parser broker.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface
{
protected $parser;
protected $parsers = [];
protected $brokers = [];
/**
* @param array|\Traversable $parsers A \Traversable of
Twig_TokenParserInterface instances
* @param array|\Traversable $brokers A \Traversable of
Twig_TokenParserBrokerInterface instances
* @param bool $triggerDeprecationError
*/
public function __construct($parsers = [], $brokers = [],
$triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__CLASS__.' class is
deprecated since version 1.12 and will be removed in 2.0.',
E_USER_DEPRECATED);
}
foreach ($parsers as $parser) {
if (!$parser instanceof TokenParserInterface) {
throw new \LogicException('$parsers must a an array of
Twig_TokenParserInterface.');
}
$this->parsers[$parser->getTag()] = $parser;
}
foreach ($brokers as $broker) {
if (!$broker instanceof Twig_TokenParserBrokerInterface) {
throw new \LogicException('$brokers must a an array of
Twig_TokenParserBrokerInterface.');
}
$this->brokers[] = $broker;
}
}
public function addTokenParser(TokenParserInterface $parser)
{
$this->parsers[$parser->getTag()] = $parser;
}
public function removeTokenParser(TokenParserInterface $parser)
{
$name = $parser->getTag();
if (isset($this->parsers[$name]) && $parser ===
$this->parsers[$name]) {
unset($this->parsers[$name]);
}
}
public function addTokenParserBroker(self $broker)
{
$this->brokers[] = $broker;
}
public function removeTokenParserBroker(self $broker)
{
if (false !== $pos = array_search($broker, $this->brokers)) {
unset($this->brokers[$pos]);
}
}
/**
* Gets a suitable TokenParser for a tag.
*
* First looks in parsers, then in brokers.
*
* @param string $tag A tag name
*
* @return TokenParserInterface|null A Twig_TokenParserInterface or
null if no suitable TokenParser was found
*/
public function getTokenParser($tag)
{
if (isset($this->parsers[$tag])) {
return $this->parsers[$tag];
}
$broker = end($this->brokers);
while (false !== $broker) {
$parser = $broker->getTokenParser($tag);
if (null !== $parser) {
return $parser;
}
$broker = prev($this->brokers);
}
}
public function getParsers()
{
return $this->parsers;
}
public function getParser()
{
return $this->parser;
}
public function setParser(Twig_ParserInterface $parser)
{
$this->parser = $parser;
foreach ($this->parsers as $tokenParser) {
$tokenParser->setParser($parser);
}
foreach ($this->brokers as $broker) {
$broker->setParser($parser);
}
}
}
PK-d�[�@v#��8vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Twig\TokenParser\TokenParserInterface;
/**
* Interface implemented by token parser brokers.
*
* Token parser brokers allows to implement custom logic in the process of
resolving a token parser for a given tag name.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_TokenParserBrokerInterface
{
/**
* Gets a TokenParser suitable for a tag.
*
* @param string $tag A tag name
*
* @return TokenParserInterface|null A Twig_TokenParserInterface or
null if no suitable TokenParser was found
*/
public function getTokenParser($tag);
/**
* Calls Twig\TokenParser\TokenParserInterface::setParser on all
parsers the implementation knows of.
*/
public function setParser(Twig_ParserInterface $parser);
/**
* Gets the Twig_ParserInterface.
*
* @return Twig_ParserInterface|null A Twig_ParserInterface instance or
null
*/
public function getParser();
}
PK-d�[����2vendor/twig/twig/lib/Twig/TokenParserInterface.phpnu�[���<?php
use Twig\TokenParser\TokenParserInterface;
class_exists('Twig\TokenParser\TokenParserInterface');
if (\false) {
class Twig_TokenParserInterface extends TokenParserInterface
{
}
}
PK-d�[�ܚ��)vendor/twig/twig/lib/Twig/TokenStream.phpnu�[���<?php
use Twig\TokenStream;
class_exists('Twig\TokenStream');
if (\false) {
class Twig_TokenStream extends TokenStream
{
}
}
PK-d�["�ǿ�7vendor/twig/twig/lib/Twig/Util/DeprecationCollector.phpnu�[���<?php
use Twig\Util\DeprecationCollector;
class_exists('Twig\Util\DeprecationCollector');
if (\false) {
class Twig_Util_DeprecationCollector extends DeprecationCollector
{
}
}
PK-d�[Z8�Q��6vendor/twig/twig/lib/Twig/Util/TemplateDirIterator.phpnu�[���<?php
use Twig\Util\TemplateDirIterator;
class_exists('Twig\Util\TemplateDirIterator');
if (\false) {
class Twig_Util_TemplateDirIterator extends TemplateDirIterator
{
}
}
PK-d�[��P;��-vendor/twig/twig/src/Cache/CacheInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Interface implemented by cache classes.
*
* It is highly recommended to always store templates on the filesystem to
* benefit from the PHP opcode cache. This interface is mostly useful if
you
* need to implement a custom strategy for storing templates on the
filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
interface CacheInterface
{
/**
* Generates a cache key for the given template class name.
*
* @param string $name The template name
* @param string $className The template class name
*
* @return string
*/
public function generateKey($name, $className);
/**
* Writes the compiled template to cache.
*
* @param string $key The cache key
* @param string $content The template representation as a PHP class
*/
public function write($key, $content);
/**
* Loads a template from the cache.
*
* @param string $key The cache key
*/
public function load($key);
/**
* Returns the modification timestamp of a key.
*
* @param string $key The cache key
*
* @return int
*/
public function getTimestamp($key);
}
class_alias('Twig\Cache\CacheInterface',
'Twig_CacheInterface');
PK-d�[E���0
0
.vendor/twig/twig/src/Cache/FilesystemCache.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Implements a cache on the filesystem.
*
* @author Andrew Tch <andrew@noop.lv>
*/
class FilesystemCache implements CacheInterface
{
const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
/**
* @param string $directory The root cache directory
* @param int $options A set of options
*/
public function __construct($directory, $options = 0)
{
$this->directory = rtrim($directory,
'\/').'/';
$this->options = $options;
}
public function generateKey($name, $className)
{
$hash = hash('sha256', $className);
return
$this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
public function load($key)
{
if (file_exists($key)) {
@include_once $key;
}
}
public function write($key, $content)
{
$dir = \dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true)) {
clearstatcache(true, $dir);
if (!is_dir($dir)) {
throw new \RuntimeException(sprintf('Unable to
create the cache directory (%s).', $dir));
}
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in
the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) &&
@rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options
& self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (\function_exists('opcache_invalidate')
&& filter_var(ini_get('opcache.enable'),
FILTER_VALIDATE_BOOLEAN)) {
@opcache_invalidate($key, true);
} elseif (\function_exists('apc_compile_file')) {
apc_compile_file($key);
}
}
return;
}
throw new \RuntimeException(sprintf('Failed to write cache
file "%s".', $key));
}
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}
class_alias('Twig\Cache\FilesystemCache',
'Twig_Cache_Filesystem');
PK-d�[�6T��(vendor/twig/twig/src/Cache/NullCache.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Implements a no-cache strategy.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class NullCache implements CacheInterface
{
public function generateKey($name, $className)
{
return '';
}
public function write($key, $content)
{
}
public function load($key)
{
}
public function getTimestamp($key)
{
return 0;
}
}
class_alias('Twig\Cache\NullCache', 'Twig_Cache_Null');
PK-d�[:��Xzz!vendor/twig/twig/src/Compiler.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Node\ModuleNode;
/**
* Compiles a node to PHP code.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Compiler implements \Twig_CompilerInterface
{
protected $lastLine;
protected $source;
protected $indentation;
protected $env;
protected $debugInfo = [];
protected $sourceOffset;
protected $sourceLine;
protected $filename;
private $varNameSalt = 0;
public function __construct(Environment $env)
{
$this->env = $env;
}
/**
* @deprecated since 1.25 (to be removed in 2.0)
*/
public function getFilename()
{
@trigger_error(sprintf('The %s() method is deprecated since
version 1.25 and will be removed in 2.0.', __FUNCTION__),
E_USER_DEPRECATED);
return $this->filename;
}
/**
* Returns the environment instance related to this compiler.
*
* @return Environment
*/
public function getEnvironment()
{
return $this->env;
}
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource()
{
return $this->source;
}
/**
* Compiles a node.
*
* @param int $indentation The current indentation
*
* @return $this
*/
public function compile(\Twig_NodeInterface $node, $indentation = 0)
{
$this->lastLine = null;
$this->source = '';
$this->debugInfo = [];
$this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we
encounter new lines)
$this->sourceLine = 1;
$this->indentation = $indentation;
$this->varNameSalt = 0;
if ($node instanceof ModuleNode) {
// to be removed in 2.0
$this->filename = $node->getTemplateName();
}
$node->compile($this);
return $this;
}
public function subcompile(\Twig_NodeInterface $node, $raw = true)
{
if (false === $raw) {
$this->source .= str_repeat(' ',
$this->indentation * 4);
}
$node->compile($this);
return $this;
}
/**
* Adds a raw string to the compiled code.
*
* @param string $string The string
*
* @return $this
*/
public function raw($string)
{
$this->source .= $string;
return $this;
}
/**
* Writes a string to the compiled code by adding indentation.
*
* @return $this
*/
public function write()
{
$strings = \func_get_args();
foreach ($strings as $string) {
$this->source .= str_repeat(' ',
$this->indentation * 4).$string;
}
return $this;
}
/**
* Appends an indentation to the current PHP code after compilation.
*
* @return $this
*
* @deprecated since 1.27 (to be removed in 2.0).
*/
public function addIndentation()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0. Use
write(\'\') instead.', E_USER_DEPRECATED);
$this->source .= str_repeat(' ', $this->indentation
* 4);
return $this;
}
/**
* Adds a quoted string to the compiled code.
*
* @param string $value The string
*
* @return $this
*/
public function string($value)
{
$this->source .= sprintf('"%s"',
addcslashes($value, "\0\t\"\$\\"));
return $this;
}
/**
* Returns a PHP representation of a given value.
*
* @param mixed $value The value to convert
*
* @return $this
*/
public function repr($value)
{
if (\is_int($value) || \is_float($value)) {
if (false !== $locale = setlocale(LC_NUMERIC, '0')) {
setlocale(LC_NUMERIC, 'C');
}
$this->raw(var_export($value, true));
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
} elseif (null === $value) {
$this->raw('null');
} elseif (\is_bool($value)) {
$this->raw($value ? 'true' : 'false');
} elseif (\is_array($value)) {
$this->raw('[');
$first = true;
foreach ($value as $key => $v) {
if (!$first) {
$this->raw(', ');
}
$first = false;
$this->repr($key);
$this->raw(' => ');
$this->repr($v);
}
$this->raw(']');
} else {
$this->string($value);
}
return $this;
}
/**
* Adds debugging information.
*
* @return $this
*/
public function addDebugInfo(\Twig_NodeInterface $node)
{
if ($node->getTemplateLine() != $this->lastLine) {
$this->write(sprintf("// line %d\n",
$node->getTemplateLine()));
// when mbstring.func_overload is set to 2
// mb_substr_count() replaces substr_count()
// but they have different signatures!
if (((int) ini_get('mbstring.func_overload')) &
2) {
@trigger_error('Support for having
"mbstring.func_overload" different from 0 is deprecated version
1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
// this is much slower than the "right" version
$this->sourceLine +=
mb_substr_count(mb_substr($this->source, $this->sourceOffset),
"\n");
} else {
$this->sourceLine += substr_count($this->source,
"\n", $this->sourceOffset);
}
$this->sourceOffset = \strlen($this->source);
$this->debugInfo[$this->sourceLine] =
$node->getTemplateLine();
$this->lastLine = $node->getTemplateLine();
}
return $this;
}
public function getDebugInfo()
{
ksort($this->debugInfo);
return $this->debugInfo;
}
/**
* Indents the generated code.
*
* @param int $step The number of indentation to add
*
* @return $this
*/
public function indent($step = 1)
{
$this->indentation += $step;
return $this;
}
/**
* Outdents the generated code.
*
* @param int $step The number of indentation to remove
*
* @return $this
*
* @throws \LogicException When trying to outdent too much so the
indentation would become negative
*/
public function outdent($step = 1)
{
// can't outdent by more steps than the current indentation
level
if ($this->indentation < $step) {
throw new \LogicException('Unable to call outdent() as the
indentation would become negative.');
}
$this->indentation -= $step;
return $this;
}
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256',
__METHOD__.$this->varNameSalt++));
}
}
class_alias('Twig\Compiler', 'Twig_Compiler');
PK-d�[��.����$vendor/twig/twig/src/Environment.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Cache\CacheInterface;
use Twig\Cache\FilesystemCache;
use Twig\Cache\NullCache;
use Twig\Error\Error;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Extension\CoreExtension;
use Twig\Extension\EscaperExtension;
use Twig\Extension\ExtensionInterface;
use Twig\Extension\GlobalsInterface;
use Twig\Extension\InitRuntimeInterface;
use Twig\Extension\OptimizerExtension;
use Twig\Extension\StagingExtension;
use Twig\Loader\ArrayLoader;
use Twig\Loader\ChainLoader;
use Twig\Loader\LoaderInterface;
use Twig\Loader\SourceContextLoaderInterface;
use Twig\Node\ModuleNode;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\RuntimeLoader\RuntimeLoaderInterface;
use Twig\TokenParser\TokenParserInterface;
/**
* Stores the Twig configuration.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Environment
{
const VERSION = '1.42.5';
const VERSION_ID = 14205;
const MAJOR_VERSION = 1;
const MINOR_VERSION = 42;
const RELEASE_VERSION = 5;
const EXTRA_VERSION = '';
protected $charset;
protected $loader;
protected $debug;
protected $autoReload;
protected $cache;
protected $lexer;
protected $parser;
protected $compiler;
protected $baseTemplateClass;
protected $extensions;
protected $parsers;
protected $visitors;
protected $filters;
protected $tests;
protected $functions;
protected $globals;
protected $runtimeInitialized = false;
protected $extensionInitialized = false;
protected $loadedTemplates;
protected $strictVariables;
protected $unaryOperators;
protected $binaryOperators;
protected $templateClassPrefix = '__TwigTemplate_';
protected $functionCallbacks = [];
protected $filterCallbacks = [];
protected $staging;
private $originalCache;
private $bcWriteCacheFile = false;
private $bcGetCacheFilename = false;
private $lastModifiedExtension = 0;
private $extensionsByClass = [];
private $runtimeLoaders = [];
private $runtimes = [];
private $optionsHash;
/**
* Constructor.
*
* Available options:
*
* * debug: When set to true, it automatically set
"auto_reload" to true as
* well (default to false).
*
* * charset: The charset used by the templates (default to UTF-8).
*
* * base_template_class: The base template class to use for generated
* templates (default to \Twig\Template).
*
* * cache: An absolute path where to store the compiled templates,
* a \Twig\Cache\CacheInterface implementation,
* or false to disable compilation cache (default).
*
* * auto_reload: Whether to reload the template if the original
source changed.
* If you don't provide the auto_reload option, it
will be
* determined automatically based on the debug value.
*
* * strict_variables: Whether to ignore invalid variables in
templates
* (default to false).
*
* * autoescape: Whether to enable auto-escaping (default to html):
* * false: disable auto-escaping
* * true: equivalent to html
* * html, js: set the autoescaping to one of the
supported strategies
* * name: set the autoescaping strategy based on the
template name extension
* * PHP callback: a PHP callback that returns an
escaping strategy based on the template "name"
*
* * optimizations: A flag that indicates which optimizations to apply
* (default to -1 which means that all optimizations
are enabled;
* set it to 0 to disable).
*/
public function __construct(LoaderInterface $loader = null, $options =
[])
{
if (null !== $loader) {
$this->setLoader($loader);
} else {
@trigger_error('Not passing a
"Twig\Lodaer\LoaderInterface" as the first constructor argument
of "Twig\Environment" is deprecated since version 1.21.',
E_USER_DEPRECATED);
}
$options = array_merge([
'debug' => false,
'charset' => 'UTF-8',
'base_template_class' =>
'\Twig\Template',
'strict_variables' => false,
'autoescape' => 'html',
'cache' => false,
'auto_reload' => null,
'optimizations' => -1,
], $options);
$this->debug = (bool) $options['debug'];
$this->charset = strtoupper($options['charset']);
$this->baseTemplateClass =
$options['base_template_class'];
$this->autoReload = null === $options['auto_reload'] ?
$this->debug : (bool) $options['auto_reload'];
$this->strictVariables = (bool)
$options['strict_variables'];
$this->setCache($options['cache']);
$this->addExtension(new CoreExtension());
$this->addExtension(new
EscaperExtension($options['autoescape']));
$this->addExtension(new
OptimizerExtension($options['optimizations']));
$this->staging = new StagingExtension();
// For BC
if (\is_string($this->originalCache)) {
$r = new \ReflectionMethod($this, 'writeCacheFile');
if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
@trigger_error('The Twig\Environment::writeCacheFile
method is deprecated since version 1.22 and will be removed in Twig
2.0.', E_USER_DEPRECATED);
$this->bcWriteCacheFile = true;
}
$r = new \ReflectionMethod($this,
'getCacheFilename');
if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
@trigger_error('The Twig\Environment::getCacheFilename
method is deprecated since version 1.22 and will be removed in Twig
2.0.', E_USER_DEPRECATED);
$this->bcGetCacheFilename = true;
}
}
}
/**
* Gets the base template class for compiled templates.
*
* @return string The base template class name
*/
public function getBaseTemplateClass()
{
return $this->baseTemplateClass;
}
/**
* Sets the base template class for compiled templates.
*
* @param string $class The base template class name
*/
public function setBaseTemplateClass($class)
{
$this->baseTemplateClass = $class;
$this->updateOptionsHash();
}
/**
* Enables debugging mode.
*/
public function enableDebug()
{
$this->debug = true;
$this->updateOptionsHash();
}
/**
* Disables debugging mode.
*/
public function disableDebug()
{
$this->debug = false;
$this->updateOptionsHash();
}
/**
* Checks if debug mode is enabled.
*
* @return bool true if debug mode is enabled, false otherwise
*/
public function isDebug()
{
return $this->debug;
}
/**
* Enables the auto_reload option.
*/
public function enableAutoReload()
{
$this->autoReload = true;
}
/**
* Disables the auto_reload option.
*/
public function disableAutoReload()
{
$this->autoReload = false;
}
/**
* Checks if the auto_reload option is enabled.
*
* @return bool true if auto_reload is enabled, false otherwise
*/
public function isAutoReload()
{
return $this->autoReload;
}
/**
* Enables the strict_variables option.
*/
public function enableStrictVariables()
{
$this->strictVariables = true;
$this->updateOptionsHash();
}
/**
* Disables the strict_variables option.
*/
public function disableStrictVariables()
{
$this->strictVariables = false;
$this->updateOptionsHash();
}
/**
* Checks if the strict_variables option is enabled.
*
* @return bool true if strict_variables is enabled, false otherwise
*/
public function isStrictVariables()
{
return $this->strictVariables;
}
/**
* Gets the current cache implementation.
*
* @param bool $original Whether to return the original cache option or
the real cache instance
*
* @return CacheInterface|string|false A Twig\Cache\CacheInterface
implementation,
* an absolute path to the compiled
templates,
* or false to disable cache
*/
public function getCache($original = true)
{
return $original ? $this->originalCache : $this->cache;
}
/**
* Sets the current cache implementation.
*
* @param CacheInterface|string|false $cache A
Twig\Cache\CacheInterface implementation,
* an absolute path to the
compiled templates,
* or false to disable cache
*/
public function setCache($cache)
{
if (\is_string($cache)) {
$this->originalCache = $cache;
$this->cache = new FilesystemCache($cache);
} elseif (false === $cache) {
$this->originalCache = $cache;
$this->cache = new NullCache();
} elseif (null === $cache) {
@trigger_error('Using "null" as the cache
strategy is deprecated since version 1.23 and will be removed in Twig
2.0.', E_USER_DEPRECATED);
$this->originalCache = false;
$this->cache = new NullCache();
} elseif ($cache instanceof CacheInterface) {
$this->originalCache = $this->cache = $cache;
} else {
throw new \LogicException(sprintf('Cache can only be a
string, false, or a \Twig\Cache\CacheInterface implementation.'));
}
}
/**
* Gets the cache filename for a given template.
*
* @param string $name The template name
*
* @return string|false The cache file name or false when caching is
disabled
*
* @deprecated since 1.22 (to be removed in 2.0)
*/
public function getCacheFilename($name)
{
@trigger_error(sprintf('The %s method is deprecated since
version 1.22 and will be removed in Twig 2.0.', __METHOD__),
E_USER_DEPRECATED);
$key = $this->cache->generateKey($name,
$this->getTemplateClass($name));
return !$key ? false : $key;
}
/**
* Gets the template class associated with the given string.
*
* The generated template class is based on the following parameters:
*
* * The cache key for the given template;
* * The currently enabled extensions;
* * Whether the Twig C extension is available or not;
* * PHP version;
* * Twig version;
* * Options with what environment was created.
*
* @param string $name The name for which to calculate the template
class name
* @param int|null $index The index if it is an embedded template
*
* @return string The template class name
*/
public function getTemplateClass($name, $index = null)
{
$key =
$this->getLoader()->getCacheKey($name).$this->optionsHash;
return $this->templateClassPrefix.hash('sha256',
$key).(null === $index ? '' : '___'.$index);
}
/**
* Gets the template class prefix.
*
* @return string The template class prefix
*
* @deprecated since 1.22 (to be removed in 2.0)
*/
public function getTemplateClassPrefix()
{
@trigger_error(sprintf('The %s method is deprecated since
version 1.22 and will be removed in Twig 2.0.', __METHOD__),
E_USER_DEPRECATED);
return $this->templateClassPrefix;
}
/**
* Renders a template.
*
* @param string|TemplateWrapper $name The template name
* @param array $context An array of parameters to
pass to the template
*
* @return string The rendered template
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
* @throws RuntimeError When an error occurred during rendering
*/
public function render($name, array $context = [])
{
return $this->load($name)->render($context);
}
/**
* Displays a template.
*
* @param string|TemplateWrapper $name The template name
* @param array $context An array of parameters to
pass to the template
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
* @throws RuntimeError When an error occurred during rendering
*/
public function display($name, array $context = [])
{
$this->load($name)->display($context);
}
/**
* Loads a template.
*
* @param string|TemplateWrapper|\Twig\Template $name The template name
*
* @throws LoaderError When the template cannot be found
* @throws RuntimeError When a previously generated cache is corrupted
* @throws SyntaxError When an error occurred during compilation
*
* @return TemplateWrapper
*/
public function load($name)
{
if ($name instanceof TemplateWrapper) {
return $name;
}
if ($name instanceof Template) {
return new TemplateWrapper($this, $name);
}
return new TemplateWrapper($this, $this->loadTemplate($name));
}
/**
* Loads a template internal representation.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The template name
* @param int $index The index if it is an embedded template
*
* @return \Twig_TemplateInterface A template instance representing the
given template name
*
* @throws LoaderError When the template cannot be found
* @throws RuntimeError When a previously generated cache is corrupted
* @throws SyntaxError When an error occurred during compilation
*
* @internal
*/
public function loadTemplate($name, $index = null)
{
return $this->loadClass($this->getTemplateClass($name),
$name, $index);
}
/**
* @internal
*/
public function loadClass($cls, $name, $index = null)
{
$mainCls = $cls;
if (null !== $index) {
$cls .= '___'.$index;
}
if (isset($this->loadedTemplates[$cls])) {
return $this->loadedTemplates[$cls];
}
if (!class_exists($cls, false)) {
if ($this->bcGetCacheFilename) {
$key = $this->getCacheFilename($name);
} else {
$key = $this->cache->generateKey($name, $mainCls);
}
if (!$this->isAutoReload() ||
$this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
$this->cache->load($key);
}
$source = null;
if (!class_exists($cls, false)) {
$loader = $this->getLoader();
if (!$loader instanceof SourceContextLoaderInterface) {
$source = new Source($loader->getSource($name),
$name);
} else {
$source = $loader->getSourceContext($name);
}
$content = $this->compileSource($source);
if ($this->bcWriteCacheFile) {
$this->writeCacheFile($key, $content);
} else {
$this->cache->write($key, $content);
$this->cache->load($key);
}
if (!class_exists($mainCls, false)) {
/* Last line of defense if either
$this->bcWriteCacheFile was used,
* $this->cache is implemented as a no-op or we have
a race condition
* where the cache was cleared between the above calls
to write to and load from
* the cache.
*/
eval('?>'.$content);
}
}
if (!class_exists($cls, false)) {
throw new RuntimeError(sprintf('Failed to load Twig
template "%s", index "%s": cache might be
corrupted.', $name, $index), -1, $source);
}
}
if (!$this->runtimeInitialized) {
$this->initRuntime();
}
return $this->loadedTemplates[$cls] = new $cls($this);
}
/**
* Creates a template from source.
*
* This method should not be used as a generic way to load templates.
*
* @param string $template The template source
* @param string $name An optional name of the template to be used
in error messages
*
* @return TemplateWrapper A template instance representing the given
template name
*
* @throws LoaderError When the template cannot be found
* @throws SyntaxError When an error occurred during compilation
*/
public function createTemplate($template, $name = null)
{
$hash = hash('sha256', $template, false);
if (null !== $name) {
$name = sprintf('%s (string template %s)', $name,
$hash);
} else {
$name = sprintf('__string_template__%s', $hash);
}
$loader = new ChainLoader([
new ArrayLoader([$name => $template]),
$current = $this->getLoader(),
]);
$this->setLoader($loader);
try {
$template = new TemplateWrapper($this,
$this->loadTemplate($name));
} catch (\Exception $e) {
$this->setLoader($current);
throw $e;
} catch (\Throwable $e) {
$this->setLoader($current);
throw $e;
}
$this->setLoader($current);
return $template;
}
/**
* Returns true if the template is still fresh.
*
* Besides checking the loader for freshness information,
* this method also checks if the enabled extensions have
* not changed.
*
* @param string $name The template name
* @param int $time The last modification time of the cached
template
*
* @return bool true if the template is fresh, false otherwise
*/
public function isTemplateFresh($name, $time)
{
if (0 === $this->lastModifiedExtension) {
foreach ($this->extensions as $extension) {
$r = new \ReflectionObject($extension);
if (file_exists($r->getFileName()) &&
($extensionTime = filemtime($r->getFileName())) >
$this->lastModifiedExtension) {
$this->lastModifiedExtension = $extensionTime;
}
}
}
return $this->lastModifiedExtension <= $time &&
$this->getLoader()->isFresh($name, $time);
}
/**
* Tries to load a template consecutively from an array.
*
* Similar to load() but it also accepts instances of \Twig\Template
and
* \Twig\TemplateWrapper, and an array of templates where each is tried
to be loaded.
*
* @param string|Template|\Twig\TemplateWrapper|array $names A template
or an array of templates to try consecutively
*
* @return TemplateWrapper|Template
*
* @throws LoaderError When none of the templates can be found
* @throws SyntaxError When an error occurred during compilation
*/
public function resolveTemplate($names)
{
if (!\is_array($names)) {
$names = [$names];
}
foreach ($names as $name) {
if ($name instanceof Template) {
return $name;
}
if ($name instanceof TemplateWrapper) {
return $name;
}
try {
return $this->loadTemplate($name);
} catch (LoaderError $e) {
if (1 === \count($names)) {
throw $e;
}
}
}
throw new LoaderError(sprintf('Unable to find one of the
following templates: "%s".', implode('",
"', $names)));
}
/**
* Clears the internal template cache.
*
* @deprecated since 1.18.3 (to be removed in 2.0)
*/
public function clearTemplateCache()
{
@trigger_error(sprintf('The %s method is deprecated since
version 1.18.3 and will be removed in Twig 2.0.', __METHOD__),
E_USER_DEPRECATED);
$this->loadedTemplates = [];
}
/**
* Clears the template cache files on the filesystem.
*
* @deprecated since 1.22 (to be removed in 2.0)
*/
public function clearCacheFiles()
{
@trigger_error(sprintf('The %s method is deprecated since
version 1.22 and will be removed in Twig 2.0.', __METHOD__),
E_USER_DEPRECATED);
if (\is_string($this->originalCache)) {
foreach (new \RecursiveIteratorIterator(new
\RecursiveDirectoryIterator($this->originalCache),
\RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if ($file->isFile()) {
@unlink($file->getPathname());
}
}
}
}
/**
* Gets the Lexer instance.
*
* @return \Twig_LexerInterface
*
* @deprecated since 1.25 (to be removed in 2.0)
*/
public function getLexer()
{
@trigger_error(sprintf('The %s() method is deprecated since
version 1.25 and will be removed in 2.0.', __FUNCTION__),
E_USER_DEPRECATED);
if (null === $this->lexer) {
$this->lexer = new Lexer($this);
}
return $this->lexer;
}
public function setLexer(\Twig_LexerInterface $lexer)
{
$this->lexer = $lexer;
}
/**
* Tokenizes a source code.
*
* @param string|Source $source The template source code
* @param string $name The template name (deprecated)
*
* @return TokenStream
*
* @throws SyntaxError When the code is syntactically wrong
*/
public function tokenize($source, $name = null)
{
if (!$source instanceof Source) {
@trigger_error(sprintf('Passing a string as the $source
argument of %s() is deprecated since version 1.27. Pass a Twig\Source
instance instead.', __METHOD__), E_USER_DEPRECATED);
$source = new Source($source, $name);
}
if (null === $this->lexer) {
$this->lexer = new Lexer($this);
}
return $this->lexer->tokenize($source);
}
/**
* Gets the Parser instance.
*
* @return \Twig_ParserInterface
*
* @deprecated since 1.25 (to be removed in 2.0)
*/
public function getParser()
{
@trigger_error(sprintf('The %s() method is deprecated since
version 1.25 and will be removed in 2.0.', __FUNCTION__),
E_USER_DEPRECATED);
if (null === $this->parser) {
$this->parser = new Parser($this);
}
return $this->parser;
}
public function setParser(\Twig_ParserInterface $parser)
{
$this->parser = $parser;
}
/**
* Converts a token stream to a node tree.
*
* @return ModuleNode
*
* @throws SyntaxError When the token stream is syntactically or
semantically wrong
*/
public function parse(TokenStream $stream)
{
if (null === $this->parser) {
$this->parser = new Parser($this);
}
return $this->parser->parse($stream);
}
/**
* Gets the Compiler instance.
*
* @return \Twig_CompilerInterface
*
* @deprecated since 1.25 (to be removed in 2.0)
*/
public function getCompiler()
{
@trigger_error(sprintf('The %s() method is deprecated since
version 1.25 and will be removed in 2.0.', __FUNCTION__),
E_USER_DEPRECATED);
if (null === $this->compiler) {
$this->compiler = new Compiler($this);
}
return $this->compiler;
}
public function setCompiler(\Twig_CompilerInterface $compiler)
{
$this->compiler = $compiler;
}
/**
* Compiles a node and returns the PHP code.
*
* @return string The compiled PHP source code
*/
public function compile(\Twig_NodeInterface $node)
{
if (null === $this->compiler) {
$this->compiler = new Compiler($this);
}
return $this->compiler->compile($node)->getSource();
}
/**
* Compiles a template source code.
*
* @param string|Source $source The template source code
* @param string $name The template name (deprecated)
*
* @return string The compiled PHP source code
*
* @throws SyntaxError When there was an error during tokenizing,
parsing or compiling
*/
public function compileSource($source, $name = null)
{
if (!$source instanceof Source) {
@trigger_error(sprintf('Passing a string as the $source
argument of %s() is deprecated since version 1.27. Pass a Twig\Source
instance instead.', __METHOD__), E_USER_DEPRECATED);
$source = new Source($source, $name);
}
try {
return
$this->compile($this->parse($this->tokenize($source)));
} catch (Error $e) {
$e->setSourceContext($source);
throw $e;
} catch (\Exception $e) {
throw new SyntaxError(sprintf('An exception has been
thrown during the compilation of a template ("%s").',
$e->getMessage()), -1, $source, $e);
}
}
public function setLoader(LoaderInterface $loader)
{
if (!$loader instanceof SourceContextLoaderInterface && 0
!== strpos(\get_class($loader), 'Mock_')) {
@trigger_error(sprintf('Twig loader "%s" should
implement Twig\Loader\SourceContextLoaderInterface since version
1.27.', \get_class($loader)), E_USER_DEPRECATED);
}
$this->loader = $loader;
}
/**
* Gets the Loader instance.
*
* @return LoaderInterface
*/
public function getLoader()
{
if (null === $this->loader) {
throw new \LogicException('You must set a loader
first.');
}
return $this->loader;
}
/**
* Sets the default template charset.
*
* @param string $charset The default charset
*/
public function setCharset($charset)
{
$this->charset = strtoupper($charset);
}
/**
* Gets the default template charset.
*
* @return string The default charset
*/
public function getCharset()
{
return $this->charset;
}
/**
* Initializes the runtime environment.
*
* @deprecated since 1.23 (to be removed in 2.0)
*/
public function initRuntime()
{
$this->runtimeInitialized = true;
foreach ($this->getExtensions() as $name => $extension) {
if (!$extension instanceof InitRuntimeInterface) {
$m = new \ReflectionMethod($extension,
'initRuntime');
$parentClass = $m->getDeclaringClass()->getName();
if ('Twig_Extension' !== $parentClass &&
'Twig\Extension\AbstractExtension' !== $parentClass) {
@trigger_error(sprintf('Defining the initRuntime()
method in the "%s" extension is deprecated since version 1.23.
Use the `needs_environment` option to get the \Twig_Environment instance in
filters, functions, or tests; or explicitly implement
Twig\Extension\InitRuntimeInterface if needed (not recommended).',
$name), E_USER_DEPRECATED);
}
}
$extension->initRuntime($this);
}
}
/**
* Returns true if the given extension is registered.
*
* @param string $class The extension class name
*
* @return bool Whether the extension is registered or not
*/
public function hasExtension($class)
{
$class = ltrim($class, '\\');
if (!isset($this->extensionsByClass[$class]) &&
class_exists($class, false)) {
// For BC/FC with namespaced aliases
$class = new \ReflectionClass($class);
$class = $class->name;
}
if (isset($this->extensions[$class])) {
if ($class !== \get_class($this->extensions[$class])) {
@trigger_error(sprintf('Referencing the "%s"
extension by its name (defined by getName()) is deprecated since 1.26 and
will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name
instead.', $class), E_USER_DEPRECATED);
}
return true;
}
return isset($this->extensionsByClass[$class]);
}
/**
* Adds a runtime loader.
*/
public function addRuntimeLoader(RuntimeLoaderInterface $loader)
{
$this->runtimeLoaders[] = $loader;
}
/**
* Gets an extension by class name.
*
* @param string $class The extension class name
*
* @return ExtensionInterface
*/
public function getExtension($class)
{
$class = ltrim($class, '\\');
if (!isset($this->extensionsByClass[$class]) &&
class_exists($class, false)) {
// For BC/FC with namespaced aliases
$class = new \ReflectionClass($class);
$class = $class->name;
}
if (isset($this->extensions[$class])) {
if ($class !== \get_class($this->extensions[$class])) {
@trigger_error(sprintf('Referencing the "%s"
extension by its name (defined by getName()) is deprecated since 1.26 and
will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name
instead.', $class), E_USER_DEPRECATED);
}
return $this->extensions[$class];
}
if (!isset($this->extensionsByClass[$class])) {
throw new RuntimeError(sprintf('The "%s"
extension is not enabled.', $class));
}
return $this->extensionsByClass[$class];
}
/**
* Returns the runtime implementation of a Twig element
(filter/function/test).
*
* @param string $class A runtime class name
*
* @return object The runtime implementation
*
* @throws RuntimeError When the template cannot be found
*/
public function getRuntime($class)
{
if (isset($this->runtimes[$class])) {
return $this->runtimes[$class];
}
foreach ($this->runtimeLoaders as $loader) {
if (null !== $runtime = $loader->load($class)) {
return $this->runtimes[$class] = $runtime;
}
}
throw new RuntimeError(sprintf('Unable to load the
"%s" runtime.', $class));
}
public function addExtension(ExtensionInterface $extension)
{
if ($this->extensionInitialized) {
throw new \LogicException(sprintf('Unable to register
extension "%s" as extensions have already been
initialized.', $extension->getName()));
}
$class = \get_class($extension);
if ($class !== $extension->getName()) {
if (isset($this->extensions[$extension->getName()])) {
unset($this->extensions[$extension->getName()],
$this->extensionsByClass[$class]);
@trigger_error(sprintf('The possibility to register
the same extension twice ("%s") is deprecated since version 1.23
and will be removed in Twig 2.0. Use proper PHP inheritance instead.',
$extension->getName()), E_USER_DEPRECATED);
}
}
$this->lastModifiedExtension = 0;
$this->extensionsByClass[$class] = $extension;
$this->extensions[$extension->getName()] = $extension;
$this->updateOptionsHash();
}
/**
* Removes an extension by name.
*
* This method is deprecated and you should not use it.
*
* @param string $name The extension name
*
* @deprecated since 1.12 (to be removed in 2.0)
*/
public function removeExtension($name)
{
@trigger_error(sprintf('The %s method is deprecated since
version 1.12 and will be removed in Twig 2.0.', __METHOD__),
E_USER_DEPRECATED);
if ($this->extensionInitialized) {
throw new \LogicException(sprintf('Unable to remove
extension "%s" as extensions have already been
initialized.', $name));
}
$class = ltrim($name, '\\');
if (!isset($this->extensionsByClass[$class]) &&
class_exists($class, false)) {
// For BC/FC with namespaced aliases
$class = new \ReflectionClass($class);
$class = $class->name;
}
if (isset($this->extensions[$class])) {
if ($class !== \get_class($this->extensions[$class])) {
@trigger_error(sprintf('Referencing the "%s"
extension by its name (defined by getName()) is deprecated since 1.26 and
will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name
instead.', $class), E_USER_DEPRECATED);
}
unset($this->extensions[$class]);
}
unset($this->extensions[$class]);
$this->updateOptionsHash();
}
/**
* Registers an array of extensions.
*
* @param array $extensions An array of extensions
*/
public function setExtensions(array $extensions)
{
foreach ($extensions as $extension) {
$this->addExtension($extension);
}
}
/**
* Returns all registered extensions.
*
* @return ExtensionInterface[] An array of extensions (keys are for
internal usage only and should not be relied on)
*/
public function getExtensions()
{
return $this->extensions;
}
public function addTokenParser(TokenParserInterface $parser)
{
if ($this->extensionInitialized) {
throw new \LogicException('Unable to add a token parser as
extensions have already been initialized.');
}
$this->staging->addTokenParser($parser);
}
/**
* Gets the registered Token Parsers.
*
* @return \Twig_TokenParserBrokerInterface
*
* @internal
*/
public function getTokenParsers()
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
return $this->parsers;
}
/**
* Gets registered tags.
*
* Be warned that this method cannot return tags defined by
\Twig_TokenParserBrokerInterface classes.
*
* @return TokenParserInterface[]
*
* @internal
*/
public function getTags()
{
$tags = [];
foreach ($this->getTokenParsers()->getParsers() as $parser) {
if ($parser instanceof TokenParserInterface) {
$tags[$parser->getTag()] = $parser;
}
}
return $tags;
}
public function addNodeVisitor(NodeVisitorInterface $visitor)
{
if ($this->extensionInitialized) {
throw new \LogicException('Unable to add a node visitor as
extensions have already been initialized.');
}
$this->staging->addNodeVisitor($visitor);
}
/**
* Gets the registered Node Visitors.
*
* @return NodeVisitorInterface[]
*
* @internal
*/
public function getNodeVisitors()
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
return $this->visitors;
}
/**
* Registers a Filter.
*
* @param string|TwigFilter $name The filter name or a
\Twig_SimpleFilter instance
* @param \Twig_FilterInterface|TwigFilter $filter
*/
public function addFilter($name, $filter = null)
{
if (!$name instanceof TwigFilter && !($filter instanceof
TwigFilter || $filter instanceof \Twig_FilterInterface)) {
throw new \LogicException('A filter must be an instance of
\Twig_FilterInterface or \Twig_SimpleFilter.');
}
if ($name instanceof TwigFilter) {
$filter = $name;
$name = $filter->getName();
} else {
@trigger_error(sprintf('Passing a name as a first argument
to the %s method is deprecated since version 1.21. Pass an instance of
"Twig_SimpleFilter" instead when defining filter
"%s".', __METHOD__, $name), E_USER_DEPRECATED);
}
if ($this->extensionInitialized) {
throw new \LogicException(sprintf('Unable to add filter
"%s" as extensions have already been initialized.', $name));
}
$this->staging->addFilter($name, $filter);
}
/**
* Get a filter by name.
*
* Subclasses may override this method and load filters differently;
* so no list of filters is available.
*
* @param string $name The filter name
*
* @return \Twig_Filter|false
*
* @internal
*/
public function getFilter($name)
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
if (isset($this->filters[$name])) {
return $this->filters[$name];
}
foreach ($this->filters as $pattern => $filter) {
$pattern = str_replace('\\*', '(.*?)',
preg_quote($pattern, '#'), $count);
if ($count) {
if (preg_match('#^'.$pattern.'$#',
$name, $matches)) {
array_shift($matches);
$filter->setArguments($matches);
return $filter;
}
}
}
foreach ($this->filterCallbacks as $callback) {
if (false !== $filter = \call_user_func($callback, $name)) {
return $filter;
}
}
return false;
}
public function registerUndefinedFilterCallback($callable)
{
$this->filterCallbacks[] = $callable;
}
/**
* Gets the registered Filters.
*
* Be warned that this method cannot return filters defined with
registerUndefinedFilterCallback.
*
* @return \Twig_FilterInterface[]
*
* @see registerUndefinedFilterCallback
*
* @internal
*/
public function getFilters()
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
return $this->filters;
}
/**
* Registers a Test.
*
* @param string|TwigTest $name The test name or a
\Twig_SimpleTest instance
* @param \Twig_TestInterface|TwigTest $test A \Twig_TestInterface
instance or a \Twig_SimpleTest instance
*/
public function addTest($name, $test = null)
{
if (!$name instanceof TwigTest && !($test instanceof
TwigTest || $test instanceof \Twig_TestInterface)) {
throw new \LogicException('A test must be an instance of
\Twig_TestInterface or \Twig_SimpleTest.');
}
if ($name instanceof TwigTest) {
$test = $name;
$name = $test->getName();
} else {
@trigger_error(sprintf('Passing a name as a first argument
to the %s method is deprecated since version 1.21. Pass an instance of
"Twig_SimpleTest" instead when defining test
"%s".', __METHOD__, $name), E_USER_DEPRECATED);
}
if ($this->extensionInitialized) {
throw new \LogicException(sprintf('Unable to add test
"%s" as extensions have already been initialized.', $name));
}
$this->staging->addTest($name, $test);
}
/**
* Gets the registered Tests.
*
* @return \Twig_TestInterface[]
*
* @internal
*/
public function getTests()
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
return $this->tests;
}
/**
* Gets a test by name.
*
* @param string $name The test name
*
* @return \Twig_Test|false
*
* @internal
*/
public function getTest($name)
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
if (isset($this->tests[$name])) {
return $this->tests[$name];
}
foreach ($this->tests as $pattern => $test) {
$pattern = str_replace('\\*', '(.*?)',
preg_quote($pattern, '#'), $count);
if ($count) {
if (preg_match('#^'.$pattern.'$#',
$name, $matches)) {
array_shift($matches);
$test->setArguments($matches);
return $test;
}
}
}
return false;
}
/**
* Registers a Function.
*
* @param string|TwigFunction $name The function
name or a \Twig_SimpleFunction instance
* @param \Twig_FunctionInterface|TwigFunction $function
*/
public function addFunction($name, $function = null)
{
if (!$name instanceof TwigFunction && !($function
instanceof TwigFunction || $function instanceof \Twig_FunctionInterface)) {
throw new \LogicException('A function must be an instance
of \Twig_FunctionInterface or \Twig_SimpleFunction.');
}
if ($name instanceof TwigFunction) {
$function = $name;
$name = $function->getName();
} else {
@trigger_error(sprintf('Passing a name as a first argument
to the %s method is deprecated since version 1.21. Pass an instance of
"Twig_SimpleFunction" instead when defining function
"%s".', __METHOD__, $name), E_USER_DEPRECATED);
}
if ($this->extensionInitialized) {
throw new \LogicException(sprintf('Unable to add function
"%s" as extensions have already been initialized.', $name));
}
$this->staging->addFunction($name, $function);
}
/**
* Get a function by name.
*
* Subclasses may override this method and load functions differently;
* so no list of functions is available.
*
* @param string $name function name
*
* @return \Twig_Function|false
*
* @internal
*/
public function getFunction($name)
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
if (isset($this->functions[$name])) {
return $this->functions[$name];
}
foreach ($this->functions as $pattern => $function) {
$pattern = str_replace('\\*', '(.*?)',
preg_quote($pattern, '#'), $count);
if ($count) {
if (preg_match('#^'.$pattern.'$#',
$name, $matches)) {
array_shift($matches);
$function->setArguments($matches);
return $function;
}
}
}
foreach ($this->functionCallbacks as $callback) {
if (false !== $function = \call_user_func($callback, $name)) {
return $function;
}
}
return false;
}
public function registerUndefinedFunctionCallback($callable)
{
$this->functionCallbacks[] = $callable;
}
/**
* Gets registered functions.
*
* Be warned that this method cannot return functions defined with
registerUndefinedFunctionCallback.
*
* @return \Twig_FunctionInterface[]
*
* @see registerUndefinedFunctionCallback
*
* @internal
*/
public function getFunctions()
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
return $this->functions;
}
/**
* Registers a Global.
*
* New globals can be added before compiling or rendering a template;
* but after, you can only update existing globals.
*
* @param string $name The global name
* @param mixed $value The global value
*/
public function addGlobal($name, $value)
{
if ($this->extensionInitialized || $this->runtimeInitialized)
{
if (null === $this->globals) {
$this->globals = $this->initGlobals();
}
if (!\array_key_exists($name, $this->globals)) {
// The deprecation notice must be turned into the following
exception in Twig 2.0
@trigger_error(sprintf('Registering global variable
"%s" at runtime or when the extensions have already been
initialized is deprecated since version 1.21.', $name),
E_USER_DEPRECATED);
//throw new \LogicException(sprintf('Unable to add
global "%s" as the runtime or the extensions have already been
initialized.', $name));
}
}
if ($this->extensionInitialized || $this->runtimeInitialized)
{
// update the value
$this->globals[$name] = $value;
} else {
$this->staging->addGlobal($name, $value);
}
}
/**
* Gets the registered Globals.
*
* @return array An array of globals
*
* @internal
*/
public function getGlobals()
{
if (!$this->runtimeInitialized &&
!$this->extensionInitialized) {
return $this->initGlobals();
}
if (null === $this->globals) {
$this->globals = $this->initGlobals();
}
return $this->globals;
}
/**
* Merges a context with the defined globals.
*
* @param array $context An array representing the context
*
* @return array The context merged with the globals
*/
public function mergeGlobals(array $context)
{
// we don't use array_merge as the context being generally
// bigger than globals, this code is faster.
foreach ($this->getGlobals() as $key => $value) {
if (!\array_key_exists($key, $context)) {
$context[$key] = $value;
}
}
return $context;
}
/**
* Gets the registered unary Operators.
*
* @return array An array of unary operators
*
* @internal
*/
public function getUnaryOperators()
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
return $this->unaryOperators;
}
/**
* Gets the registered binary Operators.
*
* @return array An array of binary operators
*
* @internal
*/
public function getBinaryOperators()
{
if (!$this->extensionInitialized) {
$this->initExtensions();
}
return $this->binaryOperators;
}
/**
* @deprecated since 1.23 (to be removed in 2.0)
*/
public function computeAlternatives($name, $items)
{
@trigger_error(sprintf('The %s method is deprecated since
version 1.23 and will be removed in Twig 2.0.', __METHOD__),
E_USER_DEPRECATED);
return SyntaxError::computeAlternatives($name, $items);
}
/**
* @internal
*/
protected function initGlobals()
{
$globals = [];
foreach ($this->extensions as $name => $extension) {
if (!$extension instanceof GlobalsInterface) {
$m = new \ReflectionMethod($extension,
'getGlobals');
$parentClass = $m->getDeclaringClass()->getName();
if ('Twig_Extension' !== $parentClass &&
'Twig\Extension\AbstractExtension' !== $parentClass) {
@trigger_error(sprintf('Defining the getGlobals()
method in the "%s" extension without explicitly implementing
Twig\Extension\GlobalsInterface is deprecated since version 1.23.',
$name), E_USER_DEPRECATED);
}
}
$extGlob = $extension->getGlobals();
if (!\is_array($extGlob)) {
throw new
\UnexpectedValueException(sprintf('"%s::getGlobals()" must
return an array of globals.', \get_class($extension)));
}
$globals[] = $extGlob;
}
$globals[] = $this->staging->getGlobals();
return \call_user_func_array('array_merge', $globals);
}
/**
* @internal
*/
protected function initExtensions()
{
if ($this->extensionInitialized) {
return;
}
$this->parsers = new \Twig_TokenParserBroker([], [], false);
$this->filters = [];
$this->functions = [];
$this->tests = [];
$this->visitors = [];
$this->unaryOperators = [];
$this->binaryOperators = [];
foreach ($this->extensions as $extension) {
$this->initExtension($extension);
}
$this->initExtension($this->staging);
// Done at the end only, so that an exception during initialization
does not mark the environment as initialized when catching the exception
$this->extensionInitialized = true;
}
/**
* @internal
*/
protected function initExtension(ExtensionInterface $extension)
{
// filters
foreach ($extension->getFilters() as $name => $filter) {
if ($filter instanceof TwigFilter) {
$name = $filter->getName();
} else {
@trigger_error(sprintf('Using an instance of
"%s" for filter "%s" is deprecated since version 1.21.
Use \Twig_SimpleFilter instead.', \get_class($filter), $name),
E_USER_DEPRECATED);
}
$this->filters[$name] = $filter;
}
// functions
foreach ($extension->getFunctions() as $name => $function) {
if ($function instanceof TwigFunction) {
$name = $function->getName();
} else {
@trigger_error(sprintf('Using an instance of
"%s" for function "%s" is deprecated since version
1.21. Use \Twig_SimpleFunction instead.', \get_class($function),
$name), E_USER_DEPRECATED);
}
$this->functions[$name] = $function;
}
// tests
foreach ($extension->getTests() as $name => $test) {
if ($test instanceof TwigTest) {
$name = $test->getName();
} else {
@trigger_error(sprintf('Using an instance of
"%s" for test "%s" is deprecated since version 1.21.
Use \Twig_SimpleTest instead.', \get_class($test), $name),
E_USER_DEPRECATED);
}
$this->tests[$name] = $test;
}
// token parsers
foreach ($extension->getTokenParsers() as $parser) {
if ($parser instanceof TokenParserInterface) {
$this->parsers->addTokenParser($parser);
} elseif ($parser instanceof \Twig_TokenParserBrokerInterface)
{
@trigger_error('Registering a
\Twig_TokenParserBrokerInterface instance is deprecated since version
1.21.', E_USER_DEPRECATED);
$this->parsers->addTokenParserBroker($parser);
} else {
throw new \LogicException('getTokenParsers() must
return an array of \Twig_TokenParserInterface or
\Twig_TokenParserBrokerInterface instances.');
}
}
// node visitors
foreach ($extension->getNodeVisitors() as $visitor) {
$this->visitors[] = $visitor;
}
// operators
if ($operators = $extension->getOperators()) {
if (!\is_array($operators)) {
throw new
\InvalidArgumentException(sprintf('"%s::getOperators()" must
return an array with operators, got "%s".',
\get_class($extension), \is_object($operators) ? \get_class($operators) :
\gettype($operators).(\is_resource($operators) ? '' :
'#'.$operators)));
}
if (2 !== \count($operators)) {
throw new
\InvalidArgumentException(sprintf('"%s::getOperators()" must
return an array of 2 elements, got %d.', \get_class($extension),
\count($operators)));
}
$this->unaryOperators =
array_merge($this->unaryOperators, $operators[0]);
$this->binaryOperators =
array_merge($this->binaryOperators, $operators[1]);
}
}
/**
* @deprecated since 1.22 (to be removed in 2.0)
*/
protected function writeCacheFile($file, $content)
{
$this->cache->write($file, $content);
}
private function updateOptionsHash()
{
$hashParts = array_merge(
array_keys($this->extensions),
[
(int)
\function_exists('twig_template_get_attributes'),
PHP_MAJOR_VERSION,
PHP_MINOR_VERSION,
self::VERSION,
(int) $this->debug,
$this->baseTemplateClass,
(int) $this->strictVariables,
]
);
$this->optionsHash = implode(':', $hashParts);
}
}
class_alias('Twig\Environment', 'Twig_Environment');
PK-d�[���&�&$vendor/twig/twig/src/Error/Error.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
use Twig\Source;
use Twig\Template;
/**
* Twig base exception.
*
* This exception class and its children must only be used when
* an error occurs during the loading of a template, when a syntax error
* is detected in a template, or when rendering a template. Other
* errors must use regular PHP exception classes (like when the template
* cache directory is not writable for instance).
*
* To help debugging template issues, this class tracks the original
template
* name and line where the error occurred.
*
* Whenever possible, you must set these information (original template
name
* and line number) yourself by passing them to the constructor. If some or
all
* these information are not available from where you throw the exception,
then
* this class will guess them automatically (when the line number is set to
-1
* and/or the name is set to null). As this is a costly operation, this
* can be disabled by passing false for both the name and the line number
* when creating a new instance of this class.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Error extends \Exception
{
protected $lineno;
// to be renamed to name in 2.0
protected $filename;
protected $rawMessage;
private $sourcePath;
private $sourceCode;
/**
* Constructor.
*
* Set the line number to -1 to enable its automatic guessing.
* Set the name to null to enable its automatic guessing.
*
* @param string $message The error message
* @param int $lineno The template line where the
error occurred
* @param Source|string|null $source The source context where the
error occurred
* @param \Exception $previous The previous exception
*/
public function __construct($message, $lineno = -1, $source = null,
\Exception $previous = null)
{
if (null === $source) {
$name = null;
} elseif (!$source instanceof Source) {
// for compat with the Twig C ext., passing the template name
as string is accepted
$name = $source;
} else {
$name = $source->getName();
$this->sourceCode = $source->getCode();
$this->sourcePath = $source->getPath();
}
parent::__construct('', 0, $previous);
$this->lineno = $lineno;
$this->filename = $name;
$this->rawMessage = $message;
$this->updateRepr();
}
/**
* Gets the raw message.
*
* @return string The raw message
*/
public function getRawMessage()
{
return $this->rawMessage;
}
/**
* Gets the logical name where the error occurred.
*
* @return string The name
*
* @deprecated since 1.27 (to be removed in 2.0). Use
getSourceContext() instead.
*/
public function getTemplateFile()
{
@trigger_error(sprintf('The "%s" method is
deprecated since version 1.27 and will be removed in 2.0. Use
getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->filename;
}
/**
* Sets the logical name where the error occurred.
*
* @param string $name The name
*
* @deprecated since 1.27 (to be removed in 2.0). Use
setSourceContext() instead.
*/
public function setTemplateFile($name)
{
@trigger_error(sprintf('The "%s" method is
deprecated since version 1.27 and will be removed in 2.0. Use
setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
$this->filename = $name;
$this->updateRepr();
}
/**
* Gets the logical name where the error occurred.
*
* @return string The name
*
* @deprecated since 1.29 (to be removed in 2.0). Use
getSourceContext() instead.
*/
public function getTemplateName()
{
@trigger_error(sprintf('The "%s" method is
deprecated since version 1.29 and will be removed in 2.0. Use
getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->filename;
}
/**
* Sets the logical name where the error occurred.
*
* @param string $name The name
*
* @deprecated since 1.29 (to be removed in 2.0). Use
setSourceContext() instead.
*/
public function setTemplateName($name)
{
@trigger_error(sprintf('The "%s" method is
deprecated since version 1.29 and will be removed in 2.0. Use
setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
$this->filename = $name;
$this->sourceCode = $this->sourcePath = null;
$this->updateRepr();
}
/**
* Gets the template line where the error occurred.
*
* @return int The template line
*/
public function getTemplateLine()
{
return $this->lineno;
}
/**
* Sets the template line where the error occurred.
*
* @param int $lineno The template line
*/
public function setTemplateLine($lineno)
{
$this->lineno = $lineno;
$this->updateRepr();
}
/**
* Gets the source context of the Twig template where the error
occurred.
*
* @return Source|null
*/
public function getSourceContext()
{
return $this->filename ? new Source($this->sourceCode,
$this->filename, $this->sourcePath) : null;
}
/**
* Sets the source context of the Twig template where the error
occurred.
*/
public function setSourceContext(Source $source = null)
{
if (null === $source) {
$this->sourceCode = $this->filename =
$this->sourcePath = null;
} else {
$this->sourceCode = $source->getCode();
$this->filename = $source->getName();
$this->sourcePath = $source->getPath();
}
$this->updateRepr();
}
public function guess()
{
$this->guessTemplateInfo();
$this->updateRepr();
}
public function appendMessage($rawMessage)
{
$this->rawMessage .= $rawMessage;
$this->updateRepr();
}
/**
* @internal
*/
protected function updateRepr()
{
$this->message = $this->rawMessage;
if ($this->sourcePath && $this->lineno > 0) {
$this->file = $this->sourcePath;
$this->line = $this->lineno;
return;
}
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
$questionMark = false;
if ('?' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$questionMark = true;
}
if ($this->filename) {
if (\is_string($this->filename) ||
(\is_object($this->filename) &&
method_exists($this->filename, '__toString'))) {
$name = sprintf('"%s"',
$this->filename);
} else {
$name = json_encode($this->filename);
}
$this->message .= sprintf(' in %s', $name);
}
if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d',
$this->lineno);
}
if ($dot) {
$this->message .= '.';
}
if ($questionMark) {
$this->message .= '?';
}
}
/**
* @internal
*/
protected function guessTemplateInfo()
{
$template = null;
$templateClass = null;
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS |
DEBUG_BACKTRACE_PROVIDE_OBJECT);
foreach ($backtrace as $trace) {
if (isset($trace['object']) &&
$trace['object'] instanceof Template &&
'Twig_Template' !== \get_class($trace['object'])) {
$currentClass = \get_class($trace['object']);
$isEmbedContainer = 0 === strpos($templateClass,
$currentClass);
if (null === $this->filename || ($this->filename ==
$trace['object']->getTemplateName() &&
!$isEmbedContainer)) {
$template = $trace['object'];
$templateClass =
\get_class($trace['object']);
}
}
}
// update template name
if (null !== $template && null === $this->filename) {
$this->filename = $template->getTemplateName();
}
// update template path if any
if (null !== $template && null === $this->sourcePath) {
$src = $template->getSourceContext();
$this->sourceCode = $src->getCode();
$this->sourcePath = $src->getPath();
}
if (null === $template || $this->lineno > -1) {
return;
}
$r = new \ReflectionObject($template);
$file = $r->getFileName();
$exceptions = [$e = $this];
while ($e instanceof self && $e = $e->getPrevious()) {
$exceptions[] = $e;
}
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
array_unshift($traces, ['file' =>
$e->getFile(), 'line' => $e->getLine()]);
while ($trace = array_shift($traces)) {
if (!isset($trace['file']) ||
!isset($trace['line']) || $file != $trace['file']) {
continue;
}
foreach ($template->getDebugInfo() as $codeLine =>
$templateLine) {
if ($codeLine <= $trace['line']) {
// update template line
$this->lineno = $templateLine;
return;
}
}
}
}
}
}
class_alias('Twig\Error\Error', 'Twig_Error');
PK-d�[��T���*vendor/twig/twig/src/Error/LoaderError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
/**
* Exception thrown when an error occurs during template loading.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class LoaderError extends Error
{
}
class_alias('Twig\Error\LoaderError',
'Twig_Error_Loader');
PK-d�[3%����+vendor/twig/twig/src/Error/RuntimeError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
/**
* Exception thrown when an error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class RuntimeError extends Error
{
}
class_alias('Twig\Error\RuntimeError',
'Twig_Error_Runtime');
PK-d�[ث�6��*vendor/twig/twig/src/Error/SyntaxError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Error;
/**
* \Exception thrown when a syntax error occurs during lexing or parsing of
a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SyntaxError extends Error
{
/**
* Tweaks the error message to include suggestions.
*
* @param string $name The original name of the item that does not
exist
* @param array $items An array of possible items
*/
public function addSuggestions($name, array $items)
{
if (!$alternatives = self::computeAlternatives($name, $items)) {
return;
}
$this->appendMessage(sprintf(' Did you mean
"%s"?', implode('", "',
$alternatives)));
}
/**
* @internal
*
* To be merged with the addSuggestions() method in 2.0.
*/
public static function computeAlternatives($name, $items)
{
$alternatives = [];
foreach ($items as $item) {
$lev = levenshtein($name, $item);
if ($lev <= \strlen($name) / 3 || false !== strpos($item,
$name)) {
$alternatives[$item] = $lev;
}
}
asort($alternatives);
return array_keys($alternatives);
}
}
class_alias('Twig\Error\SyntaxError',
'Twig_Error_Syntax');
PK-d�[��vw��)vendor/twig/twig/src/ExpressionParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ArrowFunctionExpression;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\Expression\Binary\ConcatBinary;
use Twig\Node\Expression\BlockReferenceExpression;
use Twig\Node\Expression\ConditionalExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\MethodCallExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\ParentExpression;
use Twig\Node\Expression\Unary\NegUnary;
use Twig\Node\Expression\Unary\NotUnary;
use Twig\Node\Expression\Unary\PosUnary;
use Twig\Node\Node;
/**
* Parses expressions.
*
* This parser implements a "Precedence climbing" algorithm.
*
* @see https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
* @see https://en.wikipedia.org/wiki/Operator-precedence_parser
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
class ExpressionParser
{
const OPERATOR_LEFT = 1;
const OPERATOR_RIGHT = 2;
protected $parser;
protected $unaryOperators;
protected $binaryOperators;
private $env;
public function __construct(Parser $parser, $env = null)
{
$this->parser = $parser;
if ($env instanceof Environment) {
$this->env = $env;
$this->unaryOperators = $env->getUnaryOperators();
$this->binaryOperators = $env->getBinaryOperators();
} else {
@trigger_error('Passing the operators as constructor
arguments to '.__METHOD__.' is deprecated since version 1.27.
Pass the environment instead.', E_USER_DEPRECATED);
$this->env = $parser->getEnvironment();
$this->unaryOperators = func_get_arg(1);
$this->binaryOperators = func_get_arg(2);
}
}
public function parseExpression($precedence = 0, $allowArrow = false)
{
if ($allowArrow && $arrow = $this->parseArrow()) {
return $arrow;
}
$expr = $this->getPrimary();
$token = $this->parser->getCurrentToken();
while ($this->isBinary($token) &&
$this->binaryOperators[$token->getValue()]['precedence']
>= $precedence) {
$op = $this->binaryOperators[$token->getValue()];
$this->parser->getStream()->next();
if ('is not' === $token->getValue()) {
$expr = $this->parseNotTestExpression($expr);
} elseif ('is' === $token->getValue()) {
$expr = $this->parseTestExpression($expr);
} elseif (isset($op['callable'])) {
$expr = \call_user_func($op['callable'],
$this->parser, $expr);
} else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT ===
$op['associativity'] ? $op['precedence'] + 1 :
$op['precedence']);
$class = $op['class'];
$expr = new $class($expr, $expr1, $token->getLine());
}
$token = $this->parser->getCurrentToken();
}
if (0 === $precedence) {
return $this->parseConditionalExpression($expr);
}
return $expr;
}
/**
* @return ArrowFunctionExpression|null
*/
private function parseArrow()
{
$stream = $this->parser->getStream();
// short array syntax (one argument, no parentheses)?
if ($stream->look(1)->test(Token::ARROW_TYPE)) {
$line = $stream->getCurrent()->getLine();
$token = $stream->expect(Token::NAME_TYPE);
$names = [new AssignNameExpression($token->getValue(),
$token->getLine())];
$stream->expect(Token::ARROW_TYPE);
return new
ArrowFunctionExpression($this->parseExpression(0), new Node($names),
$line);
}
// first, determine if we are parsing an arrow function by finding
=> (long form)
$i = 0;
if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE,
'(')) {
return null;
}
++$i;
while (true) {
// variable name
++$i;
if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE,
',')) {
break;
}
++$i;
}
if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE,
')')) {
return null;
}
++$i;
if (!$stream->look($i)->test(Token::ARROW_TYPE)) {
return null;
}
// yes, let's parse it properly
$token = $stream->expect(Token::PUNCTUATION_TYPE,
'(');
$line = $token->getLine();
$names = [];
while (true) {
$token = $stream->expect(Token::NAME_TYPE);
$names[] = new AssignNameExpression($token->getValue(),
$token->getLine());
if (!$stream->nextIf(Token::PUNCTUATION_TYPE,
',')) {
break;
}
}
$stream->expect(Token::PUNCTUATION_TYPE, ')');
$stream->expect(Token::ARROW_TYPE);
return new ArrowFunctionExpression($this->parseExpression(0),
new Node($names), $line);
}
protected function getPrimary()
{
$token = $this->parser->getCurrentToken();
if ($this->isUnary($token)) {
$operator = $this->unaryOperators[$token->getValue()];
$this->parser->getStream()->next();
$expr =
$this->parseExpression($operator['precedence']);
$class = $operator['class'];
return $this->parsePostfixExpression(new $class($expr,
$token->getLine()));
} elseif ($token->test(Token::PUNCTUATION_TYPE, '('))
{
$this->parser->getStream()->next();
$expr = $this->parseExpression();
$this->parser->getStream()->expect(Token::PUNCTUATION_TYPE,
')', 'An opened parenthesis is not properly closed');
return $this->parsePostfixExpression($expr);
}
return $this->parsePrimaryExpression();
}
protected function parseConditionalExpression($expr)
{
while
($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE,
'?')) {
if
(!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE,
':')) {
$expr2 = $this->parseExpression();
if
($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE,
':')) {
$expr3 = $this->parseExpression();
} else {
$expr3 = new ConstantExpression('',
$this->parser->getCurrentToken()->getLine());
}
} else {
$expr2 = $expr;
$expr3 = $this->parseExpression();
}
$expr = new ConditionalExpression($expr, $expr2, $expr3,
$this->parser->getCurrentToken()->getLine());
}
return $expr;
}
protected function isUnary(Token $token)
{
return $token->test(Token::OPERATOR_TYPE) &&
isset($this->unaryOperators[$token->getValue()]);
}
protected function isBinary(Token $token)
{
return $token->test(Token::OPERATOR_TYPE) &&
isset($this->binaryOperators[$token->getValue()]);
}
public function parsePrimaryExpression()
{
$token = $this->parser->getCurrentToken();
switch ($token->getType()) {
case Token::NAME_TYPE:
$this->parser->getStream()->next();
switch ($token->getValue()) {
case 'true':
case 'TRUE':
$node = new ConstantExpression(true,
$token->getLine());
break;
case 'false':
case 'FALSE':
$node = new ConstantExpression(false,
$token->getLine());
break;
case 'none':
case 'NONE':
case 'null':
case 'NULL':
$node = new ConstantExpression(null,
$token->getLine());
break;
default:
if ('(' ===
$this->parser->getCurrentToken()->getValue()) {
$node =
$this->getFunctionNode($token->getValue(), $token->getLine());
} else {
$node = new
NameExpression($token->getValue(), $token->getLine());
}
}
break;
case Token::NUMBER_TYPE:
$this->parser->getStream()->next();
$node = new ConstantExpression($token->getValue(),
$token->getLine());
break;
case Token::STRING_TYPE:
case Token::INTERPOLATION_START_TYPE:
$node = $this->parseStringExpression();
break;
case Token::OPERATOR_TYPE:
if (preg_match(Lexer::REGEX_NAME, $token->getValue(),
$matches) && $matches[0] == $token->getValue()) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
$node = new NameExpression($token->getValue(),
$token->getLine());
break;
} elseif
(isset($this->unaryOperators[$token->getValue()])) {
$class =
$this->unaryOperators[$token->getValue()]['class'];
$ref = new \ReflectionClass($class);
$negClass =
'Twig\Node\Expression\Unary\NegUnary';
$posClass =
'Twig\Node\Expression\Unary\PosUnary';
if (!(\in_array($ref->getName(), [$negClass,
$posClass, 'Twig_Node_Expression_Unary_Neg',
'Twig_Node_Expression_Unary_Pos'])
|| $ref->isSubclassOf($negClass) ||
$ref->isSubclassOf($posClass)
||
$ref->isSubclassOf('Twig_Node_Expression_Unary_Neg') ||
$ref->isSubclassOf('Twig_Node_Expression_Unary_Pos'))
) {
throw new SyntaxError(sprintf('Unexpected
unary operator "%s".', $token->getValue()),
$token->getLine(),
$this->parser->getStream()->getSourceContext());
}
$this->parser->getStream()->next();
$expr = $this->parsePrimaryExpression();
$node = new $class($expr, $token->getLine());
break;
}
// no break
default:
if ($token->test(Token::PUNCTUATION_TYPE,
'[')) {
$node = $this->parseArrayExpression();
} elseif ($token->test(Token::PUNCTUATION_TYPE,
'{')) {
$node = $this->parseHashExpression();
} elseif ($token->test(Token::OPERATOR_TYPE,
'=') && ('==' ===
$this->parser->getStream()->look(-1)->getValue() ||
'!=' ===
$this->parser->getStream()->look(-1)->getValue())) {
throw new SyntaxError(sprintf('Unexpected operator
of value "%s". Did you try to use "===" or
"!==" for strict comparison? Use "is same as(value)"
instead.', $token->getValue()), $token->getLine(),
$this->parser->getStream()->getSourceContext());
} else {
throw new SyntaxError(sprintf('Unexpected token
"%s" of value "%s".',
Token::typeToEnglish($token->getType()), $token->getValue()),
$token->getLine(),
$this->parser->getStream()->getSourceContext());
}
}
return $this->parsePostfixExpression($node);
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = [];
// a string cannot be followed by another string in a single
expression
$nextCanBeString = true;
while (true) {
if ($nextCanBeString && $token =
$stream->nextIf(Token::STRING_TYPE)) {
$nodes[] = new ConstantExpression($token->getValue(),
$token->getLine());
$nextCanBeString = false;
} elseif ($stream->nextIf(Token::INTERPOLATION_START_TYPE))
{
$nodes[] = $this->parseExpression();
$stream->expect(Token::INTERPOLATION_END_TYPE);
$nextCanBeString = true;
} else {
break;
}
}
$expr = array_shift($nodes);
foreach ($nodes as $node) {
$expr = new ConcatBinary($expr, $node,
$node->getTemplateLine());
}
return $expr;
}
public function parseArrayExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Token::PUNCTUATION_TYPE, '[', 'An
array element was expected');
$node = new ArrayExpression([],
$stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Token::PUNCTUATION_TYPE, ']')) {
if (!$first) {
$stream->expect(Token::PUNCTUATION_TYPE, ',',
'An array element must be followed by a comma');
// trailing ,?
if ($stream->test(Token::PUNCTUATION_TYPE,
']')) {
break;
}
}
$first = false;
$node->addElement($this->parseExpression());
}
$stream->expect(Token::PUNCTUATION_TYPE, ']', 'An
opened array is not properly closed');
return $node;
}
public function parseHashExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Token::PUNCTUATION_TYPE, '{', 'A
hash element was expected');
$node = new ArrayExpression([],
$stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) {
if (!$first) {
$stream->expect(Token::PUNCTUATION_TYPE, ',',
'A hash value must be followed by a comma');
// trailing ,?
if ($stream->test(Token::PUNCTUATION_TYPE,
'}')) {
break;
}
}
$first = false;
// a hash key can be:
//
// * a number -- 12
// * a string -- 'a'
// * a name, which is equivalent to a string -- a
// * an expression, which must be enclosed in parentheses --
(1 + 2)
if (($token = $stream->nextIf(Token::STRING_TYPE)) ||
($token = $stream->nextIf(Token::NAME_TYPE)) || $token =
$stream->nextIf(Token::NUMBER_TYPE)) {
$key = new ConstantExpression($token->getValue(),
$token->getLine());
} elseif ($stream->test(Token::PUNCTUATION_TYPE,
'(')) {
$key = $this->parseExpression();
} else {
$current = $stream->getCurrent();
throw new SyntaxError(sprintf('A hash key must be a
quoted string, a number, a name, or an expression enclosed in parentheses
(unexpected token "%s" of value "%s".',
Token::typeToEnglish($current->getType()), $current->getValue()),
$current->getLine(), $stream->getSourceContext());
}
$stream->expect(Token::PUNCTUATION_TYPE, ':',
'A hash key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(Token::PUNCTUATION_TYPE, '}', 'An
opened hash is not properly closed');
return $node;
}
public function parsePostfixExpression($node)
{
while (true) {
$token = $this->parser->getCurrentToken();
if (Token::PUNCTUATION_TYPE == $token->getType()) {
if ('.' == $token->getValue() || '['
== $token->getValue()) {
$node = $this->parseSubscriptExpression($node);
} elseif ('|' == $token->getValue()) {
$node = $this->parseFilterExpression($node);
} else {
break;
}
} else {
break;
}
}
return $node;
}
public function getFunctionNode($name, $line)
{
switch ($name) {
case 'parent':
$this->parseArguments();
if (!\count($this->parser->getBlockStack())) {
throw new SyntaxError('Calling "parent"
outside a block is forbidden.', $line,
$this->parser->getStream()->getSourceContext());
}
if (!$this->parser->getParent() &&
!$this->parser->hasTraits()) {
throw new SyntaxError('Calling "parent"
on a template that does not extend nor "use" another template is
forbidden.', $line,
$this->parser->getStream()->getSourceContext());
}
return new
ParentExpression($this->parser->peekBlockStack(), $line);
case 'block':
$args = $this->parseArguments();
if (\count($args) < 1) {
throw new SyntaxError('The "block"
function takes one argument (the block name).', $line,
$this->parser->getStream()->getSourceContext());
}
return new BlockReferenceExpression($args->getNode(0),
\count($args) > 1 ? $args->getNode(1) : null, $line);
case 'attribute':
$args = $this->parseArguments();
if (\count($args) < 2) {
throw new SyntaxError('The "attribute"
function takes at least two arguments (the variable and the
attributes).', $line,
$this->parser->getStream()->getSourceContext());
}
return new GetAttrExpression($args->getNode(0),
$args->getNode(1), \count($args) > 2 ? $args->getNode(2) : null,
Template::ANY_CALL, $line);
default:
if (null !== $alias =
$this->parser->getImportedSymbol('function', $name)) {
$arguments = new ArrayExpression([], $line);
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
$node = new
MethodCallExpression($alias['node'], $alias['name'],
$arguments, $line);
$node->setAttribute('safe', true);
return $node;
}
$args = $this->parseArguments(true);
$class = $this->getFunctionNodeClass($name, $line);
return new $class($name, $args, $line);
}
}
public function parseSubscriptExpression($node)
{
$stream = $this->parser->getStream();
$token = $stream->next();
$lineno = $token->getLine();
$arguments = new ArrayExpression([], $lineno);
$type = Template::ANY_CALL;
if ('.' == $token->getValue()) {
$token = $stream->next();
if (
Token::NAME_TYPE == $token->getType()
||
Token::NUMBER_TYPE == $token->getType()
||
(Token::OPERATOR_TYPE == $token->getType() &&
preg_match(Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new ConstantExpression($token->getValue(),
$lineno);
if ($stream->test(Token::PUNCTUATION_TYPE,
'(')) {
$type = Template::METHOD_CALL;
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
}
} else {
throw new SyntaxError('Expected name or number.',
$lineno, $stream->getSourceContext());
}
if ($node instanceof NameExpression && null !==
$this->parser->getImportedSymbol('template',
$node->getAttribute('name'))) {
if (!$arg instanceof ConstantExpression) {
throw new SyntaxError(sprintf('Dynamic macro names
are not supported (called on "%s").',
$node->getAttribute('name')), $token->getLine(),
$stream->getSourceContext());
}
$name = $arg->getAttribute('value');
if ($this->parser->isReservedMacroName($name)) {
throw new SyntaxError(sprintf('"%s"
cannot be called as macro as it is a reserved keyword.', $name),
$token->getLine(), $stream->getSourceContext());
}
$node = new MethodCallExpression($node,
'get'.$name, $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
}
} else {
$type = Template::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$arg = new ConstantExpression(0, $token->getLine());
} else {
$arg = $this->parseExpression();
}
if ($stream->nextIf(Token::PUNCTUATION_TYPE, ':'))
{
$slice = true;
}
if ($slice) {
if ($stream->test(Token::PUNCTUATION_TYPE,
']')) {
$length = new ConstantExpression(null,
$token->getLine());
} else {
$length = $this->parseExpression();
}
$class = $this->getFilterNodeClass('slice',
$token->getLine());
$arguments = new Node([$arg, $length]);
$filter = new $class($node, new
ConstantExpression('slice', $token->getLine()), $arguments,
$token->getLine());
$stream->expect(Token::PUNCTUATION_TYPE, ']');
return $filter;
}
$stream->expect(Token::PUNCTUATION_TYPE, ']');
}
return new GetAttrExpression($node, $arg, $arguments, $type,
$lineno);
}
public function parseFilterExpression($node)
{
$this->parser->getStream()->next();
return $this->parseFilterExpressionRaw($node);
}
public function parseFilterExpressionRaw($node, $tag = null)
{
while (true) {
$token =
$this->parser->getStream()->expect(Token::NAME_TYPE);
$name = new ConstantExpression($token->getValue(),
$token->getLine());
if
(!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE,
'(')) {
$arguments = new Node();
} else {
$arguments = $this->parseArguments(true, false, true);
}
$class =
$this->getFilterNodeClass($name->getAttribute('value'),
$token->getLine());
$node = new $class($node, $name, $arguments,
$token->getLine(), $tag);
if
(!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE,
'|')) {
break;
}
$this->parser->getStream()->next();
}
return $node;
}
/**
* Parses arguments.
*
* @param bool $namedArguments Whether to allow named arguments or not
* @param bool $definition Whether we are parsing arguments for a
function definition
*
* @return Node
*
* @throws SyntaxError
*/
public function parseArguments($namedArguments = false, $definition =
false, $allowArrow = false)
{
$args = [];
$stream = $this->parser->getStream();
$stream->expect(Token::PUNCTUATION_TYPE, '(', 'A
list of arguments must begin with an opening parenthesis');
while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) {
if (!empty($args)) {
$stream->expect(Token::PUNCTUATION_TYPE, ',',
'Arguments must be separated by a comma');
}
if ($definition) {
$token = $stream->expect(Token::NAME_TYPE, null,
'An argument must be a name');
$value = new NameExpression($token->getValue(),
$this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression(0, $allowArrow);
}
$name = null;
if ($namedArguments && $token =
$stream->nextIf(Token::OPERATOR_TYPE, '=')) {
if (!$value instanceof NameExpression) {
throw new SyntaxError(sprintf('A parameter name
must be a string, "%s" given.', \get_class($value)),
$token->getLine(), $stream->getSourceContext());
}
$name = $value->getAttribute('name');
if ($definition) {
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new SyntaxError(sprintf('A default value
for an argument must be a constant (a boolean, a string, a number, or an
array).'), $token->getLine(), $stream->getSourceContext());
}
} else {
$value = $this->parseExpression(0, $allowArrow);
}
}
if ($definition) {
if (null === $name) {
$name = $value->getAttribute('name');
$value = new ConstantExpression(null,
$this->parser->getCurrentToken()->getLine());
}
$args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
}
}
$stream->expect(Token::PUNCTUATION_TYPE, ')', 'A
list of arguments must be closed by a parenthesis');
return new Node($args);
}
public function parseAssignmentExpression()
{
$stream = $this->parser->getStream();
$targets = [];
while (true) {
$token = $this->parser->getCurrentToken();
if ($stream->test(Token::OPERATOR_TYPE) &&
preg_match(Lexer::REGEX_NAME, $token->getValue())) {
// in this context, string operators are variable names
$this->parser->getStream()->next();
} else {
$stream->expect(Token::NAME_TYPE, null, 'Only
variables can be assigned to');
}
$value = $token->getValue();
if (\in_array(strtr($value,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'), ['true',
'false', 'none', 'null'])) {
throw new SyntaxError(sprintf('You cannot assign a
value to "%s".', $value), $token->getLine(),
$stream->getSourceContext());
}
$targets[] = new AssignNameExpression($value,
$token->getLine());
if (!$stream->nextIf(Token::PUNCTUATION_TYPE,
',')) {
break;
}
}
return new Node($targets);
}
public function parseMultitargetExpression()
{
$targets = [];
while (true) {
$targets[] = $this->parseExpression();
if
(!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE,
',')) {
break;
}
}
return new Node($targets);
}
private function parseNotTestExpression(\Twig_NodeInterface $node)
{
return new NotUnary($this->parseTestExpression($node),
$this->parser->getCurrentToken()->getLine());
}
private function parseTestExpression(\Twig_NodeInterface $node)
{
$stream = $this->parser->getStream();
list($name, $test) =
$this->getTest($node->getTemplateLine());
$class = $this->getTestNodeClass($test);
$arguments = null;
if ($stream->test(Token::PUNCTUATION_TYPE, '(')) {
$arguments = $this->parseArguments(true);
}
return new $class($node, $name, $arguments,
$this->parser->getCurrentToken()->getLine());
}
private function getTest($line)
{
$stream = $this->parser->getStream();
$name = $stream->expect(Token::NAME_TYPE)->getValue();
if ($test = $this->env->getTest($name)) {
return [$name, $test];
}
if ($stream->test(Token::NAME_TYPE)) {
// try 2-words tests
$name = $name.'
'.$this->parser->getCurrentToken()->getValue();
if ($test = $this->env->getTest($name)) {
$stream->next();
return [$name, $test];
}
}
$e = new SyntaxError(sprintf('Unknown "%s"
test.', $name), $line, $stream->getSourceContext());
$e->addSuggestions($name,
array_keys($this->env->getTests()));
throw $e;
}
private function getTestNodeClass($test)
{
if ($test instanceof TwigTest && $test->isDeprecated())
{
$stream = $this->parser->getStream();
$message = sprintf('Twig Test "%s" is
deprecated', $test->getName());
if (!\is_bool($test->getDeprecatedVersion())) {
$message .= sprintf(' since version %s',
$test->getDeprecatedVersion());
}
if ($test->getAlternative()) {
$message .= sprintf('. Use "%s"
instead', $test->getAlternative());
}
$src = $stream->getSourceContext();
$message .= sprintf(' in %s at line %d.',
$src->getPath() ? $src->getPath() : $src->getName(),
$stream->getCurrent()->getLine());
@trigger_error($message, E_USER_DEPRECATED);
}
if ($test instanceof TwigTest) {
return $test->getNodeClass();
}
return $test instanceof \Twig_Test_Node ? $test->getClass() :
'Twig\Node\Expression\TestExpression';
}
protected function getFunctionNodeClass($name, $line)
{
if (false === $function = $this->env->getFunction($name)) {
$e = new SyntaxError(sprintf('Unknown "%s"
function.', $name), $line,
$this->parser->getStream()->getSourceContext());
$e->addSuggestions($name,
array_keys($this->env->getFunctions()));
throw $e;
}
if ($function instanceof TwigFunction &&
$function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is
deprecated', $function->getName());
if (!\is_bool($function->getDeprecatedVersion())) {
$message .= sprintf(' since version %s',
$function->getDeprecatedVersion());
}
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s"
instead', $function->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.',
$src->getPath() ? $src->getPath() : $src->getName(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
if ($function instanceof TwigFunction) {
return $function->getNodeClass();
}
return $function instanceof \Twig_Function_Node ?
$function->getClass() :
'Twig\Node\Expression\FunctionExpression';
}
protected function getFilterNodeClass($name, $line)
{
if (false === $filter = $this->env->getFilter($name)) {
$e = new SyntaxError(sprintf('Unknown "%s"
filter.', $name), $line,
$this->parser->getStream()->getSourceContext());
$e->addSuggestions($name,
array_keys($this->env->getFilters()));
throw $e;
}
if ($filter instanceof TwigFilter &&
$filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is
deprecated', $filter->getName());
if (!\is_bool($filter->getDeprecatedVersion())) {
$message .= sprintf(' since version %s',
$filter->getDeprecatedVersion());
}
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s"
instead', $filter->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.',
$src->getPath() ? $src->getPath() : $src->getName(), $line);
@trigger_error($message, E_USER_DEPRECATED);
}
if ($filter instanceof TwigFilter) {
return $filter->getNodeClass();
}
return $filter instanceof \Twig_Filter_Node ?
$filter->getClass() : 'Twig\Node\Expression\FilterExpression';
}
// checks that the node only contains "constant" elements
protected function checkConstantExpression(\Twig_NodeInterface $node)
{
if (!($node instanceof ConstantExpression || $node instanceof
ArrayExpression
|| $node instanceof NegUnary || $node instanceof PosUnary
)) {
return false;
}
foreach ($node as $n) {
if (!$this->checkConstantExpression($n)) {
return false;
}
}
return true;
}
}
class_alias('Twig\ExpressionParser',
'Twig_ExpressionParser');
PK-d�[HAAA4vendor/twig/twig/src/Extension/AbstractExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
use Twig\Environment;
abstract class AbstractExtension implements ExtensionInterface
{
/**
* @deprecated since 1.23 (to be removed in 2.0), implement
\Twig_Extension_InitRuntimeInterface instead
*/
public function initRuntime(Environment $environment)
{
}
public function getTokenParsers()
{
return [];
}
public function getNodeVisitors()
{
return [];
}
public function getFilters()
{
return [];
}
public function getTests()
{
return [];
}
public function getFunctions()
{
return [];
}
public function getOperators()
{
return [];
}
/**
* @deprecated since 1.23 (to be removed in 2.0), implement
\Twig_Extension_GlobalsInterface instead
*/
public function getGlobals()
{
return [];
}
/**
* @deprecated since 1.26 (to be removed in 2.0), not used anymore
internally
*/
public function getName()
{
return \get_class($this);
}
}
class_alias('Twig\Extension\AbstractExtension',
'Twig_Extension');
PK-d�[��k?�?�0vendor/twig/twig/src/Extension/CoreExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension {
use Twig\ExpressionParser;
use Twig\TokenParser\ApplyTokenParser;
use Twig\TokenParser\BlockTokenParser;
use Twig\TokenParser\DeprecatedTokenParser;
use Twig\TokenParser\DoTokenParser;
use Twig\TokenParser\EmbedTokenParser;
use Twig\TokenParser\ExtendsTokenParser;
use Twig\TokenParser\FilterTokenParser;
use Twig\TokenParser\FlushTokenParser;
use Twig\TokenParser\ForTokenParser;
use Twig\TokenParser\FromTokenParser;
use Twig\TokenParser\IfTokenParser;
use Twig\TokenParser\ImportTokenParser;
use Twig\TokenParser\IncludeTokenParser;
use Twig\TokenParser\MacroTokenParser;
use Twig\TokenParser\SetTokenParser;
use Twig\TokenParser\SpacelessTokenParser;
use Twig\TokenParser\UseTokenParser;
use Twig\TokenParser\WithTokenParser;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
/**
* @final
*/
class CoreExtension extends AbstractExtension
{
protected $dateFormats = ['F j, Y H:i', '%d days'];
protected $numberFormat = [0, '.', ','];
protected $timezone = null;
protected $escapers = [];
/**
* Defines a new escaper to be used via the escape filter.
*
* @param string $strategy The strategy name that should be used as a
strategy in the escape call
* @param callable $callable A valid PHP callable
*/
public function setEscaper($strategy, $callable)
{
$this->escapers[$strategy] = $callable;
}
/**
* Gets all defined escapers.
*
* @return array An array of escapers
*/
public function getEscapers()
{
return $this->escapers;
}
/**
* Sets the default format to be used by the date filter.
*
* @param string $format The default date format string
* @param string $dateIntervalFormat The default date interval format
string
*/
public function setDateFormat($format = null, $dateIntervalFormat =
null)
{
if (null !== $format) {
$this->dateFormats[0] = $format;
}
if (null !== $dateIntervalFormat) {
$this->dateFormats[1] = $dateIntervalFormat;
}
}
/**
* Gets the default format to be used by the date filter.
*
* @return array The default date format string and the default date
interval format string
*/
public function getDateFormat()
{
return $this->dateFormats;
}
/**
* Sets the default timezone to be used by the date filter.
*
* @param \DateTimeZone|string $timezone The default timezone string or
a \DateTimeZone object
*/
public function setTimezone($timezone)
{
$this->timezone = $timezone instanceof \DateTimeZone ? $timezone
: new \DateTimeZone($timezone);
}
/**
* Gets the default timezone to be used by the date filter.
*
* @return \DateTimeZone The default timezone currently in use
*/
public function getTimezone()
{
if (null === $this->timezone) {
$this->timezone = new
\DateTimeZone(date_default_timezone_get());
}
return $this->timezone;
}
/**
* Sets the default format to be used by the number_format filter.
*
* @param int $decimal the number of decimal places to use
* @param string $decimalPoint the character(s) to use for the decimal
point
* @param string $thousandSep the character(s) to use for the
thousands separator
*/
public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
{
$this->numberFormat = [$decimal, $decimalPoint, $thousandSep];
}
/**
* Get the default format used by the number_format filter.
*
* @return array The arguments for number_format()
*/
public function getNumberFormat()
{
return $this->numberFormat;
}
public function getTokenParsers()
{
return [
new ApplyTokenParser(),
new ForTokenParser(),
new IfTokenParser(),
new ExtendsTokenParser(),
new IncludeTokenParser(),
new BlockTokenParser(),
new UseTokenParser(),
new FilterTokenParser(),
new MacroTokenParser(),
new ImportTokenParser(),
new FromTokenParser(),
new SetTokenParser(),
new SpacelessTokenParser(),
new FlushTokenParser(),
new DoTokenParser(),
new EmbedTokenParser(),
new WithTokenParser(),
new DeprecatedTokenParser(),
];
}
public function getFilters()
{
$filters = [
// formatting filters
new TwigFilter('date',
'twig_date_format_filter', ['needs_environment' =>
true]),
new TwigFilter('date_modify',
'twig_date_modify_filter', ['needs_environment' =>
true]),
new TwigFilter('format', 'sprintf'),
new TwigFilter('replace',
'twig_replace_filter'),
new TwigFilter('number_format',
'twig_number_format_filter', ['needs_environment' =>
true]),
new TwigFilter('abs', 'abs'),
new TwigFilter('round', 'twig_round'),
// encoding
new TwigFilter('url_encode',
'twig_urlencode_filter'),
new TwigFilter('json_encode',
'twig_jsonencode_filter'),
new TwigFilter('convert_encoding',
'twig_convert_encoding'),
// string filters
new TwigFilter('title',
'twig_title_string_filter', ['needs_environment' =>
true]),
new TwigFilter('capitalize',
'twig_capitalize_string_filter', ['needs_environment'
=> true]),
new TwigFilter('upper', 'strtoupper'),
new TwigFilter('lower', 'strtolower'),
new TwigFilter('striptags', 'strip_tags'),
new TwigFilter('trim', 'twig_trim_filter'),
new TwigFilter('nl2br', 'nl2br',
['pre_escape' => 'html', 'is_safe' =>
['html']]),
new TwigFilter('spaceless',
'twig_spaceless', ['is_safe' =>
['html']]),
// array helpers
new TwigFilter('join', 'twig_join_filter'),
new TwigFilter('split',
'twig_split_filter', ['needs_environment' => true]),
new TwigFilter('sort', 'twig_sort_filter'),
new TwigFilter('merge',
'twig_array_merge'),
new TwigFilter('batch',
'twig_array_batch'),
new TwigFilter('filter',
'twig_array_filter'),
new TwigFilter('map', 'twig_array_map'),
new TwigFilter('reduce',
'twig_array_reduce'),
// string/array filters
new TwigFilter('reverse',
'twig_reverse_filter', ['needs_environment' =>
true]),
new TwigFilter('length',
'twig_length_filter', ['needs_environment' =>
true]),
new TwigFilter('slice', 'twig_slice',
['needs_environment' => true]),
new TwigFilter('first', 'twig_first',
['needs_environment' => true]),
new TwigFilter('last', 'twig_last',
['needs_environment' => true]),
// iteration and runtime
new TwigFilter('default',
'_twig_default_filter', ['node_class' =>
'\Twig\Node\Expression\Filter\DefaultFilter']),
new TwigFilter('keys',
'twig_get_array_keys_filter'),
// escaping
new TwigFilter('escape',
'twig_escape_filter', ['needs_environment' => true,
'is_safe_callback' =>
'twig_escape_filter_is_safe']),
new TwigFilter('e', 'twig_escape_filter',
['needs_environment' => true, 'is_safe_callback'
=> 'twig_escape_filter_is_safe']),
];
if (\function_exists('mb_get_info')) {
$filters[] = new TwigFilter('upper',
'twig_upper_filter', ['needs_environment' => true]);
$filters[] = new TwigFilter('lower',
'twig_lower_filter', ['needs_environment' => true]);
}
return $filters;
}
public function getFunctions()
{
return [
new TwigFunction('max', 'max'),
new TwigFunction('min', 'min'),
new TwigFunction('range', 'range'),
new TwigFunction('constant',
'twig_constant'),
new TwigFunction('cycle', 'twig_cycle'),
new TwigFunction('random', 'twig_random',
['needs_environment' => true]),
new TwigFunction('date',
'twig_date_converter', ['needs_environment' =>
true]),
new TwigFunction('include', 'twig_include',
['needs_environment' => true, 'needs_context' =>
true, 'is_safe' => ['all']]),
new TwigFunction('source', 'twig_source',
['needs_environment' => true, 'is_safe' =>
['all']]),
];
}
public function getTests()
{
return [
new TwigTest('even', null, ['node_class'
=> '\Twig\Node\Expression\Test\EvenTest']),
new TwigTest('odd', null, ['node_class'
=> '\Twig\Node\Expression\Test\OddTest']),
new TwigTest('defined', null, ['node_class'
=> '\Twig\Node\Expression\Test\DefinedTest']),
new TwigTest('sameas', null, ['node_class'
=> '\Twig\Node\Expression\Test\SameasTest',
'deprecated' => '1.21', 'alternative'
=> 'same as']),
new TwigTest('same as', null, ['node_class'
=> '\Twig\Node\Expression\Test\SameasTest']),
new TwigTest('none', null, ['node_class'
=> '\Twig\Node\Expression\Test\NullTest']),
new TwigTest('null', null, ['node_class'
=> '\Twig\Node\Expression\Test\NullTest']),
new TwigTest('divisibleby', null,
['node_class' =>
'\Twig\Node\Expression\Test\DivisiblebyTest',
'deprecated' => '1.21', 'alternative'
=> 'divisible by']),
new TwigTest('divisible by', null,
['node_class' =>
'\Twig\Node\Expression\Test\DivisiblebyTest']),
new TwigTest('constant', null,
['node_class' =>
'\Twig\Node\Expression\Test\ConstantTest']),
new TwigTest('empty', 'twig_test_empty'),
new TwigTest('iterable',
'twig_test_iterable'),
];
}
public function getOperators()
{
return [
[
'not' => ['precedence' => 50,
'class' => '\Twig\Node\Expression\Unary\NotUnary'],
'-' => ['precedence' => 500,
'class' => '\Twig\Node\Expression\Unary\NegUnary'],
'+' => ['precedence' => 500,
'class' => '\Twig\Node\Expression\Unary\PosUnary'],
],
[
'or' => ['precedence' => 10,
'class' => '\Twig\Node\Expression\Binary\OrBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'and' => ['precedence' => 15,
'class' => '\Twig\Node\Expression\Binary\AndBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'b-or' => ['precedence' => 16,
'class' =>
'\Twig\Node\Expression\Binary\BitwiseOrBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'b-xor' => ['precedence' => 17,
'class' =>
'\Twig\Node\Expression\Binary\BitwiseXorBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'b-and' => ['precedence' => 18,
'class' =>
'\Twig\Node\Expression\Binary\BitwiseAndBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'==' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\EqualBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'!=' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\NotEqualBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'<' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\LessBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'>' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\GreaterBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'>=' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\GreaterEqualBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'<=' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\LessEqualBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'not in' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\NotInBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'in' => ['precedence' => 20,
'class' => '\Twig\Node\Expression\Binary\InBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'matches' => ['precedence' => 20,
'class' =>
'\Twig\Node\Expression\Binary\MatchesBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'starts with' => ['precedence' =>
20, 'class' =>
'\Twig\Node\Expression\Binary\StartsWithBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'ends with' => ['precedence' =>
20, 'class' =>
'\Twig\Node\Expression\Binary\EndsWithBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'..' => ['precedence' => 25,
'class' =>
'\Twig\Node\Expression\Binary\RangeBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'+' => ['precedence' => 30,
'class' => '\Twig\Node\Expression\Binary\AddBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'-' => ['precedence' => 30,
'class' => '\Twig\Node\Expression\Binary\SubBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'~' => ['precedence' => 40,
'class' =>
'\Twig\Node\Expression\Binary\ConcatBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'*' => ['precedence' => 60,
'class' => '\Twig\Node\Expression\Binary\MulBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'/' => ['precedence' => 60,
'class' => '\Twig\Node\Expression\Binary\DivBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'//' => ['precedence' => 60,
'class' =>
'\Twig\Node\Expression\Binary\FloorDivBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'%' => ['precedence' => 60,
'class' => '\Twig\Node\Expression\Binary\ModBinary',
'associativity' => ExpressionParser::OPERATOR_LEFT],
'is' => ['precedence' => 100,
'associativity' => ExpressionParser::OPERATOR_LEFT],
'is not' => ['precedence' => 100,
'associativity' => ExpressionParser::OPERATOR_LEFT],
'**' => ['precedence' => 200,
'class' =>
'\Twig\Node\Expression\Binary\PowerBinary',
'associativity' => ExpressionParser::OPERATOR_RIGHT],
'??' => ['precedence' => 300,
'class' =>
'\Twig\Node\Expression\NullCoalesceExpression',
'associativity' => ExpressionParser::OPERATOR_RIGHT],
],
];
}
public function getName()
{
return 'core';
}
}
class_alias('Twig\Extension\CoreExtension',
'Twig_Extension_Core');
}
namespace {
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Loader\SourceContextLoaderInterface;
use Twig\Markup;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
/**
* Cycles over a value.
*
* @param \ArrayAccess|array $values
* @param int $position The cycle position
*
* @return string The next value in the cycle
*/
function twig_cycle($values, $position)
{
if (!\is_array($values) && !$values instanceof \ArrayAccess) {
return $values;
}
return $values[$position % \count($values)];
}
/**
* Returns a random value depending on the supplied parameter type:
* - a random item from a \Traversable or array
* - a random character from a string
* - a random integer between 0 and the integer parameter.
*
* @param \Traversable|array|int|float|string $values The values to pick a
random item from
* @param int|null $max Maximum value used
when $values is an int
*
* @throws RuntimeError when $values is an empty array (does not apply to
an empty string which is returned as is)
*
* @return mixed A random value from the given sequence
*/
function twig_random(Environment $env, $values = null, $max = null)
{
if (null === $values) {
return null === $max ? mt_rand() : mt_rand(0, $max);
}
if (\is_int($values) || \is_float($values)) {
if (null === $max) {
if ($values < 0) {
$max = 0;
$min = $values;
} else {
$max = $values;
$min = 0;
}
} else {
$min = $values;
$max = $max;
}
return mt_rand($min, $max);
}
if (\is_string($values)) {
if ('' === $values) {
return '';
}
if (null !== $charset = $env->getCharset()) {
if ('UTF-8' !== $charset) {
$values = twig_convert_encoding($values, 'UTF-8',
$charset);
}
// unicode version of str_split()
// split at all positions, but not after the start and not
before the end
$values = preg_split('/(?<!^)(?!$)/u', $values);
if ('UTF-8' !== $charset) {
foreach ($values as $i => $value) {
$values[$i] = twig_convert_encoding($value, $charset,
'UTF-8');
}
}
} else {
return $values[mt_rand(0, \strlen($values) - 1)];
}
}
if (!twig_test_iterable($values)) {
return $values;
}
$values = twig_to_array($values);
if (0 === \count($values)) {
throw new RuntimeError('The random function cannot pick from
an empty array.');
}
return $values[array_rand($values, 1)];
}
/**
* Converts a date to the given format.
*
* {{ post.published_at|date("m/d/Y") }}
*
* @param \DateTime|\DateTimeInterface|\DateInterval|string $date A
date
* @param string|null $format The
target format, null to use the default
* @param \DateTimeZone|string|false|null $timezone The
target timezone, null to use the default, false to leave unchanged
*
* @return string The formatted date
*/
function twig_date_format_filter(Environment $env, $date, $format = null,
$timezone = null)
{
if (null === $format) {
$formats =
$env->getExtension('\Twig\Extension\CoreExtension')->getDateFormat();
$format = $date instanceof \DateInterval ? $formats[1] :
$formats[0];
}
if ($date instanceof \DateInterval) {
return $date->format($format);
}
return twig_date_converter($env, $date, $timezone)->format($format);
}
/**
* Returns a new date object modified.
*
* {{
post.published_at|date_modify("-1day")|date("m/d/Y") }}
*
* @param \DateTime|string $date A date
* @param string $modifier A modifier string
*
* @return \DateTime
*/
function twig_date_modify_filter(Environment $env, $date, $modifier)
{
$date = twig_date_converter($env, $date, false);
$resultDate = $date->modify($modifier);
// This is a hack to ensure PHP 5.2 support and support for
\DateTimeImmutable
// \DateTime::modify does not return the modified \DateTime object <
5.3.0
// and \DateTimeImmutable does not modify $date.
return null === $resultDate ? $date : $resultDate;
}
/**
* Converts an input to a \DateTime instance.
*
* {% if date(user.created_at) < date('+2days') %}
* {# do something #}
* {% endif %}
*
* @param \DateTime|\DateTimeInterface|string|null $date A date
* @param \DateTimeZone|string|false|null $timezone The target
timezone, null to use the default, false to leave unchanged
*
* @return \DateTimeInterface
*/
function twig_date_converter(Environment $env, $date = null, $timezone =
null)
{
// determine the timezone
if (false !== $timezone) {
if (null === $timezone) {
$timezone =
$env->getExtension('\Twig\Extension\CoreExtension')->getTimezone();
} elseif (!$timezone instanceof \DateTimeZone) {
$timezone = new \DateTimeZone($timezone);
}
}
// immutable dates
if ($date instanceof \DateTimeImmutable) {
return false !== $timezone ? $date->setTimezone($timezone) :
$date;
}
if ($date instanceof \DateTime || $date instanceof \DateTimeInterface)
{
$date = clone $date;
if (false !== $timezone) {
$date->setTimezone($timezone);
}
return $date;
}
if (null === $date || 'now' === $date) {
return new \DateTime($date, false !== $timezone ? $timezone :
$env->getExtension('\Twig\Extension\CoreExtension')->getTimezone());
}
$asString = (string) $date;
if (ctype_digit($asString) || (!empty($asString) &&
'-' === $asString[0] && ctype_digit(substr($asString,
1)))) {
$date = new \DateTime('@'.$date);
} else {
$date = new \DateTime($date,
$env->getExtension('\Twig\Extension\CoreExtension')->getTimezone());
}
if (false !== $timezone) {
$date->setTimezone($timezone);
}
return $date;
}
/**
* Replaces strings within a string.
*
* @param string $str String to replace in
* @param array|\Traversable $from Replace values
* @param string|null $to Replace to, deprecated (@see
https://secure.php.net/manual/en/function.strtr.php)
*
* @return string
*/
function twig_replace_filter($str, $from, $to = null)
{
if (\is_string($from) && \is_string($to)) {
@trigger_error('Using "replace" with character by
character replacement is deprecated since version 1.22 and will be removed
in Twig 2.0', E_USER_DEPRECATED);
return strtr($str, $from, $to);
}
if (!twig_test_iterable($from)) {
throw new RuntimeError(sprintf('The "replace" filter
expects an array or "Traversable" as replace values, got
"%s".', \is_object($from) ? \get_class($from) :
\gettype($from)));
}
return strtr($str, twig_to_array($from));
}
/**
* Rounds a number.
*
* @param int|float $value The value to round
* @param int|float $precision The rounding precision
* @param string $method The method to use for rounding
*
* @return int|float The rounded number
*/
function twig_round($value, $precision = 0, $method = 'common')
{
if ('common' == $method) {
return round($value, $precision);
}
if ('ceil' != $method && 'floor' !=
$method) {
throw new RuntimeError('The round filter only supports the
"common", "ceil", and "floor"
methods.');
}
return $method($value * pow(10, $precision)) / pow(10, $precision);
}
/**
* Number format filter.
*
* All of the formatting options can be left null, in that case the
defaults will
* be used. Supplying any of the parameters will override the defaults set
in the
* environment object.
*
* @param mixed $number A float/int/string of the number to format
* @param int $decimal the number of decimal points to display
* @param string $decimalPoint the character(s) to use for the decimal
point
* @param string $thousandSep the character(s) to use for the thousands
separator
*
* @return string The formatted number
*/
function twig_number_format_filter(Environment $env, $number, $decimal =
null, $decimalPoint = null, $thousandSep = null)
{
$defaults =
$env->getExtension('\Twig\Extension\CoreExtension')->getNumberFormat();
if (null === $decimal) {
$decimal = $defaults[0];
}
if (null === $decimalPoint) {
$decimalPoint = $defaults[1];
}
if (null === $thousandSep) {
$thousandSep = $defaults[2];
}
return number_format((float) $number, $decimal, $decimalPoint,
$thousandSep);
}
/**
* URL encodes (RFC 3986) a string as a path segment or an array as a query
string.
*
* @param string|array $url A URL or an array of query parameters
*
* @return string The URL encoded value
*/
function twig_urlencode_filter($url)
{
if (\is_array($url)) {
if (\defined('PHP_QUERY_RFC3986')) {
return http_build_query($url, '', '&',
PHP_QUERY_RFC3986);
}
return http_build_query($url, '', '&');
}
return rawurlencode($url);
}
/**
* JSON encodes a variable.
*
* @param mixed $value the value to encode
* @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG,
JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT,
JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
*
* @return mixed The JSON encoded value
*/
function twig_jsonencode_filter($value, $options = 0)
{
if ($value instanceof Markup) {
$value = (string) $value;
} elseif (\is_array($value)) {
array_walk_recursive($value, '_twig_markup2string');
}
return json_encode($value, $options);
}
function _twig_markup2string(&$value)
{
if ($value instanceof Markup) {
$value = (string) $value;
}
}
/**
* Merges an array with another one.
*
* {% set items = { 'apple': 'fruit',
'orange': 'fruit' } %}
*
* {% set items = items|merge({ 'peugeot': 'car' }) %}
*
* {# items now contains { 'apple': 'fruit',
'orange': 'fruit', 'peugeot': 'car'
} #}
*
* @param array|\Traversable $arr1 An array
* @param array|\Traversable $arr2 An array
*
* @return array The merged array
*/
function twig_array_merge($arr1, $arr2)
{
if (!twig_test_iterable($arr1)) {
throw new RuntimeError(sprintf('The merge filter only works
with arrays or "Traversable", got "%s" as first
argument.', \gettype($arr1)));
}
if (!twig_test_iterable($arr2)) {
throw new RuntimeError(sprintf('The merge filter only works
with arrays or "Traversable", got "%s" as second
argument.', \gettype($arr2)));
}
return array_merge(twig_to_array($arr1), twig_to_array($arr2));
}
/**
* Slices a variable.
*
* @param mixed $item A variable
* @param int $start Start of the slice
* @param int $length Size of the slice
* @param bool $preserveKeys Whether to preserve key or not (when the
input is an array)
*
* @return mixed The sliced variable
*/
function twig_slice(Environment $env, $item, $start, $length = null,
$preserveKeys = false)
{
if ($item instanceof \Traversable) {
while ($item instanceof \IteratorAggregate) {
$item = $item->getIterator();
}
if ($start >= 0 && $length >= 0 && $item
instanceof \Iterator) {
try {
return iterator_to_array(new \LimitIterator($item, $start,
null === $length ? -1 : $length), $preserveKeys);
} catch (\OutOfBoundsException $e) {
return [];
}
}
$item = iterator_to_array($item, $preserveKeys);
}
if (\is_array($item)) {
return \array_slice($item, $start, $length, $preserveKeys);
}
$item = (string) $item;
if (\function_exists('mb_get_info') && null !==
$charset = $env->getCharset()) {
return (string) mb_substr($item, $start, null === $length ?
mb_strlen($item, $charset) - $start : $length, $charset);
}
return (string) (null === $length ? substr($item, $start) :
substr($item, $start, $length));
}
/**
* Returns the first element of the item.
*
* @param mixed $item A variable
*
* @return mixed The first element of the item
*/
function twig_first(Environment $env, $item)
{
$elements = twig_slice($env, $item, 0, 1, false);
return \is_string($elements) ? $elements : current($elements);
}
/**
* Returns the last element of the item.
*
* @param mixed $item A variable
*
* @return mixed The last element of the item
*/
function twig_last(Environment $env, $item)
{
$elements = twig_slice($env, $item, -1, 1, false);
return \is_string($elements) ? $elements : current($elements);
}
/**
* Joins the values to a string.
*
* The separators between elements are empty strings per default, you can
define them with the optional parameters.
*
* {{ [1, 2, 3]|join(', ', ' and ') }}
* {# returns 1, 2 and 3 #}
*
* {{ [1, 2, 3]|join('|') }}
* {# returns 1|2|3 #}
*
* {{ [1, 2, 3]|join }}
* {# returns 123 #}
*
* @param array $value An array
* @param string $glue The separator
* @param string|null $and The separator for the last pair
*
* @return string The concatenated string
*/
function twig_join_filter($value, $glue = '', $and = null)
{
if (!twig_test_iterable($value)) {
$value = (array) $value;
}
$value = twig_to_array($value, false);
if (0 === \count($value)) {
return '';
}
if (null === $and || $and === $glue) {
return implode($glue, $value);
}
if (1 === \count($value)) {
return $value[0];
}
return implode($glue, \array_slice($value, 0,
-1)).$and.$value[\count($value) - 1];
}
/**
* Splits the string into an array.
*
* {{ "one,two,three"|split(',') }}
* {# returns [one, two, three] #}
*
* {{ "one,two,three,four,five"|split(',', 3) }}
* {# returns [one, two, "three,four,five"] #}
*
* {{ "123"|split('') }}
* {# returns [1, 2, 3] #}
*
* {{ "aabbcc"|split('', 2) }}
* {# returns [aa, bb, cc] #}
*
* @param string $value A string
* @param string $delimiter The delimiter
* @param int $limit The limit
*
* @return array The split string as an array
*/
function twig_split_filter(Environment $env, $value, $delimiter, $limit =
null)
{
if (\strlen($delimiter) > 0) {
return null === $limit ? explode($delimiter, $value) :
explode($delimiter, $value, $limit);
}
if (!\function_exists('mb_get_info') || null === $charset =
$env->getCharset()) {
return str_split($value, null === $limit ? 1 : $limit);
}
if ($limit <= 1) {
return preg_split('/(?<!^)(?!$)/u', $value);
}
$length = mb_strlen($value, $charset);
if ($length < $limit) {
return [$value];
}
$r = [];
for ($i = 0; $i < $length; $i += $limit) {
$r[] = mb_substr($value, $i, $limit, $charset);
}
return $r;
}
// The '_default' filter is used internally to avoid using the
ternary operator
// which costs a lot for big contexts (before PHP 5.4). So, on average,
// a function call is cheaper.
/**
* @internal
*/
function _twig_default_filter($value, $default = '')
{
if (twig_test_empty($value)) {
return $default;
}
return $value;
}
/**
* Returns the keys for the given array.
*
* It is useful when you want to iterate over the keys of an array:
*
* {% for key in array|keys %}
* {# ... #}
* {% endfor %}
*
* @param array $array An array
*
* @return array The keys
*/
function twig_get_array_keys_filter($array)
{
if ($array instanceof \Traversable) {
while ($array instanceof \IteratorAggregate) {
$array = $array->getIterator();
}
if ($array instanceof \Iterator) {
$keys = [];
$array->rewind();
while ($array->valid()) {
$keys[] = $array->key();
$array->next();
}
return $keys;
}
$keys = [];
foreach ($array as $key => $item) {
$keys[] = $key;
}
return $keys;
}
if (!\is_array($array)) {
return [];
}
return array_keys($array);
}
/**
* Reverses a variable.
*
* @param array|\Traversable|string $item An array, a \Traversable
instance, or a string
* @param bool $preserveKeys Whether to preserve key
or not
*
* @return mixed The reversed input
*/
function twig_reverse_filter(Environment $env, $item, $preserveKeys =
false)
{
if ($item instanceof \Traversable) {
return array_reverse(iterator_to_array($item), $preserveKeys);
}
if (\is_array($item)) {
return array_reverse($item, $preserveKeys);
}
if (null !== $charset = $env->getCharset()) {
$string = (string) $item;
if ('UTF-8' !== $charset) {
$item = twig_convert_encoding($string, 'UTF-8',
$charset);
}
preg_match_all('/./us', $item, $matches);
$string = implode('', array_reverse($matches[0]));
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, $charset,
'UTF-8');
}
return $string;
}
return strrev((string) $item);
}
/**
* Sorts an array.
*
* @param array|\Traversable $array
*
* @return array
*/
function twig_sort_filter($array)
{
if ($array instanceof \Traversable) {
$array = iterator_to_array($array);
} elseif (!\is_array($array)) {
throw new RuntimeError(sprintf('The sort filter only works
with arrays or "Traversable", got "%s".',
\gettype($array)));
}
asort($array);
return $array;
}
/**
* @internal
*/
function twig_in_filter($value, $compare)
{
if ($value instanceof Markup) {
$value = (string) $value;
}
if ($compare instanceof Markup) {
$compare = (string) $compare;
}
if (\is_array($compare)) {
return \in_array($value, $compare, \is_object($value) ||
\is_resource($value));
} elseif (\is_string($compare) && (\is_string($value) ||
\is_int($value) || \is_float($value))) {
return '' === $value || false !== strpos($compare,
(string) $value);
} elseif ($compare instanceof \Traversable) {
if (\is_object($value) || \is_resource($value)) {
foreach ($compare as $item) {
if ($item === $value) {
return true;
}
}
} else {
foreach ($compare as $item) {
if ($item == $value) {
return true;
}
}
}
return false;
}
return false;
}
/**
* Returns a trimmed string.
*
* @return string
*
* @throws RuntimeError When an invalid trimming side is used (not a string
or not 'left', 'right', or 'both')
*/
function twig_trim_filter($string, $characterMask = null, $side =
'both')
{
if (null === $characterMask) {
$characterMask = " \t\n\r\0\x0B";
}
switch ($side) {
case 'both':
return trim($string, $characterMask);
case 'left':
return ltrim($string, $characterMask);
case 'right':
return rtrim($string, $characterMask);
default:
throw new RuntimeError('Trimming side must be
"left", "right" or "both".');
}
}
/**
* Removes whitespaces between HTML tags.
*
* @return string
*/
function twig_spaceless($content)
{
return trim(preg_replace('/>\s+</',
'><', $content));
}
/**
* Escapes a string.
*
* @param mixed $string The value to be escaped
* @param string $strategy The escaping strategy
* @param string $charset The charset
* @param bool $autoescape Whether the function is called by the
auto-escaping feature (true) or by the developer (false)
*
* @return string
*/
function twig_escape_filter(Environment $env, $string, $strategy =
'html', $charset = null, $autoescape = false)
{
if ($autoescape && $string instanceof Markup) {
return $string;
}
if (!\is_string($string)) {
if (\is_object($string) && method_exists($string,
'__toString')) {
$string = (string) $string;
} elseif (\in_array($strategy, ['html', 'js',
'css', 'html_attr', 'url'])) {
return $string;
}
}
if ('' === $string) {
return '';
}
if (null === $charset) {
$charset = $env->getCharset();
}
switch ($strategy) {
case 'html':
// see https://secure.php.net/htmlspecialchars
// Using a static variable to avoid initializing the array
// each time the function is called. Moving the declaration on
the
// top of the function slow downs other escaping strategies.
static $htmlspecialcharsCharsets = [
'ISO-8859-1' => true, 'ISO8859-1'
=> true,
'ISO-8859-15' => true, 'ISO8859-15'
=> true,
'utf-8' => true, 'UTF-8' => true,
'CP866' => true, 'IBM866' =>
true, '866' => true,
'CP1251' => true, 'WINDOWS-1251'
=> true, 'WIN-1251' => true,
'1251' => true,
'CP1252' => true, 'WINDOWS-1252'
=> true, '1252' => true,
'KOI8-R' => true, 'KOI8-RU' =>
true, 'KOI8R' => true,
'BIG5' => true, '950' => true,
'GB2312' => true, '936' => true,
'BIG5-HKSCS' => true,
'SHIFT_JIS' => true, 'SJIS' =>
true, '932' => true,
'EUC-JP' => true, 'EUCJP' =>
true,
'ISO8859-5' => true, 'ISO-8859-5'
=> true, 'MACROMAN' => true,
];
if (isset($htmlspecialcharsCharsets[$charset])) {
return htmlspecialchars($string, ENT_QUOTES |
ENT_SUBSTITUTE, $charset);
}
if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
// cache the lowercase variant for future iterations
$htmlspecialcharsCharsets[$charset] = true;
return htmlspecialchars($string, ENT_QUOTES |
ENT_SUBSTITUTE, $charset);
}
$string = twig_convert_encoding($string, 'UTF-8',
$charset);
$string = htmlspecialchars($string, ENT_QUOTES |
ENT_SUBSTITUTE, 'UTF-8');
return twig_convert_encoding($string, $charset,
'UTF-8');
case 'js':
// escape all non-alphanumeric characters
// into their \x or \uHHHH representations
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8',
$charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a
valid UTF-8 string.');
}
$string =
preg_replace_callback('#[^a-zA-Z0-9,\._]#Su',
'_twig_escape_js_callback', $string);
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, $charset,
'UTF-8');
}
return $string;
case 'css':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8',
$charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a
valid UTF-8 string.');
}
$string = preg_replace_callback('#[^a-zA-Z0-9]#Su',
'_twig_escape_css_callback', $string);
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, $charset,
'UTF-8');
}
return $string;
case 'html_attr':
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, 'UTF-8',
$charset);
}
if (!preg_match('//u', $string)) {
throw new RuntimeError('The string to escape is not a
valid UTF-8 string.');
}
$string =
preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su',
'_twig_escape_html_attr_callback', $string);
if ('UTF-8' !== $charset) {
$string = twig_convert_encoding($string, $charset,
'UTF-8');
}
return $string;
case 'url':
return rawurlencode($string);
default:
static $escapers;
if (null === $escapers) {
$escapers =
$env->getExtension('\Twig\Extension\CoreExtension')->getEscapers();
}
if (isset($escapers[$strategy])) {
return \call_user_func($escapers[$strategy], $env, $string,
$charset);
}
$validStrategies = implode(', ',
array_merge(['html', 'js', 'url',
'css', 'html_attr'], array_keys($escapers)));
throw new RuntimeError(sprintf('Invalid escaping strategy
"%s" (valid ones: %s).', $strategy, $validStrategies));
}
}
/**
* @internal
*/
function twig_escape_filter_is_safe(Node $filterArgs)
{
foreach ($filterArgs as $arg) {
if ($arg instanceof ConstantExpression) {
return [$arg->getAttribute('value')];
}
return [];
}
return ['html'];
}
if (\function_exists('mb_convert_encoding')) {
function twig_convert_encoding($string, $to, $from)
{
return mb_convert_encoding($string, $to, $from);
}
} elseif (\function_exists('iconv')) {
function twig_convert_encoding($string, $to, $from)
{
return iconv($from, $to, $string);
}
} else {
function twig_convert_encoding($string, $to, $from)
{
throw new RuntimeError('No suitable convert encoding function
(use UTF-8 as your encoding or install the iconv or mbstring
extension).');
}
}
if (\function_exists('mb_ord')) {
function twig_ord($string)
{
return mb_ord($string, 'UTF-8');
}
} else {
function twig_ord($string)
{
$code = ($string = unpack('C*', substr($string, 0, 4))) ?
$string[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($string[2] - 0x80)
<< 12) + (($string[3] - 0x80) << 6) + $string[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($string[2] - 0x80)
<< 6) + $string[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $string[2] - 0x80;
}
return $code;
}
}
function _twig_escape_js_callback($matches)
{
$char = $matches[0];
/*
* A few characters have short escape sequences in JSON and JavaScript.
* Escape sequences supported only by JavaScript, not JSON, are
ommitted.
* \" is also supported but omitted, because the resulting string
is not HTML safe.
*/
static $shortMap = [
'\\' => '\\\\',
'/' => '\\/',
"\x08" => '\b',
"\x0C" => '\f',
"\x0A" => '\n',
"\x0D" => '\r',
"\x09" => '\t',
];
if (isset($shortMap[$char])) {
return $shortMap[$char];
}
// \uHHHH
$char = twig_convert_encoding($char, 'UTF-16BE',
'UTF-8');
$char = strtoupper(bin2hex($char));
if (4 >= \strlen($char)) {
return sprintf('\u%04s', $char);
}
return sprintf('\u%04s\u%04s', substr($char, 0, -4),
substr($char, -4));
}
function _twig_escape_css_callback($matches)
{
$char = $matches[0];
return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) :
twig_ord($char));
}
/**
* This function is adapted from code coming from Zend Framework.
*
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc.
(https://www.zend.com)
* @license https://framework.zend.com/license/new-bsd New BSD License
*/
function _twig_escape_html_attr_callback($matches)
{
$chr = $matches[0];
$ord = \ord($chr);
/*
* The following replaces characters undefined in HTML with the
* hex entity for the Unicode replacement character.
*/
if (($ord <= 0x1f && "\t" != $chr &&
"\n" != $chr && "\r" != $chr) || ($ord >=
0x7f && $ord <= 0x9f)) {
return '�';
}
/*
* Check if the current character to escape has a name entity we should
* replace it with while grabbing the hex value of the character.
*/
if (1 == \strlen($chr)) {
/*
* While HTML supports far more named entities, the lowest common
denominator
* has become HTML5's XML Serialisation which is restricted to
the those named
* entities that XML supports. Using HTML entities would result in
this error:
* XML Parsing Error: undefined entity
*/
static $entityMap = [
34 => '"', /* quotation mark */
38 => '&', /* ampersand */
60 => '<', /* less-than sign */
62 => '>', /* greater-than sign */
];
if (isset($entityMap[$ord])) {
return $entityMap[$ord];
}
return sprintf('&#x%02X;', $ord);
}
/*
* Per OWASP recommendations, we'll use hex entities for any other
* characters where a named entity does not exist.
*/
return sprintf('&#x%04X;', twig_ord($chr));
}
// add multibyte extensions if possible
if (\function_exists('mb_get_info')) {
/**
* Returns the length of a variable.
*
* @param mixed $thing A variable
*
* @return int The length of the value
*/
function twig_length_filter(Environment $env, $thing)
{
if (null === $thing) {
return 0;
}
if (is_scalar($thing)) {
return mb_strlen($thing, $env->getCharset());
}
if ($thing instanceof \Countable || \is_array($thing) || $thing
instanceof \SimpleXMLElement) {
return \count($thing);
}
if ($thing instanceof \Traversable) {
return iterator_count($thing);
}
if (\is_object($thing) && method_exists($thing,
'__toString')) {
return mb_strlen((string) $thing, $env->getCharset());
}
return 1;
}
/**
* Converts a string to uppercase.
*
* @param string $string A string
*
* @return string The uppercased string
*/
function twig_upper_filter(Environment $env, $string)
{
if (null !== $charset = $env->getCharset()) {
return mb_strtoupper($string, $charset);
}
return strtoupper($string);
}
/**
* Converts a string to lowercase.
*
* @param string $string A string
*
* @return string The lowercased string
*/
function twig_lower_filter(Environment $env, $string)
{
if (null !== $charset = $env->getCharset()) {
return mb_strtolower($string, $charset);
}
return strtolower($string);
}
/**
* Returns a titlecased string.
*
* @param string $string A string
*
* @return string The titlecased string
*/
function twig_title_string_filter(Environment $env, $string)
{
if (null !== $charset = $env->getCharset()) {
return mb_convert_case($string, MB_CASE_TITLE, $charset);
}
return ucwords(strtolower($string));
}
/**
* Returns a capitalized string.
*
* @param string $string A string
*
* @return string The capitalized string
*/
function twig_capitalize_string_filter(Environment $env, $string)
{
if (null !== $charset = $env->getCharset()) {
return mb_strtoupper(mb_substr($string, 0, 1, $charset),
$charset).mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset),
$charset), $charset);
}
return ucfirst(strtolower($string));
}
}
// and byte fallback
else {
/**
* Returns the length of a variable.
*
* @param mixed $thing A variable
*
* @return int The length of the value
*/
function twig_length_filter(Environment $env, $thing)
{
if (null === $thing) {
return 0;
}
if (is_scalar($thing)) {
return \strlen($thing);
}
if ($thing instanceof \SimpleXMLElement) {
return \count($thing);
}
if (\is_object($thing) && method_exists($thing,
'__toString') && !$thing instanceof \Countable) {
return \strlen((string) $thing);
}
if ($thing instanceof \Countable || \is_array($thing)) {
return \count($thing);
}
if ($thing instanceof \IteratorAggregate) {
return iterator_count($thing);
}
return 1;
}
/**
* Returns a titlecased string.
*
* @param string $string A string
*
* @return string The titlecased string
*/
function twig_title_string_filter(Environment $env, $string)
{
return ucwords(strtolower($string));
}
/**
* Returns a capitalized string.
*
* @param string $string A string
*
* @return string The capitalized string
*/
function twig_capitalize_string_filter(Environment $env, $string)
{
return ucfirst(strtolower($string));
}
}
/**
* @internal
*/
function twig_ensure_traversable($seq)
{
if ($seq instanceof \Traversable || \is_array($seq)) {
return $seq;
}
return [];
}
/**
* @internal
*/
function twig_to_array($seq, $preserveKeys = true)
{
if ($seq instanceof \Traversable) {
return iterator_to_array($seq, $preserveKeys);
}
if (!\is_array($seq)) {
return $seq;
}
return $preserveKeys ? $seq : array_values($seq);
}
/**
* Checks if a variable is empty.
*
* {# evaluates to true if the foo variable is null, false, or the empty
string #}
* {% if foo is empty %}
* {# ... #}
* {% endif %}
*
* @param mixed $value A variable
*
* @return bool true if the value is empty, false otherwise
*/
function twig_test_empty($value)
{
if ($value instanceof \Countable) {
return 0 == \count($value);
}
if ($value instanceof \Traversable) {
return !iterator_count($value);
}
if (\is_object($value) && method_exists($value,
'__toString')) {
return '' === (string) $value;
}
return '' === $value || false === $value || null === $value
|| [] === $value;
}
/**
* Checks if a variable is traversable.
*
* {# evaluates to true if the foo variable is an array or a traversable
object #}
* {% if foo is iterable %}
* {# ... #}
* {% endif %}
*
* @param mixed $value A variable
*
* @return bool true if the value is traversable
*/
function twig_test_iterable($value)
{
return $value instanceof \Traversable || \is_array($value);
}
/**
* Renders a template.
*
* @param array $context
* @param string|array $template The template to render or an array of
templates to try consecutively
* @param array $variables The variables to pass to the template
* @param bool $withContext
* @param bool $ignoreMissing Whether to ignore missing templates
or not
* @param bool $sandboxed Whether to sandbox the template or
not
*
* @return string The rendered template
*/
function twig_include(Environment $env, $context, $template, $variables =
[], $withContext = true, $ignoreMissing = false, $sandboxed = false)
{
$alreadySandboxed = false;
$sandbox = null;
if ($withContext) {
$variables = array_merge($context, $variables);
}
if ($isSandboxed = $sandboxed &&
$env->hasExtension('\Twig\Extension\SandboxExtension')) {
$sandbox =
$env->getExtension('\Twig\Extension\SandboxExtension');
if (!$alreadySandboxed = $sandbox->isSandboxed()) {
$sandbox->enableSandbox();
}
}
$loaded = null;
try {
$loaded = $env->resolveTemplate($template);
} catch (LoaderError $e) {
if (!$ignoreMissing) {
if ($isSandboxed && !$alreadySandboxed) {
$sandbox->disableSandbox();
}
throw $e;
}
} catch (\Throwable $e) {
if ($isSandboxed && !$alreadySandboxed) {
$sandbox->disableSandbox();
}
throw $e;
} catch (\Exception $e) {
if ($isSandboxed && !$alreadySandboxed) {
$sandbox->disableSandbox();
}
throw $e;
}
try {
$ret = $loaded ? $loaded->render($variables) : '';
} catch (\Exception $e) {
if ($isSandboxed && !$alreadySandboxed) {
$sandbox->disableSandbox();
}
throw $e;
}
if ($isSandboxed && !$alreadySandboxed) {
$sandbox->disableSandbox();
}
return $ret;
}
/**
* Returns a template content without rendering it.
*
* @param string $name The template name
* @param bool $ignoreMissing Whether to ignore missing templates or not
*
* @return string The template source
*/
function twig_source(Environment $env, $name, $ignoreMissing = false)
{
$loader = $env->getLoader();
try {
if (!$loader instanceof SourceContextLoaderInterface) {
return $loader->getSource($name);
} else {
return $loader->getSourceContext($name)->getCode();
}
} catch (LoaderError $e) {
if (!$ignoreMissing) {
throw $e;
}
}
}
/**
* Provides the ability to get constants from instances as well as
class/global constants.
*
* @param string $constant The name of the constant
* @param object|null $object The object to get the constant from
*
* @return string
*/
function twig_constant($constant, $object = null)
{
if (null !== $object) {
$constant = \get_class($object).'::'.$constant;
}
return \constant($constant);
}
/**
* Checks if a constant exists.
*
* @param string $constant The name of the constant
* @param object|null $object The object to get the constant from
*
* @return bool
*/
function twig_constant_is_defined($constant, $object = null)
{
if (null !== $object) {
$constant = \get_class($object).'::'.$constant;
}
return \defined($constant);
}
/**
* Batches item.
*
* @param array $items An array of items
* @param int $size The size of the batch
* @param mixed $fill A value used to fill missing items
*
* @return array
*/
function twig_array_batch($items, $size, $fill = null, $preserveKeys =
true)
{
if (!twig_test_iterable($items)) {
throw new RuntimeError(sprintf('The "batch" filter
expects an array or "Traversable", got "%s".',
\is_object($items) ? \get_class($items) : \gettype($items)));
}
$size = ceil($size);
$result = array_chunk(twig_to_array($items, $preserveKeys), $size,
$preserveKeys);
if (null !== $fill && $result) {
$last = \count($result) - 1;
if ($fillCount = $size - \count($result[$last])) {
for ($i = 0; $i < $fillCount; ++$i) {
$result[$last][] = $fill;
}
}
}
return $result;
}
function twig_array_filter($array, $arrow)
{
if (\is_array($array)) {
if (\PHP_VERSION_ID >= 50600) {
return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
}
return array_filter($array, $arrow);
}
// the IteratorIterator wrapping is needed as some internal PHP classes
are \Traversable but do not implement \Iterator
return new \CallbackFilterIterator(new \IteratorIterator($array),
$arrow);
}
function twig_array_map($array, $arrow)
{
$r = [];
foreach ($array as $k => $v) {
$r[$k] = $arrow($v, $k);
}
return $r;
}
function twig_array_reduce($array, $arrow, $initial = null)
{
if (!\is_array($array)) {
$array = iterator_to_array($array);
}
return array_reduce($array, $arrow, $initial);
}
}
PK-d�[6����1vendor/twig/twig/src/Extension/DebugExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension {
use Twig\TwigFunction;
/**
* @final
*/
class DebugExtension extends AbstractExtension
{
public function getFunctions()
{
// dump is safe if var_dump is overridden by xdebug
$isDumpOutputHtmlSafe = \extension_loaded('xdebug')
// false means that it was not set (and the default is on) or
it explicitly enabled
&& (false ===
ini_get('xdebug.overload_var_dump') ||
ini_get('xdebug.overload_var_dump'))
// false means that it was not set (and the default is on) or
it explicitly enabled
// xdebug.overload_var_dump produces HTML only when html_errors
is also enabled
&& (false === ini_get('html_errors') ||
ini_get('html_errors'))
|| 'cli' === \PHP_SAPI
;
return [
new TwigFunction('dump', 'twig_var_dump',
['is_safe' => $isDumpOutputHtmlSafe ? ['html'] : [],
'needs_context' => true, 'needs_environment' =>
true, 'is_variadic' => true]),
];
}
public function getName()
{
return 'debug';
}
}
class_alias('Twig\Extension\DebugExtension',
'Twig_Extension_Debug');
}
namespace {
use Twig\Environment;
use Twig\Template;
use Twig\TemplateWrapper;
function twig_var_dump(Environment $env, $context, array $vars = [])
{
if (!$env->isDebug()) {
return;
}
ob_start();
if (!$vars) {
$vars = [];
foreach ($context as $key => $value) {
if (!$value instanceof Template && !$value instanceof
TemplateWrapper) {
$vars[$key] = $value;
}
}
var_dump($vars);
} else {
foreach ($vars as $var) {
var_dump($var);
}
}
return ob_get_clean();
}
}
PK-d�[�%ϑ��3vendor/twig/twig/src/Extension/EscaperExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension {
use Twig\NodeVisitor\EscaperNodeVisitor;
use Twig\TokenParser\AutoEscapeTokenParser;
use Twig\TwigFilter;
/**
* @final
*/
class EscaperExtension extends AbstractExtension
{
protected $defaultStrategy;
/**
* @param string|false|callable $defaultStrategy An escaping strategy
*
* @see setDefaultStrategy()
*/
public function __construct($defaultStrategy = 'html')
{
$this->setDefaultStrategy($defaultStrategy);
}
public function getTokenParsers()
{
return [new AutoEscapeTokenParser()];
}
public function getNodeVisitors()
{
return [new EscaperNodeVisitor()];
}
public function getFilters()
{
return [
new TwigFilter('raw', 'twig_raw_filter',
['is_safe' => ['all']]),
];
}
/**
* Sets the default strategy to use when not defined by the user.
*
* The strategy can be a valid PHP callback that takes the template
* name as an argument and returns the strategy to use.
*
* @param string|false|callable $defaultStrategy An escaping strategy
*/
public function setDefaultStrategy($defaultStrategy)
{
// for BC
if (true === $defaultStrategy) {
@trigger_error('Using "true" as the default
strategy is deprecated since version 1.21. Use "html"
instead.', E_USER_DEPRECATED);
$defaultStrategy = 'html';
}
if ('filename' === $defaultStrategy) {
@trigger_error('Using "filename" as the default
strategy is deprecated since version 1.27. Use "name"
instead.', E_USER_DEPRECATED);
$defaultStrategy = 'name';
}
if ('name' === $defaultStrategy) {
$defaultStrategy =
['\Twig\FileExtensionEscapingStrategy', 'guess'];
}
$this->defaultStrategy = $defaultStrategy;
}
/**
* Gets the default strategy to use when not defined by the user.
*
* @param string $name The template name
*
* @return string|false The default strategy to use for the template
*/
public function getDefaultStrategy($name)
{
// disable string callables to avoid calling a function named html
or js,
// or any other upcoming escaping strategy
if (!\is_string($this->defaultStrategy) && false !==
$this->defaultStrategy) {
return \call_user_func($this->defaultStrategy, $name);
}
return $this->defaultStrategy;
}
public function getName()
{
return 'escaper';
}
}
class_alias('Twig\Extension\EscaperExtension',
'Twig_Extension_Escaper');
}
namespace {
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*
* @return string
*/
function twig_raw_filter($string)
{
return $string;
}
}
PK-d�[Ϡ��B
B
5vendor/twig/twig/src/Extension/ExtensionInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
use Twig\Environment;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
/**
* Interface implemented by extension classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ExtensionInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions
for instance.
*
* @deprecated since 1.23 (to be removed in 2.0), implement
\Twig_Extension_InitRuntimeInterface instead
*/
public function initRuntime(Environment $environment);
/**
* Returns the token parser instances to add to the existing list.
*
* @return TokenParserInterface[]
*/
public function getTokenParsers();
/**
* Returns the node visitor instances to add to the existing list.
*
* @return NodeVisitorInterface[]
*/
public function getNodeVisitors();
/**
* Returns a list of filters to add to the existing list.
*
* @return TwigFilter[]
*/
public function getFilters();
/**
* Returns a list of tests to add to the existing list.
*
* @return TwigTest[]
*/
public function getTests();
/**
* Returns a list of functions to add to the existing list.
*
* @return TwigFunction[]
*/
public function getFunctions();
/**
* Returns a list of operators to add to the existing list.
*
* @return array<array> First array of unary operators, second
array of binary operators
*/
public function getOperators();
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*
* @deprecated since 1.23 (to be removed in 2.0), implement
\Twig_Extension_GlobalsInterface instead
*/
public function getGlobals();
/**
* Returns the name of the extension.
*
* @return string The extension name
*
* @deprecated since 1.26 (to be removed in 2.0), not used anymore
internally
*/
public function getName();
}
class_alias('Twig\Extension\ExtensionInterface',
'Twig_ExtensionInterface');
// Ensure that the aliased name is loaded to keep BC for classes
implementing the typehint with the old aliased name.
class_exists('Twig\Environment');
PK-d�[{e�rr3vendor/twig/twig/src/Extension/GlobalsInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
/**
* Enables usage of the deprecated
Twig\Extension\AbstractExtension::getGlobals() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated getGlobals() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface GlobalsInterface
{
}
class_alias('Twig\Extension\GlobalsInterface',
'Twig_Extension_GlobalsInterface');
PK-d�[�Cˀ�7vendor/twig/twig/src/Extension/InitRuntimeInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
/**
* Enables usage of the deprecated
Twig\Extension\AbstractExtension::initRuntime() method.
*
* Explicitly implement this interface if you really need to implement the
* deprecated initRuntime() method in your extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface InitRuntimeInterface
{
}
class_alias('Twig\Extension\InitRuntimeInterface',
'Twig_Extension_InitRuntimeInterface');
PK-d�[yxD��5vendor/twig/twig/src/Extension/OptimizerExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
use Twig\NodeVisitor\OptimizerNodeVisitor;
/**
* @final
*/
class OptimizerExtension extends AbstractExtension
{
protected $optimizers;
public function __construct($optimizers = -1)
{
$this->optimizers = $optimizers;
}
public function getNodeVisitors()
{
return [new OptimizerNodeVisitor($this->optimizers)];
}
public function getName()
{
return 'optimizer';
}
}
class_alias('Twig\Extension\OptimizerExtension',
'Twig_Extension_Optimizer');
PK-d�[Em
�__4vendor/twig/twig/src/Extension/ProfilerExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
use Twig\Profiler\NodeVisitor\ProfilerNodeVisitor;
use Twig\Profiler\Profile;
class ProfilerExtension extends AbstractExtension
{
private $actives = [];
public function __construct(Profile $profile)
{
$this->actives[] = $profile;
}
public function enter(Profile $profile)
{
$this->actives[0]->addProfile($profile);
array_unshift($this->actives, $profile);
}
public function leave(Profile $profile)
{
$profile->leave();
array_shift($this->actives);
if (1 === \count($this->actives)) {
$this->actives[0]->leave();
}
}
public function getNodeVisitors()
{
return [new ProfilerNodeVisitor(\get_class($this))];
}
public function getName()
{
return 'profiler';
}
}
class_alias('Twig\Extension\ProfilerExtension',
'Twig_Extension_Profiler');
PK-d�[��FF<vendor/twig/twig/src/Extension/RuntimeExtensionInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
interface RuntimeExtensionInterface
{
}
PK-d�[c ��T T 3vendor/twig/twig/src/Extension/SandboxExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
use Twig\NodeVisitor\SandboxNodeVisitor;
use Twig\Sandbox\SecurityPolicyInterface;
use Twig\TokenParser\SandboxTokenParser;
/**
* @final
*/
class SandboxExtension extends AbstractExtension
{
protected $sandboxedGlobally;
protected $sandboxed;
protected $policy;
public function __construct(SecurityPolicyInterface $policy, $sandboxed
= false)
{
$this->policy = $policy;
$this->sandboxedGlobally = $sandboxed;
}
public function getTokenParsers()
{
return [new SandboxTokenParser()];
}
public function getNodeVisitors()
{
return [new SandboxNodeVisitor()];
}
public function enableSandbox()
{
$this->sandboxed = true;
}
public function disableSandbox()
{
$this->sandboxed = false;
}
public function isSandboxed()
{
return $this->sandboxedGlobally || $this->sandboxed;
}
public function isSandboxedGlobally()
{
return $this->sandboxedGlobally;
}
public function setSecurityPolicy(SecurityPolicyInterface $policy)
{
$this->policy = $policy;
}
public function getSecurityPolicy()
{
return $this->policy;
}
public function checkSecurity($tags, $filters, $functions)
{
if ($this->isSandboxed()) {
$this->policy->checkSecurity($tags, $filters,
$functions);
}
}
public function checkMethodAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkMethodAllowed($obj, $method);
}
}
public function checkPropertyAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkPropertyAllowed($obj, $method);
}
}
public function ensureToStringAllowed($obj)
{
if ($this->isSandboxed() && \is_object($obj) &&
method_exists($obj, '__toString')) {
$this->policy->checkMethodAllowed($obj,
'__toString');
}
return $obj;
}
public function getName()
{
return 'sandbox';
}
}
class_alias('Twig\Extension\SandboxExtension',
'Twig_Extension_Sandbox');
PK-d�[������3vendor/twig/twig/src/Extension/StagingExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
/**
* Internal class.
*
* This class is used by \Twig\Environment as a staging area and must not
be used directly.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
class StagingExtension extends AbstractExtension
{
protected $functions = [];
protected $filters = [];
protected $visitors = [];
protected $tokenParsers = [];
protected $globals = [];
protected $tests = [];
public function addFunction($name, $function)
{
if (isset($this->functions[$name])) {
@trigger_error(sprintf('Overriding function "%s"
that is already registered is deprecated since version 1.30 and won\'t
be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->functions[$name] = $function;
}
public function getFunctions()
{
return $this->functions;
}
public function addFilter($name, $filter)
{
if (isset($this->filters[$name])) {
@trigger_error(sprintf('Overriding filter "%s"
that is already registered is deprecated since version 1.30 and won\'t
be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->filters[$name] = $filter;
}
public function getFilters()
{
return $this->filters;
}
public function addNodeVisitor(NodeVisitorInterface $visitor)
{
$this->visitors[] = $visitor;
}
public function getNodeVisitors()
{
return $this->visitors;
}
public function addTokenParser(TokenParserInterface $parser)
{
if (isset($this->tokenParsers[$parser->getTag()])) {
@trigger_error(sprintf('Overriding tag "%s" that
is already registered is deprecated since version 1.30 and won\'t be
possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED);
}
$this->tokenParsers[$parser->getTag()] = $parser;
}
public function getTokenParsers()
{
return $this->tokenParsers;
}
public function addGlobal($name, $value)
{
$this->globals[$name] = $value;
}
public function getGlobals()
{
return $this->globals;
}
public function addTest($name, $test)
{
if (isset($this->tests[$name])) {
@trigger_error(sprintf('Overriding test "%s"
that is already registered is deprecated since version 1.30 and won\'t
be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
}
$this->tests[$name] = $test;
}
public function getTests()
{
return $this->tests;
}
public function getName()
{
return 'staging';
}
}
class_alias('Twig\Extension\StagingExtension',
'Twig_Extension_Staging');
PK-d�[�iy��8vendor/twig/twig/src/Extension/StringLoaderExtension.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extension {
use Twig\TwigFunction;
/**
* @final
*/
class StringLoaderExtension extends AbstractExtension
{
public function getFunctions()
{
return [
new TwigFunction('template_from_string',
'twig_template_from_string', ['needs_environment' =>
true]),
];
}
public function getName()
{
return 'string_loader';
}
}
class_alias('Twig\Extension\StringLoaderExtension',
'Twig_Extension_StringLoader');
}
namespace {
use Twig\Environment;
use Twig\TemplateWrapper;
/**
* Loads a template from a string.
*
* {{ include(template_from_string("Hello {{ name }}")) }}
*
* @param string $template A template as a string or object implementing
__toString()
* @param string $name An optional name of the template to be used in
error messages
*
* @return TemplateWrapper
*/
function twig_template_from_string(Environment $env, $template, $name =
null)
{
return $env->createTemplate((string) $template, $name);
}
}
PK-d�[W���6vendor/twig/twig/src/FileExtensionEscapingStrategy.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
/**
* Default autoescaping strategy based on file names.
*
* This strategy sets the HTML as the default autoescaping strategy,
* but changes it based on the template name.
*
* Note that there is no runtime performance impact as the
* default autoescaping strategy is set at compilation time.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileExtensionEscapingStrategy
{
/**
* Guesses the best autoescaping strategy based on the file name.
*
* @param string $name The template name
*
* @return string|false The escaping strategy name to use or false to
disable
*/
public static function guess($name)
{
if (\in_array(substr($name, -1), ['/', '\\']))
{
return 'html'; // return html for directories
}
if ('.twig' === substr($name, -5)) {
$name = substr($name, 0, -5);
}
$extension = pathinfo($name, PATHINFO_EXTENSION);
switch ($extension) {
case 'js':
return 'js';
case 'css':
return 'css';
case 'txt':
return false;
default:
return 'html';
}
}
}
class_alias('Twig\FileExtensionEscapingStrategy',
'Twig_FileExtensionEscapingStrategy');
PK-d�[z���dPdPvendor/twig/twig/src/Lexer.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Error\SyntaxError;
/**
* Lexes a template string.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Lexer implements \Twig_LexerInterface
{
protected $tokens;
protected $code;
protected $cursor;
protected $lineno;
protected $end;
protected $state;
protected $states;
protected $brackets;
protected $env;
// to be renamed to $name in 2.0 (where it is private)
protected $filename;
protected $options;
protected $regexes;
protected $position;
protected $positions;
protected $currentVarBlockLine;
private $source;
const STATE_DATA = 0;
const STATE_BLOCK = 1;
const STATE_VAR = 2;
const STATE_STRING = 3;
const STATE_INTERPOLATION = 4;
const REGEX_NAME =
'/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
const REGEX_NUMBER =
'/[0-9]+(?:\.[0-9]+)?([Ee][\+\-][0-9]+)?/A';
const REGEX_STRING =
'/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const REGEX_DQ_STRING_DELIM = '/"/A';
const REGEX_DQ_STRING_PART =
'/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
const PUNCTUATION = '()[]{}?:.,|';
public function __construct(Environment $env, array $options = [])
{
$this->env = $env;
$this->options = array_merge([
'tag_comment' => ['{#', '#}'],
'tag_block' => ['{%', '%}'],
'tag_variable' => ['{{',
'}}'],
'whitespace_trim' => '-',
'whitespace_line_trim' => '~',
'whitespace_line_chars' => ' \t\0\x0B',
'interpolation' => ['#{',
'}'],
], $options);
// when PHP 7.3 is the min version, we will be able to remove the
'#' part in preg_quote as it's part of the default
$this->regexes = [
// }}
'lex_var' => '{
\s*
(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1],
'#').'\s*'. // -}}\s*
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_variable'][1],
'#').'['.$this->options['whitespace_line_chars'].']*'.
// ~}}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_variable'][1], '#').
// }}
')
}Ax',
// %}
'lex_block' => '{
\s*
(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1],
'#').'\s*\n?'. // -%}\s*\n?
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_block'][1],
'#').'['.$this->options['whitespace_line_chars'].']*'.
// ~%}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_block'][1],
'#').'\n?'. // %}\n?
')
}Ax',
// {% endverbatim %}
'lex_raw_data' => '{'.
preg_quote($this->options['tag_block'][0],
'#'). // {%
'('.
$this->options['whitespace_trim']. // -
'|'.
$this->options['whitespace_line_trim']. //
~
')?\s*'.
'(?:end%s)'. // endraw or endverbatim
'\s*'.
'(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1],
'#').'\s*'. // -%}
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_block'][1],
'#').'['.$this->options['whitespace_line_chars'].']*'.
// ~%}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_block'][1],
'#'). // %}
')
}sx',
'operator' => $this->getOperatorRegex(),
// #}
'lex_comment' => '{
(?:'.
preg_quote($this->options['whitespace_trim']).preg_quote($this->options['tag_comment'][1],
'#').'\s*\n?'. // -#}\s*\n?
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_comment'][1],
'#').'['.$this->options['whitespace_line_chars'].']*'.
// ~#}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_comment'][1],
'#').'\n?'. // #}\n?
')
}sx',
// verbatim %}
'lex_block_raw' => '{
\s*
(raw|verbatim)
\s*
(?:'.
preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1],
'#').'\s*'. // -%}\s*
'|'.
preg_quote($this->options['whitespace_line_trim'].$this->options['tag_block'][1],
'#').'['.$this->options['whitespace_line_chars'].']*'.
// ~%}[ \t\0\x0B]*
'|'.
preg_quote($this->options['tag_block'][1],
'#'). // %}
')
}Asx',
'lex_block_line' =>
'{\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1],
'#').'}As',
// {{ or {% or {#
'lex_tokens_start' => '{
('.
preg_quote($this->options['tag_variable'][0], '#').
// {{
'|'.
preg_quote($this->options['tag_block'][0],
'#'). // {%
'|'.
preg_quote($this->options['tag_comment'][0], '#').
// {#
')('.
preg_quote($this->options['whitespace_trim'], '#').
// -
'|'.
preg_quote($this->options['whitespace_line_trim'],
'#'). // ~
')?
}sx',
'interpolation_start' =>
'{'.preg_quote($this->options['interpolation'][0],
'#').'\s*}A',
'interpolation_end' =>
'{\s*'.preg_quote($this->options['interpolation'][1],
'#').'}A',
];
}
public function tokenize($code, $name = null)
{
if (!$code instanceof Source) {
@trigger_error(sprintf('Passing a string as the $code
argument of %s() is deprecated since version 1.27 and will be removed in
2.0. Pass a \Twig\Source instance instead.', __METHOD__),
E_USER_DEPRECATED);
$this->source = new Source($code, $name);
} else {
$this->source = $code;
}
if (((int) ini_get('mbstring.func_overload')) & 2) {
@trigger_error('Support for having
"mbstring.func_overload" different from 0 is deprecated version
1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
}
if (\function_exists('mb_internal_encoding') &&
((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
} else {
$mbEncoding = null;
}
$this->code = str_replace(["\r\n", "\r"],
"\n", $this->source->getCode());
$this->filename = $this->source->getName();
$this->cursor = 0;
$this->lineno = 1;
$this->end = \strlen($this->code);
$this->tokens = [];
$this->state = self::STATE_DATA;
$this->states = [];
$this->brackets = [];
$this->position = -1;
// find all token starts in one go
preg_match_all($this->regexes['lex_tokens_start'],
$this->code, $matches, PREG_OFFSET_CAPTURE);
$this->positions = $matches;
while ($this->cursor < $this->end) {
// dispatch to the lexing functions depending
// on the current state
switch ($this->state) {
case self::STATE_DATA:
$this->lexData();
break;
case self::STATE_BLOCK:
$this->lexBlock();
break;
case self::STATE_VAR:
$this->lexVar();
break;
case self::STATE_STRING:
$this->lexString();
break;
case self::STATE_INTERPOLATION:
$this->lexInterpolation();
break;
}
}
$this->pushToken(Token::EOF_TYPE);
if (!empty($this->brackets)) {
list($expect, $lineno) = array_pop($this->brackets);
throw new SyntaxError(sprintf('Unclosed
"%s".', $expect), $lineno, $this->source);
}
if ($mbEncoding) {
mb_internal_encoding($mbEncoding);
}
return new TokenStream($this->tokens, $this->source);
}
protected function lexData()
{
// if no matches are left we return the rest of the template as
simple text token
if ($this->position == \count($this->positions[0]) - 1) {
$this->pushToken(Token::TEXT_TYPE, substr($this->code,
$this->cursor));
$this->cursor = $this->end;
return;
}
// Find the first token after the current cursor
$position = $this->positions[0][++$this->position];
while ($position[1] < $this->cursor) {
if ($this->position == \count($this->positions[0]) - 1) {
return;
}
$position = $this->positions[0][++$this->position];
}
// push the template text first
$text = $textContent = substr($this->code, $this->cursor,
$position[1] - $this->cursor);
// trim?
if (isset($this->positions[2][$this->position][0])) {
if ($this->options['whitespace_trim'] ===
$this->positions[2][$this->position][0]) {
// whitespace_trim detected ({%-, {{- or {#-)
$text = rtrim($text);
} elseif ($this->options['whitespace_line_trim']
=== $this->positions[2][$this->position][0]) {
// whitespace_line_trim detected ({%~, {{~ or {#~)
// don't trim \r and \n
$text = rtrim($text, " \t\0\x0B");
}
}
$this->pushToken(Token::TEXT_TYPE, $text);
$this->moveCursor($textContent.$position[0]);
switch ($this->positions[1][$this->position][0]) {
case $this->options['tag_comment'][0]:
$this->lexComment();
break;
case $this->options['tag_block'][0]:
// raw data?
if
(preg_match($this->regexes['lex_block_raw'], $this->code,
$match, 0, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lexRawData($match[1]);
// {% line \d+ %}
} elseif
(preg_match($this->regexes['lex_block_line'], $this->code,
$match, 0, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lineno = (int) $match[1];
} else {
$this->pushToken(Token::BLOCK_START_TYPE);
$this->pushState(self::STATE_BLOCK);
$this->currentVarBlockLine = $this->lineno;
}
break;
case $this->options['tag_variable'][0]:
$this->pushToken(Token::VAR_START_TYPE);
$this->pushState(self::STATE_VAR);
$this->currentVarBlockLine = $this->lineno;
break;
}
}
protected function lexBlock()
{
if (empty($this->brackets) &&
preg_match($this->regexes['lex_block'], $this->code,
$match, 0, $this->cursor)) {
$this->pushToken(Token::BLOCK_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexVar()
{
if (empty($this->brackets) &&
preg_match($this->regexes['lex_var'], $this->code, $match,
0, $this->cursor)) {
$this->pushToken(Token::VAR_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexExpression()
{
// whitespace
if (preg_match('/\s+/A', $this->code, $match, 0,
$this->cursor)) {
$this->moveCursor($match[0]);
if ($this->cursor >= $this->end) {
throw new SyntaxError(sprintf('Unclosed
"%s".', self::STATE_BLOCK === $this->state ?
'block' : 'variable'), $this->currentVarBlockLine,
$this->source);
}
}
// arrow function
if ('=' === $this->code[$this->cursor] &&
'>' === $this->code[$this->cursor + 1]) {
$this->pushToken(Token::ARROW_TYPE, '=>');
$this->moveCursor('=>');
}
// operators
elseif (preg_match($this->regexes['operator'],
$this->code, $match, 0, $this->cursor)) {
$this->pushToken(Token::OPERATOR_TYPE,
preg_replace('/\s+/', ' ', $match[0]));
$this->moveCursor($match[0]);
}
// names
elseif (preg_match(self::REGEX_NAME, $this->code, $match, 0,
$this->cursor)) {
$this->pushToken(Token::NAME_TYPE, $match[0]);
$this->moveCursor($match[0]);
}
// numbers
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, 0,
$this->cursor)) {
$number = (float) $match[0]; // floats
if (ctype_digit($match[0]) && $number <=
PHP_INT_MAX) {
$number = (int) $match[0]; // integers lower than the
maximum
}
$this->pushToken(Token::NUMBER_TYPE, $number);
$this->moveCursor($match[0]);
}
// punctuation
elseif (false !== strpos(self::PUNCTUATION,
$this->code[$this->cursor])) {
// opening bracket
if (false !== strpos('([{',
$this->code[$this->cursor])) {
$this->brackets[] = [$this->code[$this->cursor],
$this->lineno];
}
// closing bracket
elseif (false !== strpos(')]}',
$this->code[$this->cursor])) {
if (empty($this->brackets)) {
throw new SyntaxError(sprintf('Unexpected
"%s".', $this->code[$this->cursor]), $this->lineno,
$this->source);
}
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != strtr($expect,
'([{', ')]}')) {
throw new SyntaxError(sprintf('Unclosed
"%s".', $expect), $lineno, $this->source);
}
}
$this->pushToken(Token::PUNCTUATION_TYPE,
$this->code[$this->cursor]);
++$this->cursor;
}
// strings
elseif (preg_match(self::REGEX_STRING, $this->code, $match, 0,
$this->cursor)) {
$this->pushToken(Token::STRING_TYPE,
stripcslashes(substr($match[0], 1, -1)));
$this->moveCursor($match[0]);
}
// opening double quoted string
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code,
$match, 0, $this->cursor)) {
$this->brackets[] = ['"', $this->lineno];
$this->pushState(self::STATE_STRING);
$this->moveCursor($match[0]);
}
// unlexable
else {
throw new SyntaxError(sprintf('Unexpected character
"%s".', $this->code[$this->cursor]), $this->lineno,
$this->source);
}
}
protected function lexRawData($tag)
{
if ('raw' === $tag) {
@trigger_error(sprintf('Twig Tag "raw" is
deprecated since version 1.21. Use "verbatim" instead in %s at
line %d.', $this->filename, $this->lineno), E_USER_DEPRECATED);
}
if (!preg_match(str_replace('%s', $tag,
$this->regexes['lex_raw_data']), $this->code, $match,
PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new SyntaxError(sprintf('Unexpected end of file:
Unclosed "%s" block.', $tag), $this->lineno,
$this->source);
}
$text = substr($this->code, $this->cursor, $match[0][1] -
$this->cursor);
$this->moveCursor($text.$match[0][0]);
// trim?
if (isset($match[1][0])) {
if ($this->options['whitespace_trim'] ===
$match[1][0]) {
// whitespace_trim detected ({%-, {{- or {#-)
$text = rtrim($text);
} else {
// whitespace_line_trim detected ({%~, {{~ or {#~)
// don't trim \r and \n
$text = rtrim($text, " \t\0\x0B");
}
}
$this->pushToken(Token::TEXT_TYPE, $text);
}
protected function lexComment()
{
if (!preg_match($this->regexes['lex_comment'],
$this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new SyntaxError('Unclosed comment.',
$this->lineno, $this->source);
}
$this->moveCursor(substr($this->code, $this->cursor,
$match[0][1] - $this->cursor).$match[0][0]);
}
protected function lexString()
{
if (preg_match($this->regexes['interpolation_start'],
$this->code, $match, 0, $this->cursor)) {
$this->brackets[] =
[$this->options['interpolation'][0], $this->lineno];
$this->pushToken(Token::INTERPOLATION_START_TYPE);
$this->moveCursor($match[0]);
$this->pushState(self::STATE_INTERPOLATION);
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code,
$match, 0, $this->cursor) && \strlen($match[0]) > 0) {
$this->pushToken(Token::STRING_TYPE,
stripcslashes($match[0]));
$this->moveCursor($match[0]);
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code,
$match, 0, $this->cursor)) {
list($expect, $lineno) = array_pop($this->brackets);
if ('"' != $this->code[$this->cursor]) {
throw new SyntaxError(sprintf('Unclosed
"%s".', $expect), $lineno, $this->source);
}
$this->popState();
++$this->cursor;
} else {
// unlexable
throw new SyntaxError(sprintf('Unexpected character
"%s".', $this->code[$this->cursor]), $this->lineno,
$this->source);
}
}
protected function lexInterpolation()
{
$bracket = end($this->brackets);
if ($this->options['interpolation'][0] === $bracket[0]
&& preg_match($this->regexes['interpolation_end'],
$this->code, $match, 0, $this->cursor)) {
array_pop($this->brackets);
$this->pushToken(Token::INTERPOLATION_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function pushToken($type, $value = '')
{
// do not push empty text tokens
if (Token::TEXT_TYPE === $type && '' === $value)
{
return;
}
$this->tokens[] = new Token($type, $value, $this->lineno);
}
protected function moveCursor($text)
{
$this->cursor += \strlen($text);
$this->lineno += substr_count($text, "\n");
}
protected function getOperatorRegex()
{
$operators = array_merge(
['='],
array_keys($this->env->getUnaryOperators()),
array_keys($this->env->getBinaryOperators())
);
$operators = array_combine($operators,
array_map('strlen', $operators));
arsort($operators);
$regex = [];
foreach ($operators as $operator => $length) {
// an operator that ends with a character must be followed by
// a whitespace or a parenthesis
if (ctype_alpha($operator[$length - 1])) {
$r = preg_quote($operator,
'/').'(?=[\s()])';
} else {
$r = preg_quote($operator, '/');
}
// an operator with a space can be any amount of whitespaces
$r = preg_replace('/\s+/', '\s+', $r);
$regex[] = $r;
}
return '/'.implode('|', $regex).'/A';
}
protected function pushState($state)
{
$this->states[] = $this->state;
$this->state = $state;
}
protected function popState()
{
if (0 === \count($this->states)) {
throw new \LogicException('Cannot pop state without a
previous state.');
}
$this->state = array_pop($this->states);
}
}
class_alias('Twig\Lexer', 'Twig_Lexer');
PK-d�[�i��
�
+vendor/twig/twig/src/Loader/ArrayLoader.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* Loads a template from an array.
*
* When using this loader with a cache mechanism, you should know that a
new cache
* key is generated each time a template content "changes" (the
cache key being the
* source code of the template). If you don't want to see your cache
grows out of
* control, you need to take care of clearing the old cache file by
yourself.
*
* This loader should only be used for unit testing.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ArrayLoader implements LoaderInterface, ExistsLoaderInterface,
SourceContextLoaderInterface
{
protected $templates = [];
/**
* @param array $templates An array of templates (keys are the names,
and values are the source code)
*/
public function __construct(array $templates = [])
{
$this->templates = $templates;
}
/**
* Adds or overrides a template.
*
* @param string $name The template name
* @param string $template The template source
*/
public function setTemplate($name, $template)
{
$this->templates[(string) $name] = $template;
}
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on
"%s" is deprecated since 1.27. Use getSourceContext()
instead.', \get_class($this)), E_USER_DEPRECATED);
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is
not defined.', $name));
}
return $this->templates[$name];
}
public function getSourceContext($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is
not defined.', $name));
}
return new Source($this->templates[$name], $name);
}
public function exists($name)
{
return isset($this->templates[(string) $name]);
}
public function getCacheKey($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is
not defined.', $name));
}
return $name.':'.$this->templates[$name];
}
public function isFresh($name, $time)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is
not defined.', $name));
}
return true;
}
}
class_alias('Twig\Loader\ArrayLoader',
'Twig_Loader_Array');
PK-d�[]�O9))+vendor/twig/twig/src/Loader/ChainLoader.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* Loads templates from other loaders.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ChainLoader implements LoaderInterface, ExistsLoaderInterface,
SourceContextLoaderInterface
{
private $hasSourceCache = [];
protected $loaders = [];
/**
* @param LoaderInterface[] $loaders
*/
public function __construct(array $loaders = [])
{
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
public function addLoader(LoaderInterface $loader)
{
$this->loaders[] = $loader;
$this->hasSourceCache = [];
}
/**
* @return LoaderInterface[]
*/
public function getLoaders()
{
return $this->loaders;
}
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on
"%s" is deprecated since 1.27. Use getSourceContext()
instead.', \get_class($this)), E_USER_DEPRECATED);
$exceptions = [];
foreach ($this->loaders as $loader) {
if ($loader instanceof ExistsLoaderInterface &&
!$loader->exists($name)) {
continue;
}
try {
return $loader->getSource($name);
} catch (LoaderError $e) {
$exceptions[] = $e->getMessage();
}
}
throw new LoaderError(sprintf('Template "%s" is not
defined%s.', $name, $exceptions ? ' ('.implode(',
', $exceptions).')' : ''));
}
public function getSourceContext($name)
{
$exceptions = [];
foreach ($this->loaders as $loader) {
if ($loader instanceof ExistsLoaderInterface &&
!$loader->exists($name)) {
continue;
}
try {
if ($loader instanceof SourceContextLoaderInterface) {
return $loader->getSourceContext($name);
}
return new Source($loader->getSource($name), $name);
} catch (LoaderError $e) {
$exceptions[] = $e->getMessage();
}
}
throw new LoaderError(sprintf('Template "%s" is not
defined%s.', $name, $exceptions ? ' ('.implode(',
', $exceptions).')' : ''));
}
public function exists($name)
{
$name = (string) $name;
if (isset($this->hasSourceCache[$name])) {
return $this->hasSourceCache[$name];
}
foreach ($this->loaders as $loader) {
if ($loader instanceof ExistsLoaderInterface) {
if ($loader->exists($name)) {
return $this->hasSourceCache[$name] = true;
}
continue;
}
try {
if ($loader instanceof SourceContextLoaderInterface) {
$loader->getSourceContext($name);
} else {
$loader->getSource($name);
}
return $this->hasSourceCache[$name] = true;
} catch (LoaderError $e) {
}
}
return $this->hasSourceCache[$name] = false;
}
public function getCacheKey($name)
{
$exceptions = [];
foreach ($this->loaders as $loader) {
if ($loader instanceof ExistsLoaderInterface &&
!$loader->exists($name)) {
continue;
}
try {
return $loader->getCacheKey($name);
} catch (LoaderError $e) {
$exceptions[] = \get_class($loader).':
'.$e->getMessage();
}
}
throw new LoaderError(sprintf('Template "%s" is not
defined%s.', $name, $exceptions ? ' ('.implode(',
', $exceptions).')' : ''));
}
public function isFresh($name, $time)
{
$exceptions = [];
foreach ($this->loaders as $loader) {
if ($loader instanceof ExistsLoaderInterface &&
!$loader->exists($name)) {
continue;
}
try {
return $loader->isFresh($name, $time);
} catch (LoaderError $e) {
$exceptions[] = \get_class($loader).':
'.$e->getMessage();
}
}
throw new LoaderError(sprintf('Template "%s" is not
defined%s.', $name, $exceptions ? ' ('.implode(',
', $exceptions).')' : ''));
}
}
class_alias('Twig\Loader\ChainLoader',
'Twig_Loader_Chain');
PK-d�[vH5vendor/twig/twig/src/Loader/ExistsLoaderInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Loader;
/**
* Adds an exists() method for loaders.
*
* @author Florin Patan <florinpatan@gmail.com>
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface ExistsLoaderInterface
{
/**
* Check if we have the source code of a template, given its name.
*
* @param string $name The name of the template to check if we can load
*
* @return bool If the template source code is handled by this loader
or not
*/
public function exists($name);
}
class_alias('Twig\Loader\ExistsLoaderInterface',
'Twig_ExistsLoaderInterface');
PK-d�[�(��$�$0vendor/twig/twig/src/Loader/FilesystemLoader.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* Loads template from the filesystem.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface,
SourceContextLoaderInterface
{
/** Identifier of the main namespace. */
const MAIN_NAMESPACE = '__main__';
protected $paths = [];
protected $cache = [];
protected $errorCache = [];
private $rootPath;
/**
* @param string|array $paths A path or an array of paths where to
look for templates
* @param string|null $rootPath The root path common to all relative
paths (null for getcwd())
*/
public function __construct($paths = [], $rootPath = null)
{
$this->rootPath = (null === $rootPath ? getcwd() :
$rootPath).\DIRECTORY_SEPARATOR;
if (false !== $realPath = realpath($rootPath)) {
$this->rootPath = $realPath.\DIRECTORY_SEPARATOR;
}
if ($paths) {
$this->setPaths($paths);
}
}
/**
* Returns the paths to the templates.
*
* @param string $namespace A path namespace
*
* @return array The array of paths where to look for templates
*/
public function getPaths($namespace = self::MAIN_NAMESPACE)
{
return isset($this->paths[$namespace]) ?
$this->paths[$namespace] : [];
}
/**
* Returns the path namespaces.
*
* The main namespace is always defined.
*
* @return array The array of defined namespaces
*/
public function getNamespaces()
{
return array_keys($this->paths);
}
/**
* Sets the paths where templates are stored.
*
* @param string|array $paths A path or an array of paths where to
look for templates
* @param string $namespace A path namespace
*/
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
{
if (!\is_array($paths)) {
$paths = [$paths];
}
$this->paths[$namespace] = [];
foreach ($paths as $path) {
$this->addPath($path, $namespace);
}
}
/**
* Adds a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path namespace
*
* @throws LoaderError
*/
public function addPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = $this->errorCache = [];
$checkPath = $this->isAbsolutePath($path) ? $path :
$this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new LoaderError(sprintf('The "%s"
directory does not exist ("%s").', $path, $checkPath));
}
$this->paths[$namespace][] = rtrim($path, '/\\');
}
/**
* Prepends a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path namespace
*
* @throws LoaderError
*/
public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = $this->errorCache = [];
$checkPath = $this->isAbsolutePath($path) ? $path :
$this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new LoaderError(sprintf('The "%s"
directory does not exist ("%s").', $path, $checkPath));
}
$path = rtrim($path, '/\\');
if (!isset($this->paths[$namespace])) {
$this->paths[$namespace][] = $path;
} else {
array_unshift($this->paths[$namespace], $path);
}
}
public function getSource($name)
{
@trigger_error(sprintf('Calling "getSource" on
"%s" is deprecated since 1.27. Use getSourceContext()
instead.', \get_class($this)), E_USER_DEPRECATED);
if (null === ($path = $this->findTemplate($name)) || false ===
$path) {
return '';
}
return file_get_contents($path);
}
public function getSourceContext($name)
{
if (null === ($path = $this->findTemplate($name)) || false ===
$path) {
return new Source('', $name, '');
}
return new Source(file_get_contents($path), $name, $path);
}
public function getCacheKey($name)
{
if (null === ($path = $this->findTemplate($name)) || false ===
$path) {
return '';
}
$len = \strlen($this->rootPath);
if (0 === strncmp($this->rootPath, $path, $len)) {
return substr($path, $len);
}
return $path;
}
public function exists($name)
{
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return true;
}
try {
return null !== ($path = $this->findTemplate($name, false))
&& false !== $path;
} catch (LoaderError $e) {
@trigger_error(sprintf('In %s::findTemplate(), you must
accept a second argument that when set to "false" returns
"false" instead of throwing an exception. Not supporting this
argument is deprecated since version 1.27.', \get_class($this)),
E_USER_DEPRECATED);
return false;
}
}
public function isFresh($name, $time)
{
// false support to be removed in 3.0
if (null === ($path = $this->findTemplate($name)) || false ===
$path) {
return false;
}
return filemtime($path) < $time;
}
/**
* Checks if the template can be found.
*
* @param string $name The template name
*
* @return string|false|null The template name or false/null
*/
protected function findTemplate($name)
{
$throw = \func_num_args() > 1 ? func_get_arg(1) : true;
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return $this->cache[$name];
}
if (isset($this->errorCache[$name])) {
if (!$throw) {
return false;
}
throw new LoaderError($this->errorCache[$name]);
}
try {
$this->validateName($name);
list($namespace, $shortname) = $this->parseName($name);
} catch (LoaderError $e) {
if (!$throw) {
return false;
}
throw $e;
}
if (!isset($this->paths[$namespace])) {
$this->errorCache[$name] = sprintf('There are no
registered paths for namespace "%s".', $namespace);
if (!$throw) {
return false;
}
throw new LoaderError($this->errorCache[$name]);
}
foreach ($this->paths[$namespace] as $path) {
if (!$this->isAbsolutePath($path)) {
$path = $this->rootPath.$path;
}
if (is_file($path.'/'.$shortname)) {
if (false !== $realpath =
realpath($path.'/'.$shortname)) {
return $this->cache[$name] = $realpath;
}
return $this->cache[$name] =
$path.'/'.$shortname;
}
}
$this->errorCache[$name] = sprintf('Unable to find template
"%s" (looked into: %s).', $name, implode(', ',
$this->paths[$namespace]));
if (!$throw) {
return false;
}
throw new LoaderError($this->errorCache[$name]);
}
protected function parseName($name, $default = self::MAIN_NAMESPACE)
{
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new LoaderError(sprintf('Malformed namespaced
template name "%s" (expecting
"@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$shortname = substr($name, $pos + 1);
return [$namespace, $shortname];
}
return [$default, $name];
}
protected function normalizeName($name)
{
return preg_replace('#/{2,}#', '/',
str_replace('\\', '/', (string) $name));
}
protected function validateName($name)
{
if (false !== strpos($name, "\0")) {
throw new LoaderError('A template name cannot contain NUL
bytes.');
}
$name = ltrim($name, '/');
$parts = explode('/', $name);
$level = 0;
foreach ($parts as $part) {
if ('..' === $part) {
--$level;
} elseif ('.' !== $part) {
++$level;
}
if ($level < 0) {
throw new LoaderError(sprintf('Looks like you try to
load a template outside configured directories (%s).', $name));
}
}
}
private function isAbsolutePath($file)
{
return strspn($file, '/\\', 0, 1)
|| (\strlen($file) > 3 && ctype_alpha($file[0])
&& ':' === substr($file, 1, 1)
&& strspn($file, '/\\', 2, 1)
)
|| null !== parse_url($file, PHP_URL_SCHEME)
;
}
}
class_alias('Twig\Loader\FilesystemLoader',
'Twig_Loader_Filesystem');
PK-d�[O(�##/vendor/twig/twig/src/Loader/LoaderInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
/**
* Interface all loaders must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface LoaderInterface
{
/**
* Gets the source code of a template, given its name.
*
* @param string $name The name of the template to load
*
* @return string The template source code
*
* @throws LoaderError When $name is not found
*
* @deprecated since 1.27 (to be removed in 2.0), implement
Twig\Loader\SourceContextLoaderInterface
*/
public function getSource($name);
/**
* Gets the cache key to use for the cache for a given template name.
*
* @param string $name The name of the template to load
*
* @return string The cache key
*
* @throws LoaderError When $name is not found
*/
public function getCacheKey($name);
/**
* Returns true if the template is still fresh.
*
* @param string $name The template name
* @param int $time Timestamp of the last modification time of the
* cached template
*
* @return bool true if the template is fresh, false otherwise
*
* @throws LoaderError When $name is not found
*/
public function isFresh($name, $time);
}
class_alias('Twig\Loader\LoaderInterface',
'Twig_LoaderInterface');
PK-d�[0ӗPP<vendor/twig/twig/src/Loader/SourceContextLoaderInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Loader;
use Twig\Error\LoaderError;
use Twig\Source;
/**
* Adds a getSourceContext() method for loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since 1.27 (to be removed in 3.0)
*/
interface SourceContextLoaderInterface
{
/**
* Returns the source context for a given template logical name.
*
* @param string $name The template logical name
*
* @return Source
*
* @throws LoaderError When $name is not found
*/
public function getSourceContext($name);
}
class_alias('Twig\Loader\SourceContextLoaderInterface',
'Twig_SourceContextLoaderInterface');
PK-d�[��Rh22vendor/twig/twig/src/Markup.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
/**
* Marks a content as safe.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Markup implements \Countable
{
protected $content;
protected $charset;
public function __construct($content, $charset)
{
$this->content = (string) $content;
$this->charset = $charset;
}
public function __toString()
{
return $this->content;
}
public function count()
{
return \function_exists('mb_get_info') ?
mb_strlen($this->content, $this->charset) :
\strlen($this->content);
}
}
class_alias('Twig\Markup', 'Twig_Markup');
PK-d�[鉅���,vendor/twig/twig/src/Node/AutoEscapeNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents an autoescape node.
*
* The value is the escaping strategy (can be html, js, ...)
*
* The true value is equivalent to html.
*
* If autoescaping is disabled, then the value is false.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AutoEscapeNode extends Node
{
public function __construct($value, \Twig_NodeInterface $body, $lineno,
$tag = 'autoescape')
{
parent::__construct(['body' => $body],
['value' => $value], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler->subcompile($this->getNode('body'));
}
}
class_alias('Twig\Node\AutoEscapeNode',
'Twig_Node_AutoEscape');
PK-d�[���'vendor/twig/twig/src/Node/BlockNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a block node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class BlockNode extends Node
{
public function __construct($name, \Twig_NodeInterface $body, $lineno,
$tag = null)
{
parent::__construct(['body' => $body],
['name' => $name], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write(sprintf("public function block_%s(\$context,
array \$blocks = [])\n", $this->getAttribute('name')),
"{\n")
->indent()
;
$compiler
->subcompile($this->getNode('body'))
->outdent()
->write("}\n\n")
;
}
}
class_alias('Twig\Node\BlockNode', 'Twig_Node_Block');
PK-d�[���qq0vendor/twig/twig/src/Node/BlockReferenceNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a block call node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class BlockReferenceNode extends Node implements NodeOutputInterface
{
public function __construct($name, $lineno, $tag = null)
{
parent::__construct([], ['name' => $name], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write(sprintf("\$this->displayBlock('%s', \$context,
\$blocks);\n", $this->getAttribute('name')))
;
}
}
class_alias('Twig\Node\BlockReferenceNode',
'Twig_Node_BlockReference');
PK-d�[_c����&vendor/twig/twig/src/Node/BodyNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
/**
* Represents a body node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class BodyNode extends Node
{
}
class_alias('Twig\Node\BodyNode', 'Twig_Node_Body');
PK-d�[���/vendor/twig/twig/src/Node/CheckSecurityNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class CheckSecurityNode extends Node
{
protected $usedFilters;
protected $usedTags;
protected $usedFunctions;
public function __construct(array $usedFilters, array $usedTags, array
$usedFunctions)
{
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
$this->usedFunctions = $usedFunctions;
parent::__construct();
}
public function compile(Compiler $compiler)
{
$tags = $filters = $functions = [];
foreach (['tags', 'filters',
'functions'] as $type) {
foreach ($this->{'used'.ucfirst($type)} as $name
=> $node) {
if ($node instanceof Node) {
${$type}[$name] = $node->getTemplateLine();
} else {
${$type}[$node] = null;
}
}
}
$compiler
->write("\$this->sandbox =
\$this->env->getExtension('\Twig\Extension\SandboxExtension');\n")
->write('$tags =
')->repr(array_filter($tags))->raw(";\n")
->write('$filters =
')->repr(array_filter($filters))->raw(";\n")
->write('$functions =
')->repr(array_filter($functions))->raw(";\n\n")
->write("try {\n")
->indent()
->write("\$this->sandbox->checkSecurity(\n")
->indent()
->write(!$tags ? "[],\n" :
"['".implode("', '",
array_keys($tags))."'],\n")
->write(!$filters ? "[],\n" :
"['".implode("', '",
array_keys($filters))."'],\n")
->write(!$functions ? "[]\n" :
"['".implode("', '",
array_keys($functions))."']\n")
->outdent()
->write(");\n")
->outdent()
->write("} catch (SecurityError \$e) {\n")
->indent()
->write("\$e->setSourceContext(\$this->getSourceContext());\n\n")
->write("if (\$e instanceof SecurityNotAllowedTagError
&& isset(\$tags[\$e->getTagName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
->outdent()
->write("} elseif (\$e instanceof
SecurityNotAllowedFilterError &&
isset(\$filters[\$e->getFilterName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n")
->outdent()
->write("} elseif (\$e instanceof
SecurityNotAllowedFunctionError &&
isset(\$functions[\$e->getFunctionName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$functions[\$e->getFunctionName()]);\n")
->outdent()
->write("}\n\n")
->write("throw \$e;\n")
->outdent()
->write("}\n\n")
;
}
}
class_alias('Twig\Node\CheckSecurityNode',
'Twig_Node_CheckSecurity');
PK-d�[� N�ss/vendor/twig/twig/src/Node/CheckToStringNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
/**
* Checks if casting an expression to __toString() is allowed by the
sandbox.
*
* For instance, when there is a simple Print statement, like {{ article
}},
* and if the sandbox is enabled, we need to check that the __toString()
* method is allowed if 'article' is an object. The same goes for
{{ article|upper }}
* or {{ random(article) }}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class CheckToStringNode extends AbstractExpression
{
public function __construct(AbstractExpression $expr)
{
parent::__construct(['expr' => $expr], [],
$expr->getTemplateLine(), $expr->getNodeTag());
}
public function compile(Compiler $compiler)
{
$compiler
->raw('$this->sandbox->ensureToStringAllowed(')
->subcompile($this->getNode('expr'))
->raw(')')
;
}
}
PK-d�[qS��,vendor/twig/twig/src/Node/DeprecatedNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ConstantExpression;
/**
* Represents a deprecated node.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class DeprecatedNode extends Node
{
public function __construct(AbstractExpression $expr, $lineno, $tag =
null)
{
parent::__construct(['expr' => $expr], [], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
$compiler->addDebugInfo($this);
$expr = $this->getNode('expr');
if ($expr instanceof ConstantExpression) {
$compiler->write('@trigger_error(')
->subcompile($expr);
} else {
$varName = $compiler->getVarName();
$compiler->write(sprintf('$%s = ', $varName))
->subcompile($expr)
->raw(";\n")
->write(sprintf('@trigger_error($%s',
$varName));
}
$compiler
->raw('.')
->string(sprintf(' ("%s" at line %d).',
$this->getTemplateName(), $this->getTemplateLine()))
->raw(", E_USER_DEPRECATED);\n")
;
}
}
class_alias('Twig\Node\DeprecatedNode',
'Twig_Node_Deprecated');
PK-d�[���BB$vendor/twig/twig/src/Node/DoNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
/**
* Represents a do node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DoNode extends Node
{
public function __construct(AbstractExpression $expr, $lineno, $tag =
null)
{
parent::__construct(['expr' => $expr], [], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('')
->subcompile($this->getNode('expr'))
->raw(";\n")
;
}
}
class_alias('Twig\Node\DoNode', 'Twig_Node_Do');
PK-d�[;�h!
'vendor/twig/twig/src/Node/EmbedNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ConstantExpression;
/**
* Represents an embed node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class EmbedNode extends IncludeNode
{
// we don't inject the module to avoid node visitors to traverse
it twice (as it will be already visited in the main module)
public function __construct($name, $index, AbstractExpression
$variables = null, $only = false, $ignoreMissing = false, $lineno, $tag =
null)
{
parent::__construct(new ConstantExpression('not_used',
$lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
$this->setAttribute('name', $name);
// to be removed in 2.0, used name instead
$this->setAttribute('filename', $name);
$this->setAttribute('index', $index);
}
protected function addGetTemplate(Compiler $compiler)
{
$compiler
->write('$this->loadTemplate(')
->string($this->getAttribute('name'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(', ')
->string($this->getAttribute('index'))
->raw(')')
;
}
}
class_alias('Twig\Node\EmbedNode', 'Twig_Node_Embed');
PK-d�[��;vendor/twig/twig/src/Node/Expression/AbstractExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Node\Node;
/**
* Abstract class for all nodes that represents an expression.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class AbstractExpression extends Node
{
}
class_alias('Twig\Node\Expression\AbstractExpression',
'Twig_Node_Expression');
PK-d�[�:
8vendor/twig/twig/src/Node/Expression/ArrayExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
class ArrayExpression extends AbstractExpression
{
protected $index;
public function __construct(array $elements, $lineno)
{
parent::__construct($elements, [], $lineno);
$this->index = -1;
foreach ($this->getKeyValuePairs() as $pair) {
if ($pair['key'] instanceof ConstantExpression
&& ctype_digit((string)
$pair['key']->getAttribute('value')) &&
$pair['key']->getAttribute('value') >
$this->index) {
$this->index =
$pair['key']->getAttribute('value');
}
}
}
public function getKeyValuePairs()
{
$pairs = [];
foreach (array_chunk($this->nodes, 2) as $pair) {
$pairs[] = [
'key' => $pair[0],
'value' => $pair[1],
];
}
return $pairs;
}
public function hasElement(AbstractExpression $key)
{
foreach ($this->getKeyValuePairs() as $pair) {
// we compare the string representation of the keys
// to avoid comparing the line numbers which are not relevant
here.
if ((string) $key === (string) $pair['key']) {
return true;
}
}
return false;
}
public function addElement(AbstractExpression $value,
AbstractExpression $key = null)
{
if (null === $key) {
$key = new ConstantExpression(++$this->index,
$value->getTemplateLine());
}
array_push($this->nodes, $key, $value);
}
public function compile(Compiler $compiler)
{
$compiler->raw('[');
$first = true;
foreach ($this->getKeyValuePairs() as $pair) {
if (!$first) {
$compiler->raw(', ');
}
$first = false;
$compiler
->subcompile($pair['key'])
->raw(' => ')
->subcompile($pair['value'])
;
}
$compiler->raw(']');
}
}
class_alias('Twig\Node\Expression\ArrayExpression',
'Twig_Node_Expression_Array');
PK-d�[���(@vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\Node\Node;
/**
* Represents an arrow function.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ArrowFunctionExpression extends AbstractExpression
{
public function __construct(AbstractExpression $expr, Node $names,
$lineno, $tag = null)
{
parent::__construct(['expr' => $expr,
'names' => $names], [], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->raw('function (')
;
foreach ($this->getNode('names') as $i => $name) {
if ($i) {
$compiler->raw(', ');
}
$compiler
->raw('$__')
->raw($name->getAttribute('name'))
->raw('__')
;
}
$compiler
->raw(') use ($context) { ')
;
foreach ($this->getNode('names') as $name) {
$compiler
->raw('$context["')
->raw($name->getAttribute('name'))
->raw('"] = $__')
->raw($name->getAttribute('name'))
->raw('__; ')
;
}
$compiler
->raw('return ')
->subcompile($this->getNode('expr'))
->raw('; }')
;
}
}
PK-d�[�07Hii=vendor/twig/twig/src/Node/Expression/AssignNameExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
class AssignNameExpression extends NameExpression
{
public function compile(Compiler $compiler)
{
$compiler
->raw('$context[')
->string($this->getAttribute('name'))
->raw(']')
;
}
}
class_alias('Twig\Node\Expression\AssignNameExpression',
'Twig_Node_Expression_AssignName');
PK-d�[rXe11>vendor/twig/twig/src/Node/Expression/Binary/AbstractBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
abstract class AbstractBinary extends AbstractExpression
{
public function __construct(\Twig_NodeInterface $left,
\Twig_NodeInterface $right, $lineno)
{
parent::__construct(['left' => $left,
'right' => $right], [], $lineno);
}
public function compile(Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('left'))
->raw(' ')
;
$this->operator($compiler);
$compiler
->raw(' ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
abstract public function operator(Compiler $compiler);
}
class_alias('Twig\Node\Expression\Binary\AbstractBinary',
'Twig_Node_Expression_Binary');
PK-d�[vr9vendor/twig/twig/src/Node/Expression/Binary/AddBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class AddBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('+');
}
}
class_alias('Twig\Node\Expression\Binary\AddBinary',
'Twig_Node_Expression_Binary_Add');
PK-d�[�r}�9vendor/twig/twig/src/Node/Expression/Binary/AndBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class AndBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('&&');
}
}
class_alias('Twig\Node\Expression\Binary\AndBinary',
'Twig_Node_Expression_Binary_And');
PK-d�[n(�@vendor/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class BitwiseAndBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('&');
}
}
class_alias('Twig\Node\Expression\Binary\BitwiseAndBinary',
'Twig_Node_Expression_Binary_BitwiseAnd');
PK-d�[��?vendor/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class BitwiseOrBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('|');
}
}
class_alias('Twig\Node\Expression\Binary\BitwiseOrBinary',
'Twig_Node_Expression_Binary_BitwiseOr');
PK-d�[�Y�W@vendor/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class BitwiseXorBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('^');
}
}
class_alias('Twig\Node\Expression\Binary\BitwiseXorBinary',
'Twig_Node_Expression_Binary_BitwiseXor');
PK-d�[���<vendor/twig/twig/src/Node/Expression/Binary/ConcatBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class ConcatBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('.');
}
}
class_alias('Twig\Node\Expression\Binary\ConcatBinary',
'Twig_Node_Expression_Binary_Concat');
PK-d�[4ֽD9vendor/twig/twig/src/Node/Expression/Binary/DivBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class DivBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('/');
}
}
class_alias('Twig\Node\Expression\Binary\DivBinary',
'Twig_Node_Expression_Binary_Div');
PK-d�[�����>vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class EndsWithBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(sprintf(') && is_string($%s = ',
$right))
->subcompile($this->getNode('right'))
->raw(sprintf(') && (\'\' === $%2$s
|| $%2$s === substr($%1$s, -strlen($%2$s))))', $left, $right))
;
}
public function operator(Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig\Node\Expression\Binary\EndsWithBinary',
'Twig_Node_Expression_Binary_EndsWith');
PK-d�[oI����;vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class EqualBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('==');
}
}
class_alias('Twig\Node\Expression\Binary\EqualBinary',
'Twig_Node_Expression_Binary_Equal');
PK-d�[�'�)��>vendor/twig/twig/src/Node/Expression/Binary/FloorDivBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class FloorDivBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
$compiler->raw('(int) floor(');
parent::compile($compiler);
$compiler->raw(')');
}
public function operator(Compiler $compiler)
{
return $compiler->raw('/');
}
}
class_alias('Twig\Node\Expression\Binary\FloorDivBinary',
'Twig_Node_Expression_Binary_FloorDiv');
PK-d�[���=vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class GreaterBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('>');
}
}
class_alias('Twig\Node\Expression\Binary\GreaterBinary',
'Twig_Node_Expression_Binary_Greater');
PK-d�[Lt1tBvendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class GreaterEqualBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('>=');
}
}
class_alias('Twig\Node\Expression\Binary\GreaterEqualBinary',
'Twig_Node_Expression_Binary_GreaterEqual');
PK-d�[���'��8vendor/twig/twig/src/Node/Expression/Binary/InBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class InBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
$compiler
->raw('twig_in_filter(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Compiler $compiler)
{
return $compiler->raw('in');
}
}
class_alias('Twig\Node\Expression\Binary\InBinary',
'Twig_Node_Expression_Binary_In');
PK-d�[�o#��:vendor/twig/twig/src/Node/Expression/Binary/LessBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class LessBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('<');
}
}
class_alias('Twig\Node\Expression\Binary\LessBinary',
'Twig_Node_Expression_Binary_Less');
PK-d�[םz��?vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class LessEqualBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('<=');
}
}
class_alias('Twig\Node\Expression\Binary\LessEqualBinary',
'Twig_Node_Expression_Binary_LessEqual');
PK-d�[L[��=vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class MatchesBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
$compiler
->raw('preg_match(')
->subcompile($this->getNode('right'))
->raw(', ')
->subcompile($this->getNode('left'))
->raw(')')
;
}
public function operator(Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig\Node\Expression\Binary\MatchesBinary',
'Twig_Node_Expression_Binary_Matches');
PK-d�[�>Ӗ9vendor/twig/twig/src/Node/Expression/Binary/ModBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class ModBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('%');
}
}
class_alias('Twig\Node\Expression\Binary\ModBinary',
'Twig_Node_Expression_Binary_Mod');
PK-d�[51�9vendor/twig/twig/src/Node/Expression/Binary/MulBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class MulBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('*');
}
}
class_alias('Twig\Node\Expression\Binary\MulBinary',
'Twig_Node_Expression_Binary_Mul');
PK-d�[��H���>vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class NotEqualBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('!=');
}
}
class_alias('Twig\Node\Expression\Binary\NotEqualBinary',
'Twig_Node_Expression_Binary_NotEqual');
PK-d�[>�K;vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class NotInBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
$compiler
->raw('!twig_in_filter(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Compiler $compiler)
{
return $compiler->raw('not in');
}
}
class_alias('Twig\Node\Expression\Binary\NotInBinary',
'Twig_Node_Expression_Binary_NotIn');
PK-d�[�ך8vendor/twig/twig/src/Node/Expression/Binary/OrBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class OrBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('||');
}
}
class_alias('Twig\Node\Expression\Binary\OrBinary',
'Twig_Node_Expression_Binary_Or');
PK-d�[6�TZZ;vendor/twig/twig/src/Node/Expression/Binary/PowerBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class PowerBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
if (\PHP_VERSION_ID >= 50600) {
return parent::compile($compiler);
}
$compiler
->raw('pow(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Compiler $compiler)
{
return $compiler->raw('**');
}
}
class_alias('Twig\Node\Expression\Binary\PowerBinary',
'Twig_Node_Expression_Binary_Power');
PK-d�[��j���;vendor/twig/twig/src/Node/Expression/Binary/RangeBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class RangeBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
$compiler
->raw('range(')
->subcompile($this->getNode('left'))
->raw(', ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
public function operator(Compiler $compiler)
{
return $compiler->raw('..');
}
}
class_alias('Twig\Node\Expression\Binary\RangeBinary',
'Twig_Node_Expression_Binary_Range');
PK-d�[f����@vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class StartsWithBinary extends AbstractBinary
{
public function compile(Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(sprintf(') && is_string($%s = ',
$right))
->subcompile($this->getNode('right'))
->raw(sprintf(') && (\'\' === $%2$s
|| 0 === strpos($%1$s, $%2$s)))', $left, $right))
;
}
public function operator(Compiler $compiler)
{
return $compiler->raw('');
}
}
class_alias('Twig\Node\Expression\Binary\StartsWithBinary',
'Twig_Node_Expression_Binary_StartsWith');
PK-d�[�4�9vendor/twig/twig/src/Node/Expression/Binary/SubBinary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Binary;
use Twig\Compiler;
class SubBinary extends AbstractBinary
{
public function operator(Compiler $compiler)
{
return $compiler->raw('-');
}
}
class_alias('Twig\Node\Expression\Binary\SubBinary',
'Twig_Node_Expression_Binary_Sub');
PK-d�[�H�
�
Avendor/twig/twig/src/Node/Expression/BlockReferenceExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\Node\Node;
/**
* Represents a block call node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class BlockReferenceExpression extends AbstractExpression
{
/**
* @param Node|null $template
*/
public function __construct(\Twig_NodeInterface $name, $template =
null, $lineno, $tag = null)
{
if (\is_bool($template)) {
@trigger_error(sprintf('The %s method
"$asString" argument is deprecated since version 1.28 and will be
removed in 2.0.', __METHOD__), E_USER_DEPRECATED);
$template = null;
}
$nodes = ['name' => $name];
if (null !== $template) {
$nodes['template'] = $template;
}
parent::__construct($nodes, ['is_defined_test' =>
false, 'output' => false], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
if ($this->getAttribute('is_defined_test')) {
$this->compileTemplateCall($compiler, 'hasBlock');
} else {
if ($this->getAttribute('output')) {
$compiler->addDebugInfo($this);
$this
->compileTemplateCall($compiler,
'displayBlock')
->raw(";\n");
} else {
$this->compileTemplateCall($compiler,
'renderBlock');
}
}
}
private function compileTemplateCall(Compiler $compiler, $method)
{
if (!$this->hasNode('template')) {
$compiler->write('$this');
} else {
$compiler
->write('$this->loadTemplate(')
->subcompile($this->getNode('template'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(')')
;
}
$compiler->raw(sprintf('->%s', $method));
$this->compileBlockArguments($compiler);
return $compiler;
}
private function compileBlockArguments(Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('name'))
->raw(', $context');
if (!$this->hasNode('template')) {
$compiler->raw(', $blocks');
}
return $compiler->raw(')');
}
}
class_alias('Twig\Node\Expression\BlockReferenceExpression',
'Twig_Node_Expression_BlockReference');
PK-d�[�sa��-�-7vendor/twig/twig/src/Node/Expression/CallExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\Error\SyntaxError;
use Twig\Extension\ExtensionInterface;
use Twig\Node\Node;
abstract class CallExpression extends AbstractExpression
{
private $reflector;
protected function compileCallable(Compiler $compiler)
{
$closingParenthesis = false;
$isArray = false;
if ($this->hasAttribute('callable') &&
$callable = $this->getAttribute('callable')) {
if (\is_string($callable) && false ===
strpos($callable, '::')) {
$compiler->raw($callable);
} else {
list($r, $callable) = $this->reflectCallable($callable);
if ($r instanceof \ReflectionMethod &&
\is_string($callable[0])) {
if ($r->isStatic()) {
$compiler->raw(sprintf('%s::%s',
$callable[0], $callable[1]));
} else {
$compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s',
$callable[0], $callable[1]));
}
} elseif ($r instanceof \ReflectionMethod &&
$callable[0] instanceof ExtensionInterface) {
$compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s',
\get_class($callable[0]), $callable[1]));
} else {
$type =
ucfirst($this->getAttribute('type'));
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(),
', $type, $this->getAttribute('name')));
$closingParenthesis = true;
$isArray = true;
}
}
} else {
$compiler->raw($this->getAttribute('thing')->compile());
}
$this->compileArguments($compiler, $isArray);
if ($closingParenthesis) {
$compiler->raw(')');
}
}
protected function compileArguments(Compiler $compiler, $isArray =
false)
{
$compiler->raw($isArray ? '[' : '(');
$first = true;
if ($this->hasAttribute('needs_environment')
&& $this->getAttribute('needs_environment')) {
$compiler->raw('$this->env');
$first = false;
}
if ($this->hasAttribute('needs_context') &&
$this->getAttribute('needs_context')) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->raw('$context');
$first = false;
}
if ($this->hasAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as
$argument) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->string($argument);
$first = false;
}
}
if ($this->hasNode('node')) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->subcompile($this->getNode('node'));
$first = false;
}
if ($this->hasNode('arguments')) {
$callable = $this->hasAttribute('callable') ?
$this->getAttribute('callable') : null;
$arguments = $this->getArguments($callable,
$this->getNode('arguments'));
foreach ($arguments as $node) {
if (!$first) {
$compiler->raw(', ');
}
$compiler->subcompile($node);
$first = false;
}
}
$compiler->raw($isArray ? ']' : ')');
}
protected function getArguments($callable, $arguments)
{
$callType = $this->getAttribute('type');
$callName = $this->getAttribute('name');
$parameters = [];
$named = false;
foreach ($arguments as $name => $node) {
if (!\is_int($name)) {
$named = true;
$name = $this->normalizeName($name);
} elseif ($named) {
throw new SyntaxError(sprintf('Positional arguments
cannot be used after named arguments for %s "%s".',
$callType, $callName), $this->getTemplateLine(),
$this->getSourceContext());
}
$parameters[$name] = $node;
}
$isVariadic = $this->hasAttribute('is_variadic')
&& $this->getAttribute('is_variadic');
if (!$named && !$isVariadic) {
return $parameters;
}
if (!$callable) {
if ($named) {
$message = sprintf('Named arguments are not supported
for %s "%s".', $callType, $callName);
} else {
$message = sprintf('Arbitrary positional arguments are
not supported for %s "%s".', $callType, $callName);
}
throw new \LogicException($message);
}
$callableParameters = $this->getCallableParameters($callable,
$isVariadic);
$arguments = [];
$names = [];
$missingArguments = [];
$optionalArguments = [];
$pos = 0;
foreach ($callableParameters as $callableParameter) {
$names[] = $name =
$this->normalizeName($callableParameter->name);
if (\array_key_exists($name, $parameters)) {
if (\array_key_exists($pos, $parameters)) {
throw new SyntaxError(sprintf('Argument
"%s" is defined twice for %s "%s".', $name,
$callType, $callName), $this->getTemplateLine(),
$this->getSourceContext());
}
if (\count($missingArguments)) {
throw new SyntaxError(sprintf(
'Argument "%s" could not be assigned
for %s "%s(%s)" because it is mapped to an internal PHP function
which cannot determine default value for optional argument%s
"%s".',
$name, $callType, $callName, implode(',
', $names), \count($missingArguments) > 1 ? 's' :
'', implode('", "', $missingArguments)
), $this->getTemplateLine(),
$this->getSourceContext());
}
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$name];
unset($parameters[$name]);
$optionalArguments = [];
} elseif (\array_key_exists($pos, $parameters)) {
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $parameters[$pos];
unset($parameters[$pos]);
$optionalArguments = [];
++$pos;
} elseif ($callableParameter->isDefaultValueAvailable()) {
$optionalArguments[] = new
ConstantExpression($callableParameter->getDefaultValue(), -1);
} elseif ($callableParameter->isOptional()) {
if (empty($parameters)) {
break;
} else {
$missingArguments[] = $name;
}
} else {
throw new SyntaxError(sprintf('Value for argument
"%s" is required for %s "%s".', $name, $callType,
$callName), $this->getTemplateLine(), $this->getSourceContext());
}
}
if ($isVariadic) {
$arbitraryArguments = new ArrayExpression([], -1);
foreach ($parameters as $key => $value) {
if (\is_int($key)) {
$arbitraryArguments->addElement($value);
} else {
$arbitraryArguments->addElement($value, new
ConstantExpression($key, -1));
}
unset($parameters[$key]);
}
if ($arbitraryArguments->count()) {
$arguments = array_merge($arguments, $optionalArguments);
$arguments[] = $arbitraryArguments;
}
}
if (!empty($parameters)) {
$unknownParameter = null;
foreach ($parameters as $parameter) {
if ($parameter instanceof Node) {
$unknownParameter = $parameter;
break;
}
}
throw new SyntaxError(
sprintf(
'Unknown argument%s "%s" for %s
"%s(%s)".',
\count($parameters) > 1 ? 's' :
'', implode('", "', array_keys($parameters)),
$callType, $callName, implode(', ', $names)
),
$unknownParameter ? $unknownParameter->getTemplateLine()
: $this->getTemplateLine(),
$unknownParameter ?
$unknownParameter->getSourceContext() : $this->getSourceContext()
);
}
return $arguments;
}
protected function normalizeName($name)
{
return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/',
'/([a-z\d])([A-Z])/'], ['\\1_\\2',
'\\1_\\2'], $name));
}
private function getCallableParameters($callable, $isVariadic)
{
list($r) = $this->reflectCallable($callable);
if (null === $r) {
return [];
}
$parameters = $r->getParameters();
if ($this->hasNode('node')) {
array_shift($parameters);
}
if ($this->hasAttribute('needs_environment')
&& $this->getAttribute('needs_environment')) {
array_shift($parameters);
}
if ($this->hasAttribute('needs_context') &&
$this->getAttribute('needs_context')) {
array_shift($parameters);
}
if ($this->hasAttribute('arguments') && null
!== $this->getAttribute('arguments')) {
foreach ($this->getAttribute('arguments') as
$argument) {
array_shift($parameters);
}
}
if ($isVariadic) {
$argument = end($parameters);
if ($argument && $argument->isArray() &&
$argument->isDefaultValueAvailable() && [] ===
$argument->getDefaultValue()) {
array_pop($parameters);
} else {
$callableName = $r->name;
if ($r instanceof \ReflectionMethod) {
$callableName =
$r->getDeclaringClass()->name.'::'.$callableName;
}
throw new \LogicException(sprintf('The last parameter
of "%s" for %s "%s" must be an array with default
value, eg. "array $arg = []".', $callableName,
$this->getAttribute('type'),
$this->getAttribute('name')));
}
}
return $parameters;
}
private function reflectCallable($callable)
{
if (null !== $this->reflector) {
return $this->reflector;
}
if (\is_array($callable)) {
if (!method_exists($callable[0], $callable[1])) {
// __call()
return [null, []];
}
$r = new \ReflectionMethod($callable[0], $callable[1]);
} elseif (\is_object($callable) && !$callable instanceof
\Closure) {
$r = new \ReflectionObject($callable);
$r = $r->getMethod('__invoke');
$callable = [$callable, '__invoke'];
} elseif (\is_string($callable) && false !== $pos =
strpos($callable, '::')) {
$class = substr($callable, 0, $pos);
$method = substr($callable, $pos + 2);
if (!method_exists($class, $method)) {
// __staticCall()
return [null, []];
}
$r = new \ReflectionMethod($callable);
$callable = [$class, $method];
} else {
$r = new \ReflectionFunction($callable);
}
return $this->reflector = [$r, $callable];
}
}
class_alias('Twig\Node\Expression\CallExpression',
'Twig_Node_Expression_Call');
PK-d�[Yz^���>vendor/twig/twig/src/Node/Expression/ConditionalExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
class ConditionalExpression extends AbstractExpression
{
public function __construct(AbstractExpression $expr1,
AbstractExpression $expr2, AbstractExpression $expr3, $lineno)
{
parent::__construct(['expr1' => $expr1,
'expr2' => $expr2, 'expr3' => $expr3], [],
$lineno);
}
public function compile(Compiler $compiler)
{
$compiler
->raw('((')
->subcompile($this->getNode('expr1'))
->raw(') ? (')
->subcompile($this->getNode('expr2'))
->raw(') : (')
->subcompile($this->getNode('expr3'))
->raw('))')
;
}
}
class_alias('Twig\Node\Expression\ConditionalExpression',
'Twig_Node_Expression_Conditional');
PK-d�[�7�˗�;vendor/twig/twig/src/Node/Expression/ConstantExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
class ConstantExpression extends AbstractExpression
{
public function __construct($value, $lineno)
{
parent::__construct([], ['value' => $value], $lineno);
}
public function compile(Compiler $compiler)
{
$compiler->repr($this->getAttribute('value'));
}
}
class_alias('Twig\Node\Expression\ConstantExpression',
'Twig_Node_Expression_Constant');
PK-d�[��nn=vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Filter;
use Twig\Compiler;
use Twig\Node\Expression\ConditionalExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\Test\DefinedTest;
use Twig\Node\Node;
/**
* Returns the value or the default value when it is undefined or empty.
*
* {{ var.foo|default('foo item on var is not defined') }}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DefaultFilter extends FilterExpression
{
public function __construct(\Twig_NodeInterface $node,
ConstantExpression $filterName, \Twig_NodeInterface $arguments, $lineno,
$tag = null)
{
$default = new FilterExpression($node, new
ConstantExpression('default', $node->getTemplateLine()),
$arguments, $node->getTemplateLine());
if ('default' ===
$filterName->getAttribute('value') && ($node
instanceof NameExpression || $node instanceof GetAttrExpression)) {
$test = new DefinedTest(clone $node, 'defined', new
Node(), $node->getTemplateLine());
$false = \count($arguments) ? $arguments->getNode(0) : new
ConstantExpression('', $node->getTemplateLine());
$node = new ConditionalExpression($test, $default, $false,
$node->getTemplateLine());
} else {
$node = $default;
}
parent::__construct($node, $filterName, $arguments, $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler->subcompile($this->getNode('node'));
}
}
class_alias('Twig\Node\Expression\Filter\DefaultFilter',
'Twig_Node_Expression_Filter_Default');
PK-d�[�aGCC9vendor/twig/twig/src/Node/Expression/FilterExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\TwigFilter;
class FilterExpression extends CallExpression
{
public function __construct(\Twig_NodeInterface $node,
ConstantExpression $filterName, \Twig_NodeInterface $arguments, $lineno,
$tag = null)
{
parent::__construct(['node' => $node,
'filter' => $filterName, 'arguments' =>
$arguments], [], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$name =
$this->getNode('filter')->getAttribute('value');
$filter = $compiler->getEnvironment()->getFilter($name);
$this->setAttribute('name', $name);
$this->setAttribute('type', 'filter');
$this->setAttribute('thing', $filter);
$this->setAttribute('needs_environment',
$filter->needsEnvironment());
$this->setAttribute('needs_context',
$filter->needsContext());
$this->setAttribute('arguments',
$filter->getArguments());
if ($filter instanceof \Twig_FilterCallableInterface || $filter
instanceof TwigFilter) {
$this->setAttribute('callable',
$filter->getCallable());
}
if ($filter instanceof TwigFilter) {
$this->setAttribute('is_variadic',
$filter->isVariadic());
}
$this->compileCallable($compiler);
}
}
class_alias('Twig\Node\Expression\FilterExpression',
'Twig_Node_Expression_Filter');
PK-d�[�Sqǵ�;vendor/twig/twig/src/Node/Expression/FunctionExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\TwigFunction;
class FunctionExpression extends CallExpression
{
public function __construct($name, \Twig_NodeInterface $arguments,
$lineno)
{
parent::__construct(['arguments' => $arguments],
['name' => $name, 'is_defined_test' => false],
$lineno);
}
public function compile(Compiler $compiler)
{
$name = $this->getAttribute('name');
$function = $compiler->getEnvironment()->getFunction($name);
$this->setAttribute('name', $name);
$this->setAttribute('type', 'function');
$this->setAttribute('thing', $function);
$this->setAttribute('needs_environment',
$function->needsEnvironment());
$this->setAttribute('needs_context',
$function->needsContext());
$this->setAttribute('arguments',
$function->getArguments());
if ($function instanceof \Twig_FunctionCallableInterface ||
$function instanceof TwigFunction) {
$callable = $function->getCallable();
if ('constant' === $name &&
$this->getAttribute('is_defined_test')) {
$callable = 'twig_constant_is_defined';
}
$this->setAttribute('callable', $callable);
}
if ($function instanceof TwigFunction) {
$this->setAttribute('is_variadic',
$function->isVariadic());
}
$this->compileCallable($compiler);
}
}
class_alias('Twig\Node\Expression\FunctionExpression',
'Twig_Node_Expression_Function');
PK-d�[\a��
�
:vendor/twig/twig/src/Node/Expression/GetAttrExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\Template;
class GetAttrExpression extends AbstractExpression
{
public function __construct(AbstractExpression $node,
AbstractExpression $attribute, AbstractExpression $arguments = null, $type,
$lineno)
{
$nodes = ['node' => $node, 'attribute' =>
$attribute];
if (null !== $arguments) {
$nodes['arguments'] = $arguments;
}
parent::__construct($nodes, ['type' => $type,
'is_defined_test' => false, 'ignore_strict_check'
=> false, 'disable_c_ext' => false], $lineno);
}
public function compile(Compiler $compiler)
{
if ($this->getAttribute('disable_c_ext')) {
@trigger_error(sprintf('Using the
"disable_c_ext" attribute on %s is deprecated since version 1.30
and will be removed in 2.0.', __CLASS__), E_USER_DEPRECATED);
}
if (\function_exists('twig_template_get_attributes')
&& !$this->getAttribute('disable_c_ext')) {
$compiler->raw('twig_template_get_attributes($this,
');
} else {
$compiler->raw('$this->getAttribute(');
}
if ($this->getAttribute('ignore_strict_check')) {
$this->getNode('node')->setAttribute('ignore_strict_check',
true);
}
$compiler->subcompile($this->getNode('node'));
$compiler->raw(',
')->subcompile($this->getNode('attribute'));
// only generate optional arguments when needed (to make generated
code more readable)
$needFourth =
$this->getAttribute('ignore_strict_check');
$needThird = $needFourth ||
$this->getAttribute('is_defined_test');
$needSecond = $needThird || Template::ANY_CALL !==
$this->getAttribute('type');
$needFirst = $needSecond ||
$this->hasNode('arguments');
if ($needFirst) {
if ($this->hasNode('arguments')) {
$compiler->raw(',
')->subcompile($this->getNode('arguments'));
} else {
$compiler->raw(', []');
}
}
if ($needSecond) {
$compiler->raw(',
')->repr($this->getAttribute('type'));
}
if ($needThird) {
$compiler->raw(',
')->repr($this->getAttribute('is_defined_test'));
}
if ($needFourth) {
$compiler->raw(',
')->repr($this->getAttribute('ignore_strict_check'));
}
$compiler->raw(')');
}
}
class_alias('Twig\Node\Expression\GetAttrExpression',
'Twig_Node_Expression_GetAttr');
PK-d�[��jț�4vendor/twig/twig/src/Node/Expression/InlinePrint.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\Node\Node;
/**
* @internal
*/
final class InlinePrint extends AbstractExpression
{
public function __construct(Node $node, $lineno)
{
parent::__construct(['node' => $node], [], $lineno);
}
public function compile(Compiler $compiler)
{
$compiler
->raw('print (')
->subcompile($this->getNode('node'))
->raw(')')
;
}
}
PK-d�[���=vendor/twig/twig/src/Node/Expression/MethodCallExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
class MethodCallExpression extends AbstractExpression
{
public function __construct(AbstractExpression $node, $method,
ArrayExpression $arguments, $lineno)
{
parent::__construct(['node' => $node,
'arguments' => $arguments], ['method' => $method,
'safe' => false], $lineno);
if ($node instanceof NameExpression) {
$node->setAttribute('always_defined', true);
}
}
public function compile(Compiler $compiler)
{
$compiler
->subcompile($this->getNode('node'))
->raw('->')
->raw($this->getAttribute('method'))
->raw('(')
;
$first = true;
foreach
($this->getNode('arguments')->getKeyValuePairs() as $pair)
{
if (!$first) {
$compiler->raw(', ');
}
$first = false;
$compiler->subcompile($pair['value']);
}
$compiler->raw(')');
}
}
class_alias('Twig\Node\Expression\MethodCallExpression',
'Twig_Node_Expression_MethodCall');
PK-d�[Q%?{{7vendor/twig/twig/src/Node/Expression/NameExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
class NameExpression extends AbstractExpression
{
protected $specialVars = [
'_self' => '$this',
'_context' => '$context',
'_charset' =>
'$this->env->getCharset()',
];
public function __construct($name, $lineno)
{
parent::__construct([], ['name' => $name,
'is_defined_test' => false, 'ignore_strict_check'
=> false, 'always_defined' => false], $lineno);
}
public function compile(Compiler $compiler)
{
$name = $this->getAttribute('name');
$compiler->addDebugInfo($this);
if ($this->getAttribute('is_defined_test')) {
if ($this->isSpecial()) {
$compiler->repr(true);
} elseif (\PHP_VERSION_ID >= 700400) {
$compiler
->raw('array_key_exists(')
->string($name)
->raw(', $context)')
;
} else {
$compiler
->raw('(isset($context[')
->string($name)
->raw(']) || array_key_exists(')
->string($name)
->raw(', $context))')
;
}
} elseif ($this->isSpecial()) {
$compiler->raw($this->specialVars[$name]);
} elseif ($this->getAttribute('always_defined')) {
$compiler
->raw('$context[')
->string($name)
->raw(']')
;
} else {
if (\PHP_VERSION_ID >= 70000) {
// use PHP 7 null coalescing operator
$compiler
->raw('($context[')
->string($name)
->raw('] ?? ')
;
if ($this->getAttribute('ignore_strict_check')
|| !$compiler->getEnvironment()->isStrictVariables()) {
$compiler->raw('null)');
} else {
$compiler->raw('$this->getContext($context,
')->string($name)->raw('))');
}
} elseif (\PHP_VERSION_ID >= 50400) {
// PHP 5.4 ternary operator performance was optimized
$compiler
->raw('(isset($context[')
->string($name)
->raw(']) ? $context[')
->string($name)
->raw('] : ')
;
if ($this->getAttribute('ignore_strict_check')
|| !$compiler->getEnvironment()->isStrictVariables()) {
$compiler->raw('null)');
} else {
$compiler->raw('$this->getContext($context,
')->string($name)->raw('))');
}
} else {
$compiler
->raw('$this->getContext($context, ')
->string($name)
;
if
($this->getAttribute('ignore_strict_check')) {
$compiler->raw(', true');
}
$compiler
->raw(')')
;
}
}
}
public function isSpecial()
{
return
isset($this->specialVars[$this->getAttribute('name')]);
}
public function isSimple()
{
return !$this->isSpecial() &&
!$this->getAttribute('is_defined_test');
}
}
class_alias('Twig\Node\Expression\NameExpression',
'Twig_Node_Expression_Name');
PK-d�[T��o��?vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\Node\Expression\Binary\AndBinary;
use Twig\Node\Expression\Test\DefinedTest;
use Twig\Node\Expression\Test\NullTest;
use Twig\Node\Expression\Unary\NotUnary;
use Twig\Node\Node;
class NullCoalesceExpression extends ConditionalExpression
{
public function __construct(\Twig_NodeInterface $left,
\Twig_NodeInterface $right, $lineno)
{
$test = new DefinedTest(clone $left, 'defined', new
Node(), $left->getTemplateLine());
// for "block()", we don't need the null test as the
return value is always a string
if (!$left instanceof BlockReferenceExpression) {
$test = new AndBinary(
$test,
new NotUnary(new NullTest($left, 'null', new
Node(), $left->getTemplateLine()), $left->getTemplateLine()),
$left->getTemplateLine()
);
}
parent::__construct($test, $left, $right, $lineno);
}
public function compile(Compiler $compiler)
{
/*
* This optimizes only one case. PHP 7 also supports more complex
expressions
* that can return null. So, for instance, if log is defined,
log("foo") ?? "..." works,
* but log($a["foo"]) ?? "..." does not if
$a["foo"] is not defined. More advanced
* cases might be implemented as an optimizer node visitor, but has
not been done
* as benefits are probably not worth the added complexity.
*/
if (\PHP_VERSION_ID >= 70000 &&
$this->getNode('expr2') instanceof NameExpression) {
$this->getNode('expr2')->setAttribute('always_defined',
true);
$compiler
->raw('((')
->subcompile($this->getNode('expr2'))
->raw(') ?? (')
->subcompile($this->getNode('expr3'))
->raw('))')
;
} else {
parent::compile($compiler);
}
}
}
class_alias('Twig\Node\Expression\NullCoalesceExpression',
'Twig_Node_Expression_NullCoalesce');
PK-d�[<O�n��9vendor/twig/twig/src/Node/Expression/ParentExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
/**
* Represents a parent node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ParentExpression extends AbstractExpression
{
public function __construct($name, $lineno, $tag = null)
{
parent::__construct([], ['output' => false,
'name' => $name], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
if ($this->getAttribute('output')) {
$compiler
->addDebugInfo($this)
->write('$this->displayParentBlock(')
->string($this->getAttribute('name'))
->raw(", \$context, \$blocks);\n")
;
} else {
$compiler
->raw('$this->renderParentBlock(')
->string($this->getAttribute('name'))
->raw(', $context, $blocks)')
;
}
}
}
class_alias('Twig\Node\Expression\ParentExpression',
'Twig_Node_Expression_Parent');
PK-d�[�/c��;vendor/twig/twig/src/Node/Expression/TempNameExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
class TempNameExpression extends AbstractExpression
{
public function __construct($name, $lineno)
{
parent::__construct([], ['name' => $name], $lineno);
}
public function compile(Compiler $compiler)
{
$compiler
->raw('$_')
->raw($this->getAttribute('name'))
->raw('_')
;
}
}
class_alias('Twig\Node\Expression\TempNameExpression',
'Twig_Node_Expression_TempName');
PK-d�[T�o��:vendor/twig/twig/src/Node/Expression/Test/ConstantTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Test;
use Twig\Compiler;
use Twig\Node\Expression\TestExpression;
/**
* Checks if a variable is the exact same value as a constant.
*
* {% if post.status is constant('Post::PUBLISHED') %}
* the status attribute is exactly the same as Post::PUBLISHED
* {% endif %}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ConstantTest extends TestExpression
{
public function compile(Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' === constant(')
;
if ($this->getNode('arguments')->hasNode(1)) {
$compiler
->raw('get_class(')
->subcompile($this->getNode('arguments')->getNode(1))
->raw(')."::".')
;
}
$compiler
->subcompile($this->getNode('arguments')->getNode(0))
->raw('))')
;
}
}
class_alias('Twig\Node\Expression\Test\ConstantTest',
'Twig_Node_Expression_Test_Constant');
PK-d�[Q� � 9vendor/twig/twig/src/Node/Expression/Test/DefinedTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Test;
use Twig\Compiler;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\BlockReferenceExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\TestExpression;
/**
* Checks if a variable is defined in the current context.
*
* {# defined works with variable names and variable attributes #}
* {% if foo is defined %}
* {# ... #}
* {% endif %}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DefinedTest extends TestExpression
{
public function __construct(\Twig_NodeInterface $node, $name,
\Twig_NodeInterface $arguments = null, $lineno)
{
if ($node instanceof NameExpression) {
$node->setAttribute('is_defined_test', true);
} elseif ($node instanceof GetAttrExpression) {
$node->setAttribute('is_defined_test', true);
$this->changeIgnoreStrictCheck($node);
} elseif ($node instanceof BlockReferenceExpression) {
$node->setAttribute('is_defined_test', true);
} elseif ($node instanceof FunctionExpression &&
'constant' === $node->getAttribute('name')) {
$node->setAttribute('is_defined_test', true);
} elseif ($node instanceof ConstantExpression || $node instanceof
ArrayExpression) {
$node = new ConstantExpression(true,
$node->getTemplateLine());
} else {
throw new SyntaxError('The "defined" test only
works with simple variables.', $lineno);
}
parent::__construct($node, $name, $arguments, $lineno);
}
protected function changeIgnoreStrictCheck(GetAttrExpression $node)
{
$node->setAttribute('ignore_strict_check', true);
if ($node->getNode('node') instanceof
GetAttrExpression) {
$this->changeIgnoreStrictCheck($node->getNode('node'));
}
}
public function compile(Compiler $compiler)
{
$compiler->subcompile($this->getNode('node'));
}
}
class_alias('Twig\Node\Expression\Test\DefinedTest',
'Twig_Node_Expression_Test_Defined');
PK-d�[qC�uu=vendor/twig/twig/src/Node/Expression/Test/DivisiblebyTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Test;
use Twig\Compiler;
use Twig\Node\Expression\TestExpression;
/**
* Checks if a variable is divisible by a number.
*
* {% if loop.index is divisible by(3) %}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DivisiblebyTest extends TestExpression
{
public function compile(Compiler $compiler)
{
$compiler
->raw('(0 == ')
->subcompile($this->getNode('node'))
->raw(' % ')
->subcompile($this->getNode('arguments')->getNode(0))
->raw(')')
;
}
}
class_alias('Twig\Node\Expression\Test\DivisiblebyTest',
'Twig_Node_Expression_Test_Divisibleby');
PK-d�[�J����6vendor/twig/twig/src/Node/Expression/Test/EvenTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Test;
use Twig\Compiler;
use Twig\Node\Expression\TestExpression;
/**
* Checks if a number is even.
*
* {{ var is even }}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class EvenTest extends TestExpression
{
public function compile(Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' % 2 == 0')
->raw(')')
;
}
}
class_alias('Twig\Node\Expression\Test\EvenTest',
'Twig_Node_Expression_Test_Even');
PK-d�[!d����6vendor/twig/twig/src/Node/Expression/Test/NullTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Test;
use Twig\Compiler;
use Twig\Node\Expression\TestExpression;
/**
* Checks that a variable is null.
*
* {{ var is none }}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class NullTest extends TestExpression
{
public function compile(Compiler $compiler)
{
$compiler
->raw('(null === ')
->subcompile($this->getNode('node'))
->raw(')')
;
}
}
class_alias('Twig\Node\Expression\Test\NullTest',
'Twig_Node_Expression_Test_Null');
PK-d�[ja�c��5vendor/twig/twig/src/Node/Expression/Test/OddTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Test;
use Twig\Compiler;
use Twig\Node\Expression\TestExpression;
/**
* Checks if a number is odd.
*
* {{ var is odd }}
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class OddTest extends TestExpression
{
public function compile(Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' % 2 == 1')
->raw(')')
;
}
}
class_alias('Twig\Node\Expression\Test\OddTest',
'Twig_Node_Expression_Test_Odd');
PK-d�[���DD8vendor/twig/twig/src/Node/Expression/Test/SameasTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Test;
use Twig\Compiler;
use Twig\Node\Expression\TestExpression;
/**
* Checks if a variable is the same as another one (=== in PHP).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SameasTest extends TestExpression
{
public function compile(Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('node'))
->raw(' === ')
->subcompile($this->getNode('arguments')->getNode(0))
->raw(')')
;
}
}
class_alias('Twig\Node\Expression\Test\SameasTest',
'Twig_Node_Expression_Test_Sameas');
PK-d�[�e���7vendor/twig/twig/src/Node/Expression/TestExpression.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression;
use Twig\Compiler;
use Twig\TwigTest;
class TestExpression extends CallExpression
{
public function __construct(\Twig_NodeInterface $node, $name,
\Twig_NodeInterface $arguments = null, $lineno)
{
$nodes = ['node' => $node];
if (null !== $arguments) {
$nodes['arguments'] = $arguments;
}
parent::__construct($nodes, ['name' => $name],
$lineno);
}
public function compile(Compiler $compiler)
{
$name = $this->getAttribute('name');
$test = $compiler->getEnvironment()->getTest($name);
$this->setAttribute('name', $name);
$this->setAttribute('type', 'test');
$this->setAttribute('thing', $test);
if ($test instanceof TwigTest) {
$this->setAttribute('arguments',
$test->getArguments());
}
if ($test instanceof \Twig_TestCallableInterface || $test
instanceof TwigTest) {
$this->setAttribute('callable',
$test->getCallable());
}
if ($test instanceof TwigTest) {
$this->setAttribute('is_variadic',
$test->isVariadic());
}
$this->compileCallable($compiler);
}
}
class_alias('Twig\Node\Expression\TestExpression',
'Twig_Node_Expression_Test');
PK-d�[s��ZZ<vendor/twig/twig/src/Node/Expression/Unary/AbstractUnary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Unary;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
abstract class AbstractUnary extends AbstractExpression
{
public function __construct(\Twig_NodeInterface $node, $lineno)
{
parent::__construct(['node' => $node], [], $lineno);
}
public function compile(Compiler $compiler)
{
$compiler->raw(' ');
$this->operator($compiler);
$compiler->subcompile($this->getNode('node'));
}
abstract public function operator(Compiler $compiler);
}
class_alias('Twig\Node\Expression\Unary\AbstractUnary',
'Twig_Node_Expression_Unary');
PK-d�[�5���7vendor/twig/twig/src/Node/Expression/Unary/NegUnary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Unary;
use Twig\Compiler;
class NegUnary extends AbstractUnary
{
public function operator(Compiler $compiler)
{
$compiler->raw('-');
}
}
class_alias('Twig\Node\Expression\Unary\NegUnary',
'Twig_Node_Expression_Unary_Neg');
PK-d�[���7vendor/twig/twig/src/Node/Expression/Unary/NotUnary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Unary;
use Twig\Compiler;
class NotUnary extends AbstractUnary
{
public function operator(Compiler $compiler)
{
$compiler->raw('!');
}
}
class_alias('Twig\Node\Expression\Unary\NotUnary',
'Twig_Node_Expression_Unary_Not');
PK-d�['W���7vendor/twig/twig/src/Node/Expression/Unary/PosUnary.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Unary;
use Twig\Compiler;
class PosUnary extends AbstractUnary
{
public function operator(Compiler $compiler)
{
$compiler->raw('+');
}
}
class_alias('Twig\Node\Expression\Unary\PosUnary',
'Twig_Node_Expression_Unary_Pos');
PK-d�[��ޱ�'vendor/twig/twig/src/Node/FlushNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a flush node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FlushNode extends Node
{
public function __construct($lineno, $tag)
{
parent::__construct([], [], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write("flush();\n")
;
}
}
class_alias('Twig\Node\FlushNode', 'Twig_Node_Flush');
PK-d�[I�j11)vendor/twig/twig/src/Node/ForLoopNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Internal node used by the for node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ForLoopNode extends Node
{
public function __construct($lineno, $tag = null)
{
parent::__construct([], ['with_loop' => false,
'ifexpr' => false, 'else' => false], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
if ($this->getAttribute('else')) {
$compiler->write("\$context['_iterated'] =
true;\n");
}
if ($this->getAttribute('with_loop')) {
$compiler
->write("++\$context['loop']['index0'];\n")
->write("++\$context['loop']['index'];\n")
->write("\$context['loop']['first'] =
false;\n")
;
if (!$this->getAttribute('ifexpr')) {
$compiler
->write("if
(isset(\$context['loop']['length'])) {\n")
->indent()
->write("--\$context['loop']['revindex0'];\n")
->write("--\$context['loop']['revindex'];\n")
->write("\$context['loop']['last'] = 0 ===
\$context['loop']['revindex0'];\n")
->outdent()
->write("}\n")
;
}
}
}
}
class_alias('Twig\Node\ForLoopNode',
'Twig_Node_ForLoop');
PK-d�[���%vendor/twig/twig/src/Node/ForNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\AssignNameExpression;
/**
* Represents a for node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ForNode extends Node
{
protected $loop;
public function __construct(AssignNameExpression $keyTarget,
AssignNameExpression $valueTarget, AbstractExpression $seq,
AbstractExpression $ifexpr = null, \Twig_NodeInterface $body,
\Twig_NodeInterface $else = null, $lineno, $tag = null)
{
$body = new Node([$body, $this->loop = new ForLoopNode($lineno,
$tag)]);
if (null !== $ifexpr) {
$body = new IfNode(new Node([$ifexpr, $body]), null, $lineno,
$tag);
}
$nodes = ['key_target' => $keyTarget,
'value_target' => $valueTarget, 'seq' => $seq,
'body' => $body];
if (null !== $else) {
$nodes['else'] = $else;
}
parent::__construct($nodes, ['with_loop' => true,
'ifexpr' => null !== $ifexpr], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write("\$context['_parent'] =
\$context;\n")
->write("\$context['_seq'] =
twig_ensure_traversable(")
->subcompile($this->getNode('seq'))
->raw(");\n")
;
if ($this->hasNode('else')) {
$compiler->write("\$context['_iterated'] =
false;\n");
}
if ($this->getAttribute('with_loop')) {
$compiler
->write("\$context['loop'] = [\n")
->write(" 'parent' =>
\$context['_parent'],\n")
->write(" 'index0' => 0,\n")
->write(" 'index' => 1,\n")
->write(" 'first' => true,\n")
->write("];\n")
;
if (!$this->getAttribute('ifexpr')) {
$compiler
->write("if
(is_array(\$context['_seq']) ||
(is_object(\$context['_seq']) &&
\$context['_seq'] instanceof \Countable)) {\n")
->indent()
->write("\$length =
count(\$context['_seq']);\n")
->write("\$context['loop']['revindex0'] =
\$length - 1;\n")
->write("\$context['loop']['revindex'] =
\$length;\n")
->write("\$context['loop']['length'] =
\$length;\n")
->write("\$context['loop']['last'] = 1 ===
\$length;\n")
->outdent()
->write("}\n")
;
}
}
$this->loop->setAttribute('else',
$this->hasNode('else'));
$this->loop->setAttribute('with_loop',
$this->getAttribute('with_loop'));
$this->loop->setAttribute('ifexpr',
$this->getAttribute('ifexpr'));
$compiler
->write("foreach (\$context['_seq'] as
")
->subcompile($this->getNode('key_target'))
->raw(' => ')
->subcompile($this->getNode('value_target'))
->raw(") {\n")
->indent()
->subcompile($this->getNode('body'))
->outdent()
->write("}\n")
;
if ($this->hasNode('else')) {
$compiler
->write("if (!\$context['_iterated'])
{\n")
->indent()
->subcompile($this->getNode('else'))
->outdent()
->write("}\n")
;
}
$compiler->write("\$_parent =
\$context['_parent'];\n");
// remove some "private" loop variables (needed for
nested loops)
$compiler->write('unset($context[\'_seq\'],
$context[\'_iterated\'],
$context[\''.$this->getNode('key_target')->getAttribute('name').'\'],
$context[\''.$this->getNode('value_target')->getAttribute('name').'\'],
$context[\'_parent\'],
$context[\'loop\']);'."\n");
// keep the values set in the inner context for variables defined
in the outer context
$compiler->write("\$context =
array_intersect_key(\$context, \$_parent) + \$_parent;\n");
}
}
class_alias('Twig\Node\ForNode', 'Twig_Node_For');
PK-d�[�X�m��$vendor/twig/twig/src/Node/IfNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents an if node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class IfNode extends Node
{
public function __construct(\Twig_NodeInterface $tests,
\Twig_NodeInterface $else = null, $lineno, $tag = null)
{
$nodes = ['tests' => $tests];
if (null !== $else) {
$nodes['else'] = $else;
}
parent::__construct($nodes, [], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler->addDebugInfo($this);
for ($i = 0, $count = \count($this->getNode('tests'));
$i < $count; $i += 2) {
if ($i > 0) {
$compiler
->outdent()
->write('} elseif (')
;
} else {
$compiler
->write('if (')
;
}
$compiler
->subcompile($this->getNode('tests')->getNode($i))
->raw(") {\n")
->indent()
->subcompile($this->getNode('tests')->getNode($i + 1))
;
}
if ($this->hasNode('else')) {
$compiler
->outdent()
->write("} else {\n")
->indent()
->subcompile($this->getNode('else'))
;
}
$compiler
->outdent()
->write("}\n");
}
}
class_alias('Twig\Node\IfNode', 'Twig_Node_If');
PK-d�[2�x8��(vendor/twig/twig/src/Node/ImportNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\NameExpression;
/**
* Represents an import node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ImportNode extends Node
{
public function __construct(AbstractExpression $expr,
AbstractExpression $var, $lineno, $tag = null)
{
parent::__construct(['expr' => $expr, 'var'
=> $var], [], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('')
->subcompile($this->getNode('var'))
->raw(' = ')
;
if ($this->getNode('expr') instanceof NameExpression
&& '_self' ===
$this->getNode('expr')->getAttribute('name')) {
$compiler->raw('$this');
} else {
$compiler
->raw('$this->loadTemplate(')
->subcompile($this->getNode('expr'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(')->unwrap()')
;
}
$compiler->raw(";\n");
}
}
class_alias('Twig\Node\ImportNode',
'Twig_Node_Import');
PK-d�[��||)vendor/twig/twig/src/Node/IncludeNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
/**
* Represents an include node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class IncludeNode extends Node implements NodeOutputInterface
{
public function __construct(AbstractExpression $expr,
AbstractExpression $variables = null, $only = false, $ignoreMissing =
false, $lineno, $tag = null)
{
$nodes = ['expr' => $expr];
if (null !== $variables) {
$nodes['variables'] = $variables;
}
parent::__construct($nodes, ['only' => (bool) $only,
'ignore_missing' => (bool) $ignoreMissing], $lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler->addDebugInfo($this);
if ($this->getAttribute('ignore_missing')) {
$template = $compiler->getVarName();
$compiler
->write(sprintf("$%s = null;\n", $template))
->write("try {\n")
->indent()
->write(sprintf('$%s = ', $template))
;
$this->addGetTemplate($compiler);
$compiler
->raw(";\n")
->outdent()
->write("} catch (LoaderError \$e) {\n")
->indent()
->write("// ignore missing template\n")
->outdent()
->write("}\n")
->write(sprintf("if ($%s) {\n", $template))
->indent()
->write(sprintf('$%s->display(',
$template))
;
$this->addTemplateArguments($compiler);
$compiler
->raw(");\n")
->outdent()
->write("}\n")
;
} else {
$this->addGetTemplate($compiler);
$compiler->raw('->display(');
$this->addTemplateArguments($compiler);
$compiler->raw(");\n");
}
}
protected function addGetTemplate(Compiler $compiler)
{
$compiler
->write('$this->loadTemplate(')
->subcompile($this->getNode('expr'))
->raw(', ')
->repr($this->getTemplateName())
->raw(', ')
->repr($this->getTemplateLine())
->raw(')')
;
}
protected function addTemplateArguments(Compiler $compiler)
{
if (!$this->hasNode('variables')) {
$compiler->raw(false ===
$this->getAttribute('only') ? '$context' :
'[]');
} elseif (false === $this->getAttribute('only')) {
$compiler
->raw('twig_array_merge($context, ')
->subcompile($this->getNode('variables'))
->raw(')')
;
} else {
$compiler->raw('twig_to_array(');
$compiler->subcompile($this->getNode('variables'));
$compiler->raw(')');
}
}
}
class_alias('Twig\Node\IncludeNode',
'Twig_Node_Include');
PK-d�[u�i'vendor/twig/twig/src/Node/MacroNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Error\SyntaxError;
/**
* Represents a macro node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class MacroNode extends Node
{
const VARARGS_NAME = 'varargs';
public function __construct($name, \Twig_NodeInterface $body,
\Twig_NodeInterface $arguments, $lineno, $tag = null)
{
foreach ($arguments as $argumentName => $argument) {
if (self::VARARGS_NAME === $argumentName) {
throw new SyntaxError(sprintf('The argument
"%s" in macro "%s" cannot be defined because the
variable "%s" is reserved for arbitrary arguments.',
self::VARARGS_NAME, $name, self::VARARGS_NAME),
$argument->getTemplateLine(), $argument->getSourceContext());
}
}
parent::__construct(['body' => $body,
'arguments' => $arguments], ['name' => $name],
$lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write(sprintf('public function get%s(',
$this->getAttribute('name')))
;
$count = \count($this->getNode('arguments'));
$pos = 0;
foreach ($this->getNode('arguments') as $name =>
$default) {
$compiler
->raw('$__'.$name.'__ = ')
->subcompile($default)
;
if (++$pos < $count) {
$compiler->raw(', ');
}
}
if (\PHP_VERSION_ID >= 50600) {
if ($count) {
$compiler->raw(', ');
}
$compiler->raw('...$__varargs__');
}
$compiler
->raw(")\n")
->write("{\n")
->indent()
;
$compiler
->write("\$context =
\$this->env->mergeGlobals([\n")
->indent()
;
foreach ($this->getNode('arguments') as $name =>
$default) {
$compiler
->write('')
->string($name)
->raw(' => $__'.$name.'__')
->raw(",\n")
;
}
$compiler
->write('')
->string(self::VARARGS_NAME)
->raw(' => ')
;
if (\PHP_VERSION_ID >= 50600) {
$compiler->raw("\$__varargs__,\n");
} else {
$compiler
->raw('func_num_args() > ')
->repr($count)
->raw(' ? array_slice(func_get_args(), ')
->repr($count)
->raw(") : [],\n")
;
}
$compiler
->outdent()
->write("]);\n\n")
->write("\$blocks = [];\n\n")
;
if ($compiler->getEnvironment()->isDebug()) {
$compiler->write("ob_start();\n");
} else {
$compiler->write("ob_start(function () { return
''; });\n");
}
$compiler
->write("try {\n")
->indent()
->subcompile($this->getNode('body'))
->outdent()
->write("} catch (\Exception \$e) {\n")
->indent()
->write("ob_end_clean();\n\n")
->write("throw \$e;\n")
->outdent()
->write("} catch (\Throwable \$e) {\n")
->indent()
->write("ob_end_clean();\n\n")
->write("throw \$e;\n")
->outdent()
->write("}\n\n")
->write("return ('' === \$tmp =
ob_get_clean()) ? '' : new Markup(\$tmp,
\$this->env->getCharset());\n")
->outdent()
->write("}\n\n")
;
}
}
class_alias('Twig\Node\MacroNode', 'Twig_Node_Macro');
PK-d�[&J�I??(vendor/twig/twig/src/Node/ModuleNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Source;
/**
* Represents a module node.
*
* Consider this class as being final. If you need to customize the
behavior of
* the generated class, consider adding nodes to the following nodes:
display_start,
* display_end, constructor_start, constructor_end, and class_end.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ModuleNode extends Node
{
public function __construct(\Twig_NodeInterface $body,
AbstractExpression $parent = null, \Twig_NodeInterface $blocks,
\Twig_NodeInterface $macros, \Twig_NodeInterface $traits,
$embeddedTemplates, $name, $source = '')
{
if (!$name instanceof Source) {
@trigger_error(sprintf('Passing a string as the $name
argument of %s() is deprecated since version 1.27. Pass a \Twig\Source
instance instead.', __METHOD__), E_USER_DEPRECATED);
$source = new Source($source, $name);
} else {
$source = $name;
}
$nodes = [
'body' => $body,
'blocks' => $blocks,
'macros' => $macros,
'traits' => $traits,
'display_start' => new Node(),
'display_end' => new Node(),
'constructor_start' => new Node(),
'constructor_end' => new Node(),
'class_end' => new Node(),
];
if (null !== $parent) {
$nodes['parent'] = $parent;
}
// embedded templates are set as attributes so that they are only
visited once by the visitors
parent::__construct($nodes, [
// source to be remove in 2.0
'source' => $source->getCode(),
// filename to be remove in 2.0 (use getTemplateName() instead)
'filename' => $source->getName(),
'index' => null,
'embedded_templates' => $embeddedTemplates,
], 1);
// populate the template name of all node children
$this->setTemplateName($source->getName());
$this->setSourceContext($source);
}
public function setIndex($index)
{
$this->setAttribute('index', $index);
}
public function compile(Compiler $compiler)
{
$this->compileTemplate($compiler);
foreach ($this->getAttribute('embedded_templates') as
$template) {
$compiler->subcompile($template);
}
}
protected function compileTemplate(Compiler $compiler)
{
if (!$this->getAttribute('index')) {
$compiler->write('<?php');
}
$this->compileClassHeader($compiler);
if (
\count($this->getNode('blocks'))
|| \count($this->getNode('traits'))
|| !$this->hasNode('parent')
|| $this->getNode('parent') instanceof
ConstantExpression
|| \count($this->getNode('constructor_start'))
|| \count($this->getNode('constructor_end'))
) {
$this->compileConstructor($compiler);
}
$this->compileGetParent($compiler);
$this->compileDisplay($compiler);
$compiler->subcompile($this->getNode('blocks'));
$this->compileMacros($compiler);
$this->compileGetTemplateName($compiler);
$this->compileIsTraitable($compiler);
$this->compileDebugInfo($compiler);
$this->compileGetSource($compiler);
$this->compileGetSourceContext($compiler);
$this->compileClassFooter($compiler);
}
protected function compileGetParent(Compiler $compiler)
{
if (!$this->hasNode('parent')) {
return;
}
$parent = $this->getNode('parent');
$compiler
->write("protected function doGetParent(array
\$context)\n", "{\n")
->indent()
->addDebugInfo($parent)
->write('return ')
;
if ($parent instanceof ConstantExpression) {
$compiler->subcompile($parent);
} else {
$compiler
->raw('$this->loadTemplate(')
->subcompile($parent)
->raw(', ')
->repr($this->getSourceContext()->getName())
->raw(', ')
->repr($parent->getTemplateLine())
->raw(')')
;
}
$compiler
->raw(";\n")
->outdent()
->write("}\n\n")
;
}
protected function compileClassHeader(Compiler $compiler)
{
$compiler
->write("\n\n")
;
if (!$this->getAttribute('index')) {
$compiler
->write("use Twig\Environment;\n")
->write("use Twig\Error\LoaderError;\n")
->write("use Twig\Error\RuntimeError;\n")
->write("use Twig\Markup;\n")
->write("use Twig\Sandbox\SecurityError;\n")
->write("use
Twig\Sandbox\SecurityNotAllowedTagError;\n")
->write("use
Twig\Sandbox\SecurityNotAllowedFilterError;\n")
->write("use
Twig\Sandbox\SecurityNotAllowedFunctionError;\n")
->write("use Twig\Source;\n")
->write("use Twig\Template;\n\n")
;
}
$compiler
// if the template name contains */, add a blank to avoid a PHP
parse error
->write('/* '.str_replace('*/', '*
/', $this->getSourceContext()->getName())." */\n")
->write('class
'.$compiler->getEnvironment()->getTemplateClass($this->getSourceContext()->getName(),
$this->getAttribute('index')))
->raw(sprintf(" extends %s\n",
$compiler->getEnvironment()->getBaseTemplateClass()))
->write("{\n")
->indent()
;
}
protected function compileConstructor(Compiler $compiler)
{
$compiler
->write("public function __construct(Environment
\$env)\n", "{\n")
->indent()
->subcompile($this->getNode('constructor_start'))
->write("parent::__construct(\$env);\n\n")
;
// parent
if (!$this->hasNode('parent')) {
$compiler->write("\$this->parent =
false;\n\n");
}
$countTraits = \count($this->getNode('traits'));
if ($countTraits) {
// traits
foreach ($this->getNode('traits') as $i =>
$trait) {
$this->compileLoadTemplate($compiler,
$trait->getNode('template'), sprintf('$_trait_%s',
$i));
$node = $trait->getNode('template');
$compiler
->addDebugInfo($node)
->write(sprintf("if
(!\$_trait_%s->isTraitable()) {\n", $i))
->indent()
->write("throw new RuntimeError('Template
\"'.")
->subcompile($trait->getNode('template'))
->raw(".'\" cannot be used as a
trait.', ")
->repr($node->getTemplateLine())
->raw(",
\$this->getSourceContext());\n")
->outdent()
->write("}\n")
->write(sprintf("\$_trait_%s_blocks =
\$_trait_%s->getBlocks();\n\n", $i, $i))
;
foreach ($trait->getNode('targets') as $key
=> $value) {
$compiler
->write(sprintf('if
(!isset($_trait_%s_blocks[', $i))
->string($key)
->raw("])) {\n")
->indent()
->write("throw new
RuntimeError(sprintf('Block ")
->string($key)
->raw(' is not defined in trait ')
->subcompile($trait->getNode('template'))
->raw(".'), ")
->repr($node->getTemplateLine())
->raw(",
\$this->getSourceContext());\n")
->outdent()
->write("}\n\n")
->write(sprintf('$_trait_%s_blocks[',
$i))
->subcompile($value)
->raw(sprintf('] =
$_trait_%s_blocks[', $i))
->string($key)
->raw(sprintf('];
unset($_trait_%s_blocks[', $i))
->string($key)
->raw("]);\n\n")
;
}
}
if ($countTraits > 1) {
$compiler
->write("\$this->traits =
array_merge(\n")
->indent()
;
for ($i = 0; $i < $countTraits; ++$i) {
$compiler
->write(sprintf('$_trait_%s_blocks'.($i == $countTraits - 1 ?
'' : ',')."\n", $i))
;
}
$compiler
->outdent()
->write(");\n\n")
;
} else {
$compiler
->write("\$this->traits =
\$_trait_0_blocks;\n\n")
;
}
$compiler
->write("\$this->blocks = array_merge(\n")
->indent()
->write("\$this->traits,\n")
->write("[\n")
;
} else {
$compiler
->write("\$this->blocks = [\n")
;
}
// blocks
$compiler
->indent()
;
foreach ($this->getNode('blocks') as $name =>
$node) {
$compiler
->write(sprintf("'%s' => [\$this,
'block_%s'],\n", $name, $name))
;
}
if ($countTraits) {
$compiler
->outdent()
->write("]\n")
->outdent()
->write(");\n")
;
} else {
$compiler
->outdent()
->write("];\n")
;
}
$compiler
->subcompile($this->getNode('constructor_end'))
->outdent()
->write("}\n\n")
;
}
protected function compileDisplay(Compiler $compiler)
{
$compiler
->write("protected function doDisplay(array \$context,
array \$blocks = [])\n", "{\n")
->indent()
->subcompile($this->getNode('display_start'))
->subcompile($this->getNode('body'))
;
if ($this->hasNode('parent')) {
$parent = $this->getNode('parent');
$compiler->addDebugInfo($parent);
if ($parent instanceof ConstantExpression) {
$compiler
->write('$this->parent =
$this->loadTemplate(')
->subcompile($parent)
->raw(', ')
->repr($this->getSourceContext()->getName())
->raw(', ')
->repr($parent->getTemplateLine())
->raw(");\n")
;
$compiler->write('$this->parent');
} else {
$compiler->write('$this->getParent($context)');
}
$compiler->raw("->display(\$context,
array_merge(\$this->blocks, \$blocks));\n");
}
$compiler
->subcompile($this->getNode('display_end'))
->outdent()
->write("}\n\n")
;
}
protected function compileClassFooter(Compiler $compiler)
{
$compiler
->subcompile($this->getNode('class_end'))
->outdent()
->write("}\n")
;
}
protected function compileMacros(Compiler $compiler)
{
$compiler->subcompile($this->getNode('macros'));
}
protected function compileGetTemplateName(Compiler $compiler)
{
$compiler
->write("public function getTemplateName()\n",
"{\n")
->indent()
->write('return ')
->repr($this->getSourceContext()->getName())
->raw(";\n")
->outdent()
->write("}\n\n")
;
}
protected function compileIsTraitable(Compiler $compiler)
{
// A template can be used as a trait if:
// * it has no parent
// * it has no macros
// * it has no body
//
// Put another way, a template can be used as a trait if it
// only contains blocks and use statements.
$traitable = !$this->hasNode('parent') && 0
=== \count($this->getNode('macros'));
if ($traitable) {
if ($this->getNode('body') instanceof BodyNode) {
$nodes =
$this->getNode('body')->getNode(0);
} else {
$nodes = $this->getNode('body');
}
if (!\count($nodes)) {
$nodes = new Node([$nodes]);
}
foreach ($nodes as $node) {
if (!\count($node)) {
continue;
}
if ($node instanceof TextNode &&
ctype_space($node->getAttribute('data'))) {
continue;
}
if ($node instanceof BlockReferenceNode) {
continue;
}
$traitable = false;
break;
}
}
if ($traitable) {
return;
}
$compiler
->write("public function isTraitable()\n",
"{\n")
->indent()
->write(sprintf("return %s;\n", $traitable ?
'true' : 'false'))
->outdent()
->write("}\n\n")
;
}
protected function compileDebugInfo(Compiler $compiler)
{
$compiler
->write("public function getDebugInfo()\n",
"{\n")
->indent()
->write(sprintf("return %s;\n",
str_replace("\n", '',
var_export(array_reverse($compiler->getDebugInfo(), true), true))))
->outdent()
->write("}\n\n")
;
}
protected function compileGetSource(Compiler $compiler)
{
$compiler
->write("/** @deprecated since 1.27 (to be removed in
2.0). Use getSourceContext() instead */\n")
->write("public function getSource()\n",
"{\n")
->indent()
->write("@trigger_error('The
'.__METHOD__.' method is deprecated since version 1.27 and will
be removed in 2.0. Use getSourceContext() instead.',
E_USER_DEPRECATED);\n\n")
->write('return
$this->getSourceContext()->getCode();')
->raw("\n")
->outdent()
->write("}\n\n")
;
}
protected function compileGetSourceContext(Compiler $compiler)
{
$compiler
->write("public function getSourceContext()\n",
"{\n")
->indent()
->write('return new Source(')
->string($compiler->getEnvironment()->isDebug() ?
$this->getSourceContext()->getCode() : '')
->raw(', ')
->string($this->getSourceContext()->getName())
->raw(', ')
->string($this->getSourceContext()->getPath())
->raw(");\n")
->outdent()
->write("}\n")
;
}
protected function compileLoadTemplate(Compiler $compiler, $node, $var)
{
if ($node instanceof ConstantExpression) {
$compiler
->write(sprintf('%s =
$this->loadTemplate(', $var))
->subcompile($node)
->raw(', ')
->repr($node->getTemplateName())
->raw(', ')
->repr($node->getTemplateLine())
->raw(");\n")
;
} else {
throw new \LogicException('Trait templates can only be
constant nodes.');
}
}
}
class_alias('Twig\Node\ModuleNode',
'Twig_Node_Module');
PK-d�[���ee"vendor/twig/twig/src/Node/Node.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Source;
/**
* Represents a node in the AST.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Node implements \Twig_NodeInterface
{
protected $nodes;
protected $attributes;
protected $lineno;
protected $tag;
private $name;
private $sourceContext;
/**
* @param array $nodes An array of named nodes
* @param array $attributes An array of attributes (should not be
nodes)
* @param int $lineno The line number
* @param string $tag The tag name associated with the Node
*/
public function __construct(array $nodes = [], array $attributes = [],
$lineno = 0, $tag = null)
{
foreach ($nodes as $name => $node) {
if (!$node instanceof \Twig_NodeInterface) {
@trigger_error(sprintf('Using "%s" for the
value of node "%s" of "%s" is deprecated since version
1.25 and will be removed in 2.0.', \is_object($node) ?
\get_class($node) : (null === $node ? 'null' : \gettype($node)),
$name, \get_class($this)), E_USER_DEPRECATED);
}
}
$this->nodes = $nodes;
$this->attributes = $attributes;
$this->lineno = $lineno;
$this->tag = $tag;
}
public function __toString()
{
$attributes = [];
foreach ($this->attributes as $name => $value) {
$attributes[] = sprintf('%s: %s', $name,
str_replace("\n", '', var_export($value, true)));
}
$repr = [\get_class($this).'('.implode(', ',
$attributes)];
if (\count($this->nodes)) {
foreach ($this->nodes as $name => $node) {
$len = \strlen($name) + 4;
$noderepr = [];
foreach (explode("\n", (string) $node) as $line)
{
$noderepr[] = str_repeat(' ', $len).$line;
}
$repr[] = sprintf(' %s: %s', $name,
ltrim(implode("\n", $noderepr)));
}
$repr[] = ')';
} else {
$repr[0] .= ')';
}
return implode("\n", $repr);
}
/**
* @deprecated since 1.16.1 (to be removed in 2.0)
*/
public function toXml($asDom = false)
{
@trigger_error(sprintf('%s is deprecated since version 1.16.1
and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED);
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$dom->appendChild($xml =
$dom->createElement('twig'));
$xml->appendChild($node =
$dom->createElement('node'));
$node->setAttribute('class', \get_class($this));
foreach ($this->attributes as $name => $value) {
$node->appendChild($attribute =
$dom->createElement('attribute'));
$attribute->setAttribute('name', $name);
$attribute->appendChild($dom->createTextNode($value));
}
foreach ($this->nodes as $name => $n) {
if (null === $n) {
continue;
}
$child =
$n->toXml(true)->getElementsByTagName('node')->item(0);
$child = $dom->importNode($child, true);
$child->setAttribute('name', $name);
$node->appendChild($child);
}
return $asDom ? $dom : $dom->saveXML();
}
public function compile(Compiler $compiler)
{
foreach ($this->nodes as $node) {
$node->compile($compiler);
}
}
public function getTemplateLine()
{
return $this->lineno;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getLine()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0. Use
getTemplateLine() instead.', E_USER_DEPRECATED);
return $this->lineno;
}
public function getNodeTag()
{
return $this->tag;
}
/**
* @return bool
*/
public function hasAttribute($name)
{
return \array_key_exists($name, $this->attributes);
}
/**
* @return mixed
*/
public function getAttribute($name)
{
if (!\array_key_exists($name, $this->attributes)) {
throw new \LogicException(sprintf('Attribute
"%s" does not exist for Node "%s".', $name,
\get_class($this)));
}
return $this->attributes[$name];
}
/**
* @param string $name
* @param mixed $value
*/
public function setAttribute($name, $value)
{
$this->attributes[$name] = $value;
}
public function removeAttribute($name)
{
unset($this->attributes[$name]);
}
/**
* @return bool
*/
public function hasNode($name)
{
return \array_key_exists($name, $this->nodes);
}
/**
* @return Node
*/
public function getNode($name)
{
if (!\array_key_exists($name, $this->nodes)) {
throw new \LogicException(sprintf('Node "%s"
does not exist for Node "%s".', $name, \get_class($this)));
}
return $this->nodes[$name];
}
public function setNode($name, $node = null)
{
if (!$node instanceof \Twig_NodeInterface) {
@trigger_error(sprintf('Using "%s" for the value
of node "%s" of "%s" is deprecated since version 1.25
and will be removed in 2.0.', \is_object($node) ? \get_class($node) :
(null === $node ? 'null' : \gettype($node)), $name,
\get_class($this)), E_USER_DEPRECATED);
}
$this->nodes[$name] = $node;
}
public function removeNode($name)
{
unset($this->nodes[$name]);
}
public function count()
{
return \count($this->nodes);
}
public function getIterator()
{
return new \ArrayIterator($this->nodes);
}
public function setTemplateName($name)
{
$this->name = $name;
foreach ($this->nodes as $node) {
if (null !== $node) {
$node->setTemplateName($name);
}
}
}
public function getTemplateName()
{
return $this->name;
}
public function setSourceContext(Source $source)
{
$this->sourceContext = $source;
foreach ($this->nodes as $node) {
if ($node instanceof Node) {
$node->setSourceContext($source);
}
}
}
public function getSourceContext()
{
return $this->sourceContext;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function setFilename($name)
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0. Use
setTemplateName() instead.', E_USER_DEPRECATED);
$this->setTemplateName($name);
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getFilename()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0. Use
getTemplateName() instead.', E_USER_DEPRECATED);
return $this->name;
}
}
class_alias('Twig\Node\Node', 'Twig_Node');
// Ensure that the aliased name is loaded to keep BC for classes
implementing the typehint with the old aliased name.
class_exists('Twig\Compiler');
PK-d�[��m��2vendor/twig/twig/src/Node/NodeCaptureInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
/**
* Represents a node that captures any nested displayable nodes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface NodeCaptureInterface
{
}
class_alias('Twig\Node\NodeCaptureInterface',
'Twig_NodeCaptureInterface');
PK-d�[
*����1vendor/twig/twig/src/Node/NodeOutputInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
/**
* Represents a displayable node in the AST.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface NodeOutputInterface
{
}
class_alias('Twig\Node\NodeOutputInterface',
'Twig_NodeOutputInterface');
PK-d�[�����'vendor/twig/twig/src/Node/PrintNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
/**
* Represents a node that outputs an expression.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class PrintNode extends Node implements NodeOutputInterface
{
public function __construct(AbstractExpression $expr, $lineno, $tag =
null)
{
parent::__construct(['expr' => $expr], [], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('echo ')
->subcompile($this->getNode('expr'))
->raw(";\n")
;
}
}
class_alias('Twig\Node\PrintNode', 'Twig_Node_Print');
PK-d�[;r8�//0vendor/twig/twig/src/Node/SandboxedPrintNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
/**
* Adds a check for the __toString() method when the variable is an object
and the sandbox is activated.
*
* When there is a simple Print statement, like {{ article }},
* and if the sandbox is enabled, we need to check that the __toString()
* method is allowed if 'article' is an object.
*
* Not used anymore, to be deprecated in 2.x and removed in 3.0
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SandboxedPrintNode extends PrintNode
{
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('echo ')
;
$expr = $this->getNode('expr');
if ($expr instanceof ConstantExpression) {
$compiler
->subcompile($expr)
->raw(";\n")
;
} else {
$compiler
->write('$this->env->getExtension(\'\Twig\Extension\SandboxExtension\')->ensureToStringAllowed(')
->subcompile($expr)
->raw(");\n")
;
}
}
/**
* Removes node filters.
*
* This is mostly needed when another visitor adds filters (like the
escaper one).
*
* @return Node
*/
protected function removeNodeFilter(Node $node)
{
if ($node instanceof FilterExpression) {
return
$this->removeNodeFilter($node->getNode('node'));
}
return $node;
}
}
class_alias('Twig\Node\SandboxedPrintNode',
'Twig_Node_SandboxedPrint');
PK-d�[���j��)vendor/twig/twig/src/Node/SandboxNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a sandbox node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SandboxNode extends Node
{
public function __construct(\Twig_NodeInterface $body, $lineno, $tag =
null)
{
parent::__construct(['body' => $body], [], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write("if (!\$alreadySandboxed =
\$this->sandbox->isSandboxed()) {\n")
->indent()
->write("\$this->sandbox->enableSandbox();\n")
->outdent()
->write("}\n")
->subcompile($this->getNode('body'))
->write("if (!\$alreadySandboxed) {\n")
->indent()
->write("\$this->sandbox->disableSandbox();\n")
->outdent()
->write("}\n")
;
}
}
class_alias('Twig\Node\SandboxNode',
'Twig_Node_Sandbox');
PK-d�[�(�|g
g
%vendor/twig/twig/src/Node/SetNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
use Twig\Node\Expression\ConstantExpression;
/**
* Represents a set node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SetNode extends Node implements NodeCaptureInterface
{
public function __construct($capture, \Twig_NodeInterface $names,
\Twig_NodeInterface $values, $lineno, $tag = null)
{
parent::__construct(['names' => $names,
'values' => $values], ['capture' => $capture,
'safe' => false], $lineno, $tag);
/*
* Optimizes the node when capture is used for a large block of
text.
*
* {% set foo %}foo{% endset %} is compiled to
$context['foo'] = new Twig\Markup("foo");
*/
if ($this->getAttribute('capture')) {
$this->setAttribute('safe', true);
$values = $this->getNode('values');
if ($values instanceof TextNode) {
$this->setNode('values', new
ConstantExpression($values->getAttribute('data'),
$values->getTemplateLine()));
$this->setAttribute('capture', false);
}
}
}
public function compile(Compiler $compiler)
{
$compiler->addDebugInfo($this);
if (\count($this->getNode('names')) > 1) {
$compiler->write('list(');
foreach ($this->getNode('names') as $idx =>
$node) {
if ($idx) {
$compiler->raw(', ');
}
$compiler->subcompile($node);
}
$compiler->raw(')');
} else {
if ($this->getAttribute('capture')) {
if ($compiler->getEnvironment()->isDebug()) {
$compiler->write("ob_start();\n");
} else {
$compiler->write("ob_start(function () { return
''; });\n");
}
$compiler
->subcompile($this->getNode('values'))
;
}
$compiler->subcompile($this->getNode('names'),
false);
if ($this->getAttribute('capture')) {
$compiler->raw(" = ('' === \$tmp =
ob_get_clean()) ? '' : new Markup(\$tmp,
\$this->env->getCharset())");
}
}
if (!$this->getAttribute('capture')) {
$compiler->raw(' = ');
if (\count($this->getNode('names')) > 1) {
$compiler->write('[');
foreach ($this->getNode('values') as $idx
=> $value) {
if ($idx) {
$compiler->raw(', ');
}
$compiler->subcompile($value);
}
$compiler->raw(']');
} else {
if ($this->getAttribute('safe')) {
$compiler
->raw("('' === \$tmp = ")
->subcompile($this->getNode('values'))
->raw(") ? '' : new Markup(\$tmp,
\$this->env->getCharset())")
;
} else {
$compiler->subcompile($this->getNode('values'));
}
}
}
$compiler->raw(";\n");
}
}
class_alias('Twig\Node\SetNode', 'Twig_Node_Set');
PK-d�[�~`-��)vendor/twig/twig/src/Node/SetTempNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* @internal
*/
class SetTempNode extends Node
{
public function __construct($name, $lineno)
{
parent::__construct([], ['name' => $name], $lineno);
}
public function compile(Compiler $compiler)
{
$name = $this->getAttribute('name');
$compiler
->addDebugInfo($this)
->write('if (isset($context[')
->string($name)
->raw('])) { $_')
->raw($name)
->raw('_ = $context[')
->repr($name)
->raw(']; } else { $_')
->raw($name)
->raw("_ = null; }\n")
;
}
}
class_alias('Twig\Node\SetTempNode',
'Twig_Node_SetTemp');
PK-d�[��$�kk+vendor/twig/twig/src/Node/SpacelessNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a spaceless node.
*
* It removes spaces between HTML tags.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SpacelessNode extends Node
{
public function __construct(\Twig_NodeInterface $body, $lineno, $tag =
'spaceless')
{
parent::__construct(['body' => $body], [], $lineno,
$tag);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
;
if ($compiler->getEnvironment()->isDebug()) {
$compiler->write("ob_start();\n");
} else {
$compiler->write("ob_start(function () { return
''; });\n");
}
$compiler
->subcompile($this->getNode('body'))
->write("echo
trim(preg_replace('/>\s+</', '><',
ob_get_clean()));\n")
;
}
}
class_alias('Twig\Node\SpacelessNode',
'Twig_Node_Spaceless');
PK-d�[�e:422&vendor/twig/twig/src/Node/TextNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a text node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TextNode extends Node implements NodeOutputInterface
{
public function __construct($data, $lineno)
{
parent::__construct([], ['data' => $data], $lineno);
}
public function compile(Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('echo ')
->string($this->getAttribute('data'))
->raw(";\n")
;
}
}
class_alias('Twig\Node\TextNode', 'Twig_Node_Text');
PK-d�[�e ��&vendor/twig/twig/src/Node/WithNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* Represents a nested "with" scope.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class WithNode extends Node
{
public function __construct(Node $body, Node $variables = null, $only =
false, $lineno, $tag = null)
{
$nodes = ['body' => $body];
if (null !== $variables) {
$nodes['variables'] = $variables;
}
parent::__construct($nodes, ['only' => (bool) $only],
$lineno, $tag);
}
public function compile(Compiler $compiler)
{
$compiler->addDebugInfo($this);
if ($this->hasNode('variables')) {
$node = $this->getNode('variables');
$varsName = $compiler->getVarName();
$compiler
->write(sprintf('$%s = ', $varsName))
->subcompile($node)
->raw(";\n")
->write(sprintf("if (!twig_test_iterable(\$%s))
{\n", $varsName))
->indent()
->write("throw new RuntimeError('Variables
passed to the \"with\" tag must be a hash.', ")
->repr($node->getTemplateLine())
->raw(", \$this->getSourceContext());\n")
->outdent()
->write("}\n")
->write(sprintf("\$%s =
twig_to_array(\$%s);\n", $varsName, $varsName))
;
if ($this->getAttribute('only')) {
$compiler->write("\$context = ['_parent'
=> \$context];\n");
} else {
$compiler->write("\$context['_parent'] =
\$context;\n");
}
$compiler->write(sprintf("\$context =
\$this->env->mergeGlobals(array_merge(\$context, \$%s));\n",
$varsName));
} else {
$compiler->write("\$context['_parent'] =
\$context;\n");
}
$compiler
->subcompile($this->getNode('body'))
->write("\$context =
\$context['_parent'];\n")
;
}
}
class_alias('Twig\Node\WithNode', 'Twig_Node_With');
PK-d�[��v&
&vendor/twig/twig/src/NodeTraverser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\NodeVisitor\NodeVisitorInterface;
/**
* A node traverser.
*
* It visits all nodes and their children and calls the given visitor for
each.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class NodeTraverser
{
protected $env;
protected $visitors = [];
/**
* @param NodeVisitorInterface[] $visitors
*/
public function __construct(Environment $env, array $visitors = [])
{
$this->env = $env;
foreach ($visitors as $visitor) {
$this->addVisitor($visitor);
}
}
public function addVisitor(NodeVisitorInterface $visitor)
{
$this->visitors[$visitor->getPriority()][] = $visitor;
}
/**
* Traverses a node and calls the registered visitors.
*
* @return \Twig_NodeInterface
*/
public function traverse(\Twig_NodeInterface $node)
{
ksort($this->visitors);
foreach ($this->visitors as $visitors) {
foreach ($visitors as $visitor) {
$node = $this->traverseForVisitor($visitor, $node);
}
}
return $node;
}
protected function traverseForVisitor(NodeVisitorInterface $visitor,
\Twig_NodeInterface $node = null)
{
if (null === $node) {
return;
}
$node = $visitor->enterNode($node, $this->env);
foreach ($node as $k => $n) {
if (null === $n) {
continue;
}
if (false !== ($m = $this->traverseForVisitor($visitor, $n))
&& null !== $m) {
if ($m !== $n) {
$node->setNode($k, $m);
}
} else {
$node->removeNode($k);
}
}
return $visitor->leaveNode($node, $this->env);
}
}
class_alias('Twig\NodeTraverser',
'Twig_NodeTraverser');
PK-d�[���#118vendor/twig/twig/src/NodeVisitor/AbstractNodeVisitor.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\NodeVisitor;
use Twig\Environment;
use Twig\Node\Node;
/**
* Used to make node visitors compatible with Twig 1.x and 2.x.
*
* To be removed in Twig 3.1.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class AbstractNodeVisitor implements NodeVisitorInterface
{
final public function enterNode(\Twig_NodeInterface $node, Environment
$env)
{
if (!$node instanceof Node) {
throw new \LogicException(sprintf('%s only supports
\Twig\Node\Node instances.', __CLASS__));
}
return $this->doEnterNode($node, $env);
}
final public function leaveNode(\Twig_NodeInterface $node, Environment
$env)
{
if (!$node instanceof Node) {
throw new \LogicException(sprintf('%s only supports
\Twig\Node\Node instances.', __CLASS__));
}
return $this->doLeaveNode($node, $env);
}
/**
* Called before child nodes are visited.
*
* @return Node The modified node
*/
abstract protected function doEnterNode(Node $node, Environment $env);
/**
* Called after child nodes are visited.
*
* @return Node|false|null The modified node or null if the node must
be removed
*/
abstract protected function doLeaveNode(Node $node, Environment $env);
}
class_alias('Twig\NodeVisitor\AbstractNodeVisitor',
'Twig_BaseNodeVisitor');
PK-d�[��,,7vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\NodeVisitor;
use Twig\Environment;
use Twig\Node\AutoEscapeNode;
use Twig\Node\BlockNode;
use Twig\Node\BlockReferenceNode;
use Twig\Node\DoNode;
use Twig\Node\Expression\ConditionalExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\InlinePrint;
use Twig\Node\ImportNode;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\NodeTraverser;
/**
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class EscaperNodeVisitor extends AbstractNodeVisitor
{
protected $statusStack = [];
protected $blocks = [];
protected $safeAnalysis;
protected $traverser;
protected $defaultStrategy = false;
protected $safeVars = [];
public function __construct()
{
$this->safeAnalysis = new SafeAnalysisNodeVisitor();
}
protected function doEnterNode(Node $node, Environment $env)
{
if ($node instanceof ModuleNode) {
if
($env->hasExtension('\Twig\Extension\EscaperExtension')
&& $defaultStrategy =
$env->getExtension('\Twig\Extension\EscaperExtension')->getDefaultStrategy($node->getTemplateName()))
{
$this->defaultStrategy = $defaultStrategy;
}
$this->safeVars = [];
$this->blocks = [];
} elseif ($node instanceof AutoEscapeNode) {
$this->statusStack[] =
$node->getAttribute('value');
} elseif ($node instanceof BlockNode) {
$this->statusStack[] =
isset($this->blocks[$node->getAttribute('name')]) ?
$this->blocks[$node->getAttribute('name')] :
$this->needEscaping($env);
} elseif ($node instanceof ImportNode) {
$this->safeVars[] =
$node->getNode('var')->getAttribute('name');
}
return $node;
}
protected function doLeaveNode(Node $node, Environment $env)
{
if ($node instanceof ModuleNode) {
$this->defaultStrategy = false;
$this->safeVars = [];
$this->blocks = [];
} elseif ($node instanceof FilterExpression) {
return $this->preEscapeFilterNode($node, $env);
} elseif ($node instanceof PrintNode && false !== $type =
$this->needEscaping($env)) {
$expression = $node->getNode('expr');
if ($expression instanceof ConditionalExpression &&
$this->shouldUnwrapConditional($expression, $env, $type)) {
return new DoNode($this->unwrapConditional($expression,
$env, $type), $expression->getTemplateLine());
}
return $this->escapePrintNode($node, $env, $type);
}
if ($node instanceof AutoEscapeNode || $node instanceof BlockNode)
{
array_pop($this->statusStack);
} elseif ($node instanceof BlockReferenceNode) {
$this->blocks[$node->getAttribute('name')] =
$this->needEscaping($env);
}
return $node;
}
private function shouldUnwrapConditional(ConditionalExpression
$expression, Environment $env, $type)
{
$expr2Safe = $this->isSafeFor($type,
$expression->getNode('expr2'), $env);
$expr3Safe = $this->isSafeFor($type,
$expression->getNode('expr3'), $env);
return $expr2Safe !== $expr3Safe;
}
private function unwrapConditional(ConditionalExpression $expression,
Environment $env, $type)
{
// convert "echo a ? b : c" to "a ? echo b : echo
c" recursively
$expr2 = $expression->getNode('expr2');
if ($expr2 instanceof ConditionalExpression &&
$this->shouldUnwrapConditional($expr2, $env, $type)) {
$expr2 = $this->unwrapConditional($expr2, $env, $type);
} else {
$expr2 = $this->escapeInlinePrintNode(new
InlinePrint($expr2, $expr2->getTemplateLine()), $env, $type);
}
$expr3 = $expression->getNode('expr3');
if ($expr3 instanceof ConditionalExpression &&
$this->shouldUnwrapConditional($expr3, $env, $type)) {
$expr3 = $this->unwrapConditional($expr3, $env, $type);
} else {
$expr3 = $this->escapeInlinePrintNode(new
InlinePrint($expr3, $expr3->getTemplateLine()), $env, $type);
}
return new
ConditionalExpression($expression->getNode('expr1'), $expr2,
$expr3, $expression->getTemplateLine());
}
private function escapeInlinePrintNode(InlinePrint $node, Environment
$env, $type)
{
$expression = $node->getNode('node');
if ($this->isSafeFor($type, $expression, $env)) {
return $node;
}
return new InlinePrint($this->getEscaperFilter($type,
$expression), $node->getTemplateLine());
}
protected function escapePrintNode(PrintNode $node, Environment $env,
$type)
{
if (false === $type) {
return $node;
}
$expression = $node->getNode('expr');
if ($this->isSafeFor($type, $expression, $env)) {
return $node;
}
$class = \get_class($node);
return new $class($this->getEscaperFilter($type, $expression),
$node->getTemplateLine());
}
protected function preEscapeFilterNode(FilterExpression $filter,
Environment $env)
{
$name =
$filter->getNode('filter')->getAttribute('value');
$type = $env->getFilter($name)->getPreEscape();
if (null === $type) {
return $filter;
}
$node = $filter->getNode('node');
if ($this->isSafeFor($type, $node, $env)) {
return $filter;
}
$filter->setNode('node',
$this->getEscaperFilter($type, $node));
return $filter;
}
protected function isSafeFor($type, \Twig_NodeInterface $expression,
$env)
{
$safe = $this->safeAnalysis->getSafe($expression);
if (null === $safe) {
if (null === $this->traverser) {
$this->traverser = new NodeTraverser($env,
[$this->safeAnalysis]);
}
$this->safeAnalysis->setSafeVars($this->safeVars);
$this->traverser->traverse($expression);
$safe = $this->safeAnalysis->getSafe($expression);
}
return \in_array($type, $safe) || \in_array('all',
$safe);
}
protected function needEscaping(Environment $env)
{
if (\count($this->statusStack)) {
return $this->statusStack[\count($this->statusStack) -
1];
}
return $this->defaultStrategy ? $this->defaultStrategy :
false;
}
protected function getEscaperFilter($type, \Twig_NodeInterface $node)
{
$line = $node->getTemplateLine();
$name = new ConstantExpression('escape', $line);
$args = new Node([new ConstantExpression((string) $type, $line),
new ConstantExpression(null, $line), new ConstantExpression(true, $line)]);
return new FilterExpression($node, $name, $args, $line);
}
public function getPriority()
{
return 0;
}
}
class_alias('Twig\NodeVisitor\EscaperNodeVisitor',
'Twig_NodeVisitor_Escaper');
PK-d�[&� �9vendor/twig/twig/src/NodeVisitor/NodeVisitorInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\NodeVisitor;
use Twig\Environment;
/**
* Interface for node visitor classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface NodeVisitorInterface
{
/**
* Called before child nodes are visited.
*
* @return \Twig_NodeInterface The modified node
*/
public function enterNode(\Twig_NodeInterface $node, Environment $env);
/**
* Called after child nodes are visited.
*
* @return \Twig_NodeInterface|false|null The modified node or null if
the node must be removed
*/
public function leaveNode(\Twig_NodeInterface $node, Environment $env);
/**
* Returns the priority for this visitor.
*
* Priority should be between -10 and 10 (0 is the default).
*
* @return int The priority level
*/
public function getPriority();
}
class_alias('Twig\NodeVisitor\NodeVisitorInterface',
'Twig_NodeVisitorInterface');
// Ensure that the aliased name is loaded to keep BC for classes
implementing the typehint with the old aliased name.
class_exists('Twig\Environment');
PK-d�[6$�"�"9vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\NodeVisitor;
use Twig\Environment;
use Twig\Node\BlockReferenceNode;
use Twig\Node\BodyNode;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\BlockReferenceExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\ParentExpression;
use Twig\Node\Expression\TempNameExpression;
use Twig\Node\ForNode;
use Twig\Node\IncludeNode;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Node\SetTempNode;
/**
* Tries to optimize the AST.
*
* This visitor is always the last registered one.
*
* You can configure which optimizations you want to activate via the
* optimizer mode.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class OptimizerNodeVisitor extends AbstractNodeVisitor
{
const OPTIMIZE_ALL = -1;
const OPTIMIZE_NONE = 0;
const OPTIMIZE_FOR = 2;
const OPTIMIZE_RAW_FILTER = 4;
const OPTIMIZE_VAR_ACCESS = 8;
protected $loops = [];
protected $loopsTargets = [];
protected $optimizers;
protected $prependedNodes = [];
protected $inABody = false;
/**
* @param int $optimizers The optimizer mode
*/
public function __construct($optimizers = -1)
{
if (!\is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR |
self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
throw new \InvalidArgumentException(sprintf('Optimizer
mode "%s" is not valid.', $optimizers));
}
$this->optimizers = $optimizers;
}
protected function doEnterNode(Node $node, Environment $env)
{
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR &
$this->optimizers)) {
$this->enterOptimizeFor($node, $env);
}
if (\PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS
=== (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) &&
!$env->isStrictVariables() &&
!$env->hasExtension('\Twig\Extension\SandboxExtension')) {
if ($this->inABody) {
if (!$node instanceof AbstractExpression) {
if ('Twig_Node' !== \get_class($node)) {
array_unshift($this->prependedNodes, []);
}
} else {
$node = $this->optimizeVariables($node, $env);
}
} elseif ($node instanceof BodyNode) {
$this->inABody = true;
}
}
return $node;
}
protected function doLeaveNode(Node $node, Environment $env)
{
$expression = $node instanceof AbstractExpression;
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR &
$this->optimizers)) {
$this->leaveOptimizeFor($node, $env);
}
if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER &
$this->optimizers)) {
$node = $this->optimizeRawFilter($node, $env);
}
$node = $this->optimizePrintNode($node, $env);
if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS &
$this->optimizers) && !$env->isStrictVariables() &&
!$env->hasExtension('\Twig\Extension\SandboxExtension')) {
if ($node instanceof BodyNode) {
$this->inABody = false;
} elseif ($this->inABody) {
if (!$expression && 'Twig_Node' !==
\get_class($node) && $prependedNodes =
array_shift($this->prependedNodes)) {
$nodes = [];
foreach (array_unique($prependedNodes) as $name) {
$nodes[] = new SetTempNode($name,
$node->getTemplateLine());
}
$nodes[] = $node;
$node = new Node($nodes);
}
}
}
return $node;
}
protected function optimizeVariables(\Twig_NodeInterface $node,
Environment $env)
{
if ('Twig_Node_Expression_Name' === \get_class($node)
&& $node->isSimple()) {
$this->prependedNodes[0][] =
$node->getAttribute('name');
return new
TempNameExpression($node->getAttribute('name'),
$node->getTemplateLine());
}
return $node;
}
/**
* Optimizes print nodes.
*
* It replaces:
*
* * "echo $this->render(Parent)Block()" with
"$this->display(Parent)Block()"
*
* @return \Twig_NodeInterface
*/
protected function optimizePrintNode(\Twig_NodeInterface $node,
Environment $env)
{
if (!$node instanceof PrintNode) {
return $node;
}
$exprNode = $node->getNode('expr');
if (
$exprNode instanceof BlockReferenceExpression ||
$exprNode instanceof ParentExpression
) {
$exprNode->setAttribute('output', true);
return $exprNode;
}
return $node;
}
/**
* Removes "raw" filters.
*
* @return \Twig_NodeInterface
*/
protected function optimizeRawFilter(\Twig_NodeInterface $node,
Environment $env)
{
if ($node instanceof FilterExpression && 'raw' ==
$node->getNode('filter')->getAttribute('value'))
{
return $node->getNode('node');
}
return $node;
}
/**
* Optimizes "for" tag by removing the "loop"
variable creation whenever possible.
*/
protected function enterOptimizeFor(\Twig_NodeInterface $node,
Environment $env)
{
if ($node instanceof ForNode) {
// disable the loop variable by default
$node->setAttribute('with_loop', false);
array_unshift($this->loops, $node);
array_unshift($this->loopsTargets,
$node->getNode('value_target')->getAttribute('name'));
array_unshift($this->loopsTargets,
$node->getNode('key_target')->getAttribute('name'));
} elseif (!$this->loops) {
// we are outside a loop
return;
}
// when do we need to add the loop variable back?
// the loop variable is referenced for the current loop
elseif ($node instanceof NameExpression && 'loop'
=== $node->getAttribute('name')) {
$node->setAttribute('always_defined', true);
$this->addLoopToCurrent();
}
// optimize access to loop targets
elseif ($node instanceof NameExpression &&
\in_array($node->getAttribute('name'),
$this->loopsTargets)) {
$node->setAttribute('always_defined', true);
}
// block reference
elseif ($node instanceof BlockReferenceNode || $node instanceof
BlockReferenceExpression) {
$this->addLoopToCurrent();
}
// include without the only attribute
elseif ($node instanceof IncludeNode &&
!$node->getAttribute('only')) {
$this->addLoopToAll();
}
// include function without the with_context=false parameter
elseif ($node instanceof FunctionExpression
&& 'include' ===
$node->getAttribute('name')
&&
(!$node->getNode('arguments')->hasNode('with_context')
|| false !==
$node->getNode('arguments')->getNode('with_context')->getAttribute('value')
)
) {
$this->addLoopToAll();
}
// the loop variable is referenced via an attribute
elseif ($node instanceof GetAttrExpression
&& (!$node->getNode('attribute')
instanceof ConstantExpression
|| 'parent' ===
$node->getNode('attribute')->getAttribute('value')
)
&& (true ===
$this->loops[0]->getAttribute('with_loop')
|| ($node->getNode('node') instanceof
NameExpression
&& 'loop' ===
$node->getNode('node')->getAttribute('name')
)
)
) {
$this->addLoopToAll();
}
}
/**
* Optimizes "for" tag by removing the "loop"
variable creation whenever possible.
*/
protected function leaveOptimizeFor(\Twig_NodeInterface $node,
Environment $env)
{
if ($node instanceof ForNode) {
array_shift($this->loops);
array_shift($this->loopsTargets);
array_shift($this->loopsTargets);
}
}
protected function addLoopToCurrent()
{
$this->loops[0]->setAttribute('with_loop', true);
}
protected function addLoopToAll()
{
foreach ($this->loops as $loop) {
$loop->setAttribute('with_loop', true);
}
}
public function getPriority()
{
return 255;
}
}
class_alias('Twig\NodeVisitor\OptimizerNodeVisitor',
'Twig_NodeVisitor_Optimizer');
PK-d�[p�<vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\NodeVisitor;
use Twig\Environment;
use Twig\Node\Expression\BlockReferenceExpression;
use Twig\Node\Expression\ConditionalExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\MethodCallExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\ParentExpression;
use Twig\Node\Node;
/**
* @final
*/
class SafeAnalysisNodeVisitor extends AbstractNodeVisitor
{
protected $data = [];
protected $safeVars = [];
public function setSafeVars($safeVars)
{
$this->safeVars = $safeVars;
}
public function getSafe(\Twig_NodeInterface $node)
{
$hash = spl_object_hash($node);
if (!isset($this->data[$hash])) {
return;
}
foreach ($this->data[$hash] as $bucket) {
if ($bucket['key'] !== $node) {
continue;
}
if (\in_array('html_attr',
$bucket['value'])) {
$bucket['value'][] = 'html';
}
return $bucket['value'];
}
}
protected function setSafe(\Twig_NodeInterface $node, array $safe)
{
$hash = spl_object_hash($node);
if (isset($this->data[$hash])) {
foreach ($this->data[$hash] as &$bucket) {
if ($bucket['key'] === $node) {
$bucket['value'] = $safe;
return;
}
}
}
$this->data[$hash][] = [
'key' => $node,
'value' => $safe,
];
}
protected function doEnterNode(Node $node, Environment $env)
{
return $node;
}
protected function doLeaveNode(Node $node, Environment $env)
{
if ($node instanceof ConstantExpression) {
// constants are marked safe for all
$this->setSafe($node, ['all']);
} elseif ($node instanceof BlockReferenceExpression) {
// blocks are safe by definition
$this->setSafe($node, ['all']);
} elseif ($node instanceof ParentExpression) {
// parent block is safe by definition
$this->setSafe($node, ['all']);
} elseif ($node instanceof ConditionalExpression) {
// intersect safeness of both operands
$safe =
$this->intersectSafe($this->getSafe($node->getNode('expr2')),
$this->getSafe($node->getNode('expr3')));
$this->setSafe($node, $safe);
} elseif ($node instanceof FilterExpression) {
// filter expression is safe when the filter is safe
$name =
$node->getNode('filter')->getAttribute('value');
$args = $node->getNode('arguments');
if (false !== $filter = $env->getFilter($name)) {
$safe = $filter->getSafe($args);
if (null === $safe) {
$safe =
$this->intersectSafe($this->getSafe($node->getNode('node')),
$filter->getPreservesSafety());
}
$this->setSafe($node, $safe);
} else {
$this->setSafe($node, []);
}
} elseif ($node instanceof FunctionExpression) {
// function expression is safe when the function is safe
$name = $node->getAttribute('name');
$args = $node->getNode('arguments');
$function = $env->getFunction($name);
if (false !== $function) {
$this->setSafe($node, $function->getSafe($args));
} else {
$this->setSafe($node, []);
}
} elseif ($node instanceof MethodCallExpression) {
if ($node->getAttribute('safe')) {
$this->setSafe($node, ['all']);
} else {
$this->setSafe($node, []);
}
} elseif ($node instanceof GetAttrExpression &&
$node->getNode('node') instanceof NameExpression) {
$name =
$node->getNode('node')->getAttribute('name');
// attributes on template instances are safe
if ('_self' == $name || \in_array($name,
$this->safeVars)) {
$this->setSafe($node, ['all']);
} else {
$this->setSafe($node, []);
}
} else {
$this->setSafe($node, []);
}
return $node;
}
protected function intersectSafe(array $a = null, array $b = null)
{
if (null === $a || null === $b) {
return [];
}
if (\in_array('all', $a)) {
return $b;
}
if (\in_array('all', $b)) {
return $a;
}
return array_intersect($a, $b);
}
public function getPriority()
{
return 0;
}
}
class_alias('Twig\NodeVisitor\SafeAnalysisNodeVisitor',
'Twig_NodeVisitor_SafeAnalysis');
PK-d�[��w��7vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\NodeVisitor;
use Twig\Environment;
use Twig\Node\CheckSecurityNode;
use Twig\Node\CheckToStringNode;
use Twig\Node\Expression\Binary\ConcatBinary;
use Twig\Node\Expression\Binary\RangeBinary;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Node\SetNode;
/**
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SandboxNodeVisitor extends AbstractNodeVisitor
{
protected $inAModule = false;
protected $tags;
protected $filters;
protected $functions;
private $needsToStringWrap = false;
protected function doEnterNode(Node $node, Environment $env)
{
if ($node instanceof ModuleNode) {
$this->inAModule = true;
$this->tags = [];
$this->filters = [];
$this->functions = [];
return $node;
} elseif ($this->inAModule) {
// look for tags
if ($node->getNodeTag() &&
!isset($this->tags[$node->getNodeTag()])) {
$this->tags[$node->getNodeTag()] = $node;
}
// look for filters
if ($node instanceof FilterExpression &&
!isset($this->filters[$node->getNode('filter')->getAttribute('value')]))
{
$this->filters[$node->getNode('filter')->getAttribute('value')]
= $node;
}
// look for functions
if ($node instanceof FunctionExpression &&
!isset($this->functions[$node->getAttribute('name')])) {
$this->functions[$node->getAttribute('name')] = $node;
}
// the .. operator is equivalent to the range() function
if ($node instanceof RangeBinary &&
!isset($this->functions['range'])) {
$this->functions['range'] = $node;
}
if ($node instanceof PrintNode) {
$this->needsToStringWrap = true;
$this->wrapNode($node, 'expr');
}
if ($node instanceof SetNode &&
!$node->getAttribute('capture')) {
$this->needsToStringWrap = true;
}
// wrap outer nodes that can implicitly call __toString()
if ($this->needsToStringWrap) {
if ($node instanceof ConcatBinary) {
$this->wrapNode($node, 'left');
$this->wrapNode($node, 'right');
}
if ($node instanceof FilterExpression) {
$this->wrapNode($node, 'node');
$this->wrapArrayNode($node, 'arguments');
}
if ($node instanceof FunctionExpression) {
$this->wrapArrayNode($node, 'arguments');
}
}
}
return $node;
}
protected function doLeaveNode(Node $node, Environment $env)
{
if ($node instanceof ModuleNode) {
$this->inAModule = false;
$node->getNode('constructor_end')->setNode('_security_check',
new Node([new CheckSecurityNode($this->filters, $this->tags,
$this->functions), $node->getNode('display_start')]));
} elseif ($this->inAModule) {
if ($node instanceof PrintNode || $node instanceof SetNode) {
$this->needsToStringWrap = false;
}
}
return $node;
}
private function wrapNode(Node $node, $name)
{
$expr = $node->getNode($name);
if ($expr instanceof NameExpression || $expr instanceof
GetAttrExpression) {
$node->setNode($name, new CheckToStringNode($expr));
}
}
private function wrapArrayNode(Node $node, $name)
{
$args = $node->getNode($name);
foreach ($args as $name => $_) {
$this->wrapNode($args, $name);
}
}
public function getPriority()
{
return 0;
}
}
class_alias('Twig\NodeVisitor\SandboxNodeVisitor',
'Twig_NodeVisitor_Sandbox');
PK-d�[(�lt�5�5vendor/twig/twig/src/Parser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Error\SyntaxError;
use Twig\Node\BlockNode;
use Twig\Node\BlockReferenceNode;
use Twig\Node\BodyNode;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\MacroNode;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Node\NodeCaptureInterface;
use Twig\Node\NodeOutputInterface;
use Twig\Node\PrintNode;
use Twig\Node\TextNode;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
/**
* Default parser implementation.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Parser implements \Twig_ParserInterface
{
protected $stack = [];
protected $stream;
protected $parent;
protected $handlers;
protected $visitors;
protected $expressionParser;
protected $blocks;
protected $blockStack;
protected $macros;
protected $env;
protected $reservedMacroNames;
protected $importedSymbols;
protected $traits;
protected $embeddedTemplates = [];
private $varNameSalt = 0;
public function __construct(Environment $env)
{
$this->env = $env;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getEnvironment()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0.',
E_USER_DEPRECATED);
return $this->env;
}
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256',
__METHOD__.$this->stream->getSourceContext()->getCode().$this->varNameSalt++));
}
/**
* @deprecated since 1.27 (to be removed in 2.0). Use
$parser->getStream()->getSourceContext()->getPath() instead.
*/
public function getFilename()
{
@trigger_error(sprintf('The "%s" method is
deprecated since version 1.27 and will be removed in 2.0. Use
$parser->getStream()->getSourceContext()->getPath()
instead.', __METHOD__), E_USER_DEPRECATED);
return $this->stream->getSourceContext()->getName();
}
public function parse(TokenStream $stream, $test = null, $dropNeedle =
false)
{
// push all variables into the stack to keep the current state of
the parser
// using get_object_vars() instead of foreach would lead to
https://bugs.php.net/71336
// This hack can be removed when min version if PHP 7.0
$vars = [];
foreach ($this as $k => $v) {
$vars[$k] = $v;
}
unset($vars['stack'], $vars['env'],
$vars['handlers'], $vars['visitors'],
$vars['expressionParser'],
$vars['reservedMacroNames']);
$this->stack[] = $vars;
// tag handlers
if (null === $this->handlers) {
$this->handlers = $this->env->getTokenParsers();
$this->handlers->setParser($this);
}
// node visitors
if (null === $this->visitors) {
$this->visitors = $this->env->getNodeVisitors();
}
if (null === $this->expressionParser) {
$this->expressionParser = new ExpressionParser($this,
$this->env);
}
$this->stream = $stream;
$this->parent = null;
$this->blocks = [];
$this->macros = [];
$this->traits = [];
$this->blockStack = [];
$this->importedSymbols = [[]];
$this->embeddedTemplates = [];
$this->varNameSalt = 0;
try {
$body = $this->subparse($test, $dropNeedle);
if (null !== $this->parent && null === $body =
$this->filterBodyNodes($body)) {
$body = new Node();
}
} catch (SyntaxError $e) {
if (!$e->getSourceContext()) {
$e->setSourceContext($this->stream->getSourceContext());
}
if (!$e->getTemplateLine()) {
$e->setTemplateLine($this->stream->getCurrent()->getLine());
}
throw $e;
}
$node = new ModuleNode(new BodyNode([$body]), $this->parent, new
Node($this->blocks), new Node($this->macros), new
Node($this->traits), $this->embeddedTemplates,
$stream->getSourceContext());
$traverser = new NodeTraverser($this->env, $this->visitors);
$node = $traverser->traverse($node);
// restore previous stack so previous parse() call can resume
working
foreach (array_pop($this->stack) as $key => $val) {
$this->$key = $val;
}
return $node;
}
public function subparse($test, $dropNeedle = false)
{
$lineno = $this->getCurrentToken()->getLine();
$rv = [];
while (!$this->stream->isEOF()) {
switch ($this->getCurrentToken()->getType()) {
case Token::TEXT_TYPE:
$token = $this->stream->next();
$rv[] = new TextNode($token->getValue(),
$token->getLine());
break;
case Token::VAR_START_TYPE:
$token = $this->stream->next();
$expr =
$this->expressionParser->parseExpression();
$this->stream->expect(Token::VAR_END_TYPE);
$rv[] = new PrintNode($expr, $token->getLine());
break;
case Token::BLOCK_START_TYPE:
$this->stream->next();
$token = $this->getCurrentToken();
if (Token::NAME_TYPE !== $token->getType()) {
throw new SyntaxError('A block must start with
a tag name.', $token->getLine(),
$this->stream->getSourceContext());
}
if (null !== $test && \call_user_func($test,
$token)) {
if ($dropNeedle) {
$this->stream->next();
}
if (1 === \count($rv)) {
return $rv[0];
}
return new Node($rv, [], $lineno);
}
$subparser =
$this->handlers->getTokenParser($token->getValue());
if (null === $subparser) {
if (null !== $test) {
$e = new SyntaxError(sprintf('Unexpected
"%s" tag', $token->getValue()), $token->getLine(),
$this->stream->getSourceContext());
if (\is_array($test) && isset($test[0])
&& $test[0] instanceof TokenParserInterface) {
$e->appendMessage(sprintf('
(expecting closing tag for the "%s" tag defined near line
%s).', $test[0]->getTag(), $lineno));
}
} else {
$e = new SyntaxError(sprintf('Unknown
"%s" tag.', $token->getValue()), $token->getLine(),
$this->stream->getSourceContext());
$e->addSuggestions($token->getValue(),
array_keys($this->env->getTags()));
}
throw $e;
}
$this->stream->next();
$node = $subparser->parse($token);
if (null !== $node) {
$rv[] = $node;
}
break;
default:
throw new SyntaxError('Lexer or parser ended up in
unsupported state.', $this->getCurrentToken()->getLine(),
$this->stream->getSourceContext());
}
}
if (1 === \count($rv)) {
return $rv[0];
}
return new Node($rv, [], $lineno);
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function addHandler($name, $class)
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0.',
E_USER_DEPRECATED);
$this->handlers[$name] = $class;
}
/**
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function addNodeVisitor(NodeVisitorInterface $visitor)
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0.',
E_USER_DEPRECATED);
$this->visitors[] = $visitor;
}
public function getBlockStack()
{
return $this->blockStack;
}
public function peekBlockStack()
{
return isset($this->blockStack[\count($this->blockStack) -
1]) ? $this->blockStack[\count($this->blockStack) - 1] : null;
}
public function popBlockStack()
{
array_pop($this->blockStack);
}
public function pushBlockStack($name)
{
$this->blockStack[] = $name;
}
public function hasBlock($name)
{
return isset($this->blocks[$name]);
}
public function getBlock($name)
{
return $this->blocks[$name];
}
public function setBlock($name, BlockNode $value)
{
$this->blocks[$name] = new BodyNode([$value], [],
$value->getTemplateLine());
}
public function hasMacro($name)
{
return isset($this->macros[$name]);
}
public function setMacro($name, MacroNode $node)
{
if ($this->isReservedMacroName($name)) {
throw new SyntaxError(sprintf('"%s" cannot be
used as a macro name as it is a reserved keyword.', $name),
$node->getTemplateLine(), $this->stream->getSourceContext());
}
$this->macros[$name] = $node;
}
public function isReservedMacroName($name)
{
if (null === $this->reservedMacroNames) {
$this->reservedMacroNames = [];
$r = new
\ReflectionClass($this->env->getBaseTemplateClass());
foreach ($r->getMethods() as $method) {
$methodName = strtr($method->getName(),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz');
if ('get' === substr($methodName, 0, 3)
&& isset($methodName[3])) {
$this->reservedMacroNames[] = substr($methodName,
3);
}
}
}
return \in_array(strtr($name,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'), $this->reservedMacroNames);
}
public function addTrait($trait)
{
$this->traits[] = $trait;
}
public function hasTraits()
{
return \count($this->traits) > 0;
}
public function embedTemplate(ModuleNode $template)
{
$template->setIndex(mt_rand());
$this->embeddedTemplates[] = $template;
}
public function addImportedSymbol($type, $alias, $name = null,
AbstractExpression $node = null)
{
$this->importedSymbols[0][$type][$alias] = ['name'
=> $name, 'node' => $node];
}
public function getImportedSymbol($type, $alias)
{
if (null !== $this->peekBlockStack()) {
foreach ($this->importedSymbols as $functions) {
if (isset($functions[$type][$alias])) {
if (\count($this->blockStack) > 1) {
return null;
}
return $functions[$type][$alias];
}
}
} else {
return isset($this->importedSymbols[0][$type][$alias]) ?
$this->importedSymbols[0][$type][$alias] : null;
}
}
public function isMainScope()
{
return 1 === \count($this->importedSymbols);
}
public function pushLocalScope()
{
array_unshift($this->importedSymbols, []);
}
public function popLocalScope()
{
array_shift($this->importedSymbols);
}
/**
* @return ExpressionParser
*/
public function getExpressionParser()
{
return $this->expressionParser;
}
public function getParent()
{
return $this->parent;
}
public function setParent($parent)
{
$this->parent = $parent;
}
/**
* @return TokenStream
*/
public function getStream()
{
return $this->stream;
}
/**
* @return Token
*/
public function getCurrentToken()
{
return $this->stream->getCurrent();
}
protected function filterBodyNodes(\Twig_NodeInterface $node)
{
// check that the body does not contain non-empty output nodes
if (
($node instanceof TextNode &&
!ctype_space($node->getAttribute('data')))
||
(!$node instanceof TextNode && !$node instanceof
BlockReferenceNode && $node instanceof NodeOutputInterface)
) {
if (false !== strpos((string) $node,
\chr(0xEF).\chr(0xBB).\chr(0xBF))) {
$t = substr($node->getAttribute('data'), 3);
if ('' === $t || ctype_space($t)) {
// bypass empty nodes starting with a BOM
return;
}
}
throw new SyntaxError('A template that extends another one
cannot include content outside Twig blocks. Did you forget to put the
content inside a {% block %} tag?', $node->getTemplateLine(),
$this->stream->getSourceContext());
}
// bypass nodes that will "capture" the output
if ($node instanceof NodeCaptureInterface) {
return $node;
}
if ($node instanceof NodeOutputInterface) {
return;
}
foreach ($node as $k => $n) {
if (null !== $n && null ===
$this->filterBodyNodes($n)) {
$node->removeNode($k);
}
}
return $node;
}
}
class_alias('Twig\Parser', 'Twig_Parser');
PK-d�[F�����3vendor/twig/twig/src/Profiler/Dumper/BaseDumper.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler\Dumper;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class BaseDumper
{
private $root;
public function dump(Profile $profile)
{
return $this->dumpProfile($profile);
}
abstract protected function formatTemplate(Profile $profile, $prefix);
abstract protected function formatNonTemplate(Profile $profile,
$prefix);
abstract protected function formatTime(Profile $profile, $percent);
private function dumpProfile(Profile $profile, $prefix = '',
$sibling = false)
{
if ($profile->isRoot()) {
$this->root = $profile->getDuration();
$start = $profile->getName();
} else {
if ($profile->isTemplate()) {
$start = $this->formatTemplate($profile, $prefix);
} else {
$start = $this->formatNonTemplate($profile, $prefix);
}
$prefix .= $sibling ? '│ ' : ' ';
}
$percent = $this->root ? $profile->getDuration() /
$this->root * 100 : 0;
if ($profile->getDuration() * 1000 < 1) {
$str = $start."\n";
} else {
$str = sprintf("%s %s\n", $start,
$this->formatTime($profile, $percent));
}
$nCount = \count($profile->getProfiles());
foreach ($profile as $i => $p) {
$str .= $this->dumpProfile($p, $prefix, $i + 1 !== $nCount);
}
return $str;
}
}
class_alias('Twig\Profiler\Dumper\BaseDumper',
'Twig_Profiler_Dumper_Base');
PK-d�[6)P!8vendor/twig/twig/src/Profiler/Dumper/BlackfireDumper.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler\Dumper;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class BlackfireDumper
{
public function dump(Profile $profile)
{
$data = [];
$this->dumpProfile('main()', $profile, $data);
$this->dumpChildren('main()', $profile, $data);
$start = sprintf('%f', microtime(true));
$str = <<<EOF
file-format: BlackfireProbe
cost-dimensions: wt mu pmu
request-start: {$start}
EOF;
foreach ($data as $name => $values) {
$str .= "{$name}//{$values['ct']}
{$values['wt']} {$values['mu']}
{$values['pmu']}\n";
}
return $str;
}
private function dumpChildren($parent, Profile $profile, &$data)
{
foreach ($profile as $p) {
if ($p->isTemplate()) {
$name = $p->getTemplate();
} else {
$name = sprintf('%s::%s(%s)',
$p->getTemplate(), $p->getType(), $p->getName());
}
$this->dumpProfile(sprintf('%s==>%s', $parent,
$name), $p, $data);
$this->dumpChildren($name, $p, $data);
}
}
private function dumpProfile($edge, Profile $profile, &$data)
{
if (isset($data[$edge])) {
++$data[$edge]['ct'];
$data[$edge]['wt'] +=
floor($profile->getDuration() * 1000000);
$data[$edge]['mu'] += $profile->getMemoryUsage();
$data[$edge]['pmu'] +=
$profile->getPeakMemoryUsage();
} else {
$data[$edge] = [
'ct' => 1,
'wt' => floor($profile->getDuration() *
1000000),
'mu' => $profile->getMemoryUsage(),
'pmu' => $profile->getPeakMemoryUsage(),
];
}
}
}
class_alias('Twig\Profiler\Dumper\BlackfireDumper',
'Twig_Profiler_Dumper_Blackfire');
PK-d�[������3vendor/twig/twig/src/Profiler/Dumper/HtmlDumper.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler\Dumper;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class HtmlDumper extends BaseDumper
{
private static $colors = [
'block' => '#dfd',
'macro' => '#ddf',
'template' => '#ffd',
'big' => '#d44',
];
public function dump(Profile $profile)
{
return
'<pre>'.parent::dump($profile).'</pre>';
}
protected function formatTemplate(Profile $profile, $prefix)
{
return sprintf('%s└ <span style="background-color:
%s">%s</span>', $prefix,
self::$colors['template'], $profile->getTemplate());
}
protected function formatNonTemplate(Profile $profile, $prefix)
{
return sprintf('%s└ %s::%s(<span
style="background-color: %s">%s</span>)', $prefix,
$profile->getTemplate(), $profile->getType(),
isset(self::$colors[$profile->getType()]) ?
self::$colors[$profile->getType()] : 'auto',
$profile->getName());
}
protected function formatTime(Profile $profile, $percent)
{
return sprintf('<span style="color:
%s">%.2fms/%.0f%%</span>', $percent > 20 ?
self::$colors['big'] : 'auto',
$profile->getDuration() * 1000, $percent);
}
}
class_alias('Twig\Profiler\Dumper\HtmlDumper',
'Twig_Profiler_Dumper_Html');
PK-d�[�C��3vendor/twig/twig/src/Profiler/Dumper/TextDumper.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler\Dumper;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class TextDumper extends BaseDumper
{
protected function formatTemplate(Profile $profile, $prefix)
{
return sprintf('%s└ %s', $prefix,
$profile->getTemplate());
}
protected function formatNonTemplate(Profile $profile, $prefix)
{
return sprintf('%s└ %s::%s(%s)', $prefix,
$profile->getTemplate(), $profile->getType(),
$profile->getName());
}
protected function formatTime(Profile $profile, $percent)
{
return sprintf('%.2fms/%.0f%%',
$profile->getDuration() * 1000, $percent);
}
}
class_alias('Twig\Profiler\Dumper\TextDumper',
'Twig_Profiler_Dumper_Text');
PK-d�[7vendor/twig/twig/src/Profiler/Node/EnterProfileNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler\Node;
use Twig\Compiler;
use Twig\Node\Node;
/**
* Represents a profile enter node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class EnterProfileNode extends Node
{
public function __construct($extensionName, $type, $name, $varName)
{
parent::__construct([], ['extension_name' =>
$extensionName, 'name' => $name, 'type' => $type,
'var_name' => $varName]);
}
public function compile(Compiler $compiler)
{
$compiler
->write(sprintf('$%s =
$this->env->getExtension(',
$this->getAttribute('var_name')))
->repr($this->getAttribute('extension_name'))
->raw(");\n")
->write(sprintf('$%s->enter($%s = new
\Twig\Profiler\Profile($this->getTemplateName(), ',
$this->getAttribute('var_name'),
$this->getAttribute('var_name').'_prof'))
->repr($this->getAttribute('type'))
->raw(', ')
->repr($this->getAttribute('name'))
->raw("));\n\n")
;
}
}
class_alias('Twig\Profiler\Node\EnterProfileNode',
'Twig_Profiler_Node_EnterProfile');
PK-d�[QH�VV7vendor/twig/twig/src/Profiler/Node/LeaveProfileNode.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler\Node;
use Twig\Compiler;
use Twig\Node\Node;
/**
* Represents a profile leave node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class LeaveProfileNode extends Node
{
public function __construct($varName)
{
parent::__construct([], ['var_name' => $varName]);
}
public function compile(Compiler $compiler)
{
$compiler
->write("\n")
->write(sprintf("\$%s->leave(\$%s);\n\n",
$this->getAttribute('var_name'),
$this->getAttribute('var_name').'_prof'))
;
}
}
class_alias('Twig\Profiler\Node\LeaveProfileNode',
'Twig_Profiler_Node_LeaveProfile');
PK-d�[6��5s s Avendor/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler\NodeVisitor;
use Twig\Environment;
use Twig\Node\BlockNode;
use Twig\Node\BodyNode;
use Twig\Node\MacroNode;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\NodeVisitor\AbstractNodeVisitor;
use Twig\Profiler\Node\EnterProfileNode;
use Twig\Profiler\Node\LeaveProfileNode;
use Twig\Profiler\Profile;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class ProfilerNodeVisitor extends AbstractNodeVisitor
{
private $extensionName;
public function __construct($extensionName)
{
$this->extensionName = $extensionName;
}
protected function doEnterNode(Node $node, Environment $env)
{
return $node;
}
protected function doLeaveNode(Node $node, Environment $env)
{
if ($node instanceof ModuleNode) {
$varName = $this->getVarName();
$node->setNode('display_start', new Node([new
EnterProfileNode($this->extensionName, Profile::TEMPLATE,
$node->getTemplateName(), $varName),
$node->getNode('display_start')]));
$node->setNode('display_end', new Node([new
LeaveProfileNode($varName), $node->getNode('display_end')]));
} elseif ($node instanceof BlockNode) {
$varName = $this->getVarName();
$node->setNode('body', new BodyNode([
new EnterProfileNode($this->extensionName,
Profile::BLOCK, $node->getAttribute('name'), $varName),
$node->getNode('body'),
new LeaveProfileNode($varName),
]));
} elseif ($node instanceof MacroNode) {
$varName = $this->getVarName();
$node->setNode('body', new BodyNode([
new EnterProfileNode($this->extensionName,
Profile::MACRO, $node->getAttribute('name'), $varName),
$node->getNode('body'),
new LeaveProfileNode($varName),
]));
}
return $node;
}
private function getVarName()
{
return sprintf('__internal_%s', hash('sha256',
$this->extensionName));
}
public function getPriority()
{
return 0;
}
}
class_alias('Twig\Profiler\NodeVisitor\ProfilerNodeVisitor',
'Twig_Profiler_NodeVisitor_Profiler');
PK-d�[����)vendor/twig/twig/src/Profiler/Profile.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Profiler;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class Profile implements \IteratorAggregate, \Serializable
{
const ROOT = 'ROOT';
const BLOCK = 'block';
const TEMPLATE = 'template';
const MACRO = 'macro';
private $template;
private $name;
private $type;
private $starts = [];
private $ends = [];
private $profiles = [];
public function __construct($template = 'main', $type =
self::ROOT, $name = 'main')
{
$this->template = $template;
$this->type = $type;
$this->name = 0 === strpos($name, '__internal_') ?
'INTERNAL' : $name;
$this->enter();
}
public function getTemplate()
{
return $this->template;
}
public function getType()
{
return $this->type;
}
public function getName()
{
return $this->name;
}
public function isRoot()
{
return self::ROOT === $this->type;
}
public function isTemplate()
{
return self::TEMPLATE === $this->type;
}
public function isBlock()
{
return self::BLOCK === $this->type;
}
public function isMacro()
{
return self::MACRO === $this->type;
}
public function getProfiles()
{
return $this->profiles;
}
public function addProfile(self $profile)
{
$this->profiles[] = $profile;
}
/**
* Returns the duration in microseconds.
*
* @return float
*/
public function getDuration()
{
if ($this->isRoot() && $this->profiles) {
// for the root node with children, duration is the sum of all
child durations
$duration = 0;
foreach ($this->profiles as $profile) {
$duration += $profile->getDuration();
}
return $duration;
}
return isset($this->ends['wt']) &&
isset($this->starts['wt']) ? $this->ends['wt'] -
$this->starts['wt'] : 0;
}
/**
* Returns the memory usage in bytes.
*
* @return int
*/
public function getMemoryUsage()
{
return isset($this->ends['mu']) &&
isset($this->starts['mu']) ? $this->ends['mu'] -
$this->starts['mu'] : 0;
}
/**
* Returns the peak memory usage in bytes.
*
* @return int
*/
public function getPeakMemoryUsage()
{
return isset($this->ends['pmu']) &&
isset($this->starts['pmu']) ? $this->ends['pmu']
- $this->starts['pmu'] : 0;
}
/**
* Starts the profiling.
*/
public function enter()
{
$this->starts = [
'wt' => microtime(true),
'mu' => memory_get_usage(),
'pmu' => memory_get_peak_usage(),
];
}
/**
* Stops the profiling.
*/
public function leave()
{
$this->ends = [
'wt' => microtime(true),
'mu' => memory_get_usage(),
'pmu' => memory_get_peak_usage(),
];
}
public function reset()
{
$this->starts = $this->ends = $this->profiles = [];
$this->enter();
}
public function getIterator()
{
return new \ArrayIterator($this->profiles);
}
public function serialize()
{
return serialize($this->__serialize());
}
public function unserialize($data)
{
$this->__unserialize(unserialize($data));
}
/**
* @internal
*/
public function __serialize()
{
return [$this->template, $this->name, $this->type,
$this->starts, $this->ends, $this->profiles];
}
/**
* @internal
*/
public function __unserialize(array $data)
{
list($this->template, $this->name, $this->type,
$this->starts, $this->ends, $this->profiles) = $data;
}
}
class_alias('Twig\Profiler\Profile',
'Twig_Profiler_Profile');
PK-d�[����=vendor/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\RuntimeLoader;
use Psr\Container\ContainerInterface;
/**
* Lazily loads Twig runtime implementations from a PSR-11 container.
*
* Note that the runtime services MUST use their class names as
identifiers.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class ContainerRuntimeLoader implements RuntimeLoaderInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function load($class)
{
if ($this->container->has($class)) {
return $this->container->get($class);
}
}
}
class_alias('Twig\RuntimeLoader\ContainerRuntimeLoader',
'Twig_ContainerRuntimeLoader');
PK-d�[P͂���;vendor/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\RuntimeLoader;
/**
* Lazy loads the runtime implementations for a Twig element.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class FactoryRuntimeLoader implements RuntimeLoaderInterface
{
private $map;
/**
* @param array $map An array where keys are class names and values
factory callables
*/
public function __construct($map = [])
{
$this->map = $map;
}
public function load($class)
{
if (isset($this->map[$class])) {
$runtimeFactory = $this->map[$class];
return $runtimeFactory();
}
}
}
class_alias('Twig\RuntimeLoader\FactoryRuntimeLoader',
'Twig_FactoryRuntimeLoader');
PK-d�[��ZW11=vendor/twig/twig/src/RuntimeLoader/RuntimeLoaderInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\RuntimeLoader;
/**
* Creates runtime implementations for Twig elements
(filters/functions/tests).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface RuntimeLoaderInterface
{
/**
* Creates the runtime implementation of a Twig element
(filter/function/test).
*
* @param string $class A runtime class
*
* @return object|null The runtime instance or null if the loader does
not know how to create the runtime for this class
*/
public function load($class);
}
class_alias('Twig\RuntimeLoader\RuntimeLoaderInterface',
'Twig_RuntimeLoaderInterface');
PK-d�[�b����.vendor/twig/twig/src/Sandbox/SecurityError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
use Twig\Error\Error;
/**
* Exception thrown when a security error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SecurityError extends Error
{
}
class_alias('Twig\Sandbox\SecurityError',
'Twig_Sandbox_SecurityError');
PK-d�[��Y�mm>vendor/twig/twig/src/Sandbox/SecurityNotAllowedFilterError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
/**
* Exception thrown when a not allowed filter is used in a template.
*
* @author Martin Hasoň <martin.hason@gmail.com>
*/
class SecurityNotAllowedFilterError extends SecurityError
{
private $filterName;
public function __construct($message, $functionName, $lineno = -1,
$filename = null, \Exception $previous = null)
{
parent::__construct($message, $lineno, $filename, $previous);
$this->filterName = $functionName;
}
public function getFilterName()
{
return $this->filterName;
}
}
class_alias('Twig\Sandbox\SecurityNotAllowedFilterError',
'Twig_Sandbox_SecurityNotAllowedFilterError');
PK-d�[�RB�}}@vendor/twig/twig/src/Sandbox/SecurityNotAllowedFunctionError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
/**
* Exception thrown when a not allowed function is used in a template.
*
* @author Martin Hasoň <martin.hason@gmail.com>
*/
class SecurityNotAllowedFunctionError extends SecurityError
{
private $functionName;
public function __construct($message, $functionName, $lineno = -1,
$filename = null, \Exception $previous = null)
{
parent::__construct($message, $lineno, $filename, $previous);
$this->functionName = $functionName;
}
public function getFunctionName()
{
return $this->functionName;
}
}
class_alias('Twig\Sandbox\SecurityNotAllowedFunctionError',
'Twig_Sandbox_SecurityNotAllowedFunctionError');
PK-d�[�ý�>vendor/twig/twig/src/Sandbox/SecurityNotAllowedMethodError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
/**
* Exception thrown when a not allowed class method is used in a template.
*
* @author Kit Burton-Senior <mail@kitbs.com>
*/
class SecurityNotAllowedMethodError extends SecurityError
{
private $className;
private $methodName;
public function __construct($message, $className, $methodName, $lineno
= -1, $filename = null, \Exception $previous = null)
{
parent::__construct($message, $lineno, $filename, $previous);
$this->className = $className;
$this->methodName = $methodName;
}
public function getClassName()
{
return $this->className;
}
public function getMethodName()
{
return $this->methodName;
}
}
class_alias('Twig\Sandbox\SecurityNotAllowedMethodError',
'Twig_Sandbox_SecurityNotAllowedMethodError');
PK-d�[X��Y@vendor/twig/twig/src/Sandbox/SecurityNotAllowedPropertyError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
/**
* Exception thrown when a not allowed class property is used in a
template.
*
* @author Kit Burton-Senior <mail@kitbs.com>
*/
class SecurityNotAllowedPropertyError extends SecurityError
{
private $className;
private $propertyName;
public function __construct($message, $className, $propertyName,
$lineno = -1, $filename = null, \Exception $previous = null)
{
parent::__construct($message, $lineno, $filename, $previous);
$this->className = $className;
$this->propertyName = $propertyName;
}
public function getClassName()
{
return $this->className;
}
public function getPropertyName()
{
return $this->propertyName;
}
}
class_alias('Twig\Sandbox\SecurityNotAllowedPropertyError',
'Twig_Sandbox_SecurityNotAllowedPropertyError');
PK-d�[B��KK;vendor/twig/twig/src/Sandbox/SecurityNotAllowedTagError.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
/**
* Exception thrown when a not allowed tag is used in a template.
*
* @author Martin Hasoň <martin.hason@gmail.com>
*/
class SecurityNotAllowedTagError extends SecurityError
{
private $tagName;
public function __construct($message, $tagName, $lineno = -1, $filename
= null, \Exception $previous = null)
{
parent::__construct($message, $lineno, $filename, $previous);
$this->tagName = $tagName;
}
public function getTagName()
{
return $this->tagName;
}
}
class_alias('Twig\Sandbox\SecurityNotAllowedTagError',
'Twig_Sandbox_SecurityNotAllowedTagError');
PK-d�[�q�3��/vendor/twig/twig/src/Sandbox/SecurityPolicy.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
use Twig\Markup;
/**
* Represents a security policy which need to be enforced when sandbox mode
is enabled.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SecurityPolicy implements SecurityPolicyInterface
{
protected $allowedTags;
protected $allowedFilters;
protected $allowedMethods;
protected $allowedProperties;
protected $allowedFunctions;
public function __construct(array $allowedTags = [], array
$allowedFilters = [], array $allowedMethods = [], array $allowedProperties
= [], array $allowedFunctions = [])
{
$this->allowedTags = $allowedTags;
$this->allowedFilters = $allowedFilters;
$this->setAllowedMethods($allowedMethods);
$this->allowedProperties = $allowedProperties;
$this->allowedFunctions = $allowedFunctions;
}
public function setAllowedTags(array $tags)
{
$this->allowedTags = $tags;
}
public function setAllowedFilters(array $filters)
{
$this->allowedFilters = $filters;
}
public function setAllowedMethods(array $methods)
{
$this->allowedMethods = [];
foreach ($methods as $class => $m) {
$this->allowedMethods[$class] = array_map(function ($value)
{ return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'); }, \is_array($m) ? $m : [$m]);
}
}
public function setAllowedProperties(array $properties)
{
$this->allowedProperties = $properties;
}
public function setAllowedFunctions(array $functions)
{
$this->allowedFunctions = $functions;
}
public function checkSecurity($tags, $filters, $functions)
{
foreach ($tags as $tag) {
if (!\in_array($tag, $this->allowedTags)) {
throw new SecurityNotAllowedTagError(sprintf('Tag
"%s" is not allowed.', $tag), $tag);
}
}
foreach ($filters as $filter) {
if (!\in_array($filter, $this->allowedFilters)) {
throw new
SecurityNotAllowedFilterError(sprintf('Filter "%s" is not
allowed.', $filter), $filter);
}
}
foreach ($functions as $function) {
if (!\in_array($function, $this->allowedFunctions)) {
throw new
SecurityNotAllowedFunctionError(sprintf('Function "%s" is
not allowed.', $function), $function);
}
}
}
public function checkMethodAllowed($obj, $method)
{
if ($obj instanceof \Twig_TemplateInterface || $obj instanceof
Markup) {
return;
}
$allowed = false;
$method = strtr($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz');
foreach ($this->allowedMethods as $class => $methods) {
if ($obj instanceof $class) {
$allowed = \in_array($method, $methods);
break;
}
}
if (!$allowed) {
$class = \get_class($obj);
throw new SecurityNotAllowedMethodError(sprintf('Calling
"%s" method on a "%s" object is not allowed.',
$method, $class), $class, $method);
}
}
public function checkPropertyAllowed($obj, $property)
{
$allowed = false;
foreach ($this->allowedProperties as $class => $properties) {
if ($obj instanceof $class) {
$allowed = \in_array($property, \is_array($properties) ?
$properties : [$properties]);
break;
}
}
if (!$allowed) {
$class = \get_class($obj);
throw new SecurityNotAllowedPropertyError(sprintf('Calling
"%s" property on a "%s" object is not allowed.',
$property, $class), $class, $property);
}
}
}
class_alias('Twig\Sandbox\SecurityPolicy',
'Twig_Sandbox_SecurityPolicy');
PK-d�[��"C��8vendor/twig/twig/src/Sandbox/SecurityPolicyInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Sandbox;
/**
* Interface that all security policy classes must implements.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface SecurityPolicyInterface
{
public function checkSecurity($tags, $filters, $functions);
public function checkMethodAllowed($obj, $method);
public function checkPropertyAllowed($obj, $method);
}
class_alias('Twig\Sandbox\SecurityPolicyInterface',
'Twig_Sandbox_SecurityPolicyInterface');
PK-d�[���vendor/twig/twig/src/Source.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
/**
* Holds information about a non-compiled Twig template.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Source
{
private $code;
private $name;
private $path;
/**
* @param string $code The template source code
* @param string $name The template logical name
* @param string $path The filesystem path of the template if any
*/
public function __construct($code, $name, $path = '')
{
$this->code = $code;
$this->name = $name;
$this->path = $path;
}
public function getCode()
{
return $this->code;
}
public function getName()
{
return $this->name;
}
public function getPath()
{
return $this->path;
}
}
class_alias('Twig\Source', 'Twig_Source');
PK-d�[q�A3sdsd!vendor/twig/twig/src/Template.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Error\Error;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
/**
* Default base class for compiled templates.
*
* This class is an implementation detail of how template compilation
currently
* works, which might change. It should never be used directly. Use
$twig->load()
* instead, which returns an instance of \Twig\TemplateWrapper.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
abstract class Template implements \Twig_TemplateInterface
{
/**
* @internal
*/
protected static $cache = [];
protected $parent;
protected $parents = [];
protected $env;
protected $blocks = [];
protected $traits = [];
protected $sandbox;
public function __construct(Environment $env)
{
$this->env = $env;
}
/**
* @internal this method will be removed in 2.0 and is only used
internally to provide an upgrade path from 1.x to 2.0
*/
public function __toString()
{
return $this->getTemplateName();
}
/**
* Returns the template name.
*
* @return string The template name
*/
abstract public function getTemplateName();
/**
* Returns debug information about the template.
*
* @return array Debug information
*/
public function getDebugInfo()
{
return [];
}
/**
* Returns the template source code.
*
* @return string The template source code
*
* @deprecated since 1.27 (to be removed in 2.0). Use
getSourceContext() instead
*/
public function getSource()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.27 and will be removed in 2.0. Use
getSourceContext() instead.', E_USER_DEPRECATED);
return '';
}
/**
* Returns information about the original template source code.
*
* @return Source
*/
public function getSourceContext()
{
return new Source('', $this->getTemplateName());
}
/**
* @deprecated since 1.20 (to be removed in 2.0)
*/
public function getEnvironment()
{
@trigger_error('The '.__METHOD__.' method is
deprecated since version 1.20 and will be removed in 2.0.',
E_USER_DEPRECATED);
return $this->env;
}
/**
* Returns the parent template.
*
* This method is for internal use only and should never be called
* directly.
*
* @param array $context
*
* @return \Twig_TemplateInterface|TemplateWrapper|false The parent
template or false if there is no parent
*
* @internal
*/
public function getParent(array $context)
{
if (null !== $this->parent) {
return $this->parent;
}
try {
$parent = $this->doGetParent($context);
if (false === $parent) {
return false;
}
if ($parent instanceof self || $parent instanceof
TemplateWrapper) {
return
$this->parents[$parent->getSourceContext()->getName()] = $parent;
}
if (!isset($this->parents[$parent])) {
$this->parents[$parent] =
$this->loadTemplate($parent);
}
} catch (LoaderError $e) {
$e->setSourceContext(null);
$e->guess();
throw $e;
}
return $this->parents[$parent];
}
protected function doGetParent(array $context)
{
return false;
}
public function isTraitable()
{
return true;
}
/**
* Displays a parent block.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The block name to display from the parent
* @param array $context The context
* @param array $blocks The current set of blocks
*/
public function displayParentBlock($name, array $context, array $blocks
= [])
{
$name = (string) $name;
if (isset($this->traits[$name])) {
$this->traits[$name][0]->displayBlock($name, $context,
$blocks, false);
} elseif (false !== $parent = $this->getParent($context)) {
$parent->displayBlock($name, $context, $blocks, false);
} else {
throw new RuntimeError(sprintf('The template has no parent
and no traits defining the "%s" block.', $name), -1,
$this->getSourceContext());
}
}
/**
* Displays a block.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The block name to display
* @param array $context The context
* @param array $blocks The current set of blocks
* @param bool $useBlocks Whether to use the current set of blocks
*/
public function displayBlock($name, array $context, array $blocks = [],
$useBlocks = true)
{
$name = (string) $name;
if ($useBlocks && isset($blocks[$name])) {
$template = $blocks[$name][0];
$block = $blocks[$name][1];
} elseif (isset($this->blocks[$name])) {
$template = $this->blocks[$name][0];
$block = $this->blocks[$name][1];
} else {
$template = null;
$block = null;
}
// avoid RCEs when sandbox is enabled
if (null !== $template && !$template instanceof self) {
throw new \LogicException('A block must be a method on a
\Twig\Template instance.');
}
if (null !== $template) {
try {
$template->$block($context, $blocks);
} catch (Error $e) {
if (!$e->getSourceContext()) {
$e->setSourceContext($template->getSourceContext());
}
// this is mostly useful for \Twig\Error\LoaderError
exceptions
// see \Twig\Error\LoaderError
if (-1 === $e->getTemplateLine()) {
$e->guess();
}
throw $e;
} catch (\Exception $e) {
$e = new RuntimeError(sprintf('An exception has been
thrown during the rendering of a template ("%s").',
$e->getMessage()), -1, $template->getSourceContext(), $e);
$e->guess();
throw $e;
}
} elseif (false !== $parent = $this->getParent($context)) {
$parent->displayBlock($name, $context,
array_merge($this->blocks, $blocks), false);
} else {
@trigger_error(sprintf('Silent display of undefined block
"%s" in template "%s" is deprecated since version 1.29
and will throw an exception in 2.0. Use the "block(\'%s\')
is defined" expression to test for block existence.', $name,
$this->getTemplateName(), $name), E_USER_DEPRECATED);
}
}
/**
* Renders a parent block.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The block name to render from the parent
* @param array $context The context
* @param array $blocks The current set of blocks
*
* @return string The rendered block
*/
public function renderParentBlock($name, array $context, array $blocks
= [])
{
if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
$this->displayParentBlock($name, $context, $blocks);
return ob_get_clean();
}
/**
* Renders a block.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The block name to render
* @param array $context The context
* @param array $blocks The current set of blocks
* @param bool $useBlocks Whether to use the current set of blocks
*
* @return string The rendered block
*/
public function renderBlock($name, array $context, array $blocks = [],
$useBlocks = true)
{
if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
$this->displayBlock($name, $context, $blocks, $useBlocks);
return ob_get_clean();
}
/**
* Returns whether a block exists or not in the current context of the
template.
*
* This method checks blocks defined in the current template
* or defined in "used" traits or defined in parent
templates.
*
* @param string $name The block name
* @param array $context The context
* @param array $blocks The current set of blocks
*
* @return bool true if the block exists, false otherwise
*/
public function hasBlock($name, array $context = null, array $blocks =
[])
{
if (null === $context) {
@trigger_error('The '.__METHOD__.' method is
internal and should never be called; calling it directly is deprecated
since version 1.28 and won\'t be possible anymore in 2.0.',
E_USER_DEPRECATED);
return isset($this->blocks[(string) $name]);
}
if (isset($blocks[$name])) {
return $blocks[$name][0] instanceof self;
}
if (isset($this->blocks[$name])) {
return true;
}
if (false !== $parent = $this->getParent($context)) {
return $parent->hasBlock($name, $context);
}
return false;
}
/**
* Returns all block names in the current context of the template.
*
* This method checks blocks defined in the current template
* or defined in "used" traits or defined in parent
templates.
*
* @param array $context The context
* @param array $blocks The current set of blocks
*
* @return array An array of block names
*/
public function getBlockNames(array $context = null, array $blocks =
[])
{
if (null === $context) {
@trigger_error('The '.__METHOD__.' method is
internal and should never be called; calling it directly is deprecated
since version 1.28 and won\'t be possible anymore in 2.0.',
E_USER_DEPRECATED);
return array_keys($this->blocks);
}
$names = array_merge(array_keys($blocks),
array_keys($this->blocks));
if (false !== $parent = $this->getParent($context)) {
$names = array_merge($names,
$parent->getBlockNames($context));
}
return array_unique($names);
}
/**
* @return Template|TemplateWrapper
*/
protected function loadTemplate($template, $templateName = null, $line
= null, $index = null)
{
try {
if (\is_array($template)) {
return $this->env->resolveTemplate($template);
}
if ($template instanceof self || $template instanceof
TemplateWrapper) {
return $template;
}
if ($template === $this->getTemplateName()) {
$class = \get_class($this);
if (false !== $pos = strrpos($class, '___', -1))
{
$class = substr($class, 0, $pos);
}
return $this->env->loadClass($class, $template,
$index);
}
return $this->env->loadTemplate($template, $index);
} catch (Error $e) {
if (!$e->getSourceContext()) {
$e->setSourceContext($templateName ? new
Source('', $templateName) : $this->getSourceContext());
}
if ($e->getTemplateLine() > 0) {
throw $e;
}
if (!$line) {
$e->guess();
} else {
$e->setTemplateLine($line);
}
throw $e;
}
}
/**
* @internal
*
* @return Template
*/
protected function unwrap()
{
return $this;
}
/**
* Returns all blocks.
*
* This method is for internal use only and should never be called
* directly.
*
* @return array An array of blocks
*/
public function getBlocks()
{
return $this->blocks;
}
public function display(array $context, array $blocks = [])
{
$this->displayWithErrorHandling($this->env->mergeGlobals($context),
array_merge($this->blocks, $blocks));
}
public function render(array $context)
{
$level = ob_get_level();
if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
try {
$this->display($context);
} catch (\Exception $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
} catch (\Throwable $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
return ob_get_clean();
}
protected function displayWithErrorHandling(array $context, array
$blocks = [])
{
try {
$this->doDisplay($context, $blocks);
} catch (Error $e) {
if (!$e->getSourceContext()) {
$e->setSourceContext($this->getSourceContext());
}
// this is mostly useful for \Twig\Error\LoaderError exceptions
// see \Twig\Error\LoaderError
if (-1 === $e->getTemplateLine()) {
$e->guess();
}
throw $e;
} catch (\Exception $e) {
$e = new RuntimeError(sprintf('An exception has been
thrown during the rendering of a template ("%s").',
$e->getMessage()), -1, $this->getSourceContext(), $e);
$e->guess();
throw $e;
}
}
/**
* Auto-generated method to display the template with the given
context.
*
* @param array $context An array of parameters to pass to the template
* @param array $blocks An array of blocks to pass to the template
*/
abstract protected function doDisplay(array $context, array $blocks =
[]);
/**
* Returns a variable from the context.
*
* This method is for internal use only and should never be called
* directly.
*
* This method should not be overridden in a sub-class as this is an
* implementation detail that has been introduced to optimize variable
* access for versions of PHP before 5.4. This is not a way to override
* the way to get a variable value.
*
* @param array $context The context
* @param string $item The variable to return from the
context
* @param bool $ignoreStrictCheck Whether to ignore the strict
variable check or not
*
* @return mixed The content of the context variable
*
* @throws RuntimeError if the variable does not exist and Twig is
running in strict mode
*
* @internal
*/
final protected function getContext($context, $item, $ignoreStrictCheck
= false)
{
if (!\array_key_exists($item, $context)) {
if ($ignoreStrictCheck ||
!$this->env->isStrictVariables()) {
return;
}
throw new RuntimeError(sprintf('Variable "%s"
does not exist.', $item), -1, $this->getSourceContext());
}
return $context[$item];
}
/**
* Returns the attribute value for a given array/object.
*
* @param mixed $object The object or array from where to
get the item
* @param mixed $item The item to get from the array or
object
* @param array $arguments An array of arguments to pass if
the item is an object method
* @param string $type The type of attribute (@see
\Twig\Template constants)
* @param bool $isDefinedTest Whether this is only a defined
check
* @param bool $ignoreStrictCheck Whether to ignore the strict
attribute check or not
*
* @return mixed The attribute value, or a Boolean when $isDefinedTest
is true, or null when the attribute is not set and $ignoreStrictCheck is
true
*
* @throws RuntimeError if the attribute does not exist and Twig is
running in strict mode and $isDefinedTest is false
*
* @internal
*/
protected function getAttribute($object, $item, array $arguments = [],
$type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
{
// array
if (self::METHOD_CALL !== $type) {
$arrayItem = \is_bool($item) || \is_float($item) ? (int) $item
: $item;
if (((\is_array($object) || $object instanceof \ArrayObject)
&& (isset($object[$arrayItem]) || \array_key_exists($arrayItem,
(array) $object)))
|| ($object instanceof \ArrayAccess &&
isset($object[$arrayItem]))
) {
if ($isDefinedTest) {
return true;
}
return $object[$arrayItem];
}
if (self::ARRAY_CALL === $type || !\is_object($object)) {
if ($isDefinedTest) {
return false;
}
if ($ignoreStrictCheck ||
!$this->env->isStrictVariables()) {
return;
}
if ($object instanceof \ArrayAccess) {
$message = sprintf('Key "%s" in object
with ArrayAccess of class "%s" does not exist.', $arrayItem,
\get_class($object));
} elseif (\is_object($object)) {
$message = sprintf('Impossible to access a key
"%s" on an object of class "%s" that does not implement
ArrayAccess interface.', $item, \get_class($object));
} elseif (\is_array($object)) {
if (empty($object)) {
$message = sprintf('Key "%s" does
not exist as the array is empty.', $arrayItem);
} else {
$message = sprintf('Key "%s" for
array with keys "%s" does not exist.', $arrayItem,
implode(', ', array_keys($object)));
}
} elseif (self::ARRAY_CALL === $type) {
if (null === $object) {
$message = sprintf('Impossible to access a key
("%s") on a null variable.', $item);
} else {
$message = sprintf('Impossible to access a key
("%s") on a %s variable ("%s").', $item,
\gettype($object), $object);
}
} elseif (null === $object) {
$message = sprintf('Impossible to access an
attribute ("%s") on a null variable.', $item);
} else {
$message = sprintf('Impossible to access an
attribute ("%s") on a %s variable ("%s").', $item,
\gettype($object), $object);
}
throw new RuntimeError($message, -1,
$this->getSourceContext());
}
}
if (!\is_object($object)) {
if ($isDefinedTest) {
return false;
}
if ($ignoreStrictCheck ||
!$this->env->isStrictVariables()) {
return;
}
if (null === $object) {
$message = sprintf('Impossible to invoke a method
("%s") on a null variable.', $item);
} elseif (\is_array($object)) {
$message = sprintf('Impossible to invoke a method
("%s") on an array.', $item);
} else {
$message = sprintf('Impossible to invoke a method
("%s") on a %s variable ("%s").', $item,
\gettype($object), $object);
}
throw new RuntimeError($message, -1,
$this->getSourceContext());
}
// object property
if (self::METHOD_CALL !== $type && !$object instanceof
self) { // \Twig\Template does not have public properties, and we
don't want to allow access to internal ones
if (isset($object->$item) || \array_key_exists((string)
$item, (array) $object)) {
if ($isDefinedTest) {
return true;
}
if
($this->env->hasExtension('\Twig\Extension\SandboxExtension'))
{
$this->env->getExtension('\Twig\Extension\SandboxExtension')->checkPropertyAllowed($object,
$item);
}
return $object->$item;
}
}
$class = \get_class($object);
// object method
if (!isset(self::$cache[$class])) {
// get_class_methods returns all methods accessible in the
scope, but we only want public ones to be accessible in templates
if ($object instanceof self) {
$ref = new \ReflectionClass($class);
$methods = [];
foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC)
as $refMethod) {
// Accessing the environment from templates is
forbidden to prevent untrusted changes to the environment
if ('getenvironment' !==
strtr($refMethod->name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')) {
$methods[] = $refMethod->name;
}
}
} else {
$methods = get_class_methods($object);
}
// sort values to have consistent behavior, so that
"get" methods win precedence over "is" methods
sort($methods);
$cache = [];
foreach ($methods as $method) {
$cache[$method] = $method;
$cache[$lcName = strtr($method,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')] = $method;
if ('g' === $lcName[0] && 0 ===
strpos($lcName, 'get')) {
$name = substr($method, 3);
$lcName = substr($lcName, 3);
} elseif ('i' === $lcName[0] && 0 ===
strpos($lcName, 'is')) {
$name = substr($method, 2);
$lcName = substr($lcName, 2);
} else {
continue;
}
// skip get() and is() methods (in which case, $name is
empty)
if ($name) {
if (!isset($cache[$name])) {
$cache[$name] = $method;
}
if (!isset($cache[$lcName])) {
$cache[$lcName] = $method;
}
}
}
self::$cache[$class] = $cache;
}
$call = false;
if (isset(self::$cache[$class][$item])) {
$method = self::$cache[$class][$item];
} elseif (isset(self::$cache[$class][$lcItem = strtr($item,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')])) {
$method = self::$cache[$class][$lcItem];
} elseif (isset(self::$cache[$class]['__call'])) {
$method = $item;
$call = true;
} else {
if ($isDefinedTest) {
return false;
}
if ($ignoreStrictCheck ||
!$this->env->isStrictVariables()) {
return;
}
throw new RuntimeError(sprintf('Neither the property
"%1$s" nor one of the methods "%1$s()",
"get%1$s()"/"is%1$s()" or "__call()" exist
and have public access in class "%2$s".', $item, $class),
-1, $this->getSourceContext());
}
if ($isDefinedTest) {
return true;
}
if
($this->env->hasExtension('\Twig\Extension\SandboxExtension'))
{
$this->env->getExtension('\Twig\Extension\SandboxExtension')->checkMethodAllowed($object,
$method);
}
// Some objects throw exceptions when they have __call, and the
method we try
// to call is not supported. If ignoreStrictCheck is true, we
should return null.
try {
if (!$arguments) {
$ret = $object->$method();
} else {
$ret = \call_user_func_array([$object, $method],
$arguments);
}
} catch (\BadMethodCallException $e) {
if ($call && ($ignoreStrictCheck ||
!$this->env->isStrictVariables())) {
return;
}
throw $e;
}
// @deprecated in 1.28
if ($object instanceof \Twig_TemplateInterface) {
$self = $object->getTemplateName() ===
$this->getTemplateName();
$message = sprintf('Calling "%s" on template
"%s" from template "%s" is deprecated since version
1.28 and won\'t be supported anymore in 2.0.', $item,
$object->getTemplateName(), $this->getTemplateName());
if ('renderBlock' === $method ||
'displayBlock' === $method) {
$message .= sprintf(' Use block("%s"%s)
instead).', $arguments[0], $self ? '' : ',
template');
} elseif ('hasBlock' === $method) {
$message .= sprintf(' Use
"block("%s"%s) is defined" instead).',
$arguments[0], $self ? '' : ', template');
} elseif ('render' === $method || 'display'
=== $method) {
$message .= sprintf(' Use include("%s")
instead).', $object->getTemplateName());
}
@trigger_error($message, E_USER_DEPRECATED);
return '' === $ret ? '' : new Markup($ret,
$this->env->getCharset());
}
return $ret;
}
}
class_alias('Twig\Template', 'Twig_Template');
PK-d�[�P�՞�(vendor/twig/twig/src/TemplateWrapper.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
/**
* Exposes a template to userland.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class TemplateWrapper
{
private $env;
private $template;
/**
* This method is for internal use only and should never be called
* directly (use Twig\Environment::load() instead).
*
* @internal
*/
public function __construct(Environment $env, Template $template)
{
$this->env = $env;
$this->template = $template;
}
/**
* Renders the template.
*
* @param array $context An array of parameters to pass to the template
*
* @return string The rendered template
*/
public function render($context = [])
{
// using func_get_args() allows to not expose the blocks argument
// as it should only be used by internal code
return $this->template->render($context, \func_num_args()
> 1 ? func_get_arg(1) : []);
}
/**
* Displays the template.
*
* @param array $context An array of parameters to pass to the template
*/
public function display($context = [])
{
// using func_get_args() allows to not expose the blocks argument
// as it should only be used by internal code
$this->template->display($context, \func_num_args() > 1 ?
func_get_arg(1) : []);
}
/**
* Checks if a block is defined.
*
* @param string $name The block name
* @param array $context An array of parameters to pass to the
template
*
* @return bool
*/
public function hasBlock($name, $context = [])
{
return $this->template->hasBlock($name, $context);
}
/**
* Returns defined block names in the template.
*
* @param array $context An array of parameters to pass to the template
*
* @return string[] An array of defined template block names
*/
public function getBlockNames($context = [])
{
return $this->template->getBlockNames($context);
}
/**
* Renders a template block.
*
* @param string $name The block name to render
* @param array $context An array of parameters to pass to the
template
*
* @return string The rendered block
*/
public function renderBlock($name, $context = [])
{
$context = $this->env->mergeGlobals($context);
$level = ob_get_level();
if ($this->env->isDebug()) {
ob_start();
} else {
ob_start(function () { return ''; });
}
try {
$this->template->displayBlock($name, $context);
} catch (\Exception $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
} catch (\Throwable $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
return ob_get_clean();
}
/**
* Displays a template block.
*
* @param string $name The block name to render
* @param array $context An array of parameters to pass to the
template
*/
public function displayBlock($name, $context = [])
{
$this->template->displayBlock($name,
$this->env->mergeGlobals($context));
}
/**
* @return Source
*/
public function getSourceContext()
{
return $this->template->getSourceContext();
}
/**
* @return string
*/
public function getTemplateName()
{
return $this->template->getTemplateName();
}
/**
* @internal
*
* @return Template
*/
public function unwrap()
{
return $this->template;
}
}
class_alias('Twig\TemplateWrapper',
'Twig_TemplateWrapper');
PK-d�[?yL!!1vendor/twig/twig/src/Test/IntegrationTestCase.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Test;
use PHPUnit\Framework\TestCase;
use Twig\Environment;
use Twig\Error\Error;
use Twig\Extension\ExtensionInterface;
use Twig\Loader\ArrayLoader;
use Twig\Loader\SourceContextLoaderInterface;
use Twig\RuntimeLoader\RuntimeLoaderInterface;
use Twig\Source;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
/**
* Integration test helper.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Karma Dordrak <drak@zikula.org>
*/
abstract class IntegrationTestCase extends TestCase
{
/**
* @return string
*/
abstract protected function getFixturesDir();
/**
* @return RuntimeLoaderInterface[]
*/
protected function getRuntimeLoaders()
{
return [];
}
/**
* @return ExtensionInterface[]
*/
protected function getExtensions()
{
return [];
}
/**
* @return TwigFilter[]
*/
protected function getTwigFilters()
{
return [];
}
/**
* @return TwigFunction[]
*/
protected function getTwigFunctions()
{
return [];
}
/**
* @return TwigTest[]
*/
protected function getTwigTests()
{
return [];
}
/**
* @dataProvider getTests
*/
public function testIntegration($file, $message, $condition,
$templates, $exception, $outputs)
{
$this->doIntegrationTest($file, $message, $condition,
$templates, $exception, $outputs);
}
/**
* @dataProvider getLegacyTests
* @group legacy
*/
public function testLegacyIntegration($file, $message, $condition,
$templates, $exception, $outputs)
{
$this->doIntegrationTest($file, $message, $condition,
$templates, $exception, $outputs);
}
public function getTests($name, $legacyTests = false)
{
$fixturesDir = realpath($this->getFixturesDir());
$tests = [];
foreach (new \RecursiveIteratorIterator(new
\RecursiveDirectoryIterator($fixturesDir),
\RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if (!preg_match('/\.test$/', $file)) {
continue;
}
if ($legacyTests xor false !== strpos($file->getRealpath(),
'.legacy.test')) {
continue;
}
$test = file_get_contents($file->getRealpath());
if
(preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx',
$test, $match)) {
$message = $match[1];
$condition = $match[2];
$templates = self::parseTemplates($match[3]);
$exception = $match[5];
$outputs = [[null, $match[4], null, '']];
} elseif
(preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s',
$test, $match)) {
$message = $match[1];
$condition = $match[2];
$templates = self::parseTemplates($match[3]);
$exception = false;
preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s',
$test, $outputs, PREG_SET_ORDER);
} else {
throw new \InvalidArgumentException(sprintf('Test
"%s" is not valid.', str_replace($fixturesDir.'/',
'', $file)));
}
$tests[] = [str_replace($fixturesDir.'/',
'', $file), $message, $condition, $templates, $exception,
$outputs];
}
if ($legacyTests && empty($tests)) {
// add a dummy test to avoid a PHPUnit message
return [['not', '-', '', [],
'', []]];
}
return $tests;
}
public function getLegacyTests()
{
return $this->getTests('testLegacyIntegration', true);
}
protected function doIntegrationTest($file, $message, $condition,
$templates, $exception, $outputs)
{
if (!$outputs) {
$this->markTestSkipped('no tests to run');
}
if ($condition) {
eval('$ret = '.$condition.';');
if (!$ret) {
$this->markTestSkipped($condition);
}
}
$loader = new ArrayLoader($templates);
foreach ($outputs as $i => $match) {
$config = array_merge([
'cache' => false,
'strict_variables' => true,
], $match[2] ? eval($match[2].';') : []);
$twig = new Environment($loader, $config);
$twig->addGlobal('global', 'global');
foreach ($this->getRuntimeLoaders() as $runtimeLoader) {
$twig->addRuntimeLoader($runtimeLoader);
}
foreach ($this->getExtensions() as $extension) {
$twig->addExtension($extension);
}
foreach ($this->getTwigFilters() as $filter) {
$twig->addFilter($filter);
}
foreach ($this->getTwigTests() as $test) {
$twig->addTest($test);
}
foreach ($this->getTwigFunctions() as $function) {
$twig->addFunction($function);
}
$p = new \ReflectionProperty($twig,
'templateClassPrefix');
$p->setAccessible(true);
$p->setValue($twig,
'__TwigTemplate_'.hash('sha256', uniqid(mt_rand(),
true), false).'_');
try {
$template = $twig->load('index.twig');
} catch (\Exception $e) {
if (false !== $exception) {
$message = $e->getMessage();
$this->assertSame(trim($exception),
trim(sprintf('%s: %s', \get_class($e), $message)));
$last = substr($message, \strlen($message) - 1);
$this->assertTrue('.' === $last ||
'?' === $last, 'Exception message must end with a dot or a
question mark.');
return;
}
throw new Error(sprintf('%s: %s', \get_class($e),
$e->getMessage()), -1, null, $e);
}
try {
$output =
trim($template->render(eval($match[1].';')), "\n ");
} catch (\Exception $e) {
if (false !== $exception) {
$this->assertSame(trim($exception),
trim(sprintf('%s: %s', \get_class($e), $e->getMessage())));
return;
}
$e = new Error(sprintf('%s: %s', \get_class($e),
$e->getMessage()), -1, null, $e);
$output = trim(sprintf('%s: %s', \get_class($e),
$e->getMessage()));
}
if (false !== $exception) {
list($class) = explode(':', $exception);
$constraintClass =
class_exists('PHPUnit\Framework\Constraint\Exception') ?
'PHPUnit\Framework\Constraint\Exception' :
'PHPUnit_Framework_Constraint_Exception';
$this->assertThat(null, new $constraintClass($class));
}
$expected = trim($match[3], "\n ");
if ($expected !== $output) {
printf("Compiled templates that failed on case
%d:\n", $i + 1);
foreach (array_keys($templates) as $name) {
echo "Template: $name\n";
$loader = $twig->getLoader();
if (!$loader instanceof SourceContextLoaderInterface) {
$source = new Source($loader->getSource($name),
$name);
} else {
$source = $loader->getSourceContext($name);
}
echo
$twig->compile($twig->parse($twig->tokenize($source)));
}
}
$this->assertEquals($expected, $output, $message.' (in
'.$file.')');
}
}
protected static function parseTemplates($test)
{
$templates = [];
preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s',
$test, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$templates[($match[1] ? $match[1] : 'index.twig')] =
$match[2];
}
return $templates;
}
}
class_alias('Twig\Test\IntegrationTestCase',
'Twig_Test_IntegrationTestCase');
PK-d�[��N�jj*vendor/twig/twig/src/Test/NodeTestCase.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Test;
use PHPUnit\Framework\TestCase;
use Twig\Compiler;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Twig\Node\Node;
abstract class NodeTestCase extends TestCase
{
abstract public function getTests();
/**
* @dataProvider getTests
*/
public function testCompile($node, $source, $environment = null,
$isPattern = false)
{
$this->assertNodeCompilation($source, $node, $environment,
$isPattern);
}
public function assertNodeCompilation($source, Node $node, Environment
$environment = null, $isPattern = false)
{
$compiler = $this->getCompiler($environment);
$compiler->compile($node);
if ($isPattern) {
$this->assertStringMatchesFormat($source,
trim($compiler->getSource()));
} else {
$this->assertEquals($source,
trim($compiler->getSource()));
}
}
protected function getCompiler(Environment $environment = null)
{
return new Compiler(null === $environment ?
$this->getEnvironment() : $environment);
}
protected function getEnvironment()
{
return new Environment(new ArrayLoader([]));
}
protected function getVariableGetter($name, $line = false)
{
$line = $line > 0 ? "// line {$line}\n" :
'';
if (\PHP_VERSION_ID >= 70000) {
return sprintf('%s($context["%s"] ??
null)', $line, $name);
}
if (\PHP_VERSION_ID >= 50400) {
return sprintf('%s(isset($context["%s"]) ?
$context["%s"] : null)', $line, $name, $name);
}
return sprintf('%s$this->getContext($context,
"%s")', $line, $name);
}
protected function getAttributeGetter()
{
if (\function_exists('twig_template_get_attributes')) {
return 'twig_template_get_attributes($this, ';
}
return '$this->getAttribute(';
}
}
class_alias('Twig\Test\NodeTestCase',
'Twig_Test_NodeTestCase');
PK-d�[�z�Siivendor/twig/twig/src/Token.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
/**
* Represents a Token.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class Token
{
protected $value;
protected $type;
protected $lineno;
const EOF_TYPE = -1;
const TEXT_TYPE = 0;
const BLOCK_START_TYPE = 1;
const VAR_START_TYPE = 2;
const BLOCK_END_TYPE = 3;
const VAR_END_TYPE = 4;
const NAME_TYPE = 5;
const NUMBER_TYPE = 6;
const STRING_TYPE = 7;
const OPERATOR_TYPE = 8;
const PUNCTUATION_TYPE = 9;
const INTERPOLATION_START_TYPE = 10;
const INTERPOLATION_END_TYPE = 11;
const ARROW_TYPE = 12;
/**
* @param int $type The type of the token
* @param string $value The token value
* @param int $lineno The line position in the source
*/
public function __construct($type, $value, $lineno)
{
$this->type = $type;
$this->value = $value;
$this->lineno = $lineno;
}
public function __toString()
{
return sprintf('%s(%s)',
self::typeToString($this->type, true), $this->value);
}
/**
* Tests the current token for a type and/or a value.
*
* Parameters may be:
* * just type
* * type and value (or array of possible values)
* * just value (or array of possible values) (NAME_TYPE is used as
type)
*
* @param array|string|int $type The type to test
* @param array|string|null $values The token value
*
* @return bool
*/
public function test($type, $values = null)
{
if (null === $values && !\is_int($type)) {
$values = $type;
$type = self::NAME_TYPE;
}
return ($this->type === $type) && (
null === $values ||
(\is_array($values) && \in_array($this->value,
$values)) ||
$this->value == $values
);
}
/**
* @return int
*/
public function getLine()
{
return $this->lineno;
}
/**
* @return int
*/
public function getType()
{
return $this->type;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Returns the constant representation (internal) of a given type.
*
* @param int $type The type as an integer
* @param bool $short Whether to return a short representation or not
*
* @return string The string representation
*/
public static function typeToString($type, $short = false)
{
switch ($type) {
case self::EOF_TYPE:
$name = 'EOF_TYPE';
break;
case self::TEXT_TYPE:
$name = 'TEXT_TYPE';
break;
case self::BLOCK_START_TYPE:
$name = 'BLOCK_START_TYPE';
break;
case self::VAR_START_TYPE:
$name = 'VAR_START_TYPE';
break;
case self::BLOCK_END_TYPE:
$name = 'BLOCK_END_TYPE';
break;
case self::VAR_END_TYPE:
$name = 'VAR_END_TYPE';
break;
case self::NAME_TYPE:
$name = 'NAME_TYPE';
break;
case self::NUMBER_TYPE:
$name = 'NUMBER_TYPE';
break;
case self::STRING_TYPE:
$name = 'STRING_TYPE';
break;
case self::OPERATOR_TYPE:
$name = 'OPERATOR_TYPE';
break;
case self::PUNCTUATION_TYPE:
$name = 'PUNCTUATION_TYPE';
break;
case self::INTERPOLATION_START_TYPE:
$name = 'INTERPOLATION_START_TYPE';
break;
case self::INTERPOLATION_END_TYPE:
$name = 'INTERPOLATION_END_TYPE';
break;
case self::ARROW_TYPE:
$name = 'ARROW_TYPE';
break;
default:
throw new \LogicException(sprintf('Token of type
"%s" does not exist.', $type));
}
return $short ? $name : 'Twig\Token::'.$name;
}
/**
* Returns the English representation of a given type.
*
* @param int $type The type as an integer
*
* @return string The string representation
*/
public static function typeToEnglish($type)
{
switch ($type) {
case self::EOF_TYPE:
return 'end of template';
case self::TEXT_TYPE:
return 'text';
case self::BLOCK_START_TYPE:
return 'begin of statement block';
case self::VAR_START_TYPE:
return 'begin of print statement';
case self::BLOCK_END_TYPE:
return 'end of statement block';
case self::VAR_END_TYPE:
return 'end of print statement';
case self::NAME_TYPE:
return 'name';
case self::NUMBER_TYPE:
return 'number';
case self::STRING_TYPE:
return 'string';
case self::OPERATOR_TYPE:
return 'operator';
case self::PUNCTUATION_TYPE:
return 'punctuation';
case self::INTERPOLATION_START_TYPE:
return 'begin of string interpolation';
case self::INTERPOLATION_END_TYPE:
return 'end of string interpolation';
case self::ARROW_TYPE:
return 'arrow function';
default:
throw new \LogicException(sprintf('Token of type
"%s" does not exist.', $type));
}
}
}
class_alias('Twig\Token', 'Twig_Token');
PK-d�[L�芁�8vendor/twig/twig/src/TokenParser/AbstractTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Parser;
/**
* Base class for all token parsers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class AbstractTokenParser implements TokenParserInterface
{
/**
* @var Parser
*/
protected $parser;
public function setParser(Parser $parser)
{
$this->parser = $parser;
}
}
class_alias('Twig\TokenParser\AbstractTokenParser',
'Twig_TokenParser');
PK-d�[�Ҕ)��5vendor/twig/twig/src/TokenParser/ApplyTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\Expression\TempNameExpression;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Node\SetNode;
use Twig\Token;
/**
* Applies filters on a section of a template.
*
* {% apply upper %}
* This text becomes uppercase
* {% endapplys %}
*/
final class ApplyTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$name = $this->parser->getVarName();
$ref = new TempNameExpression($name, $lineno);
$ref->setAttribute('always_defined', true);
$filter =
$this->parser->getExpressionParser()->parseFilterExpressionRaw($ref,
$this->getTag());
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideApplyEnd'], true);
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new Node([
new SetNode(true, $ref, $body, $lineno, $this->getTag()),
new PrintNode($filter, $lineno, $this->getTag()),
]);
}
public function decideApplyEnd(Token $token)
{
return $token->test('endapply');
}
public function getTag()
{
return 'apply';
}
}
PK-d�[�;Z
Z
:vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\AutoEscapeNode;
use Twig\Node\Expression\ConstantExpression;
use Twig\Token;
/**
* Marks a section of a template to be escaped or not.
*
* {% autoescape true %}
* Everything will be automatically escaped in this block
* {% endautoescape %}
*
* {% autoescape false %}
* Everything will be outputed as is in this block
* {% endautoescape %}
*
* {% autoescape true js %}
* Everything will be automatically escaped in this block
* using the js escaping strategy
* {% endautoescape %}
*
* @final
*/
class AutoEscapeTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
if ($stream->test(Token::BLOCK_END_TYPE)) {
$value = 'html';
} else {
$expr =
$this->parser->getExpressionParser()->parseExpression();
if (!$expr instanceof ConstantExpression) {
throw new SyntaxError('An escaping strategy must be a
string or a bool.', $stream->getCurrent()->getLine(),
$stream->getSourceContext());
}
$value = $expr->getAttribute('value');
$compat = true === $value || false === $value;
if (true === $value) {
$value = 'html';
}
if ($compat && $stream->test(Token::NAME_TYPE)) {
@trigger_error('Using the autoescape tag with
"true" or "false" before the strategy name is
deprecated since version 1.21.', E_USER_DEPRECATED);
if (false === $value) {
throw new SyntaxError('Unexpected escaping
strategy as you set autoescaping to false.',
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
$value = $stream->next()->getValue();
}
}
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$stream->expect(Token::BLOCK_END_TYPE);
return new AutoEscapeNode($value, $body, $lineno,
$this->getTag());
}
public function decideBlockEnd(Token $token)
{
return $token->test('endautoescape');
}
public function getTag()
{
return 'autoescape';
}
}
class_alias('Twig\TokenParser\AutoEscapeTokenParser',
'Twig_TokenParser_AutoEscape');
PK-d�[�e��� � 5vendor/twig/twig/src/TokenParser/BlockTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\BlockNode;
use Twig\Node\BlockReferenceNode;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Token;
/**
* Marks a section of a template as being reusable.
*
* {% block head %}
* <link rel="stylesheet" href="style.css" />
* <title>{% block title %}{% endblock %} - My
Webpage</title>
* {% endblock %}
*
* @final
*/
class BlockTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$name = $stream->expect(Token::NAME_TYPE)->getValue();
if ($this->parser->hasBlock($name)) {
throw new SyntaxError(sprintf("The block '%s'
has already been defined line %d.", $name,
$this->parser->getBlock($name)->getTemplateLine()),
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
$this->parser->setBlock($name, $block = new BlockNode($name,
new Node([]), $lineno));
$this->parser->pushLocalScope();
$this->parser->pushBlockStack($name);
if ($stream->nextIf(Token::BLOCK_END_TYPE)) {
$body = $this->parser->subparse([$this,
'decideBlockEnd'], true);
if ($token = $stream->nextIf(Token::NAME_TYPE)) {
$value = $token->getValue();
if ($value != $name) {
throw new SyntaxError(sprintf('Expected endblock
for block "%s" (but "%s" given).', $name, $value),
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
}
} else {
$body = new Node([
new
PrintNode($this->parser->getExpressionParser()->parseExpression(),
$lineno),
]);
}
$stream->expect(Token::BLOCK_END_TYPE);
$block->setNode('body', $body);
$this->parser->popBlockStack();
$this->parser->popLocalScope();
return new BlockReferenceNode($name, $lineno, $this->getTag());
}
public function decideBlockEnd(Token $token)
{
return $token->test('endblock');
}
public function getTag()
{
return 'block';
}
}
class_alias('Twig\TokenParser\BlockTokenParser',
'Twig_TokenParser_Block');
PK-d�[�f��:vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\DeprecatedNode;
use Twig\Token;
/**
* Deprecates a section of a template.
*
* {% deprecated 'The "base.twig" template is deprecated,
use "layout.twig" instead.' %}
* {% extends 'layout.html.twig' %}
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*
* @final
*/
class DeprecatedTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$expr =
$this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new DeprecatedNode($expr, $token->getLine(),
$this->getTag());
}
public function getTag()
{
return 'deprecated';
}
}
class_alias('Twig\TokenParser\DeprecatedTokenParser',
'Twig_TokenParser_Deprecated');
PK-d�[�yb
2vendor/twig/twig/src/TokenParser/DoTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\DoNode;
use Twig\Token;
/**
* Evaluates an expression, discarding the returned value.
*
* @final
*/
class DoTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$expr =
$this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new DoNode($expr, $token->getLine(), $this->getTag());
}
public function getTag()
{
return 'do';
}
}
class_alias('Twig\TokenParser\DoTokenParser',
'Twig_TokenParser_Do');
PK-d�[�w���5vendor/twig/twig/src/TokenParser/EmbedTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\EmbedNode;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Token;
/**
* Embeds a template.
*
* @final
*/
class EmbedTokenParser extends IncludeTokenParser
{
public function parse(Token $token)
{
$stream = $this->parser->getStream();
$parent =
$this->parser->getExpressionParser()->parseExpression();
list($variables, $only, $ignoreMissing) =
$this->parseArguments();
$parentToken = $fakeParentToken = new Token(Token::STRING_TYPE,
'__parent__', $token->getLine());
if ($parent instanceof ConstantExpression) {
$parentToken = new Token(Token::STRING_TYPE,
$parent->getAttribute('value'), $token->getLine());
} elseif ($parent instanceof NameExpression) {
$parentToken = new Token(Token::NAME_TYPE,
$parent->getAttribute('name'), $token->getLine());
}
// inject a fake parent to make the parent() function work
$stream->injectTokens([
new Token(Token::BLOCK_START_TYPE, '',
$token->getLine()),
new Token(Token::NAME_TYPE, 'extends',
$token->getLine()),
$parentToken,
new Token(Token::BLOCK_END_TYPE, '',
$token->getLine()),
]);
$module = $this->parser->parse($stream, [$this,
'decideBlockEnd'], true);
// override the parent with the correct one
if ($fakeParentToken === $parentToken) {
$module->setNode('parent', $parent);
}
$this->parser->embedTemplate($module);
$stream->expect(Token::BLOCK_END_TYPE);
return new EmbedNode($module->getTemplateName(),
$module->getAttribute('index'), $variables, $only,
$ignoreMissing, $token->getLine(), $this->getTag());
}
public function decideBlockEnd(Token $token)
{
return $token->test('endembed');
}
public function getTag()
{
return 'embed';
}
}
class_alias('Twig\TokenParser\EmbedTokenParser',
'Twig_TokenParser_Embed');
PK-d�[�^���7vendor/twig/twig/src/TokenParser/ExtendsTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\Node;
use Twig\Token;
/**
* Extends a template by another one.
*
* {% extends "base.html" %}
*
* @final
*/
class ExtendsTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$stream = $this->parser->getStream();
if ($this->parser->peekBlockStack()) {
throw new SyntaxError('Cannot use "extend" in a
block.', $token->getLine(), $stream->getSourceContext());
} elseif (!$this->parser->isMainScope()) {
throw new SyntaxError('Cannot use "extend" in a
macro.', $token->getLine(), $stream->getSourceContext());
}
if (null !== $this->parser->getParent()) {
throw new SyntaxError('Multiple extends tags are
forbidden.', $token->getLine(), $stream->getSourceContext());
}
$this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
$stream->expect(Token::BLOCK_END_TYPE);
return new Node();
}
public function getTag()
{
return 'extends';
}
}
class_alias('Twig\TokenParser\ExtendsTokenParser',
'Twig_TokenParser_Extends');
PK-d�[�@@6vendor/twig/twig/src/TokenParser/FilterTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\BlockNode;
use Twig\Node\Expression\BlockReferenceExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\PrintNode;
use Twig\Token;
/**
* Filters a section of a template by applying filters.
*
* {% filter upper %}
* This text becomes uppercase
* {% endfilter %}
*
* @final
*/
class FilterTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$name = $this->parser->getVarName();
$ref = new BlockReferenceExpression(new ConstantExpression($name,
$token->getLine()), null, $token->getLine(), $this->getTag());
$filter =
$this->parser->getExpressionParser()->parseFilterExpressionRaw($ref,
$this->getTag());
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
$block = new BlockNode($name, $body, $token->getLine());
$this->parser->setBlock($name, $block);
return new PrintNode($filter, $token->getLine(),
$this->getTag());
}
public function decideBlockEnd(Token $token)
{
return $token->test('endfilter');
}
public function getTag()
{
return 'filter';
}
}
class_alias('Twig\TokenParser\FilterTokenParser',
'Twig_TokenParser_Filter');
PK-d�[v����5vendor/twig/twig/src/TokenParser/FlushTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\FlushNode;
use Twig\Token;
/**
* Flushes the output to the client.
*
* @see flush()
*
* @final
*/
class FlushTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new FlushNode($token->getLine(), $this->getTag());
}
public function getTag()
{
return 'flush';
}
}
class_alias('Twig\TokenParser\FlushTokenParser',
'Twig_TokenParser_Flush');
PK-d�[��Vjj3vendor/twig/twig/src/TokenParser/ForTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\ForNode;
use Twig\Token;
use Twig\TokenStream;
/**
* Loops over each item of a sequence.
*
* <ul>
* {% for user in users %}
* <li>{{ user.username|e }}</li>
* {% endfor %}
* </ul>
*
* @final
*/
class ForTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$targets =
$this->parser->getExpressionParser()->parseAssignmentExpression();
$stream->expect(Token::OPERATOR_TYPE, 'in');
$seq =
$this->parser->getExpressionParser()->parseExpression();
$ifexpr = null;
if ($stream->nextIf(Token::NAME_TYPE, 'if')) {
$ifexpr =
$this->parser->getExpressionParser()->parseExpression();
}
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideForFork']);
if ('else' == $stream->next()->getValue()) {
$stream->expect(Token::BLOCK_END_TYPE);
$else = $this->parser->subparse([$this,
'decideForEnd'], true);
} else {
$else = null;
}
$stream->expect(Token::BLOCK_END_TYPE);
if (\count($targets) > 1) {
$keyTarget = $targets->getNode(0);
$keyTarget = new
AssignNameExpression($keyTarget->getAttribute('name'),
$keyTarget->getTemplateLine());
$valueTarget = $targets->getNode(1);
$valueTarget = new
AssignNameExpression($valueTarget->getAttribute('name'),
$valueTarget->getTemplateLine());
} else {
$keyTarget = new AssignNameExpression('_key',
$lineno);
$valueTarget = $targets->getNode(0);
$valueTarget = new
AssignNameExpression($valueTarget->getAttribute('name'),
$valueTarget->getTemplateLine());
}
if ($ifexpr) {
$this->checkLoopUsageCondition($stream, $ifexpr);
$this->checkLoopUsageBody($stream, $body);
}
return new ForNode($keyTarget, $valueTarget, $seq, $ifexpr, $body,
$else, $lineno, $this->getTag());
}
public function decideForFork(Token $token)
{
return $token->test(['else', 'endfor']);
}
public function decideForEnd(Token $token)
{
return $token->test('endfor');
}
// the loop variable cannot be used in the condition
protected function checkLoopUsageCondition(TokenStream $stream,
\Twig_NodeInterface $node)
{
if ($node instanceof GetAttrExpression &&
$node->getNode('node') instanceof NameExpression &&
'loop' ==
$node->getNode('node')->getAttribute('name')) {
throw new SyntaxError('The "loop" variable
cannot be used in a looping condition.', $node->getTemplateLine(),
$stream->getSourceContext());
}
foreach ($node as $n) {
if (!$n) {
continue;
}
$this->checkLoopUsageCondition($stream, $n);
}
}
// check usage of non-defined loop-items
// it does not catch all problems (for instance when a for is included
into another or when the variable is used in an include)
protected function checkLoopUsageBody(TokenStream $stream,
\Twig_NodeInterface $node)
{
if ($node instanceof GetAttrExpression &&
$node->getNode('node') instanceof NameExpression &&
'loop' ==
$node->getNode('node')->getAttribute('name')) {
$attribute = $node->getNode('attribute');
if ($attribute instanceof ConstantExpression &&
\in_array($attribute->getAttribute('value'),
['length', 'revindex0', 'revindex',
'last'])) {
throw new SyntaxError(sprintf('The "loop.%s"
variable is not defined when looping with a condition.',
$attribute->getAttribute('value')),
$node->getTemplateLine(), $stream->getSourceContext());
}
}
// should check for parent.loop.XXX usage
if ($node instanceof ForNode) {
return;
}
foreach ($node as $n) {
if (!$n) {
continue;
}
$this->checkLoopUsageBody($stream, $n);
}
}
public function getTag()
{
return 'for';
}
}
class_alias('Twig\TokenParser\ForTokenParser',
'Twig_TokenParser_For');
PK-d�[��xx4vendor/twig/twig/src/TokenParser/FromTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\ImportNode;
use Twig\Token;
/**
* Imports macros.
*
* {% from 'forms.html' import forms %}
*
* @final
*/
class FromTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$macro =
$this->parser->getExpressionParser()->parseExpression();
$stream = $this->parser->getStream();
$stream->expect(Token::NAME_TYPE, 'import');
$targets = [];
do {
$name = $stream->expect(Token::NAME_TYPE)->getValue();
$alias = $name;
if ($stream->nextIf('as')) {
$alias =
$stream->expect(Token::NAME_TYPE)->getValue();
}
$targets[$name] = $alias;
if (!$stream->nextIf(Token::PUNCTUATION_TYPE,
',')) {
break;
}
} while (true);
$stream->expect(Token::BLOCK_END_TYPE);
$var = new AssignNameExpression($this->parser->getVarName(),
$token->getLine());
$node = new ImportNode($macro, $var, $token->getLine(),
$this->getTag());
foreach ($targets as $name => $alias) {
if ($this->parser->isReservedMacroName($name)) {
throw new SyntaxError(sprintf('"%s" cannot
be an imported macro as it is a reserved keyword.', $name),
$token->getLine(), $stream->getSourceContext());
}
$this->parser->addImportedSymbol('function',
$alias, 'get'.$name, $var);
}
return $node;
}
public function getTag()
{
return 'from';
}
}
class_alias('Twig\TokenParser\FromTokenParser',
'Twig_TokenParser_From');
PK-d�[
B�� � 2vendor/twig/twig/src/TokenParser/IfTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\IfNode;
use Twig\Node\Node;
use Twig\Token;
/**
* Tests a condition.
*
* {% if users %}
* <ul>
* {% for user in users %}
* <li>{{ user.username|e }}</li>
* {% endfor %}
* </ul>
* {% endif %}
*
* @final
*/
class IfTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$expr =
$this->parser->getExpressionParser()->parseExpression();
$stream = $this->parser->getStream();
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideIfFork']);
$tests = [$expr, $body];
$else = null;
$end = false;
while (!$end) {
switch ($stream->next()->getValue()) {
case 'else':
$stream->expect(Token::BLOCK_END_TYPE);
$else = $this->parser->subparse([$this,
'decideIfEnd']);
break;
case 'elseif':
$expr =
$this->parser->getExpressionParser()->parseExpression();
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideIfFork']);
$tests[] = $expr;
$tests[] = $body;
break;
case 'endif':
$end = true;
break;
default:
throw new SyntaxError(sprintf('Unexpected end of
template. Twig was looking for the following tags "else",
"elseif", or "endif" to close the "if" block
started at line %d).', $lineno),
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
}
$stream->expect(Token::BLOCK_END_TYPE);
return new IfNode(new Node($tests), $else, $lineno,
$this->getTag());
}
public function decideIfFork(Token $token)
{
return $token->test(['elseif', 'else',
'endif']);
}
public function decideIfEnd(Token $token)
{
return $token->test(['endif']);
}
public function getTag()
{
return 'if';
}
}
class_alias('Twig\TokenParser\IfTokenParser',
'Twig_TokenParser_If');
PK-d�[mO/J��6vendor/twig/twig/src/TokenParser/ImportTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\ImportNode;
use Twig\Token;
/**
* Imports macros.
*
* {% import 'forms.html' as forms %}
*
* @final
*/
class ImportTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$macro =
$this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect(Token::NAME_TYPE,
'as');
$var = new
AssignNameExpression($this->parser->getStream()->expect(Token::NAME_TYPE)->getValue(),
$token->getLine());
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
$this->parser->addImportedSymbol('template',
$var->getAttribute('name'));
return new ImportNode($macro, $var, $token->getLine(),
$this->getTag());
}
public function getTag()
{
return 'import';
}
}
class_alias('Twig\TokenParser\ImportTokenParser',
'Twig_TokenParser_Import');
PK-d�[r� �SS7vendor/twig/twig/src/TokenParser/IncludeTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\IncludeNode;
use Twig\Token;
/**
* Includes a template.
*
* {% include 'header.html' %}
* Body
* {% include 'footer.html' %}
*/
class IncludeTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$expr =
$this->parser->getExpressionParser()->parseExpression();
list($variables, $only, $ignoreMissing) =
$this->parseArguments();
return new IncludeNode($expr, $variables, $only, $ignoreMissing,
$token->getLine(), $this->getTag());
}
protected function parseArguments()
{
$stream = $this->parser->getStream();
$ignoreMissing = false;
if ($stream->nextIf(Token::NAME_TYPE, 'ignore')) {
$stream->expect(Token::NAME_TYPE, 'missing');
$ignoreMissing = true;
}
$variables = null;
if ($stream->nextIf(Token::NAME_TYPE, 'with')) {
$variables =
$this->parser->getExpressionParser()->parseExpression();
}
$only = false;
if ($stream->nextIf(Token::NAME_TYPE, 'only')) {
$only = true;
}
$stream->expect(Token::BLOCK_END_TYPE);
return [$variables, $only, $ignoreMissing];
}
public function getTag()
{
return 'include';
}
}
class_alias('Twig\TokenParser\IncludeTokenParser',
'Twig_TokenParser_Include');
PK-d�[&nq�uu5vendor/twig/twig/src/TokenParser/MacroTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\BodyNode;
use Twig\Node\MacroNode;
use Twig\Node\Node;
use Twig\Token;
/**
* Defines a macro.
*
* {% macro input(name, value, type, size) %}
* <input type="{{ type|default('text') }}"
name="{{ name }}" value="{{ value|e }}" size="{{
size|default(20) }}" />
* {% endmacro %}
*
* @final
*/
class MacroTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$name = $stream->expect(Token::NAME_TYPE)->getValue();
$arguments =
$this->parser->getExpressionParser()->parseArguments(true, true);
$stream->expect(Token::BLOCK_END_TYPE);
$this->parser->pushLocalScope();
$body = $this->parser->subparse([$this,
'decideBlockEnd'], true);
if ($token = $stream->nextIf(Token::NAME_TYPE)) {
$value = $token->getValue();
if ($value != $name) {
throw new SyntaxError(sprintf('Expected endmacro for
macro "%s" (but "%s" given).', $name, $value),
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
}
$this->parser->popLocalScope();
$stream->expect(Token::BLOCK_END_TYPE);
$this->parser->setMacro($name, new MacroNode($name, new
BodyNode([$body]), $arguments, $lineno, $this->getTag()));
return new Node();
}
public function decideBlockEnd(Token $token)
{
return $token->test('endmacro');
}
public function getTag()
{
return 'macro';
}
}
class_alias('Twig\TokenParser\MacroTokenParser',
'Twig_TokenParser_Macro');
PK-d�[���$$7vendor/twig/twig/src/TokenParser/SandboxTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\IncludeNode;
use Twig\Node\SandboxNode;
use Twig\Node\TextNode;
use Twig\Token;
/**
* Marks a section of a template as untrusted code that must be evaluated
in the sandbox mode.
*
* {% sandbox %}
* {% include 'user.html' %}
* {% endsandbox %}
*
* @see https://twig.symfony.com/doc/api.html#sandbox-extension for details
*
* @final
*/
class SandboxTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$stream = $this->parser->getStream();
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$stream->expect(Token::BLOCK_END_TYPE);
// in a sandbox tag, only include tags are allowed
if (!$body instanceof IncludeNode) {
foreach ($body as $node) {
if ($node instanceof TextNode &&
ctype_space($node->getAttribute('data'))) {
continue;
}
if (!$node instanceof IncludeNode) {
throw new SyntaxError('Only "include"
tags are allowed within a "sandbox" section.',
$node->getTemplateLine(), $stream->getSourceContext());
}
}
}
return new SandboxNode($body, $token->getLine(),
$this->getTag());
}
public function decideBlockEnd(Token $token)
{
return $token->test('endsandbox');
}
public function getTag()
{
return 'sandbox';
}
}
class_alias('Twig\TokenParser\SandboxTokenParser',
'Twig_TokenParser_Sandbox');
PK-d�["��3vendor/twig/twig/src/TokenParser/SetTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\SetNode;
use Twig\Token;
/**
* Defines a variable.
*
* {% set foo = 'foo' %}
* {% set foo = [1, 2] %}
* {% set foo = {'foo': 'bar'} %}
* {% set foo = 'foo' ~ 'bar' %}
* {% set foo, bar = 'foo', 'bar' %}
* {% set foo %}Some content{% endset %}
*
* @final
*/
class SetTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$names =
$this->parser->getExpressionParser()->parseAssignmentExpression();
$capture = false;
if ($stream->nextIf(Token::OPERATOR_TYPE, '=')) {
$values =
$this->parser->getExpressionParser()->parseMultitargetExpression();
$stream->expect(Token::BLOCK_END_TYPE);
if (\count($names) !== \count($values)) {
throw new SyntaxError('When using set, you must have
the same number of variables and assignments.',
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
} else {
$capture = true;
if (\count($names) > 1) {
throw new SyntaxError('When using set with a block,
you cannot have a multi-target.',
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
$stream->expect(Token::BLOCK_END_TYPE);
$values = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$stream->expect(Token::BLOCK_END_TYPE);
}
return new SetNode($capture, $names, $values, $lineno,
$this->getTag());
}
public function decideBlockEnd(Token $token)
{
return $token->test('endset');
}
public function getTag()
{
return 'set';
}
}
class_alias('Twig\TokenParser\SetTokenParser',
'Twig_TokenParser_Set');
PK-d�[�6�9vendor/twig/twig/src/TokenParser/SpacelessTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\SpacelessNode;
use Twig\Token;
/**
* Remove whitespaces between HTML tags.
*
* {% spaceless %}
* <div>
* <strong>foo</strong>
* </div>
* {% endspaceless %}
* {# output will be
<div><strong>foo</strong></div> #}
*
* @final
*/
class SpacelessTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$lineno = $token->getLine();
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideSpacelessEnd'], true);
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new SpacelessNode($body, $lineno, $this->getTag());
}
public function decideSpacelessEnd(Token $token)
{
return $token->test('endspaceless');
}
public function getTag()
{
return 'spaceless';
}
}
class_alias('Twig\TokenParser\SpacelessTokenParser',
'Twig_TokenParser_Spaceless');
PK-d�[&�{Aqq9vendor/twig/twig/src/TokenParser/TokenParserInterface.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Parser;
use Twig\Token;
/**
* Interface implemented by token parsers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface TokenParserInterface
{
/**
* Sets the parser associated with this token parser.
*/
public function setParser(Parser $parser);
/**
* Parses a token and returns a node.
*
* @return \Twig_NodeInterface
*
* @throws SyntaxError
*/
public function parse(Token $token);
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag();
}
class_alias('Twig\TokenParser\TokenParserInterface',
'Twig_TokenParserInterface');
// Ensure that the aliased name is loaded to keep BC for classes
implementing the typehint with the old aliased name.
class_exists('Twig\Token');
class_exists('Twig\Parser');
PK-d�[}����3vendor/twig/twig/src/TokenParser/UseTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
use Twig\Token;
/**
* Imports blocks defined in another template into the current template.
*
* {% extends "base.html" %}
*
* {% use "blocks.html" %}
*
* {% block title %}{% endblock %}
* {% block content %}{% endblock %}
*
* @see https://twig.symfony.com/doc/templates.html#horizontal-reuse for
details.
*
* @final
*/
class UseTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$template =
$this->parser->getExpressionParser()->parseExpression();
$stream = $this->parser->getStream();
if (!$template instanceof ConstantExpression) {
throw new SyntaxError('The template references in a
"use" statement must be a string.',
$stream->getCurrent()->getLine(), $stream->getSourceContext());
}
$targets = [];
if ($stream->nextIf('with')) {
do {
$name =
$stream->expect(Token::NAME_TYPE)->getValue();
$alias = $name;
if ($stream->nextIf('as')) {
$alias =
$stream->expect(Token::NAME_TYPE)->getValue();
}
$targets[$name] = new ConstantExpression($alias, -1);
if (!$stream->nextIf(Token::PUNCTUATION_TYPE,
',')) {
break;
}
} while (true);
}
$stream->expect(Token::BLOCK_END_TYPE);
$this->parser->addTrait(new Node(['template' =>
$template, 'targets' => new Node($targets)]));
return new Node();
}
public function getTag()
{
return 'use';
}
}
class_alias('Twig\TokenParser\UseTokenParser',
'Twig_TokenParser_Use');
PK-d�[
O`4vendor/twig/twig/src/TokenParser/WithTokenParser.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\TokenParser;
use Twig\Node\WithNode;
use Twig\Token;
/**
* Creates a nested scope.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class WithTokenParser extends AbstractTokenParser
{
public function parse(Token $token)
{
$stream = $this->parser->getStream();
$variables = null;
$only = false;
if (!$stream->test(Token::BLOCK_END_TYPE)) {
$variables =
$this->parser->getExpressionParser()->parseExpression();
$only = $stream->nextIf(Token::NAME_TYPE, 'only');
}
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this,
'decideWithEnd'], true);
$stream->expect(Token::BLOCK_END_TYPE);
return new WithNode($body, $variables, $only, $token->getLine(),
$this->getTag());
}
public function decideWithEnd(Token $token)
{
return $token->test('endwith');
}
public function getTag()
{
return 'with';
}
}
class_alias('Twig\TokenParser\WithTokenParser',
'Twig_TokenParser_With');
PK-d�[�N:ott$vendor/twig/twig/src/TokenStream.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
* (c) Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Error\SyntaxError;
/**
* Represents a token stream.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TokenStream
{
protected $tokens;
protected $current = 0;
protected $filename;
private $source;
/**
* @param array $tokens An array of tokens
* @param string|null $name The name of the template which tokens are
associated with
* @param string|null $source The source code associated with the
tokens
*/
public function __construct(array $tokens, $name = null, $source =
null)
{
if (!$name instanceof Source) {
if (null !== $name || null !== $source) {
@trigger_error(sprintf('Passing a string as the $name
argument of %s() is deprecated since version 1.27. Pass a \Twig\Source
instance instead.', __METHOD__), E_USER_DEPRECATED);
}
$this->source = new Source($source, $name);
} else {
$this->source = $name;
}
$this->tokens = $tokens;
// deprecated, not used anymore, to be removed in 2.0
$this->filename = $this->source->getName();
}
public function __toString()
{
return implode("\n", $this->tokens);
}
public function injectTokens(array $tokens)
{
$this->tokens = array_merge(\array_slice($this->tokens, 0,
$this->current), $tokens, \array_slice($this->tokens,
$this->current));
}
/**
* Sets the pointer to the next token and returns the old one.
*
* @return Token
*/
public function next()
{
if (!isset($this->tokens[++$this->current])) {
throw new SyntaxError('Unexpected end of template.',
$this->tokens[$this->current - 1]->getLine(), $this->source);
}
return $this->tokens[$this->current - 1];
}
/**
* Tests a token, sets the pointer to the next one and returns it or
throws a syntax error.
*
* @return Token|null The next token if the condition is true, null
otherwise
*/
public function nextIf($primary, $secondary = null)
{
if ($this->tokens[$this->current]->test($primary,
$secondary)) {
return $this->next();
}
}
/**
* Tests a token and returns it or throws a syntax error.
*
* @return Token
*/
public function expect($type, $value = null, $message = null)
{
$token = $this->tokens[$this->current];
if (!$token->test($type, $value)) {
$line = $token->getLine();
throw new SyntaxError(sprintf('%sUnexpected token
"%s"%s ("%s" expected%s).',
$message ? $message.'. ' : '',
Token::typeToEnglish($token->getType()),
$token->getValue() ? sprintf(' of value
"%s"', $token->getValue()) : '',
Token::typeToEnglish($type), $value ? sprintf(' with
value "%s"', $value) : ''),
$line,
$this->source
);
}
$this->next();
return $token;
}
/**
* Looks at the next token.
*
* @param int $number
*
* @return Token
*/
public function look($number = 1)
{
if (!isset($this->tokens[$this->current + $number])) {
throw new SyntaxError('Unexpected end of template.',
$this->tokens[$this->current + $number - 1]->getLine(),
$this->source);
}
return $this->tokens[$this->current + $number];
}
/**
* Tests the current token.
*
* @return bool
*/
public function test($primary, $secondary = null)
{
return $this->tokens[$this->current]->test($primary,
$secondary);
}
/**
* Checks if end of stream was reached.
*
* @return bool
*/
public function isEOF()
{
return Token::EOF_TYPE ===
$this->tokens[$this->current]->getType();
}
/**
* @return Token
*/
public function getCurrent()
{
return $this->tokens[$this->current];
}
/**
* Gets the name associated with this stream (null if not defined).
*
* @return string|null
*
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getFilename()
{
@trigger_error(sprintf('The %s() method is deprecated since
version 1.27 and will be removed in 2.0. Use getSourceContext()
instead.', __METHOD__), E_USER_DEPRECATED);
return $this->source->getName();
}
/**
* Gets the source code associated with this stream.
*
* @return string
*
* @internal Don't use this as it might be empty depending on the
environment configuration
*
* @deprecated since 1.27 (to be removed in 2.0)
*/
public function getSource()
{
@trigger_error(sprintf('The %s() method is deprecated since
version 1.27 and will be removed in 2.0. Use getSourceContext()
instead.', __METHOD__), E_USER_DEPRECATED);
return $this->source->getCode();
}
/**
* Gets the source associated with this stream.
*
* @return Source
*
* @internal
*/
public function getSourceContext()
{
return $this->source;
}
}
class_alias('Twig\TokenStream', 'Twig_TokenStream');
PK-d�[ӉX��
�
#vendor/twig/twig/src/TwigFilter.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Node\Node;
/**
* Represents a template filter.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TwigFilter
{
protected $name;
protected $callable;
protected $options;
protected $arguments = [];
public function __construct($name, $callable, array $options = [])
{
$this->name = $name;
$this->callable = $callable;
$this->options = array_merge([
'needs_environment' => false,
'needs_context' => false,
'is_variadic' => false,
'is_safe' => null,
'is_safe_callback' => null,
'pre_escape' => null,
'preserves_safety' => null,
'node_class' =>
'\Twig\Node\Expression\FilterExpression',
'deprecated' => false,
'alternative' => null,
], $options);
}
public function getName()
{
return $this->name;
}
public function getCallable()
{
return $this->callable;
}
public function getNodeClass()
{
return $this->options['node_class'];
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Node $filterArgs)
{
if (null !== $this->options['is_safe']) {
return $this->options['is_safe'];
}
if (null !== $this->options['is_safe_callback']) {
return
\call_user_func($this->options['is_safe_callback'],
$filterArgs);
}
}
public function getPreservesSafety()
{
return $this->options['preserves_safety'];
}
public function getPreEscape()
{
return $this->options['pre_escape'];
}
public function isVariadic()
{
return $this->options['is_variadic'];
}
public function isDeprecated()
{
return (bool) $this->options['deprecated'];
}
public function getDeprecatedVersion()
{
return $this->options['deprecated'];
}
public function getAlternative()
{
return $this->options['alternative'];
}
}
class_alias('Twig\TwigFilter', 'Twig_SimpleFilter');
// Ensure that the aliased name is loaded to keep BC for classes
implementing the typehint with the old aliased name.
class_exists('Twig\Node\Node');
PK-d�[����
%vendor/twig/twig/src/TwigFunction.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
use Twig\Node\Node;
/**
* Represents a template function.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TwigFunction
{
protected $name;
protected $callable;
protected $options;
protected $arguments = [];
public function __construct($name, $callable, array $options = [])
{
$this->name = $name;
$this->callable = $callable;
$this->options = array_merge([
'needs_environment' => false,
'needs_context' => false,
'is_variadic' => false,
'is_safe' => null,
'is_safe_callback' => null,
'node_class' =>
'\Twig\Node\Expression\FunctionExpression',
'deprecated' => false,
'alternative' => null,
], $options);
}
public function getName()
{
return $this->name;
}
public function getCallable()
{
return $this->callable;
}
public function getNodeClass()
{
return $this->options['node_class'];
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Node $functionArgs)
{
if (null !== $this->options['is_safe']) {
return $this->options['is_safe'];
}
if (null !== $this->options['is_safe_callback']) {
return
\call_user_func($this->options['is_safe_callback'],
$functionArgs);
}
return [];
}
public function isVariadic()
{
return $this->options['is_variadic'];
}
public function isDeprecated()
{
return (bool) $this->options['deprecated'];
}
public function getDeprecatedVersion()
{
return $this->options['deprecated'];
}
public function getAlternative()
{
return $this->options['alternative'];
}
}
class_alias('Twig\TwigFunction',
'Twig_SimpleFunction');
// Ensure that the aliased name is loaded to keep BC for classes
implementing the typehint with the old aliased name.
class_exists('Twig\Node\Node');
PK-d�[�EVZ��!vendor/twig/twig/src/TwigTest.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig;
/**
* Represents a template test.
*
* @final
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TwigTest
{
protected $name;
protected $callable;
protected $options;
private $arguments = [];
public function __construct($name, $callable, array $options = [])
{
$this->name = $name;
$this->callable = $callable;
$this->options = array_merge([
'is_variadic' => false,
'node_class' =>
'\Twig\Node\Expression\TestExpression',
'deprecated' => false,
'alternative' => null,
], $options);
}
public function getName()
{
return $this->name;
}
public function getCallable()
{
return $this->callable;
}
public function getNodeClass()
{
return $this->options['node_class'];
}
public function isVariadic()
{
return $this->options['is_variadic'];
}
public function isDeprecated()
{
return (bool) $this->options['deprecated'];
}
public function getDeprecatedVersion()
{
return $this->options['deprecated'];
}
public function getAlternative()
{
return $this->options['alternative'];
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
}
class_alias('Twig\TwigTest', 'Twig_SimpleTest');
PK-d�[+�=��2vendor/twig/twig/src/Util/DeprecationCollector.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Util;
use Twig\Environment;
use Twig\Error\SyntaxError;
use Twig\Source;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final
*/
class DeprecationCollector
{
private $twig;
private $deprecations;
public function __construct(Environment $twig)
{
$this->twig = $twig;
}
/**
* Returns deprecations for templates contained in a directory.
*
* @param string $dir A directory where templates are stored
* @param string $ext Limit the loaded templates by extension
*
* @return array An array of deprecations
*/
public function collectDir($dir, $ext = '.twig')
{
$iterator = new \RegexIterator(
new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir),
\RecursiveIteratorIterator::LEAVES_ONLY
), '{'.preg_quote($ext).'$}'
);
return $this->collect(new TemplateDirIterator($iterator));
}
/**
* Returns deprecations for passed templates.
*
* @param \Traversable $iterator An iterator of templates (where keys
are template names and values the contents of the template)
*
* @return array An array of deprecations
*/
public function collect(\Traversable $iterator)
{
$this->deprecations = [];
set_error_handler([$this, 'errorHandler']);
foreach ($iterator as $name => $contents) {
try {
$this->twig->parse($this->twig->tokenize(new
Source($contents, $name)));
} catch (SyntaxError $e) {
// ignore templates containing syntax errors
}
}
restore_error_handler();
$deprecations = $this->deprecations;
$this->deprecations = [];
return $deprecations;
}
/**
* @internal
*/
public function errorHandler($type, $msg)
{
if (E_USER_DEPRECATED === $type) {
$this->deprecations[] = $msg;
}
}
}
class_alias('Twig\Util\DeprecationCollector',
'Twig_Util_DeprecationCollector');
PK-d�[�~�NN1vendor/twig/twig/src/Util/TemplateDirIterator.phpnu�[���<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Util;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class TemplateDirIterator extends \IteratorIterator
{
public function current()
{
return file_get_contents(parent::current());
}
public function key()
{
return (string) parent::key();
}
}
class_alias('Twig\Util\TemplateDirIterator',
'Twig_Util_TemplateDirIterator');
PKe�[ȃ�І�gantry5.phpnu�[���<?php
/**
* @package Gantry 5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
defined('_JEXEC') or die;
class plgQuickiconGantry5 extends JPlugin
{
public function __construct(&$subject, $config)
{
// Do not load if Gantry libraries are not installed or
initialised.
if (!class_exists('Gantry5\Loader')) return;
parent::__construct($subject, $config);
// Always load language.
$lang = JFactory::getLanguage();
$lang->load('com_gantry5.sys') ||
$lang->load('com_gantry5.sys', JPATH_ADMINISTRATOR .
'/components/com_gantry5');
$this->loadLanguage('plg_quickicon_gantry5.sys');
}
/**
* Display Gantry 5 backend icon
*
* @param string $context
* @return array|null
*/
public function onGetIcons($context)
{
$user = JFactory::getUser();
if ($context != $this->params->get('context',
'mod_quickicon')
|| !$user->authorise('core.manage',
'com_gantry5')) {
return null;
}
try {
$updates = null;
if ($user->authorise('core.manage',
'com_installer'))
{
// Initialise Gantry.
Gantry5\Loader::setup();
$gantry = Gantry\Framework\Gantry::instance();
$gantry['streams']->register();
/** @var Gantry\Framework\Platform $platform */
$platform = $gantry['platform'];
$updates = $platform->updates();
}
} catch (Exception $e) {
$app = JFactory::getApplication();
$app->enqueueMessage($e->getMessage(),
'warning');
$updates = false;
}
$quickicons = array(
array(
'link' =>
JRoute::_('index.php?option=com_gantry5'),
'image' => 'eye',
'text' => JText::_('COM_GANTRY5'),
'group' =>
'MOD_QUICKICON_EXTENSIONS',
'access' => array('core.manage',
'com_gantry5')
)
);
if ($updates === false) {
// Disabled
$quickicons[] = array(
'link' =>
JRoute::_('index.php?option=com_gantry5'),
'image' => 'eye',
'text' =>
JText::_('PLG_QUICKICON_GANTRY5_UPDATES_DISABLED'),
'group' =>
'MOD_QUICKICON_MAINTENANCE'
);
} elseif (!empty($updates)) {
// Has updates
$quickicons[] = array(
'link' =>
JRoute::_('index.php?option=com_installer&view=update'),
'image' => 'download',
'text' =>
JText::_('PLG_QUICKICON_GANTRY5_UPDATE_NOW'),
'group' =>
'MOD_QUICKICON_MAINTENANCE'
);
}
return $quickicons;
}
}
PKe�[Él���gantry5.xmlnu�[���<?xml
version="1.0" encoding="UTF-8"
standalone="no"?>
<extension version="3.4" type="plugin"
group="quickicon" method="upgrade">
<name>plg_quickicon_gantry5</name>
<version>5.4.37</version>
<creationDate>January 25, 2021</creationDate>
<author>RocketTheme, LLC</author>
<authorEmail>support@rockettheme.com</authorEmail>
<authorUrl>http://www.rockettheme.com</authorUrl>
<copyright>(C) 2005 - 2019 RocketTheme, LLC. All rights
reserved.</copyright>
<license>http://www.gnu.org/licenses/gpl-2.0.html
GNU/GPL</license>
<description>PLG_QUICKICON_GANTRY5_DESCRIPTION</description>
<files>
<filename
plugin="gantry5">gantry5.php</filename>
<filename>MD5SUMS</filename>
<folder>language</folder>
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field name="context"
type="text"
default="mod_quickicon"
description="PLG_QUICKICON_GANTRY5_GROUP_DESC"
label="PLG_QUICKICON_GANTRY5_GROUP_LABEL"
/>
</fieldset>
</fields>
</config>
</extension>
PKe�[5�����2language/en-GB/en-GB.plg_quickicon_gantry5.sys.ininu�[���PLG_QUICKICON_GANTRY5="Quick
Icon - Gantry 5"
PLG_QUICKICON_GANTRY5_DESCRIPTION="Displays Gantry 5 and its updates
in Joomla Control Panel page."
PLG_QUICKICON_GANTRY5_UPDATE_NOW="Gantry 5 - Update now!"
PLG_QUICKICON_GANTRY5_UPDATES_DISABLED="Gantry 5 Updates
disabled"
PLG_QUICKICON_GANTRY5_GROUP_DESC="The group of this plugin (this value
is compared with the group value used in 'Quick Icons' modules to
inject icons)"
PLG_QUICKICON_GANTRY5_GROUP_LABEL="Group"
PK$d�[<���
bootstrap.phpnu�[���PK$d�[���.�classes/Gantry/Admin/Controller/Html/About.phpnu�[���PK$d�[$�_EYY.[classes/Gantry/Admin/Controller/Html/Cache.phpnu�[���PK$d�[��x� C
classes/Gantry/Admin/Controller/Html/Configurations/Assignments.phpnu�[���PK$d�[�}mFmF>�classes/Gantry/Admin/Controller/Html/Configurations/Layout.phpnu�[���PK$d�['��L-L-<}Zclasses/Gantry/Admin/Controller/Html/Configurations/Page.phpnu�[���PK$d�[�Qޙ""@5�classes/Gantry/Admin/Controller/Html/Configurations/Settings.phpnu�[���PK%d�[�[T�
>��classes/Gantry/Admin/Controller/Html/Configurations/Styles.phpnu�[���PK%d�[���7VV7;�classes/Gantry/Admin/Controller/Html/Configurations.phpnu�[���PK%d�[��_iEE/��classes/Gantry/Admin/Controller/Html/Export.phpnu�[���PK%d�[�?�C}
}
/��classes/Gantry/Admin/Controller/Html/Import.phpnu�[���PK%d�[�^�ww0xclasses/Gantry/Admin/Controller/Html/Install.phpnu�[���PK%d�[
����F�F-O classes/Gantry/Admin/Controller/Html/Menu.phpnu�[���PK%d�[�,�ȵ*�*2�Pclasses/Gantry/Admin/Controller/Html/Positions.phpnu�[���PK%d�[�����/�{classes/Gantry/Admin/Controller/Html/Themes.phpnu�[���PK%d�[��z66.�~classes/Gantry/Admin/Controller/Json/Atoms.phpnu�[���PK%d�[7��]��2b�classes/Gantry/Admin/Controller/Json/Changelog.phpnu�[���PK%d�[�)����8��classes/Gantry/Admin/Controller/Json/Confirmdeletion.phpnu�[���PK%d�[�����0��classes/Gantry/Admin/Controller/Json/Devprod.phpnu�[���PK%d�[
PQ�>�>3Ȫclasses/Gantry/Admin/Controller/Json/Filepicker.phpnu�[���PK%d�[��l�
�
3��classes/Gantry/Admin/Controller/Json/Fontpicker.phpnu�[���PK%d�[�u#S�F�F.�classes/Gantry/Admin/Controller/Json/Icons.phpnu�[���PK%d�[�DEL
L
0�>classes/Gantry/Admin/Controller/Json/Layouts.phpnu�[���PK%d�[�e��))1�_classes/Gantry/Admin/Controller/Json/Particle.phpnu�[���PK%d�[�P_�%%0yclasses/Gantry/Admin/Controller/Json/Unsaved.phpnu�[���PK%d�[譤��&�|classes/Gantry/Admin/EventListener.phpnu�[���PK%d�[uTQ'��classes/Gantry/Admin/Page.phpnu�[���PK%d�[�Ht���"��classes/Gantry/Admin/Particles.phpnu�[���PK%d�[�w�22:�classes/Gantry/Admin/Router.phpnu�[���PK%d�[\��Ɵ
�
��classes/Gantry/Admin/Styles.phpnu�[���PK%d�[�Y�zpp��classes/Gantry/Admin/Theme.phpnu�[���PK%d�[܁l"g�classes/Gantry/Admin/ThemeList.phpnu�[���PK%d�[�(r��18classes/Gantry/Component/Admin/HtmlController.phpnu�[���PK%d�[��p���1~classes/Gantry/Component/Admin/JsonController.phpnu�[���PK%d�[ܵ����<� classes/Gantry/Component/Assignments/AbstractAssignments.phpnu�[���PK%d�[�d�//9(classes/Gantry/Component/Assignments/AssignmentFilter.phpnu�[���PK%d�[3�U���=�;classes/Gantry/Component/Assignments/AssignmentsInterface.phpnu�[���PK%d�[�)!�992
?classes/Gantry/Component/Collection/Collection.phpnu�[���PK%d�[�?�~~;�Dclasses/Gantry/Component/Collection/CollectionInterface.phpnu�[���PK&d�[�c��9$9$1�Iclasses/Gantry/Component/Config/BlueprintForm.phpnu�[���PK&d�[ù���3+nclasses/Gantry/Component/Config/BlueprintSchema.phpnu�[���PK&d�[�-��0�classes/Gantry/Component/Config/CompiledBase.phpnu�[���PK&d�[�ԂDD6l�classes/Gantry/Component/Config/CompiledBlueprints.phpnu�[���PK&d�[��ͭ
2�classes/Gantry/Component/Config/CompiledConfig.phpnu�[���PK&d�[Ѱ�Pdd*��classes/Gantry/Component/Config/Config.phpnu�[���PK&d�[ҽ`\!\!4J�classes/Gantry/Component/Config/ConfigFileFinder.phpnu�[���PK&d�[��VV.
�classes/Gantry/Component/Config/Validation.phpnu�[���PK&d�[��"7sKclasses/Gantry/Component/Config/ValidationException.phpnu�[���PK&d�[#NJ���7�Oclasses/Gantry/Component/Content/Block/ContentBlock.phpnu�[���PK&d�[{�?:xx@gclasses/Gantry/Component/Content/Block/ContentBlockInterface.phpnu�[���PK&d�[��ue�2�24�jclasses/Gantry/Component/Content/Block/HtmlBlock.phpnu�[���PK&d�[�v*B��=�classes/Gantry/Component/Content/Block/HtmlBlockInterface.phpnu�[���PK&d�[ �Q��i�i:D�classes/Gantry/Component/Content/Document/HtmlDocument.phpnu�[���PK&d�[,���6�classes/Gantry/Component/Controller/BaseController.phpnu�[���PK&d�[���006'classes/Gantry/Component/Controller/HtmlController.phpnu�[���PK&d�[0s���6�+classes/Gantry/Component/Controller/JsonController.phpnu�[���PK&d�[�VVaaB�/classes/Gantry/Component/Controller/RestfulControllerInterface.phpnu�[���PK&d�[��7��.�6classes/Gantry/Component/File/CompiledFile.phpnu�[���PK&d�[{BB2#Gclasses/Gantry/Component/File/CompiledYamlFile.phpnu�[���PK&d�[�{�+�+.�Jclasses/Gantry/Component/Filesystem/Folder.phpnu�[���PK&d�[ڀ}e
/�vclasses/Gantry/Component/Filesystem/Streams.phpnu�[���PK&d�[����WW/"�classes/Gantry/Component/Gantry/GantryTrait.phpnu�[���PK&d�[�;o�,classes/Gantry/Component/Gettext/Gettext.phpnu�[���PK&d�[�xх����*B�classes/Gantry/Component/Layout/Layout.phpnu�[���PK&d�[.|�G
0�classes/Gantry/Component/Layout/LayoutReader.phpnu�[���PK&d�[Q�E���3#classes/Gantry/Component/Layout/Version/Format0.phpnu�[���PK&d�[��+�#�#3�*classes/Gantry/Component/Layout/Version/Format1.phpnu�[���PK&d�[��]��E�E3Oclasses/Gantry/Component/Layout/Version/Format2.phpnu�[���PK&d�[j픞--.9�classes/Gantry/Component/Menu/AbstractMenu.phpnu�[���PK&d�[��1D�&�&&��classes/Gantry/Component/Menu/Item.phpnu�[���PK&d�[�{{GLGL6��classes/Gantry/Component/Outline/OutlineCollection.phpnu�[���PK&d�[�T�ڍ�,o6classes/Gantry/Component/Position/Module.phpnu�[���PK&d�[�l*�)#)#.XGclasses/Gantry/Component/Position/Position.phpnu�[���PK&d�[���../�jclasses/Gantry/Component/Position/Positions.phpnu�[���PK&d�[���O��,l�classes/Gantry/Component/Remote/Response.phpnu�[���PK&d�[��N@*U�classes/Gantry/Component/Request/Input.phpnu�[���PK&d�[(5���,��classes/Gantry/Component/Request/Request.phpnu�[���PK&d�[]�>J��2��classes/Gantry/Component/Response/HtmlResponse.phpnu�[���PK&d�[(�gg2�classes/Gantry/Component/Response/JsonResponse.phpnu�[���PK&d�[�~�776��classes/Gantry/Component/Response/RedirectResponse.phpnu�[���PK&d�[ʚ@%��.��classes/Gantry/Component/Response/Response.phpnu�[���PK&d�[V�99*��classes/Gantry/Component/Router/Router.phpnu�[���PK&d�[�M�6��3>�classes/Gantry/Component/Router/RouterInterface.phpnu�[���PK&d�[X}�q&q&3v�classes/Gantry/Component/Stylesheet/CssCompiler.phpnu�[���PK&d�[�03��<Jclasses/Gantry/Component/Stylesheet/CssCompilerInterface.phpnu�[���PK&d�[�d瑄,�,5�
classes/Gantry/Component/Stylesheet/Scss/Compiler.phpnu�[���PK&d�[�}��4sMclasses/Gantry/Component/Stylesheet/ScssCompiler.phpnu�[���PK&d�[�i}},�gclasses/Gantry/Component/System/Messages.phpnu�[���PK&d�[�Y�220�jclasses/Gantry/Component/Theme/AbstractTheme.phpnu�[���PK&d�[�����/8�classes/Gantry/Component/Theme/ThemeDetails.phpnu�[���PK&d�[1���%�%1v�classes/Gantry/Component/Theme/ThemeInstaller.phpnu�[���PK&d�[��IA��1��classes/Gantry/Component/Theme/ThemeInterface.phpnu�[���PK&d�[b����Z�Z-�classes/Gantry/Component/Theme/ThemeTrait.phpnu�[���PK&d�[$�E��
�
2h0 classes/Gantry/Component/Translator/Translator.phpnu�[���PK&d�[�f��GG;�> classes/Gantry/Component/Translator/TranslatorInterface.phpnu�[���PK&d�[�Ϸ�5@B classes/Gantry/Component/Twig/Node/TwigNodeAssets.phpnu�[���PK&d�[���y��7\K classes/Gantry/Component/Twig/Node/TwigNodeMarkdown.phpnu�[���PK&d�[7n^c��8�Q classes/Gantry/Component/Twig/Node/TwigNodePageblock.phpnu�[���PK&d�[�ܽ���6�Z classes/Gantry/Component/Twig/Node/TwigNodeScripts.phpnu�[���PK&d�[JtE5��5�\ classes/Gantry/Component/Twig/Node/TwigNodeStyles.phpnu�[���PK&d�[�$�� 5*_ classes/Gantry/Component/Twig/Node/TwigNodeSwitch.phpnu�[���PK&d�[�K��4�g classes/Gantry/Component/Twig/Node/TwigNodeThrow.phpnu�[���PK&d�[Bh���7�l classes/Gantry/Component/Twig/Node/TwigNodeTryCatch.phpnu�[���PK&d�[��5��
�
?�s classes/Gantry/Component/Twig/TokenParser/TokenParserAssets.phpnu�[���PK&d�[B�$��A�~ classes/Gantry/Component/Twig/TokenParser/TokenParserMarkdown.phpnu�[���PK&d�[I��\ \ B�� classes/Gantry/Component/Twig/TokenParser/TokenParserPageblock.phpnu�[���PK&d�[
FX���@Ŏ classes/Gantry/Component/Twig/TokenParser/TokenParserScripts.phpnu�[���PK&d�[�++B��?� classes/Gantry/Component/Twig/TokenParser/TokenParserStyles.phpnu�[���PK&d�[���#��?J� classes/Gantry/Component/Twig/TokenParser/TokenParserSwitch.phpnu�[���PK&d�[�ʱtt>�� classes/Gantry/Component/Twig/TokenParser/TokenParserThrow.phpnu�[���PK&d�[�TLLA�� classes/Gantry/Component/Twig/TokenParser/TokenParserTryCatch.phpnu�[���PK&d�[�
�5D� classes/Gantry/Component/Twig/TwigCacheFilesystem.phpnu�[���PK&d�[K�
k�Q�Q/ƿ classes/Gantry/Component/Twig/TwigExtension.phpnu�[���PK&d�[��6���$�
classes/Gantry/Component/Url/Url.phpnu�[���PK&d�[�H��AA0 "
classes/Gantry/Component/Whoops/SystemFacade.phpnu�[���PK&d�[JH��CC(�4
classes/Gantry/Framework/Assignments.phpnu�[���PK&d�[�����$�$"EL
classes/Gantry/Framework/Atoms.phpnu�[���PK&d�["��{�$�$(|q
classes/Gantry/Framework/Base/Gantry.phpnu�[���PK&d�[B�s�MM&��
classes/Gantry/Framework/Base/Page.phpnu�[���PK&d�[qyX~��*+�
classes/Gantry/Framework/Base/Platform.phpnu�[���PK&d�[3�S��&]�
classes/Gantry/Framework/Base/Site.phpnu�[���PK&d�[�1L�GG'W�
classes/Gantry/Framework/Base/Theme.phpnu�[���PK&d�[�.��+��
classes/Gantry/Framework/Configurations.phpnu�[���PK&d�[4y,cc%'�
classes/Gantry/Framework/Document.phpnu�[���PK&d�[�NE&��
classes/Gantry/Framework/Exception.phpnu�[���PK&d�[��(�+�+%M�
classes/Gantry/Framework/Exporter.phpnu�[���PK&d�[��D���#�
classes/Gantry/Framework/Gantry.phpnu�[���PK&d�["�����/�classes/Gantry/Framework/Markdown/Parsedown.phpnu�[���PK&d�[S�kn��4�classes/Gantry/Framework/Markdown/ParsedownExtra.phpnu�[���PK&d�[TD���4�classes/Gantry/Framework/Markdown/ParsedownTrait.phpnu�[���PK&d�[��.@2@2!@+classes/Gantry/Framework/Menu.phpnu�[���PK&d�[�~���!�!%�]classes/Gantry/Framework/Outlines.phpnu�[���PK&d�[�%jȌ�!�classes/Gantry/Framework/Page.phpnu�[���PK&d�["��υB�B%ێclasses/Gantry/Framework/Platform.phpnu�[���PK&d�[�8��&��classes/Gantry/Framework/Positions.phpnu�[���PK&d�[�l�$��$�classes/Gantry/Framework/Request.phpnu�[���PK&d�[#Q�ii;?�classes/Gantry/Framework/Services/ConfigServiceProvider.phpnu�[���PK&d�[��d��:�classes/Gantry/Framework/Services/ErrorServiceProvider.phpnu�[���PK&d�[�I>44<f�classes/Gantry/Framework/Services/StreamsServiceProvider.phpnu�[���PK&d�[�ɿ�mm!�classes/Gantry/Framework/Site.phpnu�[���PK&d�[7*3���"�classes/Gantry/Framework/Theme.phpnu�[���PK&d�["ݲc�E�E+�classes/Gantry/Framework/ThemeInstaller.phpnu�[���PK&d�[��g\\'�Vclasses/Gantry/Framework/Translator.phpnu�[���PK&d�[J�s3355Yclasses/Gantry/Joomla/Assignments/AssignmentsMenu.phpnu�[���PK&d�[=�|���6�aclasses/Gantry/Joomla/Assignments/AssignmentsStyle.phpnu�[���PK&d�[��%�iclasses/Gantry/Joomla/CacheHelper.phpnu�[���PK&d�[*����+
pclasses/Gantry/Joomla/Category/Category.phpnu�[���PK&d�[&��w;;1=wclasses/Gantry/Joomla/Category/CategoryFinder.phpnu�[���PK&d�[��-��)هclasses/Gantry/Joomla/Content/Content.phpnu�[���PK&d�[=3���/ɔclasses/Gantry/Joomla/Content/ContentFinder.phpnu�[���PK&d�[�v!��"�classes/Gantry/Joomla/Manifest.phpnu�[���PK&d�[�]k���' �classes/Gantry/Joomla/Module/Module.phpnu�[���PK&d�[�Y����1�classes/Gantry/Joomla/Module/ModuleCollection.phpnu�[���PK&d�[�.�H
H
-P�classes/Gantry/Joomla/Module/ModuleFinder.phpnu�[���PK&d�[嶱�2�2/��classes/Gantry/Joomla/Object/AbstractObject.phpnu�[���PK&d�[�g����+N
classes/Gantry/Joomla/Object/Collection.phpnu�[���PK&d�[T��BB'�
classes/Gantry/Joomla/Object/Finder.phpnu�[���PK&d�[�`�
�
%:)
classes/Gantry/Joomla/StyleHelper.phpnu�[���PK&d�[h��+M7
classes/Gantry/Joomla/TemplateInstaller.phpnu�[���PK&d�[%�|R��"P9
classes/Leafo/ScssPhp/Compiler.phpnu�[���PK&d�[�[����
�composer.jsonnu�[���PK&d�[_?�s����
�composer.locknu�[���PK&d�[9�&���
òLoader.phpnu�[���PK&d�[[ކ���MD5SUMSnu�[���PK&d�[��Gɮ��RealLoader.phpnu�[���PK&d�[=+d����vendor/autoload.phpnu�[���PK&d�[��@���%��vendor/composer/autoload_classmap.phpnu�[���PK&d�[�ɿ@��"
�vendor/composer/autoload_files.phpnu�[���PK&d�[LlP���'b�vendor/composer/autoload_namespaces.phpnu�[���PK&d�[$$۳��!@�vendor/composer/autoload_psr4.phpnu�[���PK&d�[��na� � !0�vendor/composer/autoload_real.phpnu�[���PK&d�[��@F��#Z�vendor/composer/autoload_static.phpnu�[���PK&d�[?�T��4�4z�vendor/composer/ClassLoader.phpnu�[���PK&d�[����f�fl&vendor/composer/installed.jsonnu�[���PK&d�[�+E�77��vendor/composer/installed.phpnu�[���PK&d�[v@��bb%9�vendor/composer/InstalledVersions.phpnu�[���PK&d�[i�
O��"�vendor/composer/platform_check.phpnu�[���PK&d�[�4�%ߵvendor/erusev/parsedown/composer.jsonnu�[���PK&d�[7�~�����%G�vendor/erusev/parsedown/Parsedown.phpnu�[���PK&d�["D_QQ+1`vendor/erusev/parsedown-extra/composer.jsonnu�[���PK&d�[�����2�20�bvendor/erusev/parsedown-extra/ParsedownExtra.phpnu�[���PK&d�[PQ(Fll
�vendor/filp/whoops/composer.jsonnu�[���PK&d�["�sCcc:̚vendor/filp/whoops/src/Whoops/Exception/ErrorException.phpnu�[���PK&d�[�)
���5��vendor/filp/whoops/src/Whoops/Exception/Formatter.phpnu�[���PK&d�[/�/tt1åvendor/filp/whoops/src/Whoops/Exception/Frame.phpnu�[���PK&d�[l1�ț�;��vendor/filp/whoops/src/Whoops/Exception/FrameCollection.phpnu�[���PK&d�[�'mB�"�"5��vendor/filp/whoops/src/Whoops/Exception/Inspector.phpnu�[���PK&d�[BU�$HH9�vendor/filp/whoops/src/Whoops/Handler/CallbackHandler.phpnu�[���PK&d�[���MM1�vendor/filp/whoops/src/Whoops/Handler/Handler.phpnu�[���PK&d�[#�Y���:Pvendor/filp/whoops/src/Whoops/Handler/HandlerInterface.phpnu�[���PK&d�[��1��=�vendor/filp/whoops/src/Whoops/Handler/JsonResponseHandler.phpnu�[���PK&d�[��\�s"s":�vendor/filp/whoops/src/Whoops/Handler/PlainTextHandler.phpnu�[���PK&d�[w9�_]_];�6vendor/filp/whoops/src/Whoops/Handler/PrettyPageHandler.phpnu�[���PK'd�[5Q��n
n
<d�vendor/filp/whoops/src/Whoops/Handler/XmlResponseHandler.phpnu�[���PK'd�[�N� . .;>�vendor/filp/whoops/src/Whoops/Resources/css/whoops.base.cssnu�[���PK'd�[��L"L";��vendor/filp/whoops/src/Whoops/Resources/js/clipboard.min.jsnu�[���PK'd�[����5�5:i�vendor/filp/whoops/src/Whoops/Resources/js/prettify.min.jsnu�[���PK'd�[g�����9�&vendor/filp/whoops/src/Whoops/Resources/js/whoops.base.jsnu�[���PK'd�[�/0�<`<`7�@vendor/filp/whoops/src/Whoops/Resources/js/zepto.min.jsnu�[���PK(d�[�-_B2�vendor/filp/whoops/src/Whoops/Resources/views/env_details.html.phpnu�[���PK(d�[
��W��G��vendor/filp/whoops/src/Whoops/Resources/views/frames_container.html.phpnu�[���PK(d�[�����I֨vendor/filp/whoops/src/Whoops/Resources/views/frames_description.html.phpnu�[���PK(d�[В:�
�
A�vendor/filp/whoops/src/Whoops/Resources/views/frame_code.html.phpnu�[���PK(d�[���A2�vendor/filp/whoops/src/Whoops/Resources/views/frame_list.html.phpnu�[���PK(d�[kg%�$�$=��vendor/filp/whoops/src/Whoops/Resources/views/header.html.phpnu�[���PK)d�[�.|w44C��vendor/filp/whoops/src/Whoops/Resources/views/header_outer.html.phpnu�[���PK)d�[b�>77=��vendor/filp/whoops/src/Whoops/Resources/views/layout.html.phpnu�[���PK)d�[�\FFD3�vendor/filp/whoops/src/Whoops/Resources/views/panel_details.html.phpnu�[���PK)d�[G�w"WWJ��vendor/filp/whoops/src/Whoops/Resources/views/panel_details_outer.html.phpnu�[���PK)d�[�"hhA��vendor/filp/whoops/src/Whoops/Resources/views/panel_left.html.phpnu�[���PK)d�[Y��yyG��vendor/filp/whoops/src/Whoops/Resources/views/panel_left_outer.html.phpnu�[���PK)d�[D&�66%��vendor/filp/whoops/src/Whoops/Run.phpnu�[���PK)d�[-2�G
G
.�vendor/filp/whoops/src/Whoops/RunInterface.phpnu�[���PK)d�[��Z���7�,vendor/filp/whoops/src/Whoops/Util/HtmlDumperOutput.phpnu�[���PK)d�[������+�/vendor/filp/whoops/src/Whoops/Util/Misc.phpnu�[���PK)d�[��'� � 3�7vendor/filp/whoops/src/Whoops/Util/SystemFacade.phpnu�[���PK)d�[{��S%S%5�Avendor/filp/whoops/src/Whoops/Util/TemplateHelper.phpnu�[���PK)d�[���WW"tgvendor/leafo/scssphp/composer.jsonnu�[���PK)d�[��zb�6�6'lvendor/leafo/scssphp/example/Server.phpnu�[���PK)d�[^��kk!�vendor/leafo/scssphp/scss.inc.phpnu�[���PK)d�[�)[\'évendor/leafo/scssphp/src/Base/Range.phpnu�[���PK*d�[a֊xx".�vendor/leafo/scssphp/src/Block.phpnu�[���PK*d�[���GG"��vendor/leafo/scssphp/src/Cache.phpnu�[���PK*d�[ߗ��((#��vendor/leafo/scssphp/src/Colors.phpnu�[���PK*d�[��ruuu1�vendor/leafo/scssphp/src/Compiler/Environment.phpnu�[���PK*d�[h������%��vendor/leafo/scssphp/src/Compiler.phpnu�[���PK*d�[�/�NN8ǽvendor/leafo/scssphp/src/Exception/CompilerException.phpnu�[���PK*d�[��iJJ6}�vendor/leafo/scssphp/src/Exception/ParserException.phpnu�[���PK*d�[�
vAA5-�vendor/leafo/scssphp/src/Exception/RangeException.phpnu�[���PK*d�[��CC6��vendor/leafo/scssphp/src/Exception/ServerException.phpnu�[���PK*d�[�&��.|�vendor/leafo/scssphp/src/Formatter/Compact.phpnu�[���PK*d�[�BtwFF1��vendor/leafo/scssphp/src/Formatter/Compressed.phpnu�[���PK*d�[�?�!��/��vendor/leafo/scssphp/src/Formatter/Crunched.phpnu�[���PK*d�[�GFH� � ,��vendor/leafo/scssphp/src/Formatter/Debug.phpnu�[���PK*d�[�:�~��/��vendor/leafo/scssphp/src/Formatter/Expanded.phpnu�[���PK+d�[�v�mjj-��vendor/leafo/scssphp/src/Formatter/Nested.phpnu�[���PK+d�[i�LL2�vendor/leafo/scssphp/src/Formatter/OutputBlock.phpnu�[���PK+d�[� T�jj&r�vendor/leafo/scssphp/src/Formatter.phpnu�[���PK+d�[�a�dd(2vendor/leafo/scssphp/src/Node/Number.phpnu�[���PK+d�[wY��!�2vendor/leafo/scssphp/src/Node.phpnu�[���PK+d�[�R��#K5vendor/leafo/scssphp/src/Parser.phpnu�[���PK,d�[P#�=��-!Kvendor/leafo/scssphp/src/SourceMap/Base64.phpnu�[���PK,d�[�9�>>07Xvendor/leafo/scssphp/src/SourceMap/Base64VLQ.phpnu�[���PK,d�[�-�|997�fvendor/leafo/scssphp/src/SourceMap/Base64VLQEncoder.phpnu�[���PK,d�[Ky��
'
'9u�vendor/leafo/scssphp/src/SourceMap/SourceMapGenerator.phpnu�[���PK,d�[�
'%%!�vendor/leafo/scssphp/src/Type.phpnu�[���PK,d�[jОpBB!^�vendor/leafo/scssphp/src/Util.phpnu�[���PK,d�[Xi�388$�vendor/leafo/scssphp/src/Version.phpnu�[���PK,d�[)?���"}�vendor/pimple/pimple/composer.jsonnu�[���PK,d�[{�$$-}�vendor/pimple/pimple/src/Pimple/Container.phpnu�[���PK,d�[T�R��HY�vendor/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.phpnu�[���PK,d�[EKeyyD��vendor/pimple/pimple/src/Pimple/Exception/FrozenServiceException.phpnu�[���PK,d�[�\氲�Op�vendor/pimple/pimple/src/Pimple/Exception/InvalidServiceIdentifierException.phpnu�[���PK,d�[�*s]��H��vendor/pimple/pimple/src/Pimple/Exception/UnknownIdentifierException.phpnu�[���PK,d�[5�ݢ��3��vendor/pimple/pimple/src/Pimple/Psr11/Container.phpnu�[���PK,d�[�%��a a 8�vendor/pimple/pimple/src/Pimple/Psr11/ServiceLocator.phpnu�[���PK-d�[�;1�oo3nvendor/pimple/pimple/src/Pimple/ServiceIterator.phpnu�[���PK-d�[���SS<@vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.phpnu�[���PK-d�[U�\��"�vendor/psr/container/composer.jsonnu�[���PK-d�[N>K���8�vendor/psr/container/src/ContainerExceptionInterface.phpnu�[���PK-d�["x��JJ/?vendor/psr/container/src/ContainerInterface.phpnu�[���PK-d�[�-��7�#vendor/psr/container/src/NotFoundExceptionInterface.phpnu�[���PK-d�[��11O%vendor/psr/log/composer.jsonnu�[���PK-d�[�Gl)�'vendor/psr/log/Psr/Log/AbstractLogger.phpnu�[���PK-d�[
�X1``354vendor/psr/log/Psr/Log/InvalidArgumentException.phpnu�[���PK-d�[�j�))/�4vendor/psr/log/Psr/Log/LoggerAwareInterface.phpnu�[���PK-d�[z%���+�6vendor/psr/log/Psr/Log/LoggerAwareTrait.phpnu�[���PK-d�[1b!q***h8vendor/psr/log/Psr/Log/LoggerInterface.phpnu�[���PK-d�[�W�jW
W
&�Dvendor/psr/log/Psr/Log/LoggerTrait.phpnu�[���PK-d�[��PP#�Rvendor/psr/log/Psr/Log/LogLevel.phpnu�[���PK-d�[���I��%<Tvendor/psr/log/Psr/Log/NullLogger.phpnu�[���PK-d�[HTg��)TWvendor/psr/log/Psr/Log/Test/DummyTest.phpnu�[���PK-d�[I\�))3�Xvendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.phpnu�[���PK-d�[�
���*4kvendor/psr/log/Psr/Log/Test/TestLogger.phpnu�[���PK-d�[�� 88:=}vendor/rockettheme/toolbox/ArrayTraits/src/ArrayAccess.phpnu�[���PK-d�[�pR��E߃vendor/rockettheme/toolbox/ArrayTraits/src/ArrayAccessWithGetters.phpnu�[���PK-d�[��-��:�vendor/rockettheme/toolbox/ArrayTraits/src/Constructor.phpnu�[���PK-d�[�9i���8*�vendor/rockettheme/toolbox/ArrayTraits/src/Countable.phpnu�[���PK-d�[�|'�FF5�vendor/rockettheme/toolbox/ArrayTraits/src/Export.phpnu�[���PK-d�[���oo>��vendor/rockettheme/toolbox/ArrayTraits/src/ExportInterface.phpnu�[���PK-d�[���[[7��vendor/rockettheme/toolbox/ArrayTraits/src/Iterator.phpnu�[���PK-d�[����33@_�vendor/rockettheme/toolbox/ArrayTraits/src/NestedArrayAccess.phpnu�[���PK-d�[H
Х�K�vendor/rockettheme/toolbox/ArrayTraits/src/NestedArrayAccessWithGetters.phpnu�[���PK-d�[����;"�vendor/rockettheme/toolbox/ArrayTraits/src/Serializable.phpnu�[���PK-d�[VVۀ7B7B;`�vendor/rockettheme/toolbox/Blueprints/src/BlueprintForm.phpnu�[���PK-d�[�-��8�vendor/rockettheme/toolbox/Blueprints/src/Blueprints.phpnu�[���PK-d�[xJ��P�P=e�vendor/rockettheme/toolbox/Blueprints/src/BlueprintSchema.phpnu�[���PK-d�[T�����K�Nvendor/rockettheme/toolbox/Compat/src/Yaml/Exception/ExceptionInterface.phpnu�[���PK-d�[��G�Pvendor/rockettheme/toolbox/Compat/src/Yaml/Exception/ParseException.phpnu�[���PK-d�[y����Ia_vendor/rockettheme/toolbox/Compat/src/Yaml/Exception/RuntimeException.phpnu�[���PK-d�[�:9;FF5�avendor/rockettheme/toolbox/Compat/src/Yaml/Inline.phpnu�[���PK-d�[
SE�:�:�5B�vendor/rockettheme/toolbox/Compat/src/Yaml/Parser.phpnu�[���PK-d�[gA�sMM8�)vendor/rockettheme/toolbox/Compat/src/Yaml/Unescaper.phpnu�[���PK-d�[l��_
_
3�;vendor/rockettheme/toolbox/Compat/src/Yaml/Yaml.phpnu�[���PK-d�[�����(XFvendor/rockettheme/toolbox/composer.jsonnu�[���PK-d�[���/tKvendor/rockettheme/toolbox/DI/src/Container.phpnu�[���PK-d�[l��66>�Lvendor/rockettheme/toolbox/DI/src/ServiceProviderInterface.phpnu�[���PK-d�[ ݅�.uNvendor/rockettheme/toolbox/Event/src/Event.phpnu�[���PK-d�[A�g��8�Pvendor/rockettheme/toolbox/Event/src/EventDispatcher.phpnu�[���PK-d�[�ҧ�VVA�Svendor/rockettheme/toolbox/Event/src/EventSubscriberInterface.phpnu�[���PK-d�[$M�)*)*,�Uvendor/rockettheme/toolbox/File/src/File.phpnu�[���PK-d�[����5D�vendor/rockettheme/toolbox/File/src/FileInterface.phpnu�[���PK-d�[\�(��/+�vendor/rockettheme/toolbox/File/src/IniFile.phpnu�[���PK-d�[��p''0
�vendor/rockettheme/toolbox/File/src/JsonFile.phpnu�[���PK-d�[-(A��/��vendor/rockettheme/toolbox/File/src/LogFile.phpnu�[���PK-d�[���%4̙vendor/rockettheme/toolbox/File/src/MarkdownFile.phpnu�[���PK-d�[��Ǥ__.M�vendor/rockettheme/toolbox/File/src/MoFile.phpnu�[���PK-d�[��?�
/
�vendor/rockettheme/toolbox/File/src/PhpFile.phpnu�[���PK-d�[<�lj��0��vendor/rockettheme/toolbox/File/src/YamlFile.phpnu�[���PK-d�[����Sl�vendor/rockettheme/toolbox/ResourceLocator/src/RecursiveUniformResourceIterator.phpnu�[���PK-d�[{�&N��K��vendor/rockettheme/toolbox/ResourceLocator/src/ResourceLocatorInterface.phpnu�[���PK-d�[ժ��iiJ��vendor/rockettheme/toolbox/ResourceLocator/src/UniformResourceIterator.phpnu�[���PK-d�[��|J9J9I��vendor/rockettheme/toolbox/ResourceLocator/src/UniformResourceLocator.phpnu�[���PK-d�[k�2{{2�(vendor/rockettheme/toolbox/Session/src/Message.phpnu�[���PK-d�[�}%�>>2a0vendor/rockettheme/toolbox/Session/src/Session.phpnu�[���PK-d�[�9�&}
}
?Fvendor/rockettheme/toolbox/StreamWrapper/src/ReadOnlyStream.phpnu�[���PK-d�[f�//7�Pvendor/rockettheme/toolbox/StreamWrapper/src/Stream.phpnu�[���PK-d�[��}}>�ovendor/rockettheme/toolbox/StreamWrapper/src/StreamBuilder.phpnu�[���PK-d�[ɠ4��
�
@nxvendor/rockettheme/toolbox/StreamWrapper/src/StreamInterface.phpnu�[���PK-d�[[��~oo-��vendor/symfony/event-dispatcher/composer.jsonnu�[���PK-d�[�N��A��vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.phpnu�[���PK-d�[O�S�I,I,B��vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.phpnu�[���PK-d�[�Ӗc##Ka�vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.phpnu�[���PK-d�[�4���9��vendor/symfony/event-dispatcher/Debug/WrappedListener.phpnu�[���PK-d�[q$z��M>�vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.phpnu�[���PK-d�[�P��
�
)��vendor/symfony/event-dispatcher/Event.phpnu�[���PK-d�[�93�
vendor/symfony/event-dispatcher/EventDispatcher.phpnu�[���PK-d�[WHC��
�
<%vendor/symfony/event-dispatcher/EventDispatcherInterface.phpnu�[���PK-d�[���<<0vendor/symfony/event-dispatcher/EventSubscriberInterface.phpnu�[���PK-d�[��d�{{0�6vendor/symfony/event-dispatcher/GenericEvent.phpnu�[���PK-d�[�_~~<�Evendor/symfony/event-dispatcher/ImmutableEventDispatcher.phpnu�[���PK-d�[�01�+}Nvendor/symfony/polyfill-ctype/bootstrap.phpnu�[���PK-d�[��-���+�Tvendor/symfony/polyfill-ctype/composer.jsonnu�[���PK-d�[\��}}'Yvendor/symfony/polyfill-ctype/Ctype.phpnu�[���PK-d�[�!�qvendor/symfony/yaml/composer.jsonnu�[���PK-d�[&�� � Muvendor/symfony/yaml/Dumper.phpnu�[���PK-d�[�hh�vendor/symfony/yaml/Escaper.phpnu�[���PK-d�[���/:�vendor/symfony/yaml/Exception/DumpException.phpnu�[���PK-d�[�^KA��4`�vendor/symfony/yaml/Exception/ExceptionInterface.phpnu�[���PK-d�[�c��
�
0�vendor/symfony/yaml/Exception/ParseException.phpnu�[���PK-d�[�_q���2ءvendor/symfony/yaml/Exception/RuntimeException.phpnu�[���PK-d�[}�S]�W�W�vendor/symfony/yaml/Inline.phpnu�[���PK-d�[�B^(7�7�6�vendor/symfony/yaml/Parser.phpnu�[���PK-d�["~uNN!�}
vendor/symfony/yaml/Unescaper.phpnu�[���PK-d�[�l���Z�
vendor/symfony/yaml/Yaml.phpnu�[���PK-d�[�ʺ9}�
vendor/twig/twig/.php_cs.distnu�[���PK-d�[_P?>���
vendor/twig/twig/composer.jsonnu�[���PK-d�[�g���(
�
vendor/twig/twig/lib/Twig/Autoloader.phpnu�[���PK-d�[&����-*�
vendor/twig/twig/lib/Twig/BaseNodeVisitor.phpnu�[���PK-d�[Q�����.G�
vendor/twig/twig/lib/Twig/Cache/Filesystem.phpnu�[���PK-d�[ ��ʑ�(N�
vendor/twig/twig/lib/Twig/Cache/Null.phpnu�[���PK-d�[�=����,7�
vendor/twig/twig/lib/Twig/CacheInterface.phpnu�[���PK-d�[�Vv3��&7�
vendor/twig/twig/lib/Twig/Compiler.phpnu�[���PK-d�[��R��/
�
vendor/twig/twig/lib/Twig/CompilerInterface.phpnu�[���PK-d�[ɻ�T��4�
vendor/twig/twig/lib/Twig/ContainerRuntimeLoader.phpnu�[���PK-d�[��9���)<�
vendor/twig/twig/lib/Twig/Environment.phpnu�[���PK-d�[�
ei��*!�
vendor/twig/twig/lib/Twig/Error/Loader.phpnu�[���PK-d�[�#ڝ�+�
vendor/twig/twig/lib/Twig/Error/Runtime.phpnu�[���PK-d�[d�˃��*�
vendor/twig/twig/lib/Twig/Error/Syntax.phpnu�[���PK-d�[�Bڨ��#��
vendor/twig/twig/lib/Twig/Error.phpnu�[���PK-d�[ð�=��3Һ
vendor/twig/twig/lib/Twig/ExistsLoaderInterface.phpnu�[���PK-d�[D;��.��
vendor/twig/twig/lib/Twig/ExpressionParser.phpnu�[���PK-d�["G���,��
vendor/twig/twig/lib/Twig/Extension/Core.phpnu�[���PK-d�[:��e��-��
vendor/twig/twig/lib/Twig/Extension/Debug.phpnu�[���PK-d�[��Aٵ�/�
vendor/twig/twig/lib/Twig/Extension/Escaper.phpnu�[���PK-d�[��I��8�
vendor/twig/twig/lib/Twig/Extension/GlobalsInterface.phpnu�[���PK-d�[�����<>�
vendor/twig/twig/lib/Twig/Extension/InitRuntimeInterface.phpnu�[���PK-d�[n���1x�
vendor/twig/twig/lib/Twig/Extension/Optimizer.phpnu�[���PK-d�[ѕu��0��
vendor/twig/twig/lib/Twig/Extension/Profiler.phpnu�[���PK-d�[��3���/��
vendor/twig/twig/lib/Twig/Extension/Sandbox.phpnu�[���PK-d�[P�El��/��
vendor/twig/twig/lib/Twig/Extension/Staging.phpnu�[���PK-d�[��"���4��
vendor/twig/twig/lib/Twig/Extension/StringLoader.phpnu�[���PK-d�[����'�
vendor/twig/twig/lib/Twig/Extension.phpnu�[���PK-d�[�3���0�
vendor/twig/twig/lib/Twig/ExtensionInterface.phpnu�[���PK-d�[�<���2'�
vendor/twig/twig/lib/Twig/FactoryRuntimeLoader.phpnu�[���PK-d�[�,L���;U�
vendor/twig/twig/lib/Twig/FileExtensionEscapingStrategy.phpnu�[���PK-d�[�R��-��
vendor/twig/twig/lib/Twig/Filter/Function.phpnu�[���PK-d�[�M�MXX+v�
vendor/twig/twig/lib/Twig/Filter/Method.phpnu�[���PK-d�[��`pp))�
vendor/twig/twig/lib/Twig/Filter/Node.phpnu�[���PK-d�[��k���$��
vendor/twig/twig/lib/Twig/Filter.phpnu�[���PK-d�[,ı+��5�
vendor/twig/twig/lib/Twig/FilterCallableInterface.phpnu�[���PK-d�[� �?[[-P�
vendor/twig/twig/lib/Twig/FilterInterface.phpnu�[���PK-d�[�Ὢ��/�
vendor/twig/twig/lib/Twig/Function/Function.phpnu�[���PK-d�[�a��{{-�
vendor/twig/twig/lib/Twig/Function/Method.phpnu�[���PK-d�[ �|||+��
vendor/twig/twig/lib/Twig/Function/Node.phpnu�[���PK-d�[So�)��&��
vendor/twig/twig/lib/Twig/Function.phpnu�[���PK-d�[d����7��
vendor/twig/twig/lib/Twig/FunctionCallableInterface.phpnu�[���PK-d�[9t/,,/<�
vendor/twig/twig/lib/Twig/FunctionInterface.phpnu�[���PK-d�[��t�tt#�!vendor/twig/twig/lib/Twig/Lexer.phpnu�[���PK-d�[�Y�,�!vendor/twig/twig/lib/Twig/LexerInterface.phpnu�[���PK-d�[�) ��*!vendor/twig/twig/lib/Twig/Loader/Array.phpnu�[���PK-d�[�#�ʛ�*�!vendor/twig/twig/lib/Twig/Loader/Chain.phpnu�[���PK-d�[4`v˯�/�!vendor/twig/twig/lib/Twig/Loader/Filesystem.phpnu�[���PK-d�[T����+�!vendor/twig/twig/lib/Twig/Loader/String.phpnu�[���PK-d�[7b����-N!vendor/twig/twig/lib/Twig/LoaderInterface.phpnu�[���PK-d�[^�<�xx$U!vendor/twig/twig/lib/Twig/Markup.phpnu�[���PK-d�[���-!!vendor/twig/twig/lib/Twig/Node/AutoEscape.phpnu�[���PK-d�[V��~��(!!vendor/twig/twig/lib/Twig/Node/Block.phpnu�[���PK-d�[<B�G��1!vendor/twig/twig/lib/Twig/Node/BlockReference.phpnu�[���PK-d�[�Z�
��'!vendor/twig/twig/lib/Twig/Node/Body.phpnu�[���PK-d�[m8�2��0�!vendor/twig/twig/lib/Twig/Node/CheckSecurity.phpnu�[���PK-d�[c��ţ�-
!vendor/twig/twig/lib/Twig/Node/Deprecated.phpnu�[���PK-d�[�a���%
!vendor/twig/twig/lib/Twig/Node/Do.phpnu�[���PK-d�[C��ԏ�(�!vendor/twig/twig/lib/Twig/Node/Embed.phpnu�[���PK-d�[����3�!vendor/twig/twig/lib/Twig/Node/Expression/Array.phpnu�[���PK-d�[B&���8�!vendor/twig/twig/lib/Twig/Node/Expression/AssignName.phpnu�[���PK-d�[2K����8/!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.phpnu�[���PK-d�[�~����8Z!vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.phpnu�[���PK-d�[S
���?�!vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.phpnu�[���PK-d�[�ѣ���>�!vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.phpnu�[���PK-d�[���?
!vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.phpnu�[���PK-d�[������;j!!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.phpnu�[���PK-d�[(�B���8�"!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.phpnu�[���PK-d�[W��G��=�#!vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.phpnu�[���PK-d�[}�n2��:%!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.phpnu�[���PK-d�[�*�/��=H&!vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.phpnu�[���PK-d�[-�Z��<�'!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.phpnu�[���PK-d�[ߞ����A�(!vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.phpnu�[���PK-d�[K�n���7#*!vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.phpnu�[���PK-d�[�w�~��9I+!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.phpnu�[���PK-d�[�[�%��>y,!vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.phpnu�[���PK-d�[�y����<�-!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.phpnu�[���PK-d�[�aL���8/!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.phpnu�[���PK-d�[8Vd'��8,0!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.phpnu�[���PK-d�[DCO��=W1!vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.phpnu�[���PK-d�[�ސB��:�2!vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.phpnu�[���PK-d�[�����7�3!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.phpnu�[���PK-d�[�~u@��:�4!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.phpnu�[���PK-d�[ٰ�w��:+6!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.phpnu�[���PK-d�[��s��?`7!vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.phpnu�[���PK-d�[�nڸ��8�8!vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.phpnu�[���PK-d�[��q5��4�9!vendor/twig/twig/lib/Twig/Node/Expression/Binary.phpnu�[���PK-d�[(d���<;!vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.phpnu�[���PK-d�[p��,��2]<!vendor/twig/twig/lib/Twig/Node/Expression/Call.phpnu�[���PK-d�[�R�!��9}=!vendor/twig/twig/lib/Twig/Node/Expression/Conditional.phpnu�[���PK-d�[���T��6�>!vendor/twig/twig/lib/Twig/Node/Expression/Constant.phpnu�[���PK-d�[����@�?!vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.phpnu�[���PK-d�[#�"0��<D!vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.phpnu�[���PK-d�[f��4VE!vendor/twig/twig/lib/Twig/Node/Expression/Filter.phpnu�[���PK-d�[��j!��6�F!vendor/twig/twig/lib/Twig/Node/Expression/Function.phpnu�[���PK-d�[����5�G!vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.phpnu�[���PK-d�[�����8�H!vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.phpnu�[���PK-d�[�c�Ѿ�2!J!vendor/twig/twig/lib/Twig/Node/Expression/Name.phpnu�[���PK-d�[�=߲��:AK!vendor/twig/twig/lib/Twig/Node/Expression/NullCoalesce.phpnu�[���PK-d�[4\3���4�L!vendor/twig/twig/lib/Twig/Node/Expression/Parent.phpnu�[���PK-d�[�U��6�M!vendor/twig/twig/lib/Twig/Node/Expression/TempName.phpnu�[���PK-d�[�7o��;�N!vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.phpnu�[���PK-d�[��!%��:P!vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.phpnu�[���PK-d�[�h�n��>NQ!vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.phpnu�[���PK-d�[�DLc��7�R!vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.phpnu�[���PK-d�[���7�S!vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.phpnu�[���PK-d�[��H��6�T!vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.phpnu�[���PK-d�[b@R���9�U!vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.phpnu�[���PK-d�[��C��2
W!vendor/twig/twig/lib/Twig/Node/Expression/Test.phpnu�[���PK-d�[��\C��7@X!vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.phpnu�[���PK-d�[V�I��7dY!vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.phpnu�[���PK-d�[�P����7�Z!vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.phpnu�[���PK-d�[=��y��3�[!vendor/twig/twig/lib/Twig/Node/Expression/Unary.phpnu�[���PK-d�[b��d��-�\!vendor/twig/twig/lib/Twig/Node/Expression.phpnu�[���PK-d�[FzP��(�]!vendor/twig/twig/lib/Twig/Node/Flush.phpnu�[���PK-d�[*�b��&�^!vendor/twig/twig/lib/Twig/Node/For.phpnu�[���PK-d�[�Nח�*�_!vendor/twig/twig/lib/Twig/Node/ForLoop.phpnu�[���PK-d�[w=����%�`!vendor/twig/twig/lib/Twig/Node/If.phpnu�[���PK-d�[��n��)�a!vendor/twig/twig/lib/Twig/Node/Import.phpnu�[���PK-d�[�0��*rb!vendor/twig/twig/lib/Twig/Node/Include.phpnu�[���PK-d�[��<A��(cc!vendor/twig/twig/lib/Twig/Node/Macro.phpnu�[���PK-d�[��禎�)Jd!vendor/twig/twig/lib/Twig/Node/Module.phpnu�[���PK-d�[ԡ�Ï�(6e!vendor/twig/twig/lib/Twig/Node/Print.phpnu�[���PK-d�[�~���*f!vendor/twig/twig/lib/Twig/Node/Sandbox.phpnu�[���PK-d�[�y�@��1g!vendor/twig/twig/lib/Twig/Node/SandboxedPrint.phpnu�[���PK-d�[絡߇�&"h!vendor/twig/twig/lib/Twig/Node/Set.phpnu�[���PK-d�[0�f��*�h!vendor/twig/twig/lib/Twig/Node/SetTemp.phpnu�[���PK-d�[��͟�,�i!vendor/twig/twig/lib/Twig/Node/Spaceless.phpnu�[���PK-d�[5c�x��'�j!vendor/twig/twig/lib/Twig/Node/Text.phpnu�[���PK-d�[@3�&��'�k!vendor/twig/twig/lib/Twig/Node/With.phpnu�[���PK-d�[~ң�zz"�l!vendor/twig/twig/lib/Twig/Node.phpnu�[���PK-d�[��N��2{m!vendor/twig/twig/lib/Twig/NodeCaptureInterface.phpnu�[���PK-d�[br����+�n!vendor/twig/twig/lib/Twig/NodeInterface.phpnu�[���PK-d�[O�8��1�q!vendor/twig/twig/lib/Twig/NodeOutputInterface.phpnu�[���PK-d�[��퓔�+�r!vendor/twig/twig/lib/Twig/NodeTraverser.phpnu�[���PK-d�[h��1�s!vendor/twig/twig/lib/Twig/NodeVisitor/Escaper.phpnu�[���PK-d�[$�����3�t!vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.phpnu�[���PK-d�[�����6�u!vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.phpnu�[���PK-d�[�����1"w!vendor/twig/twig/lib/Twig/NodeVisitor/Sandbox.phpnu�[���PK-d�[�N@��2Dx!vendor/twig/twig/lib/Twig/NodeVisitorInterface.phpnu�[���PK-d�[�(%xx$ny!vendor/twig/twig/lib/Twig/Parser.phpnu�[���PK-d�[L�E���-:z!vendor/twig/twig/lib/Twig/ParserInterface.phpnu�[���PK-d�[
��2\}!vendor/twig/twig/lib/Twig/Profiler/Dumper/Base.phpnu�[���PK-d�[w���7p~!vendor/twig/twig/lib/Twig/Profiler/Dumper/Blackfire.phpnu�[���PK-d�[X�f���2�!vendor/twig/twig/lib/Twig/Profiler/Dumper/Html.phpnu�[���PK-d�[�����2��!vendor/twig/twig/lib/Twig/Profiler/Dumper/Text.phpnu�[���PK-d�[d����8Ł!vendor/twig/twig/lib/Twig/Profiler/Node/EnterProfile.phpnu�[���PK-d�[�����8�!vendor/twig/twig/lib/Twig/Profiler/Node/LeaveProfile.phpnu�[���PK-d�[~�~��;!�!vendor/twig/twig/lib/Twig/Profiler/NodeVisitor/Profiler.phpnu�[���PK-d�[%V��.l�!vendor/twig/twig/lib/Twig/Profiler/Profile.phpnu�[���PK-d�[Stʼ��4a�!vendor/twig/twig/lib/Twig/RuntimeLoaderInterface.phpnu�[���PK-d�[
����3��!vendor/twig/twig/lib/Twig/Sandbox/SecurityError.phpnu�[���PK-d�[�����C��!vendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.phpnu�[���PK-d�[����E�!vendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.phpnu�[���PK-d�[y,����Cp�!vendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedMethodError.phpnu�[���PK-d�[PMQ��Eό!vendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.phpnu�[���PK-d�[�M����@8�!vendor/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.phpnu�[���PK-d�[�}@���4��!vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicy.phpnu�[���PK-d�[��W���=��!vendor/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.phpnu�[���PK-d�[�S�*ݑ!vendor/twig/twig/lib/Twig/SimpleFilter.phpnu�[���PK-d�[�\��,��!vendor/twig/twig/lib/Twig/SimpleFunction.phpnu�[���PK-d�[���m��(��!vendor/twig/twig/lib/Twig/SimpleTest.phpnu�[���PK-d�[��vxx$��!vendor/twig/twig/lib/Twig/Source.phpnu�[���PK-d�[�����:U�!vendor/twig/twig/lib/Twig/SourceContextLoaderInterface.phpnu�[���PK-d�[ֹ鈀�&��!vendor/twig/twig/lib/Twig/Template.phpnu�[���PK-d�[�yv���/s�!vendor/twig/twig/lib/Twig/TemplateInterface.phpnu�[���PK-d�[�����-��!vendor/twig/twig/lib/Twig/TemplateWrapper.phpnu�[���PK-d�[i��WW+��!vendor/twig/twig/lib/Twig/Test/Function.phpnu�[���PK-d�[��U��6H�!vendor/twig/twig/lib/Twig/Test/IntegrationTestCase.phpnu�[���PK-d�[_�<**)i�!vendor/twig/twig/lib/Twig/Test/Method.phpnu�[���PK-d�[�r�\&&'�!vendor/twig/twig/lib/Twig/Test/Node.phpnu�[���PK-d�[��P^��/i�!vendor/twig/twig/lib/Twig/Test/NodeTestCase.phpnu�[���PK-d�[�@'tt"g�!vendor/twig/twig/lib/Twig/Test.phpnu�[���PK-d�[�5}��3-�!vendor/twig/twig/lib/Twig/TestCallableInterface.phpnu�[���PK-d�[�J3��+>�!vendor/twig/twig/lib/Twig/TestInterface.phpnu�[���PK-d�[�tt#��!vendor/twig/twig/lib/Twig/Token.phpnu�[���PK-d�[ ��R��4X�!vendor/twig/twig/lib/Twig/TokenParser/AutoEscape.phpnu�[���PK-d�[���/��!vendor/twig/twig/lib/Twig/TokenParser/Block.phpnu�[���PK-d�[�+�b��4��!vendor/twig/twig/lib/Twig/TokenParser/Deprecated.phpnu�[���PK-d�[:IA[��,ҷ!vendor/twig/twig/lib/Twig/TokenParser/Do.phpnu�[���PK-d�[�!'�/۸!vendor/twig/twig/lib/Twig/TokenParser/Embed.phpnu�[���PK-d�[�z���1�!vendor/twig/twig/lib/Twig/TokenParser/Extends.phpnu�[���PK-d�[�UTK��0�!vendor/twig/twig/lib/Twig/TokenParser/Filter.phpnu�[���PK-d�[�����/2�!vendor/twig/twig/lib/Twig/TokenParser/Flush.phpnu�[���PK-d�[N
���-J�!vendor/twig/twig/lib/Twig/TokenParser/For.phpnu�[���PK-d�[e�mU��.X�!vendor/twig/twig/lib/Twig/TokenParser/From.phpnu�[���PK-d�[?_d`��,k�!vendor/twig/twig/lib/Twig/TokenParser/If.phpnu�[���PK-d�[�1 ��0t�!vendor/twig/twig/lib/Twig/TokenParser/Import.phpnu�[���PK-d�[�@�|��1��!vendor/twig/twig/lib/Twig/TokenParser/Include.phpnu�[���PK-d�[Bl�
��/��!vendor/twig/twig/lib/Twig/TokenParser/Macro.phpnu�[���PK-d�[�V̐��1��!vendor/twig/twig/lib/Twig/TokenParser/Sandbox.phpnu�[���PK-d�[g����-��!vendor/twig/twig/lib/Twig/TokenParser/Set.phpnu�[���PK-d�[������3��!vendor/twig/twig/lib/Twig/TokenParser/Spaceless.phpnu�[���PK-d�[A�[��-'�!vendor/twig/twig/lib/Twig/TokenParser/Use.phpnu�[���PK-d�[�ou��.5�!vendor/twig/twig/lib/Twig/TokenParser/With.phpnu�[���PK-d�[/u�:��)H�!vendor/twig/twig/lib/Twig/TokenParser.phpnu�[���PK-d�[��Z�/]�!vendor/twig/twig/lib/Twig/TokenParserBroker.phpnu�[���PK-d�[�@v#��8��!vendor/twig/twig/lib/Twig/TokenParserBrokerInterface.phpnu�[���PK-d�[����2��!vendor/twig/twig/lib/Twig/TokenParserInterface.phpnu�[���PK-d�[�ܚ��)�!vendor/twig/twig/lib/Twig/TokenStream.phpnu�[���PK-d�["�ǿ�7�!vendor/twig/twig/lib/Twig/Util/DeprecationCollector.phpnu�[���PK-d�[Z8�Q��6(�!vendor/twig/twig/lib/Twig/Util/TemplateDirIterator.phpnu�[���PK-d�[��P;��-I�!vendor/twig/twig/src/Cache/CacheInterface.phpnu�[���PK-d�[E���0
0
.d�!vendor/twig/twig/src/Cache/FilesystemCache.phpnu�[���PK-d�[�6T��(��!vendor/twig/twig/src/Cache/NullCache.phpnu�[���PK-d�[:��Xzz!��!vendor/twig/twig/src/Compiler.phpnu�[���PK-d�[��.����$�"vendor/twig/twig/src/Environment.phpnu�[���PK-d�[���&�&$��"vendor/twig/twig/src/Error/Error.phpnu�[���PK-d�[��T���*$ #vendor/twig/twig/src/Error/LoaderError.phpnu�[���PK-d�[3%����+>#vendor/twig/twig/src/Error/RuntimeError.phpnu�[���PK-d�[ث�6��*e
#vendor/twig/twig/src/Error/SyntaxError.phpnu�[���PK-d�[��vw��)�#vendor/twig/twig/src/ExpressionParser.phpnu�[���PK-d�[HAAA4Փ#vendor/twig/twig/src/Extension/AbstractExtension.phpnu�[���PK-d�[��k?�?�0z�#vendor/twig/twig/src/Extension/CoreExtension.phpnu�[���PK-d�[6����1p$vendor/twig/twig/src/Extension/DebugExtension.phpnu�[���PK-d�[�%ϑ��3x$vendor/twig/twig/src/Extension/EscaperExtension.phpnu�[���PK-d�[Ϡ��B
B
5V�$vendor/twig/twig/src/Extension/ExtensionInterface.phpnu�[���PK-d�[{e�rr3��$vendor/twig/twig/src/Extension/GlobalsInterface.phpnu�[���PK-d�[�Cˀ�7ґ$vendor/twig/twig/src/Extension/InitRuntimeInterface.phpnu�[���PK-d�[yxD��5��$vendor/twig/twig/src/Extension/OptimizerExtension.phpnu�[���PK-d�[Em
�__4�$vendor/twig/twig/src/Extension/ProfilerExtension.phpnu�[���PK-d�[�Ă�FF<Ŝ$vendor/twig/twig/src/Extension/RuntimeExtensionInterface.phpnu�[���PK-d�[c ��T T 3w�$vendor/twig/twig/src/Extension/SandboxExtension.phpnu�[���PK-d�[������3.�$vendor/twig/twig/src/Extension/StagingExtension.phpnu�[���PK-d�[�iy��8S�$vendor/twig/twig/src/Extension/StringLoaderExtension.phpnu�[���PK-d�[W���6n�$vendor/twig/twig/src/FileExtensionEscapingStrategy.phpnu�[���PK-d�[z���dPdPſ$vendor/twig/twig/src/Lexer.phpnu�[���PK-d�[�i��
�
+w%vendor/twig/twig/src/Loader/ArrayLoader.phpnu�[���PK-d�[]�O9))+�%vendor/twig/twig/src/Loader/ChainLoader.phpnu�[���PK-d�[vH5Q.%vendor/twig/twig/src/Loader/ExistsLoaderInterface.phpnu�[���PK-d�[�(��$�$0�1%vendor/twig/twig/src/Loader/FilesystemLoader.phpnu�[���PK-d�[O(�##/�V%vendor/twig/twig/src/Loader/LoaderInterface.phpnu�[���PK-d�[0ӗPP<^]%vendor/twig/twig/src/Loader/SourceContextLoaderInterface.phpnu�[���PK-d�[��Rh22a%vendor/twig/twig/src/Markup.phpnu�[���PK-d�[鉅���,�d%vendor/twig/twig/src/Node/AutoEscapeNode.phpnu�[���PK-d�[���'�h%vendor/twig/twig/src/Node/BlockNode.phpnu�[���PK-d�[���qq0�l%vendor/twig/twig/src/Node/BlockReferenceNode.phpnu�[���PK-d�[_c����&�p%vendor/twig/twig/src/Node/BodyNode.phpnu�[���PK-d�[���/�r%vendor/twig/twig/src/Node/CheckSecurityNode.phpnu�[���PK-d�[� N�ss/%vendor/twig/twig/src/Node/CheckToStringNode.phpnu�[���PK-d�[qS��,�%vendor/twig/twig/src/Node/DeprecatedNode.phpnu�[���PK-d�[���BB$ډ%vendor/twig/twig/src/Node/DoNode.phpnu�[���PK-d�[;�h!
'p�%vendor/twig/twig/src/Node/EmbedNode.phpnu�[���PK-d�[��;ԓ%vendor/twig/twig/src/Node/Expression/AbstractExpression.phpnu�[���PK-d�[�:
8T�%vendor/twig/twig/src/Node/Expression/ArrayExpression.phpnu�[���PK-d�[���(@ɟ%vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.phpnu�[���PK-d�[�07Hii=U�%vendor/twig/twig/src/Node/Expression/AssignNameExpression.phpnu�[���PK-d�[rXe11>+�%vendor/twig/twig/src/Node/Expression/Binary/AbstractBinary.phpnu�[���PK-d�[vr9ʭ%vendor/twig/twig/src/Node/Expression/Binary/AddBinary.phpnu�[���PK-d�[�r}�95�%vendor/twig/twig/src/Node/Expression/Binary/AndBinary.phpnu�[���PK-d�[n(�@��%vendor/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.phpnu�[���PK-d�[��?(�%vendor/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.phpnu�[���PK-d�[�Y�W@��%vendor/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.phpnu�[���PK-d�[���<2�%vendor/twig/twig/src/Node/Expression/Binary/ConcatBinary.phpnu�[���PK-d�[4ֽD9��%vendor/twig/twig/src/Node/Expression/Binary/DivBinary.phpnu�[���PK-d�[�����>�%vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.phpnu�[���PK-d�[oI����;m�%vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.phpnu�[���PK-d�[�'�)��>��%vendor/twig/twig/src/Node/Expression/Binary/FloorDivBinary.phpnu�[���PK-d�[���=��%vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.phpnu�[���PK-d�[Lt1tB?�%vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.phpnu�[���PK-d�[���'��8��%vendor/twig/twig/src/Node/Expression/Binary/InBinary.phpnu�[���PK-d�[�o#��:�%vendor/twig/twig/src/Node/Expression/Binary/LessBinary.phpnu�[���PK-d�[םz��?t�%vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.phpnu�[���PK-d�[L[��=��%vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.phpnu�[���PK-d�[�>Ӗ9R�%vendor/twig/twig/src/Node/Expression/Binary/ModBinary.phpnu�[���PK-d�[51�9��%vendor/twig/twig/src/Node/Expression/Binary/MulBinary.phpnu�[���PK-d�[��H���>(�%vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.phpnu�[���PK-d�[>�K;��%vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.phpnu�[���PK-d�[�ך8�%vendor/twig/twig/src/Node/Expression/Binary/OrBinary.phpnu�[���PK-d�[6�TZZ;m�%vendor/twig/twig/src/Node/Expression/Binary/PowerBinary.phpnu�[���PK-d�[��j���;2�%vendor/twig/twig/src/Node/Expression/Binary/RangeBinary.phpnu�[���PK-d�[f����@��%vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.phpnu�[���PK-d�[�4�9��%vendor/twig/twig/src/Node/Expression/Binary/SubBinary.phpnu�[���PK-d�[�H�
�
AV�%vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.phpnu�[���PK-d�[�sa��-�-7I�%vendor/twig/twig/src/Node/Expression/CallExpression.phpnu�[���PK-d�[Yz^���>�-&vendor/twig/twig/src/Node/Expression/ConditionalExpression.phpnu�[���PK-d�[�7�˗�;�1&vendor/twig/twig/src/Node/Expression/ConstantExpression.phpnu�[���PK-d�[��nn=�4&vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.phpnu�[���PK-d�[�aGCC9�<&vendor/twig/twig/src/Node/Expression/FilterExpression.phpnu�[���PK-d�[�Sqǵ�;C&vendor/twig/twig/src/Node/Expression/FunctionExpression.phpnu�[���PK-d�[\a��
�
:�J&vendor/twig/twig/src/Node/Expression/GetAttrExpression.phpnu�[���PK-d�[��jț�4�U&vendor/twig/twig/src/Node/Expression/InlinePrint.phpnu�[���PK-d�[���=�X&vendor/twig/twig/src/Node/Expression/MethodCallExpression.phpnu�[���PK-d�[Q%?{{7-^&vendor/twig/twig/src/Node/Expression/NameExpression.phpnu�[���PK-d�[T��o��?m&vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.phpnu�[���PK-d�[<O�n��9Fv&vendor/twig/twig/src/Node/Expression/ParentExpression.phpnu�[���PK-d�[�/c��;q{&vendor/twig/twig/src/Node/Expression/TempNameExpression.phpnu�[���PK-d�[T�o��:�~&vendor/twig/twig/src/Node/Expression/Test/ConstantTest.phpnu�[���PK-d�[QΫ� � 9��&vendor/twig/twig/src/Node/Expression/Test/DefinedTest.phpnu�[���PK-d�[qC�uu=�&vendor/twig/twig/src/Node/Expression/Test/DivisiblebyTest.phpnu�[���PK-d�[�J����6ˑ&vendor/twig/twig/src/Node/Expression/Test/EvenTest.phpnu�[���PK-d�[!d����6(�&vendor/twig/twig/src/Node/Expression/Test/NullTest.phpnu�[���PK-d�[ja�c��5s�&vendor/twig/twig/src/Node/Expression/Test/OddTest.phpnu�[���PK-d�[���DD8ʛ&vendor/twig/twig/src/Node/Expression/Test/SameasTest.phpnu�[���PK-d�[�e���7v�&vendor/twig/twig/src/Node/Expression/TestExpression.phpnu�[���PK-d�[s��ZZ<��&vendor/twig/twig/src/Node/Expression/Unary/AbstractUnary.phpnu�[���PK-d�[�5���7f�&vendor/twig/twig/src/Node/Expression/Unary/NegUnary.phpnu�[���PK-d�[���7«&vendor/twig/twig/src/Node/Expression/Unary/NotUnary.phpnu�[���PK-d�['W���7�&vendor/twig/twig/src/Node/Expression/Unary/PosUnary.phpnu�[���PK-d�[��ޱ�'z�&vendor/twig/twig/src/Node/FlushNode.phpnu�[���PK-d�[I�j11)��&vendor/twig/twig/src/Node/ForLoopNode.phpnu�[���PK-d�[���%�&vendor/twig/twig/src/Node/ForNode.phpnu�[���PK-d�[�X�m��$V�&vendor/twig/twig/src/Node/IfNode.phpnu�[���PK-d�[2�x8��(e�&vendor/twig/twig/src/Node/ImportNode.phpnu�[���PK-d�[Ā��||)��&vendor/twig/twig/src/Node/IncludeNode.phpnu�[���PK-d�[u�i'X�&vendor/twig/twig/src/Node/MacroNode.phpnu�[���PK-d�[&J�I??(��&vendor/twig/twig/src/Node/ModuleNode.phpnu�[���PK-d�[���ee"(4'vendor/twig/twig/src/Node/Node.phpnu�[���PK-d�[��m��2�Q'vendor/twig/twig/src/Node/NodeCaptureInterface.phpnu�[���PK-d�[
*����1T'vendor/twig/twig/src/Node/NodeOutputInterface.phpnu�[���PK-d�[�����'%V'vendor/twig/twig/src/Node/PrintNode.phpnu�[���PK-d�[;r8�//0Z'vendor/twig/twig/src/Node/SandboxedPrintNode.phpnu�[���PK-d�[���j��)�a'vendor/twig/twig/src/Node/SandboxNode.phpnu�[���PK-d�[�(�|g
g
%�f'vendor/twig/twig/src/Node/SetNode.phpnu�[���PK-d�[�~`-��)Jt'vendor/twig/twig/src/Node/SetTempNode.phpnu�[���PK-d�[��$�kk+Gx'vendor/twig/twig/src/Node/SpacelessNode.phpnu�[���PK-d�[�e:422&
}'vendor/twig/twig/src/Node/TextNode.phpnu�[���PK-d�[�e ��&��'vendor/twig/twig/src/Node/WithNode.phpnu�[���PK-d�[��v&
&��'vendor/twig/twig/src/NodeTraverser.phpnu�[���PK-d�[���#118�'vendor/twig/twig/src/NodeVisitor/AbstractNodeVisitor.phpnu�[���PK-d�[��,,7��'vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.phpnu�[���PK-d�[&� �9.�'vendor/twig/twig/src/NodeVisitor/NodeVisitorInterface.phpnu�[���PK-d�[6$�"�"9��'vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.phpnu�[���PK-d�[p�<��'vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.phpnu�[���PK-d�[��w��7u�'vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.phpnu�[���PK-d�[(�lt�5�5�(vendor/twig/twig/src/Parser.phpnu�[���PK-d�[F�����3�9(vendor/twig/twig/src/Profiler/Dumper/BaseDumper.phpnu�[���PK-d�[6)P!8�@(vendor/twig/twig/src/Profiler/Dumper/BlackfireDumper.phpnu�[���PK-d�[������3SI(vendor/twig/twig/src/Profiler/Dumper/HtmlDumper.phpnu�[���PK-d�[�C��3�O(vendor/twig/twig/src/Profiler/Dumper/TextDumper.phpnu�[���PK-d�[7�S(vendor/twig/twig/src/Profiler/Node/EnterProfileNode.phpnu�[���PK-d�[QH�VV7.Y(vendor/twig/twig/src/Profiler/Node/LeaveProfileNode.phpnu�[���PK-d�[6��5s s A�\(vendor/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.phpnu�[���PK-d�[��З��)�f(vendor/twig/twig/src/Profiler/Profile.phpnu�[���PK-d�[����="w(vendor/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.phpnu�[���PK-d�[P͂���;a{(vendor/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.phpnu�[���PK-d�[��ZW11=O(vendor/twig/twig/src/RuntimeLoader/RuntimeLoaderInterface.phpnu�[���PK-d�[�b����.�(vendor/twig/twig/src/Sandbox/SecurityError.phpnu�[���PK-d�[��Y�mm>.�(vendor/twig/twig/src/Sandbox/SecurityNotAllowedFilterError.phpnu�[���PK-d�[�RB�}}@ �(vendor/twig/twig/src/Sandbox/SecurityNotAllowedFunctionError.phpnu�[���PK-d�[�ý�>��(vendor/twig/twig/src/Sandbox/SecurityNotAllowedMethodError.phpnu�[���PK-d�[X��Y@k�(vendor/twig/twig/src/Sandbox/SecurityNotAllowedPropertyError.phpnu�[���PK-d�[B��KK;��(vendor/twig/twig/src/Sandbox/SecurityNotAllowedTagError.phpnu�[���PK-d�[�q�3��/��(vendor/twig/twig/src/Sandbox/SecurityPolicy.phpnu�[���PK-d�[��"C��8ީ(vendor/twig/twig/src/Sandbox/SecurityPolicyInterface.phpnu�[���PK-d�[���ڬ(vendor/twig/twig/src/Source.phpnu�[���PK-d�[q�A3sdsd!.�(vendor/twig/twig/src/Template.phpnu�[���PK-d�[�P�՞�(�)vendor/twig/twig/src/TemplateWrapper.phpnu�[���PK-d�[?yL!!1�%)vendor/twig/twig/src/Test/IntegrationTestCase.phpnu�[���PK-d�[��N�jj*JG)vendor/twig/twig/src/Test/NodeTestCase.phpnu�[���PK-d�[�z�SiiP)vendor/twig/twig/src/Token.phpnu�[���PK-d�[L�芁�8�g)vendor/twig/twig/src/TokenParser/AbstractTokenParser.phpnu�[���PK-d�[�Ҕ)��5�j)vendor/twig/twig/src/TokenParser/ApplyTokenParser.phpnu�[���PK-d�[�;Z
Z
:�p)vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.phpnu�[���PK-d�[�e��� � 5�{)vendor/twig/twig/src/TokenParser/BlockTokenParser.phpnu�[���PK-d�[�f��:��)vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.phpnu�[���PK-d�[�yb
2�)vendor/twig/twig/src/TokenParser/DoTokenParser.phpnu�[���PK-d�[�w���5��)vendor/twig/twig/src/TokenParser/EmbedTokenParser.phpnu�[���PK-d�[�^���7��)vendor/twig/twig/src/TokenParser/ExtendsTokenParser.phpnu�[���PK-d�[�@@6��)vendor/twig/twig/src/TokenParser/FilterTokenParser.phpnu�[���PK-d�[v����5G�)vendor/twig/twig/src/TokenParser/FlushTokenParser.phpnu�[���PK-d�[��Vjj3��)vendor/twig/twig/src/TokenParser/ForTokenParser.phpnu�[���PK-d�[��xx4W�)vendor/twig/twig/src/TokenParser/FromTokenParser.phpnu�[���PK-d�[
B�� � 23�)vendor/twig/twig/src/TokenParser/IfTokenParser.phpnu�[���PK-d�[mO/J��6`�)vendor/twig/twig/src/TokenParser/ImportTokenParser.phpnu�[���PK-d�[r� �SS7L�)vendor/twig/twig/src/TokenParser/IncludeTokenParser.phpnu�[���PK-d�[&nq�uu5�)vendor/twig/twig/src/TokenParser/MacroTokenParser.phpnu�[���PK-d�[���$$7��)vendor/twig/twig/src/TokenParser/SandboxTokenParser.phpnu�[���PK-d�["��3k�)vendor/twig/twig/src/TokenParser/SetTokenParser.phpnu�[���PK-d�[�6�9��)vendor/twig/twig/src/TokenParser/SpacelessTokenParser.phpnu�[���PK-d�[&�{Aqq9�)vendor/twig/twig/src/TokenParser/TokenParserInterface.phpnu�[���PK-d�[}����3�)vendor/twig/twig/src/TokenParser/UseTokenParser.phpnu�[���PK-d�[
O`4*vendor/twig/twig/src/TokenParser/WithTokenParser.phpnu�[���PK-d�[�N:ott${*vendor/twig/twig/src/TokenStream.phpnu�[���PK-d�[ӉX��
�
#C*vendor/twig/twig/src/TwigFilter.phpnu�[���PK-d�[����
%�'*vendor/twig/twig/src/TwigFunction.phpnu�[���PK-d�[�EVZ��!�1*vendor/twig/twig/src/TwigTest.phpnu�[���PK-d�[+�=��2�8*vendor/twig/twig/src/Util/DeprecationCollector.phpnu�[���PK-d�[�~�NN1+B*vendor/twig/twig/src/Util/TemplateDirIterator.phpnu�[���PKe�[ȃ�І��D*gantry5.phpnu�[���PKe�[Él����P*gantry5.xmlnu�[���PKe�[5�����2�U*language/en-GB/en-GB.plg_quickicon_gantry5.sys.ininu�[���PK���A�W*