Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla4/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla4/Gantry.zip

PK���[���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���[$�_EYYAdmin/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���[��x�		4Admin/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���[�}mFmF/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���['��L-L--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���[�Qޙ""1Admin/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���[�[T� 
/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���[���7VV(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���[��_iEE
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���[�?�C}
}
 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���[�^�ww!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���[
����F�FAdmin/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) ?:
'&nbsp;';
        }
    }

    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���[�,�ȵ*�*#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���[�����
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���[��z66Admin/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���[7��]��#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���[�)����)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���[�����!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���[
PQ�>�>$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���[��l�
�
$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���[�u#S�F�FAdmin/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���[�DEL L
!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���[�e��))"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���[�P_�%%!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���[譤��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���[uTQ'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���[�Ht���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���[�w�22Admin/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���[\��Ɵ
�
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���[�Y�zppAdmin/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���[܁lAdmin/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���[�(r��"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���[��p���"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���[ܵ����-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�//*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���[3�U���.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���[�)!�99#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���[�?�~~,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���[�c��9$9$"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���[ù���$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���[�-��!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���[�ԂDD'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���[��ͭ

#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���[Ѱ�PddComponent/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���[ҽ`\!\!%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���[��VVComponent/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���[��"(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���[#NJ���(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���[{�?:xx1Component/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���[��ue�2�2%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���[�v*B��.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���[	�Q��i�i+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 '&#xFFFD;';
        }

        /*
         * 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 => '&quot;', /* quotation mark */
                38 => '&amp;',  /* ampersand */
                60 => '&lt;',   /* less-than sign */
                62 => '&gt;',   /* 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���[,���'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���[���00'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���[0s���'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���[�VVaa3Component/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���[��7��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���[{BB#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���[�{�+�+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���[ڀ}e


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���[����WW
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���[�;o�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���[�xх����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���[.|�G	
	
!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���[Q�E���$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���[��+�#�#$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���[��]��E�E$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���[j픞--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���[��1D�&�&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���[�{{GLGL'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���[�T�ڍ�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���[�l*�)#)#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���[���..
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���[���O��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���[��N@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���[(5���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���[]�>J��#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���[(�gg#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���[�~�77'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���[ʚ@%��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���[V�99Component/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���[�M�6��$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���[X}�q&q&$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���[�03��-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瑄,�,&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���[�}��%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���[�i}}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���[�Y�22!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���[�����
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���[1���%�%"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���[��IA��"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���[b����Z�ZComponent/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���[$�E��
�
#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���[�f��GG,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���[�Ϸ�&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���[���y��(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���[7n^c��)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���[�ܽ���'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���[JtE5��&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���[�$��		&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���[�K��%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���[Bh���(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���[��5��
�
0Component/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���[B�$��2Component/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���[I��\	\	3Component/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���[
FX���1Component/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���[�++B��0Component/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���[���#��0Component/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���[�ʱtt/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���[�TLL2Component/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���[�
�&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���[K�
k�Q�Q
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���[��6���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���[�H��AA!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���[JH��CCFramework/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���[�����$�$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���["��{�$�$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���[B�s�MMFramework/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���[qyX~��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���[3�S��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���[�1L�GGFramework/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���[�.��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���[4y,ccFramework/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���[�NEFramework/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���[��(�+�+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���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���["�����
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���[S�kn��%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���[TD���%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' => '&amp;',
                '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���[��.@2@2Framework/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('&nbsp;
', 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���[�~���!�!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���[�%jȌ�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���["��υB�BFramework/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���[�8��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���[�l�$��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���[#Q�ii,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��+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���[�I>44-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���[�ɿ�mmFramework/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���[7*3���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���["ݲc�E�EFramework/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���[��g\\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���[J�s33&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���[=�|���'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���[��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���[*����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���[&��w;;"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���[��-��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���[=3���
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���[�v!��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���[�]k���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���[�Y����"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���[�.�H
H
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���[嶱�2�2
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���[�g����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���[T��BBJoomla/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���[�`�
�
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���[h��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���[���Admin/Controller/Html/About.phpnu�[���PK���[$�_EYYZAdmin/Controller/Html/Cache.phpnu�[���PK���[��x�		4Admin/Controller/Html/Configurations/Assignments.phpnu�[���PK���[�}mFmF/�Admin/Controller/Html/Configurations/Layout.phpnu�[���PK���['��L-L--OXAdmin/Controller/Html/Configurations/Page.phpnu�[���PK���[�Qޙ""1��Admin/Controller/Html/Configurations/Settings.phpnu�[���PK���[�[T�

/r�Admin/Controller/Html/Configurations/Styles.phpnu�[���PK���[���7VV(��Admin/Controller/Html/Configurations.phpnu�[���PK���[��_iEE
��Admin/Controller/Html/Export.phpnu�[���PK���[�?�C}
}
 #�Admin/Controller/Html/Import.phpnu�[���PK���[�^�ww!�Admin/Controller/Html/Install.phpnu�[���PK���[
����F�F�Admin/Controller/Html/Menu.phpnu�[���PK���[�,�ȵ*�*#�MAdmin/Controller/Html/Positions.phpnu�[���PK���[�����
�xAdmin/Controller/Html/Themes.phpnu�[���PK���[��z66
|Admin/Controller/Json/Atoms.phpnu�[���PK���[7��]��#��Admin/Controller/Json/Changelog.phpnu�[���PK���[�)����)ȞAdmin/Controller/Json/Confirmdeletion.phpnu�[���PK���[�����!��Admin/Controller/Json/Devprod.phpnu�[���PK���[
PQ�>�>$ȧAdmin/Controller/Json/Filepicker.phpnu�[���PK���[��l�
�
$��Admin/Controller/Json/Fontpicker.phpnu�[���PK���[�u#S�F�F��Admin/Controller/Json/Icons.phpnu�[���PK���[�DEL
L
!�;Admin/Controller/Json/Layouts.phpnu�[���PK���[�e��))"T\Admin/Controller/Json/Particle.phpnu�[���PK���[�P_�%%!�uAdmin/Controller/Json/Unsaved.phpnu�[���PK���[譤��EyAdmin/EventListener.phpnu�[���PK���[uTQ'3�Admin/Page.phpnu�[���PK���[�Ht�����Admin/Particles.phpnu�[���PK���[�w�22��Admin/Router.phpnu�[���PK���[\��Ɵ
�
%�Admin/Styles.phpnu�[���PK���[�Y�zpp�Admin/Theme.phpnu�[���PK���[܁l��Admin/ThemeList.phpnu�[���PK���[�(r��"u�Component/Admin/HtmlController.phpnu�[���PK���[��p���"�Component/Admin/JsonController.phpnu�[���PK���[ܵ����-�Component/Assignments/AbstractAssignments.phpnu�[���PK���[�d�//**$Component/Assignments/AssignmentFilter.phpnu�[���PK���[3�U���.�7Component/Assignments/AssignmentsInterface.phpnu�[���PK���[�)!�99#�:Component/Collection/Collection.phpnu�[���PK���[�?�~~,�@Component/Collection/CollectionInterface.phpnu�[���PK���[�c��9$9$"eEComponent/Config/BlueprintForm.phpnu�[���PK���[ù���$�iComponent/Config/BlueprintSchema.phpnu�[���PK���[�-��!5�Component/Config/CompiledBase.phpnu�[���PK���[�ԂDD'�Component/Config/CompiledBlueprints.phpnu�[���PK���[��ͭ

#��Component/Config/CompiledConfig.phpnu�[���PK���[Ѱ�Pdd�Component/Config/Config.phpnu�[���PK���[ҽ`\!\!%��Component/Config/ConfigFileFinder.phpnu�[���PK���[��VVu�Component/Config/Validation.phpnu�[���PK���[��"(�FComponent/Config/ValidationException.phpnu�[���PK���[#NJ���()KComponent/Content/Block/ContentBlock.phpnu�[���PK���[{�?:xx1TbComponent/Content/Block/ContentBlockInterface.phpnu�[���PK���[��ue�2�2%-fComponent/Content/Block/HtmlBlock.phpnu�[���PK���[�v*B��./�Component/Content/Block/HtmlBlockInterface.phpnu�[���PK���[	�Q��i�i+U�Component/Content/Document/HtmlDocument.phpnu�[���PK���[,���'�Component/Controller/BaseController.phpnu�[���PK���[���00'�!Component/Controller/HtmlController.phpnu�[���PK���[0s���'�&Component/Controller/JsonController.phpnu�[���PK���[�VVaa3�*Component/Controller/RestfulControllerInterface.phpnu�[���PK���[��7���1Component/File/CompiledFile.phpnu�[���PK���[{BB#�AComponent/File/CompiledYamlFile.phpnu�[���PK���[�{�+�+oEComponent/Filesystem/Folder.phpnu�[���PK���[ڀ}e


OqComponent/Filesystem/Streams.phpnu�[���PK���[����WW
�|Component/Gantry/GantryTrait.phpnu�[���PK���[�;o�S�Component/Gettext/Gettext.phpnu�[���PK���[�xх������Component/Layout/Layout.phpnu�[���PK���[.|�G	
	
!�Component/Layout/LayoutReader.phpnu�[���PK���[Q�E���$NComponent/Layout/Version/Format0.phpnu�[���PK���[��+�#�#$#%Component/Layout/Version/Format1.phpnu�[���PK���[��]��E�E$@IComponent/Layout/Version/Format2.phpnu�[���PK���[j픞--Z�Component/Menu/AbstractMenu.phpnu�[���PK���[��1D�&�&¼Component/Menu/Item.phpnu�[���PK���[�{{GLGL'��Component/Outline/OutlineCollection.phpnu�[���PK���[�T�ڍ�c0Component/Position/Module.phpnu�[���PK���[�l*�)#)#=AComponent/Position/Position.phpnu�[���PK���[���..
�dComponent/Position/Positions.phpnu�[���PK���[���O��3~Component/Remote/Response.phpnu�[���PK���[��N@
�Component/Request/Input.phpnu�[���PK���[(5���f�Component/Request/Request.phpnu�[���PK���[]�>J��#��Component/Response/HtmlResponse.phpnu�[���PK���[(�gg#��Component/Response/JsonResponse.phpnu�[���PK���[�~�77'a�Component/Response/RedirectResponse.phpnu�[���PK���[ʚ@%����Component/Response/Response.phpnu�[���PK���[V�99	�Component/Router/Router.phpnu�[���PK���[�M�6��$��Component/Router/RouterInterface.phpnu�[���PK���[X}�q&q&$��Component/Stylesheet/CssCompiler.phpnu�[���PK���[�03��-{Component/Stylesheet/CssCompilerInterface.phpnu�[���PK���[�d瑄,�,&�Component/Stylesheet/Scss/Compiler.phpnu�[���PK���[�}��%�FComponent/Stylesheet/ScssCompiler.phpnu�[���PK���[�i}}�`Component/System/Messages.phpnu�[���PK���[�Y�22!�cComponent/Theme/AbstractTheme.phpnu�[���PK���[�����
�Component/Theme/ThemeDetails.phpnu�[���PK���[1���%�%"M�Component/Theme/ThemeInstaller.phpnu�[���PK���[��IA��"��Component/Theme/ThemeInterface.phpnu�[���PK���[b����Z�Z��Component/Theme/ThemeTrait.phpnu�[���PK���[$�E��
�
#)	Component/Translator/Translator.phpnu�[���PK���[�f��GG,)7	Component/Translator/TranslatorInterface.phpnu�[���PK���[�Ϸ�&�:	Component/Twig/Node/TwigNodeAssets.phpnu�[���PK���[���y��(�C	Component/Twig/Node/TwigNodeMarkdown.phpnu�[���PK���[7n^c��)�I	Component/Twig/Node/TwigNodePageblock.phpnu�[���PK���[�ܽ���'�R	Component/Twig/Node/TwigNodeScripts.phpnu�[���PK���[JtE5��&'U	Component/Twig/Node/TwigNodeStyles.phpnu�[���PK���[�$��		&kW	Component/Twig/Node/TwigNodeSwitch.phpnu�[���PK���[�K��%�_	Component/Twig/Node/TwigNodeThrow.phpnu�[���PK���[Bh���(�d	Component/Twig/Node/TwigNodeTryCatch.phpnu�[���PK���[��5��
�
0�k	Component/Twig/TokenParser/TokenParserAssets.phpnu�[���PK���[B�$��2�v	Component/Twig/TokenParser/TokenParserMarkdown.phpnu�[���PK���[I��\	\	3�|	Component/Twig/TokenParser/TokenParserPageblock.phpnu�[���PK���[
FX���1��	Component/Twig/TokenParser/TokenParserScripts.phpnu�[���PK���[�++B��0�	Component/Twig/TokenParser/TokenParserStyles.phpnu�[���PK���[���#��0�	Component/Twig/TokenParser/TokenParserSwitch.phpnu�[���PK���[�ʱtt/_�	Component/Twig/TokenParser/TokenParserThrow.phpnu�[���PK���[�TLL22�	Component/Twig/TokenParser/TokenParserTryCatch.phpnu�[���PK���[�
�&�	Component/Twig/TwigCacheFilesystem.phpnu�[���PK���[K�
k�Q�Q
S�	Component/Twig/TwigExtension.phpnu�[���PK���[��6���Z	
Component/Url/Url.phpnu�[���PK���[�H��AA!x
Component/Whoops/SystemFacade.phpnu�[���PK���[JH��CC
,
Framework/Assignments.phpnu�[���PK���[�����$�$�C
Framework/Atoms.phpnu�[���PK���["��{�$�$�h
Framework/Base/Gantry.phpnu�[���PK���[B�s�MM��
Framework/Base/Page.phpnu�[���PK���[qyX~��O�
Framework/Base/Platform.phpnu�[���PK���[3�S��r�
Framework/Base/Site.phpnu�[���PK���[�1L�GG]�
Framework/Base/Theme.phpnu�[���PK���[�.���
Framework/Configurations.phpnu�[���PK���[4y,cc�
Framework/Document.phpnu�[���PK���[�NE��
Framework/Exception.phpnu�[���PK���[��(�+�+�
Framework/Exporter.phpnu�[���PK���[��D���NFramework/Gantry.phpnu�[���PK���["�����
m
Framework/Markdown/Parsedown.phpnu�[���PK���[S�kn��%T
Framework/Markdown/ParsedownExtra.phpnu�[���PK���[TD���%�Framework/Markdown/ParsedownTrait.phpnu�[���PK���[��.@2@2�!Framework/Menu.phpnu�[���PK���[�~���!�!ATFramework/Outlines.phpnu�[���PK���[�%jȌ�_vFramework/Page.phpnu�[���PK���["��υB�B-�Framework/Platform.phpnu�[���PK���[�8����Framework/Positions.phpnu�[���PK���[�l�$��4�Framework/Request.phpnu�[���PK���[#Q�ii,d�Framework/Services/ConfigServiceProvider.phpnu�[���PK���[��d��+)�Framework/Services/ErrorServiceProvider.phpnu�[���PK���[�I>44-m�Framework/Services/StreamsServiceProvider.phpnu�[���PK���[�ɿ�mm��Framework/Site.phpnu�[���PK���[7*3�����Framework/Theme.phpnu�[���PK���["ݲc�E�EwFramework/ThemeInstaller.phpnu�[���PK���[��g\\MLFramework/Translator.phpnu�[���PK���[J�s33&�NJoomla/Assignments/AssignmentsMenu.phpnu�[���PK���[=�|���'zWJoomla/Assignments/AssignmentsStyle.phpnu�[���PK���[��b_Joomla/CacheHelper.phpnu�[���PK���[*�����eJoomla/Category/Category.phpnu�[���PK���[&��w;;"�lJoomla/Category/CategoryFinder.phpnu�[���PK���[��-��J}Joomla/Content/Content.phpnu�[���PK���[=3���
+�Joomla/Content/ContentFinder.phpnu�[���PK���[�v!��6�Joomla/Manifest.phpnu�[���PK���[�]k���M�Joomla/Module/Module.phpnu�[���PK���[�Y����"9�Joomla/Module/ModuleCollection.phpnu�[���PK���[�.�H
H
v�Joomla/Module/ModuleFinder.phpnu�[���PK���[嶱�2�2
�Joomla/Object/AbstractObject.phpnu�[���PK���[�g����V
Joomla/Object/Collection.phpnu�[���PK���[T��BB�
Joomla/Object/Finder.phpnu�[���PK���[�`�
�
$
Joomla/StyleHelper.phpnu�[���PK���[h��(,
Joomla/TemplateInstaller.phpnu�[���PK��<.