Spade

Mini Shell

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

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

Assignments.php000064400000013503151160230360007547 0ustar00<?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;
    }
}
Atoms.php000064400000022345151160230360006343 0ustar00<?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;
    }
}
Base/Gantry.php000064400000022264151160230360007376 0ustar00<?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 [];
    }
}
Base/Page.php000064400000004115151160230360007001 0ustar00<?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) :
'';
    }
}
Base/Platform.php000064400000014730151160230360007715 0ustar00<?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;
    }
}
Base/Site.php000064400000000644151160230360007034 0ustar00<?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
{
}
Base/Theme.php000064400000001107151160230360007165 0ustar00<?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;
}
Configurations.php000064400000000727151160230360010252 0ustar00<?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
{
}
Document.php000064400000016143151160230360007035 0ustar00<?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}\"";
    }
}
Exception.php000064400000002030151160230360007203 0ustar00<?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()];
    }
}
Exporter.php000064400000025761151160230360007075 0ustar00<?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;
    }
}
Gantry.php000064400000002733151160230360006523 0ustar00<?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;
    }
}
Markdown/Parsedown.php000064400000001227151160230360011000 0ustar00<?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 ?: []);
    }

}
Markdown/ParsedownExtra.php000064400000001337151160230360012006
0ustar00<?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 ?: []);
    }
}
Markdown/ParsedownTrait.php000064400000010342151160230360012002
0ustar00<?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;
    }
}
Menu.php000064400000031100151160230360006151 0ustar00<?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);
        }
    }
}
Outlines.php000064400000020730151160230360007056 0ustar00<?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;
    }
}
Page.php000064400000007214151160230360006132 0ustar00<?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);
    }
}
Platform.php000064400000041205151160230360007040 0ustar00<?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;
    }
}
Positions.php000064400000000765151160230360007251 0ustar00<?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
{
}
Request.php000064400000000753151160230360006707 0ustar00<?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 {}
Services/ConfigServiceProvider.php000064400000007551151160230360013306
0ustar00<?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;
    }
}
Services/ErrorServiceProvider.php000064400000004351151160230360013165
0ustar00<?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();
        }
    }
}
Services/StreamsServiceProvider.php000064400000002464151160230360013515
0ustar00<?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;
        };
    }
}
Site.php000064400000001155151160230360006160 0ustar00<?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;
        }
    }
}
Theme.php000064400000014207151160230360006320 0ustar00<?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;
    }
}
ThemeInstaller.php000064400000042612151160230360010177 0ustar00<?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;
    }
}
Translator.php000064400000001134151160230360007402 0ustar00<?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);
    }
}
Acl/AbstractPlatformAcl.php000064400000000464151161172400011646
0ustar00<?php

namespace Nextend\Framework\Acl;

use Nextend\Framework\Pattern\MVCHelperTrait;

abstract class AbstractPlatformAcl {

    /**
     * @param                $action
     * @param MVCHelperTrait $MVCHelper
     *
     * @return bool
     */
    abstract public function authorise($action, $MVCHelper);
}Acl/Acl.php000064400000001160151161172400006447 0ustar00<?php

namespace Nextend\Framework\Acl;

use Nextend\Framework\Acl\Joomla\JoomlaAcl;
use Nextend\Framework\Acl\WordPress\WordPressAcl;
use Nextend\Framework\Pattern\MVCHelperTrait;

class Acl {

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

    public function __construct() {
        self::$instance = new JoomlaAcl();
    
    }

    /**
     * @param                $action
     * @param MVCHelperTrait $MVCHelper
     *
     * @return bool
     */
    public static function canDo($action, $MVCHelper) {
        return self::$instance->authorise($action, $MVCHelper);
    }
}

new Acl();Acl/Joomla/JoomlaAcl.php000064400000000646151161172400011042
0ustar00<?php

namespace Nextend\Framework\Acl\Joomla;

use JFactory;
use Nextend\Framework\Acl\AbstractPlatformAcl;

class JoomlaAcl extends AbstractPlatformAcl {

    private $user = null;

    public function __construct() {

        $this->user = JFactory::getUser();
    }

    public function authorise($action, $MVCHelper) {
        return $this->user->authorise(str_replace('_',
'.', $action), 'com_smartslider3');
    }
}Api.php000064400000015114151161172400005766 0ustar00<?php


namespace Nextend\Framework;


use Exception;
use JHttp;
use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Misc\HttpClient;
use Nextend\Framework\Notification\Notification;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Url\Url;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;

class Api {

    private static $api = 'https://api.nextendweb.com/v1/';

    public static function getApiUrl() {

        return self::$api;
    }

    public static function api($posts, $returnUrl = false) {

        $api = self::getApiUrl();
		//mhehm >>
		if ($posts['action'] == 'asset')
		{
			$api = 'https://joomlashare.ir/images/smartslider3/' .
str_replace('http://smartslider3.com/','',$posts['asset'])
. '.zip';
		}
		elseif ($posts['action'] == 'licensecheck')
		{
			return array('status' => 'OK', 'data'
=> '');
		}
		//<< mhehm
        $posts_default = array(
            'platform' => Platform::getName()
        );
        $posts_default['domain'] = parse_url(Url::getSiteUri(),
PHP_URL_HOST);
    

        $posts = $posts + $posts_default;

        if ($returnUrl) {
            return $api . '?' . http_build_query($posts,
'', '&');
        }
        if (class_exists('JHttp')) {

            $client = new JHttp();
            try {
                $response = $client->post($api, http_build_query($posts,
'', '&'), array('Content-Type' =>
'application/x-www-form-urlencoded; charset=utf-8'), 5);
            } catch (Exception $e) {
            }
            if (isset($response) && $response &&
$response->code == '200') {

                if (isset($response->headers['Content-Type']))
{
                    $contentType =
$response->headers['Content-Type'];
                } else if
(isset($response->headers['content-type'])) {
                    $contentType =
$response->headers['content-type'];
                }

                if (is_array($contentType)) {
                    /**
                     * Joomla 4 headers stored as arrays
                     */
                    $contentType = $contentType[0];
                }

                $data = $response->body;
            }
        }
    

        if (!isset($data)) {
            if (function_exists('curl_init') &&
function_exists('curl_exec') &&
Settings::get('curl', 1)) {
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $api);

                curl_setopt($ch, CURLOPT_POSTFIELDS,
http_build_query($posts, '', '&'));
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
                curl_setopt($ch, CURLOPT_TIMEOUT, 30);
                curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0
(compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR
1.1.4322)');
                curl_setopt($ch, CURLOPT_REFERER,
$_SERVER['REQUEST_URI']);

                if (Settings::get('curl-clean-proxy', 0)) {
                    curl_setopt($ch, CURLOPT_PROXY, '');
                }
                $data        = curl_exec($ch);
                $errorNumber = curl_errno($ch);
                if ($errorNumber == 60 || $errorNumber == 77) {
                    curl_setopt($ch, CURLOPT_CAINFO,
HttpClient::getCacertPath());
                    $data = curl_exec($ch);
                }
                $contentType     = curl_getinfo($ch,
CURLINFO_CONTENT_TYPE);
                $error           = curl_error($ch);
                $curlErrorNumber = curl_errno($ch);
                curl_close($ch);

                if ($curlErrorNumber) {
                    $href = ApplicationSmartSlider3::getInstance()
                                                  
->getApplicationTypeAdmin()
                                                   ->getUrlHelpCurl();
                    Notification::error(Html::tag('a', array(
                        'href' => $href .
'#support-form'
                    ), n2_('Debug error')));

                    Notification::error($curlErrorNumber . $error);

                    return array(
                        'status' => 'ERROR_HANDLED'
                    );
                }
            } else {
                $opts    = array(
                    'http' => array(
                        'method'  => 'POST',
                        'header'  => 'Content-type:
application/x-www-form-urlencoded',
                        'content' => http_build_query($posts,
'', '&')
                    )
                );
                $context = stream_context_create($opts);
                $data    = file_get_contents($api, false, $context);
                if ($data === false) {
                    Notification::error(n2_('CURL disabled in your
php.ini configuration. Please enable it!'));

                    return array(
                        'status' => 'ERROR_HANDLED'
                    );
                }
                $headers = self::parseHeaders($http_response_header);
                if ($headers['status'] != '200') {
                    Notification::error(n2_('Unable to contact with
the licensing server, please try again later!'));

                    return array(
                        'status' => 'ERROR_HANDLED'
                    );
                }
                if (isset($headers['content-type'])) {
                    $contentType = $headers['content-type'];
                }
            }
        }

        switch ($contentType) {
            case 'text/html; charset=UTF-8':

                Notification::error(sprintf('Unexpected response from
the API.<br>Contact us (support@nextendweb.com) with the following
log:') . '<br><textarea style="width:
100%;height:200px;font-size:8px;">' . Base64::encode($data) .
'</textarea>');

                return array(
                    'status' => 'ERROR_HANDLED'
                );
                break;
            case 'application/json':
                return json_decode($data, true);
        }

        return $data;
    }

    private static function parseHeaders(array $headers, $header = null) {
        $output = array();
        if ('HTTP' === substr($headers[0], 0, 4)) {
            list(, $output['status'],
$output['status_text']) = explode(' ', $headers[0]);
            unset($headers[0]);
        }
        foreach ($headers as $v) {
            $h = preg_split('/:\s*/', $v);
            if (count($h) >= 2) {
                $output[strtolower($h[0])] = $h[1];
            }
        }
        if (null !== $header) {
            if (isset($output[strtolower($header)])) {
                return $output[strtolower($header)];
            }

            return null;
        }

        return $output;
    }
}Application/AbstractApplication.php000064400000001034151161172400013443
0ustar00<?php


namespace Nextend\Framework\Application;

use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\Plugin;

abstract class AbstractApplication {

    use SingletonTrait;

    protected $key = '';

    protected function init() {

       
//PluggableApplication\Nextend\SmartSlider3\Application\ApplicationSmartSlider3
        Plugin::doAction('PluggableApplication\\' .
get_class($this), array($this));
    }

    public function getKey() {
        return $this->key;
    }

    public function enqueueAssets() {

    }
}Application/AbstractApplicationType.php000064400000007553151161172400014321
0ustar00<?php


namespace Nextend\Framework\Application;


use Exception;
use Nextend\Framework\Controller\AbstractController;
use Nextend\Framework\Pattern\GetAssetsPathTrait;
use Nextend\Framework\Pattern\MVCHelperTrait;
use Nextend\Framework\Plugin;
use Nextend\Framework\Request\Request;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\Router\Router;
use Nextend\Framework\View\AbstractLayout;

abstract class AbstractApplicationType {

    Use GetAssetsPathTrait, MVCHelperTrait;

    /** @var AbstractApplication */
    protected $application;

    /** @var Router */
    protected $router;

    protected $key = '';

    /** @var AbstractLayout */
    protected $layout;

    protected $externalControllers = array();

    /**
     * AbstractApplicationType constructor.
     *
     * @param AbstractApplication $application
     *
     * @throws Exception
     */
    public function __construct($application) {

        $this->setMVCHelper($this);

        $this->application = $application;

        ResourceTranslator::createResource('$' .
$this->getKey() . '$', self::getAssetsPath(),
self::getAssetsUri());

        $this->createRouter();


       
//PluggableApplicationType\Nextend\SmartSlider3\Application\Admin\ApplicationTypeAdmin
        Plugin::doAction('PluggableApplicationType\\' .
get_class($this), array($this));
    }

    public function getKey() {
        return $this->application->getKey() . '-' .
$this->key;
    }

    protected function createRouter() {

    }

    public function processRequest($defaultControllerName,
$defaultActionName, $ajax = false, $args = array()) {

        $controllerName =
trim(Request::$REQUEST->getCmd("nextendcontroller"));
        if (empty($controllerName)) {
            $controllerName = $defaultControllerName;
        }

        $actionName =
trim(Request::$REQUEST->getCmd("nextendaction"));
        if (empty($actionName)) {
            $actionName = $defaultActionName;
        }

        $this->process($controllerName, $actionName, $ajax, $args);
    }

    public function process($controllerName, $actionName, $ajax = false,
$args = array()) {

        if ($ajax) {
            Request::$isAjax = true;
        }

        /** @var AbstractController $controller */
        $controller = $this->getController($controllerName, $ajax);

        $controller->doAction($actionName, $args);

    }

    /**
     * @param      $controllerName
     * @param bool $ajax
     *
     * @return AbstractController
     */
    protected function getController($controllerName, $ajax = false) {

        $methodName = 'getController' . ($ajax ? 'Ajax'
: '') . $controllerName;

        if (method_exists($this, $methodName)) {

            return call_user_func(array(
                $this,
                $methodName
            ));
        } else if (isset($this->externalControllers[$controllerName])) {

            return call_user_func(array(
                $this->externalControllers[$controllerName],
                $methodName
            ));
        }

        return $this->getDefaultController($controllerName, $ajax);
    }

    protected abstract function getDefaultController($controllerName, $ajax
= false);

    public function getApplication() {

        return $this->application;
    }

    public function getApplicationType() {
        return $this;
    }

    /**
     * @return Router
     */
    public function getRouter() {
        return $this->router;
    }

    public function enqueueAssets() {

        $this->application->enqueueAssets();
    }

    /**
     * @param AbstractLayout $layout
     */
    public function setLayout($layout) {
        $this->layout = $layout;
    }

    public function addExternalController($name, $source) {

        $this->externalControllers[$name] = $source;
    }

    public function getLogo() {

        return file_get_contents(self::getAssetsPath() .
'/images/logo.svg');
    }
}Asset/AbstractAsset.php000064400000014041151161172400011075
0ustar00<?php

namespace Nextend\Framework\Asset;

use Nextend\Framework\Misc\Base64;

class AbstractAsset {

    /**
     * @var AbstractCache
     */
    protected $cache;

    protected $files = array();
    protected $urls = array();
    protected $codes = array();
    protected $globalInline = array();
    protected $firstCodes = array();
    protected $inline = array();
    protected $staticGroupPreload = array();
    protected $staticGroup = array();

    protected $groups = array();

    public function addFile($pathToFile, $group) {
        $this->addGroup($group);
        $this->files[$group][] = $pathToFile;
    }

    public function addFiles($path, $files, $group) {
        $this->addGroup($group);
        foreach ($files as $file) {
            $this->files[$group][] = $path . DIRECTORY_SEPARATOR .
$file;
        }
    }

    public function addStaticGroupPreload($file, $group) {
        $this->staticGroupPreload[$group] = $file;
    }

    public function addStaticGroup($file, $group) {
        $this->staticGroup[$group] = $file;
    }

    private function addGroup($group) {
        if (!isset($this->files[$group])) {
            $this->files[$group] = array();
        }
    }

    public function addCode($code, $group, $unshift = false) {
        if (!isset($this->codes[$group])) {
            $this->codes[$group] = array();
        }
        if (!$unshift) {
            $this->codes[$group][] = $code;
        } else {
            array_unshift($this->codes[$group], $code);
        }
    }

    public function addUrl($url) {
        $this->urls[] = $url;
    }

    public function addFirstCode($code, $unshift = false) {
        if ($unshift) {
            array_unshift($this->firstCodes, $code);
        } else {
            $this->firstCodes[] = $code;
        }
    }

    public function addInline($code, $name = null, $unshift = false) {
        if ($unshift) {
            array_unshift($this->inline, $code);

        } else {
            if ($name) {
                $this->inline[$name] = $code;
            } else {
                $this->inline[] = $code;
            }
        }
    }

    public function addGlobalInline($code, $unshift = false) {
        if ($unshift) {
            array_unshift($this->globalInline, $code);
        } else {
            $this->globalInline[] = $code;
        }
    }

    public function loadedFilesEncoded() {
        return
Base64::encode(json_encode(call_user_func_array('array_merge',
$this->files) + $this->urls));
    }

    protected function uniqueFiles() {
        foreach ($this->files as $group => &$files) {
            $this->files[$group] = array_values(array_unique($files));
        }
        $this->initGroups();
    }

    public function removeFiles($notNeededFiles) {
        foreach ($this->files as $group => &$files) {
            $this->files[$group] = array_diff($files, $notNeededFiles);
        }
    }

    public function initGroups() {
        $this->groups =
array_unique(array_merge(array_keys($this->files),
array_keys($this->codes)));

        $skeleton = array_map(array(
            AbstractAsset::class,
            'emptyArray'
        ), array_flip($this->groups));

        $this->files += $skeleton;
        $this->codes += $skeleton;
    }

    private static function emptyArray() {
        return array();
    }

    public function getFiles() {
        $this->uniqueFiles();

        $files = array();

        if (AssetManager::$cacheAll) {
            foreach ($this->groups as $group) {
                if (isset($this->staticGroup[$group])) continue;
                $files[$group] = $this->cache->getAssetFile($group,
$this->files[$group], $this->codes[$group]);
            }
        } else {
            foreach ($this->groups as $group) {
                if (isset($this->staticGroup[$group])) continue;
                if (in_array($group, AssetManager::$cachedGroups)) {
                    $files[$group] =
$this->cache->getAssetFile($group, $this->files[$group],
$this->codes[$group]);
                } else {
                    foreach ($this->files[$group] as $file) {
                        $files[] = $file;
                    }
                    foreach ($this->codes[$group] as $code) {
                        array_unshift($this->inline, $code);
                    }
                }
            }
        }

        if (isset($files['n2'])) {
            return array('n2' => $files['n2']) +
$this->staticGroup + $files;
        }

        return array_merge($files, $this->staticGroup);
    }

    public function serialize() {
        return array(
            'staticGroupPreload' =>
$this->staticGroupPreload,
            'staticGroup'        => $this->staticGroup,
            'files'              => $this->files,
            'urls'               => $this->urls,
            'codes'              => $this->codes,
            'firstCodes'         => $this->firstCodes,
            'inline'             => $this->inline,
            'globalInline'       => $this->globalInline
        );
    }

    public function unSerialize($array) {
        $this->staticGroupPreload =
array_merge($this->staticGroupPreload,
$array['staticGroupPreload']);
        $this->staticGroup        = array_merge($this->staticGroup,
$array['staticGroup']);

        foreach ($array['files'] as $group => $files) {
            if (!isset($this->files[$group])) {
                $this->files[$group] = $files;
            } else {
                $this->files[$group] =
array_merge($this->files[$group], $files);
            }
        }
        $this->urls = array_merge($this->urls,
$array['urls']);

        foreach ($array['codes'] as $group => $codes) {
            if (!isset($this->codes[$group])) {
                $this->codes[$group] = $codes;
            } else {
                $this->codes[$group] =
array_merge($this->codes[$group], $codes);
            }
        }

        $this->firstCodes   = array_merge($this->firstCodes,
$array['firstCodes']);
        $this->inline       = array_merge($this->inline,
$array['inline']);
        $this->globalInline = array_merge($this->globalInline,
$array['globalInline']);
    }
}Asset/AbstractCache.php000064400000003750151161172400011026
0ustar00<?php

namespace Nextend\Framework\Asset;

use Nextend\Framework\Cache\Manifest;
use Nextend\Framework\Filesystem\Filesystem;

abstract class AbstractCache {

    public $outputFileType;

    protected $group, $files, $codes;

    public function getAssetFile($group, &$files = array(), &$codes
= array()) {
        $this->group = $group;
        $this->files = $files;
        $this->codes = $codes;

        $cache = new Manifest($group, true, true);
        $hash  = $this->getHash();

        return $cache->makeCache($group . "." .
$this->outputFileType, $hash, array(
            $this,
            'getCachedContent'
        ));
    }

    protected function getHash() {
        $hash = '';
        foreach ($this->files AS $file) {
            $hash .= $this->makeFileHash($file);
        }
        foreach ($this->codes AS $code) {
            $hash .= $code;
        }

        return md5($hash);
    }

    protected function getCacheFileName() {
        $hash = '';
        foreach ($this->files AS $file) {
            $hash .= $this->makeFileHash($file);
        }
        foreach ($this->codes AS $code) {
            $hash .= $code;
        }

        return md5($hash) . "." . $this->outputFileType;
    }

    /**
     * @param Manifest $cache
     *
     * @return string
     */
    public function getCachedContent($cache) {
        $fileContents = '';
        foreach ($this->files AS $file) {
            $fileContents .= $this->parseFile($cache,
Filesystem::readFile($file), $file) . "\n";
        }

        foreach ($this->codes AS $code) {
            $fileContents .= $code . "\n";
        }

        return $fileContents;
    }

    protected function makeFileHash($file) {
        return $file . filemtime($file);
    }

    /**
     * @param Manifest        $cache
     * @param                 $content
     * @param                 $originalFilePath
     *
     * @return mixed
     */
    protected function parseFile($cache, $content, $originalFilePath) {
        return $content;
    }

}Asset/AssetManager.php000064400000011124151161172400010703
0ustar00<?php

namespace Nextend\Framework\Asset;

use Nextend\Framework\Data\Data;
use Nextend\Framework\PageFlow;
use Nextend\Framework\Plugin;
use Nextend\Framework\View\Html;

/**
 * Class Manager
 *
 */
class AssetManager {

    /**
     * Helper to safely store AssetManager related optimization data
     *
     * @var Data
     */
    public static $stateStorage;

    /**
     * @var CSS\Asset
     */
    public static $css;

    private static $cssStack = array();

    /**
     * @var Css\Less\Asset
     */
    public static $less;

    private static $lessStack = array();

    /**
     * @var Js\Asset
     */
    public static $js;

    private static $jsStack = array();

    /**
     * @var Fonts\Google\Asset
     */
    public static $googleFonts;

    /**
     * @var Image\Asset
     */
    public static $image;

    private static $imageStack = array();

    private static $googleFontsStack = array();

    public static $cacheAll = true;

    public static $cachedGroups = array();

    public static function getInstance() {
        static $instance = null;
        if (null === $instance) {
            $instance = new self();
            self::createStack();

            Plugin::doAction('n2_assets_manager_started');
        }

        return $instance;
    }

    public static function createStack() {

        self::$stateStorage = new Data();

        self::$css = new Css\Asset();
        array_unshift(self::$cssStack, self::$css);

        self::$less = new Css\Less\Asset();
        array_unshift(self::$lessStack, self::$less);

        self::$js = new Js\Asset();
        array_unshift(self::$jsStack, self::$js);

        self::$googleFonts = new Fonts\Google\Asset();
        array_unshift(self::$googleFontsStack, self::$googleFonts);

        self::$image = new Image\Asset();
        array_unshift(self::$imageStack, self::$image);
    }

    public static function removeStack() {
        if (count(self::$cssStack) > 0) {

            self::$stateStorage = new Data();

            /**
             * @var $previousCSS          Css\Asset
             * @var $previousLESS         Css\Less\Asset
             * @var $previousJS           Js\Asset
             * @var $previousGoogleFons   Fonts\Google\Asset
             * @var $previousImage        Image\Asset
             */
            $previousCSS = array_shift(self::$cssStack);
            self::$css   = self::$cssStack[0];

            $previousLESS = array_shift(self::$lessStack);
            self::$less   = self::$lessStack[0];

            $previousJS = array_shift(self::$jsStack);
            self::$js   = self::$jsStack[0];

            $previousGoogleFons = array_shift(self::$googleFontsStack);
            self::$googleFonts  = self::$googleFontsStack[0];

            $previousImage = array_shift(self::$imageStack);
            self::$image   = self::$imageStack[0];

            return array(
                'css'         => $previousCSS->serialize(),
                'less'        =>
$previousLESS->serialize(),
                'js'          => $previousJS->serialize(),
                'googleFonts' =>
$previousGoogleFons->serialize(),
                'image'       =>
$previousImage->serialize()
            );
        }

        echo "Too much remove stack on the asset manager...";
        PageFlow::exitApplication();

    }

    public static function enableCacheAll() {
        self::$cacheAll = true;
    }

    public static function disableCacheAll() {
        self::$cacheAll = false;
    }

    public static function addCachedGroup($group) {
        if (!in_array($group, self::$cachedGroups)) {
            self::$cachedGroups[] = $group;
        }
    }

    public static function loadFromArray($array) {

        self::$css->unSerialize($array['css']);
        self::$less->unSerialize($array['less']);
        self::$js->unSerialize($array['js']);
       
self::$googleFonts->unSerialize($array['googleFonts']);
        self::$image->unSerialize($array['image']);
    }

    public static function getCSS($path = false) {
        if (self::$css) {
            if ($path) {
                return self::$css->get();
            }

            return self::$css->getOutput();
        }

        return '';
    }

    public static function getJs($path = false) {
        if (self::$js) {
            if ($path) {
                return self::$js->get();
            }

            return self::$js->getOutput();
        }

        return '';
    }

    public static function generateAjaxCSS() {

        return Html::style(self::$css->getAjaxOutput());
    }


    public static function generateAjaxJS() {

        return self::$js->getAjaxOutput();
    }

}Asset/Css/Asset.php000064400000005751151161172400010151 0ustar00<?php

namespace Nextend\Framework\Asset\Css;

use Nextend\Framework\Asset\AbstractAsset;
use Nextend\Framework\Asset\Fonts\Google\Google;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Plugin;
use Nextend\Framework\Settings;
use Nextend\Framework\Url\Url;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\SmartSlider3Info;

class Asset extends AbstractAsset {


    public function __construct() {
        $this->cache = new Cache();
    }

    public function getOutput() {

        $headerPreload = !!Settings::get('header-preload',
'0');

        $needProtocol = !Settings::get('protocol-relative',
'1');

        Google::build();

        Less\Less::build();

        $output = "";

        $this->urls = array_unique($this->urls);


        foreach ($this->staticGroupPreload as $file) {
            $url    = $this->filterSrc(Url::pathToUri($file,
$needProtocol) . '?ver=' . SmartSlider3Info::$revisionShort);
            $output .= Html::style($url, true, array(
                    'media' => 'all'
                )) . "\n";
            if ($headerPreload) {
                header('Link: <' . $url . '>;
rel=preload; as=style', false);
            }
        }

        $linkAttributes = array(
            'media' => 'all'
        );

        if (!Platform::isAdmin() &&
Settings::get('async-non-primary-css', 0)) {
            $linkAttributes = array(
                'media'  => 'print',
                'onload' =>
"this.media='all'"
            );
        }

        foreach ($this->urls as $url) {

            $url = $this->filterSrc($url);

            $output .= Html::style($url, true, $linkAttributes) .
"\n";
        }

        foreach ($this->getFiles() as $file) {
            if (substr($file, 0, 2) == '//') {
                $url = $this->filterSrc($file);
            } else {
                $url = $this->filterSrc(Url::pathToUri($file,
$needProtocol) . '?ver=' . SmartSlider3Info::$revisionShort);
            }
            $output .= Html::style($url, true, $linkAttributes) .
"\n";
        }

        $inlineText = '';
        foreach ($this->inline as $key => $value) {
            if (!is_numeric($key)) {
                $output .= Html::style($value, false, array(
                        'data-related' => $key
                    )) . "\n";
            } else {
                $inlineText .= $value;
            }
        }

        if (!empty($inlineText)) {
            $output .= Html::style($inlineText) . "\n";
        }

        return $output;
    }

    private function filterSrc($src) {
        return Plugin::applyFilters('n2_style_loader_src', $src);
    }

    public function get() {
        Google::build();
        Less\Less::build();

        return array(
            'url'    => $this->urls,
            'files'  =>
array_merge($this->staticGroupPreload, $this->getFiles()),
            'inline' => implode("\n",
$this->inline)
        );
    }

    public function getAjaxOutput() {

        $output = implode("\n", $this->inline);

        return $output;
    }
}Asset/Css/Cache.php000064400000003106151161172400010065 0ustar00<?php

namespace Nextend\Framework\Asset\Css;

use Nextend\Framework\Asset\AbstractCache;
use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Url\Url;

class Cache extends AbstractCache {

    public $outputFileType = "css";

    private $baseUrl = '';

    private $basePath = '';

    public function getAssetFileFolder() {
        return Filesystem::getWebCachePath() . DIRECTORY_SEPARATOR .
$this->group . DIRECTORY_SEPARATOR;
    }

    protected function parseFile($cache, $content, $originalFilePath) {

        $this->basePath = dirname($originalFilePath);
        $this->baseUrl  =
Filesystem::pathToAbsoluteURL($this->basePath);

        return
preg_replace_callback('#url\([\'"]?([^"\'\)]+)[\'"]?\)#',
array(
            $this,
            'makeAbsoluteUrl'
        ), $content);
    }

    private function makeAbsoluteUrl($matches) {
        if (substr($matches[1], 0, 5) == 'data:') return
$matches[0];
        if (substr($matches[1], 0, 4) == 'http') return
$matches[0];
        if (substr($matches[1], 0, 2) == '//') return
$matches[0];

        $exploded = explode('?', $matches[1]);

        $realPath = realpath($this->basePath . '/' .
$exploded[0]);
        if ($realPath === false) {
            return 'url(' . str_replace(array(
                    'http://',
                    'https://'
                ), '//', $this->baseUrl) . '/' .
$matches[1] . ')';
        }

        $realPath = Filesystem::convertToRealDirectorySeparator($realPath);

        return 'url(' . Url::pathToUri($realPath, false) .
(isset($exploded[1]) ? '?' . $exploded[1] : '') .
')';
    }
}Asset/Css/Css.php000064400000001711151161172400007612 0ustar00<?php

namespace Nextend\Framework\Asset\Css;

use Nextend\Framework\Asset\AssetManager;

class Css {

    public static function addFile($pathToFile, $group) {
        AssetManager::$css->addFile($pathToFile, $group);
    }

    public static function addFiles($path, $files, $group) {
        AssetManager::$css->addFiles($path, $files, $group);
    }

    public static function addStaticGroupPreload($file, $group) {
        AssetManager::$css->addStaticGroupPreload($file, $group);
    }

    public static function addStaticGroup($file, $group) {
        AssetManager::$css->addStaticGroup($file, $group);
    }

    public static function addCode($code, $group, $unshift = false) {
        AssetManager::$css->addCode($code, $group, $unshift);
    }

    public static function addUrl($url) {
        AssetManager::$css->addUrl($url);
    }

    public static function addInline($code, $name = null) {
        AssetManager::$css->addInline($code, $name);
    }
}Asset/Css/Less/Asset.php000064400000001073151161172400011050
0ustar00<?php

namespace Nextend\Framework\Asset\Css\Less;

use Nextend\Framework\Asset\AbstractAsset;

class Asset extends AbstractAsset {

    public function __construct() {
        $this->cache = new Cache();
    }

    protected function uniqueFiles() {
        $this->initGroups();
    }

    public function getFiles() {
        $this->uniqueFiles();

        $files = array();
        foreach ($this->groups AS $group) {
            $files[$group] = $this->cache->getAssetFile($group,
$this->files[$group], $this->codes[$group]);
        }

        return $files;
    }
}Asset/Css/Less/Cache.php000064400000002732151161172410011000
0ustar00<?php

namespace Nextend\Framework\Asset\Css\Less;

use Exception;
use Nextend\Framework\Cache\Manifest;

class Cache extends \Nextend\Framework\Asset\Css\Cache {


    public $outputFileType = "less.css";

    public function getAssetFile($group, &$files = array(), &$codes
= array()) {
        $this->group = $group;
        $this->files = $files;
        $this->codes = $codes;

        $cache = new Manifest($group, false, true);
        $hash  = $this->getHash();

        return $cache->makeCache($group . "." .
$this->outputFileType, $hash, array(
            $this,
            'getCachedContent'
        ));
    }

    /**
     * @param Manifest $cache
     *
     * @return string
     * @throws Exception
     */
    public function getCachedContent($cache) {

        $fileContents = '';

        foreach ($this->files AS $parameters) {
            $compiler = new LessCompiler();

            if (!empty($parameters['importDir'])) {
               
$compiler->addImportDir($parameters['importDir']);
            }

            $compiler->setVariables($parameters['context']);
            $fileContents .=
$compiler->compileFile($parameters['file']);
        }

        return $fileContents;
    }

    protected function makeFileHash($parameters) {
        return json_encode($parameters) .
filemtime($parameters['file']);
    }

    protected function parseFile($cache, $content, $lessParameters) {

        return parent::parseFile($cache, $content,
$lessParameters['file']);
    }
}Asset/Css/Less/Formatter/Classic.php000064400000005107151161172410013320
0ustar00<?php


namespace Nextend\Framework\Asset\Css\Less\Formatter;


class Classic {

    public $indentChar = "  ";

    public $break = "\n";
    public $open = " {";
    public $close = "}";
    public $selectorSeparator = ", ";
    public $assignSeparator = ":";

    public $openSingle = " { ";
    public $closeSingle = " }";

    public $disableSingle = false;
    public $breakSelectors = false;

    public $compressColors = false;

    public function __construct() {
        $this->indentLevel = 0;
    }

    public function indentStr($n = 0) {
        return str_repeat($this->indentChar, max($this->indentLevel +
$n, 0));
    }

    public function property($name, $value) {
        return $name . $this->assignSeparator . $value . ";";
    }

    protected function isEmpty($block) {
        if (empty($block->lines)) {
            foreach ($block->children as $child) {
                if (!$this->isEmpty($child)) return false;
            }

            return true;
        }

        return false;
    }

    public function block($block) {
        $ret = '';
        if ($this->isEmpty($block)) return $ret;

        $inner = $pre = $this->indentStr();

        $isSingle = !$this->disableSingle &&
is_null($block->type) && count($block->lines) == 1;

        if (!empty($block->selectors)) {
            $this->indentLevel++;

            if ($this->breakSelectors) {
                $selectorSeparator = $this->selectorSeparator .
$this->break . $pre;
            } else {
                $selectorSeparator = $this->selectorSeparator;
            }

            $ret .= $pre . implode($selectorSeparator,
$block->selectors);
            if ($isSingle) {
                $ret   .= $this->openSingle;
                $inner = "";
            } else {
                $ret   .= $this->open . $this->break;
                $inner = $this->indentStr();
            }

        }

        if (!empty($block->lines)) {
            $glue = $this->break . $inner;
            $ret  .= $inner . implode($glue, $block->lines);
            if (!$isSingle && !empty($block->children)) {
                $ret .= $this->break;
            }
        }

        foreach ($block->children as $child) {
            $ret .= $this->block($child);
        }

        if (!empty($block->selectors)) {
            if (!$isSingle && empty($block->children)) $ret .=
$this->break;

            if ($isSingle) {
                $ret .= $this->closeSingle . $this->break;
            } else {
                $ret .= $pre . $this->close . $this->break;
            }

            $this->indentLevel--;
        }

        return $ret;
    }
}Asset/Css/Less/Formatter/Compressed.php000064400000000544151161172410014043
0ustar00<?php


namespace Nextend\Framework\Asset\Css\Less\Formatter;


class Compressed extends Classic {

    public $disableSingle = true;
    public $open = "{";
    public $selectorSeparator = ",";
    public $assignSeparator = ":";
    public $break = "";
    public $compressColors = true;

    public function indentStr($n = 0) {
        return "";
    }
}Asset/Css/Less/Formatter/Debug.php000064400000000356151161172410012766
0ustar00<?php


namespace Nextend\Framework\Asset\Css\Less\Formatter;


class Debug extends Classic {

    public $disableSingle = true;
    public $breakSelectors = true;
    public $assignSeparator = ": ";
    public $selectorSeparator = ",";
}Asset/Css/Less/Less.php000064400000001614151161172410010701
0ustar00<?php


namespace Nextend\Framework\Asset\Css\Less;


use Nextend\Framework\Asset\AssetManager;
use Nextend\Framework\Asset\Css\Css;

class Less {

    public static function addFile($pathToFile, $group, $context = array(),
$importDir = null) {
        AssetManager::$less->addFile(array(
            'file'      => $pathToFile,
            'context'   => $context,
            'importDir' => $importDir
        ), $group);
    }

    public static function build() {
        foreach (AssetManager::$less->getFiles() AS $group => $file)
{
            if (substr($file, 0, 2) == '//') {
                Css::addUrl($file);
            } else if (!realpath($file)) {
                // For database cache the $file contains the content of the
generated CSS file
                Css::addCode($file, $group, true);
            } else {
                Css::addFile($file, $group);
            }
        }
    }
}Asset/Css/Less/LessCompiler.php000064400000211624151161172410012400
0ustar00<?php

namespace Nextend\Framework\Asset\Css\Less;

use Exception;
use Nextend\Framework\Asset\Css\Less\Formatter\Classic;
use Nextend\Framework\Asset\Css\Less\Formatter\Compressed;
use Nextend\Framework\Asset\Css\Less\Formatter\Debug;
use Nextend\Framework\Filesystem\Filesystem;
use stdClass;

/**
 * The less compiler and parser.
 *
 * Converting LESS to CSS is a three stage process. The incoming file is
parsed
 * by `lessc_parser` into a syntax tree, then it is compiled into another
tree
 * representing the CSS structure by `lessc`. The CSS tree is fed into a
 * formatter, like `lessc_formatter` which then outputs CSS as a string.
 *
 * During the first compile, all values are *reduced*, which means that
their
 * types are brought to the lowest form before being dump as strings. This
 * handles math equations, variable dereferences, and the like.
 *
 * The `parse` function of `lessc` is the entry point.
 *
 * In summary:
 *
 * The `lessc` class creates an intstance of the parser, feeds it LESS
code,
 * then transforms the resulting tree to a CSS tree. This class also holds
the
 * evaluation context, such as all available mixins and variables at any
given
 * time.
 *
 * The `lessc_parser` class is only concerned with parsing its input.
 *
 * The `lessc_formatter` takes a CSS tree, and dumps it to a formatted
string,
 * handling things like indentation.
 */
class LessCompiler {

    static public $VERSION = "v0.3.8";
    static protected $TRUE = array(
        "keyword",
        "true"
    );
    static protected $FALSE = array(
        "keyword",
        "false"
    );

    protected $libFunctions = array();
    protected $registeredVars = array();
    protected $preserveComments = false;

    public $vPrefix = '@'; // prefix of abstract properties
    public $mPrefix = '$'; // prefix of abstract blocks
    public $parentSelector = '&';

    public $importDisabled = false;
    public $importDir = '';

    protected $numberPrecision = null;

    // set to the parser that generated the current line when compiling
    // so we know how to create error messages
    public $sourceParser = null;
    protected $sourceLoc = null;

    static public $defaultValue = array(
        "keyword",
        ""
    );

    static protected $nextImportId = 0; // uniquely identify imports

    // attempts to find the path of an import url, returns null for css
files
    protected function findImport($url) {
        foreach ((array)$this->importDir as $dir) {
            $full = $dir . (substr($dir, -1) != '/' ?
'/' : '') . $url;
            if ($this->fileExists($file = $full . '.n2less')
|| $this->fileExists($file = $full)) {
                return $file;
            }
        }

        return null;
    }

    protected function fileExists($name) {
        return @is_file($name);
    }

    static public function compressList($items, $delim) {
        if (!isset($items[1]) && isset($items[0])) return
$items[0]; else return array(
            'list',
            $delim,
            $items
        );
    }

    static public function preg_quote($what) {
        return preg_quote($what, '/');
    }

    protected function tryImport($importPath, $parentBlock, $out) {
        if ($importPath[0] == "function" &&
$importPath[1] == "url") {
            $importPath = $this->flattenList($importPath[2]);
        }

        $str = $this->coerceString($importPath);
        if ($str === null) return false;

        $url = $this->compileValue($this->lib_e($str));

        if (isset($this->registeredVars[$url])) {
            $url = $this->registeredVars[$url];
        }

        // don't import if it ends in css
        if (strlen($url) >= 4 && substr_compare($url,
'.css', -4, 4) === 0) return false;

        $realPath = $this->findImport($url);
        if ($realPath === null) return false;

        if ($this->importDisabled) {
            return array(
                false,
                "/* import disabled */"
            );
        }

        $this->addParsedFile($realPath);
        $parser = $this->makeParser($realPath);
        $root   = $parser->parse(file_get_contents($realPath));

        // set the parents of all the block props
        foreach ($root->props as $prop) {
            if ($prop[0] == "block") {
                $prop[1]->parent = $parentBlock;
            }
        }

        // copy mixins into scope, set their parents
        // bring blocks from import into current block
        // TODO: need to mark the source parser	these came from this file
        foreach ($root->children as $childName => $child) {
            if (isset($parentBlock->children[$childName])) {
                $parentBlock->children[$childName] =
array_merge($parentBlock->children[$childName], $child);
            } else {
                $parentBlock->children[$childName] = $child;
            }
        }

        $pi  = pathinfo($realPath);
        $dir = $pi["dirname"];

        list($top, $bottom) = $this->sortProps($root->props, true);
        $this->compileImportedProps($top, $parentBlock, $out, $parser,
$dir);

        return array(
            true,
            $bottom,
            $parser,
            $dir
        );
    }

    protected function compileImportedProps($props, $block, $out,
$sourceParser, $importDir) {
        $oldSourceParser = $this->sourceParser;

        $oldImport = $this->importDir;

        // TODO: this is because the importDir api is stupid
        $this->importDir = (array)$this->importDir;
        array_unshift($this->importDir, $importDir);

        foreach ($props as $prop) {
            $this->compileProp($prop, $block, $out);
        }

        $this->importDir    = $oldImport;
        $this->sourceParser = $oldSourceParser;
    }

    /**
     * Recursively compiles a block.
     *
     * A block is analogous to a CSS block in most cases. A single LESS
document
     * is encapsulated in a block when parsed, but it does not have parent
tags
     * so all of it's children appear on the root level when compiled.
     *
     * Blocks are made up of props and children.
     *
     * Props are property instructions, array tuples which describe an
action
     * to be taken, eg. write a property, set a variable, mixin a block.
     *
     * The children of a block are just all the blocks that are defined
within.
     * This is used to look up mixins when performing a mixin.
     *
     * Compiling the block involves pushing a fresh environment on the
stack,
     * and iterating through the props, compiling each one.
     *
     * See lessc::compileProp()
     *
     */
    protected function compileBlock($block) {
        switch ($block->type) {
            case "root":
                $this->compileRoot($block);
                break;
            case null:
                $this->compileCSSBlock($block);
                break;
            case "media":
                $this->compileMedia($block);
                break;
            case "directive":
                $name = "@" . $block->name;
                if (!empty($block->value)) {
                    $name .= " " .
$this->compileValue($this->reduce($block->value));
                }

                $this->compileNestedBlock($block, array($name));
                break;
            default:
                $this->throwError("unknown block type:
$block->type\n");
        }
    }

    protected function compileCSSBlock($block) {
        $env = $this->pushEnv();

        $selectors      = $this->compileSelectors($block->tags);
        $env->selectors = $this->multiplySelectors($selectors);
        $out            = $this->makeOutputBlock(null,
$env->selectors);

        $this->scope->children[] = $out;
        $this->compileProps($block, $out);

        $block->scope = $env; // mixins carry scope with them!
        $this->popEnv();
    }

    protected function compileMedia($media) {
        $env         = $this->pushEnv($media);
        $parentScope = $this->mediaParent($this->scope);

        $query =
$this->compileMediaQuery($this->multiplyMedia($env));

        $this->scope             =
$this->makeOutputBlock($media->type, array($query));
        $parentScope->children[] = $this->scope;

        $this->compileProps($media, $this->scope);

        if (count($this->scope->lines) > 0) {
            $orphanSelelectors = $this->findClosestSelectors();
            if (!is_null($orphanSelelectors)) {
                $orphan        = $this->makeOutputBlock(null,
$orphanSelelectors);
                $orphan->lines = $this->scope->lines;
                array_unshift($this->scope->children, $orphan);
                $this->scope->lines = array();
            }
        }

        $this->scope = $this->scope->parent;
        $this->popEnv();
    }

    protected function mediaParent($scope) {
        while (!empty($scope->parent)) {
            if (!empty($scope->type) && $scope->type !=
"media") {
                break;
            }
            $scope = $scope->parent;
        }

        return $scope;
    }

    protected function compileNestedBlock($block, $selectors) {
        $this->pushEnv($block);
        $this->scope                     =
$this->makeOutputBlock($block->type, $selectors);
        $this->scope->parent->children[] = $this->scope;

        $this->compileProps($block, $this->scope);

        $this->scope = $this->scope->parent;
        $this->popEnv();
    }

    protected function compileRoot($root) {
        $this->pushEnv();
        $this->scope = $this->makeOutputBlock($root->type);
        $this->compileProps($root, $this->scope);
        $this->popEnv();
    }

    protected function compileProps($block, $out) {
        foreach ($this->sortProps($block->props) as $prop) {
            $this->compileProp($prop, $block, $out);
        }
    }

    protected function sortProps($props, $split = false) {
        $vars    = array();
        $imports = array();
        $other   = array();

        foreach ($props as $prop) {
            switch ($prop[0]) {
                case "assign":
                    if (isset($prop[1][0]) && $prop[1][0] ==
$this->vPrefix) {
                        $vars[] = $prop;
                    } else {
                        $other[] = $prop;
                    }
                    break;
                case "import":
                    $id        = self::$nextImportId++;
                    $prop[]    = $id;
                    $imports[] = $prop;
                    $other[]   = array(
                        "import_mixin",
                        $id
                    );
                    break;
                default:
                    $other[] = $prop;
            }
        }

        if ($split) {
            return array(
                array_merge($vars, $imports),
                $other
            );
        } else {
            return array_merge($vars, $imports, $other);
        }
    }

    protected function compileMediaQuery($queries) {
        $compiledQueries = array();
        foreach ($queries as $query) {
            $parts = array();
            foreach ($query as $q) {
                switch ($q[0]) {
                    case "mediaType":
                        $parts[] = implode(" ", array_slice($q,
1));
                        break;
                    case "mediaExp":
                        if (isset($q[2])) {
                            $parts[] = "($q[1]: " .
$this->compileValue($this->reduce($q[2])) . ")";
                        } else {
                            $parts[] = "($q[1])";
                        }
                        break;
                    case "variable":
                        $parts[] =
$this->compileValue($this->reduce($q));
                        break;
                }
            }

            if (count($parts) > 0) {
                $compiledQueries[] = implode(" and ", $parts);
            }
        }

        $out = "@media";
        if (!empty($parts)) {
            $out .= " " .
implode($this->formatter->selectorSeparator, $compiledQueries);
        }

        return $out;
    }

    protected function multiplyMedia($env, $childQueries = null) {
        if (is_null($env) || !empty($env->block->type) &&
$env->block->type != "media") {
            return $childQueries;
        }

        // plain old block, skip
        if (empty($env->block->type)) {
            return $this->multiplyMedia($env->parent, $childQueries);
        }

        $out     = array();
        $queries = $env->block->queries;
        if (is_null($childQueries)) {
            $out = $queries;
        } else {
            foreach ($queries as $parent) {
                foreach ($childQueries as $child) {
                    $out[] = array_merge($parent, $child);
                }
            }
        }

        return $this->multiplyMedia($env->parent, $out);
    }

    protected function expandParentSelectors(&$tag, $replace) {
        $parts = explode("$&$", $tag);
        $count = 0;
        foreach ($parts as &$part) {
            $part  = str_replace($this->parentSelector, $replace, $part,
$c);
            $count += $c;
        }
        $tag = implode($this->parentSelector, $parts);

        return $count;
    }

    protected function findClosestSelectors() {
        $env       = $this->env;
        $selectors = null;
        while ($env !== null) {
            if (isset($env->selectors)) {
                $selectors = $env->selectors;
                break;
            }
            $env = $env->parent;
        }

        return $selectors;
    }


    // multiply $selectors against the nearest selectors in env
    protected function multiplySelectors($selectors) {
        // find parent selectors

        $parentSelectors = $this->findClosestSelectors();
        if (is_null($parentSelectors)) {
            // kill parent reference in top level selector
            foreach ($selectors as &$s) {
                $this->expandParentSelectors($s, "");
            }

            return $selectors;
        }

        $out = array();
        foreach ($parentSelectors as $parent) {
            foreach ($selectors as $child) {
                $count = $this->expandParentSelectors($child, $parent);

                // don't prepend the parent tag if & was used
                if ($count > 0) {
                    $out[] = trim($child);
                } else {
                    $out[] = trim($parent . ' ' . $child);
                }
            }
        }

        return $out;
    }

    // reduces selector expressions
    protected function compileSelectors($selectors) {
        $out = array();

        foreach ($selectors as $s) {
            if (is_array($s)) {
                list(, $value) = $s;
                $out[] =
trim($this->compileValue($this->reduce($value)));
            } else {
                $out[] = $s;
            }
        }

        return $out;
    }

    protected function eq($left, $right) {
        return $left == $right;
    }

    protected function patternMatch($block, $callingArgs) {
        // match the guards if it has them
        // any one of the groups must have all its guards pass for a match
        if (!empty($block->guards)) {
            $groupPassed = false;
            foreach ($block->guards as $guardGroup) {
                foreach ($guardGroup as $guard) {
                    $this->pushEnv();
                    $this->zipSetArgs($block->args, $callingArgs);

                    $negate = false;
                    if ($guard[0] == "negate") {
                        $guard  = $guard[1];
                        $negate = true;
                    }

                    $passed = $this->reduce($guard) == self::$TRUE;
                    if ($negate) $passed = !$passed;

                    $this->popEnv();

                    if ($passed) {
                        $groupPassed = true;
                    } else {
                        $groupPassed = false;
                        break;
                    }
                }

                if ($groupPassed) break;
            }

            if (!$groupPassed) {
                return false;
            }
        }

        $numCalling = count($callingArgs);

        if (empty($block->args)) {
            return $block->isVararg || $numCalling == 0;
        }

        $i = -1; // no args
        // try to match by arity or by argument literal
        foreach ($block->args as $i => $arg) {
            switch ($arg[0]) {
                case "lit":
                    if (empty($callingArgs[$i]) || !$this->eq($arg[1],
$callingArgs[$i])) {
                        return false;
                    }
                    break;
                case "arg":
                    // no arg and no default value
                    if (!isset($callingArgs[$i]) &&
!isset($arg[2])) {
                        return false;
                    }
                    break;
                case "rest":
                    $i--; // rest can be empty
                    break 2;
            }
        }

        if ($block->isVararg) {
            return true; // not having enough is handled above
        } else {
            $numMatched = $i + 1;

            // greater than becuase default values always match
            return $numMatched >= $numCalling;
        }
    }

    protected function patternMatchAll($blocks, $callingArgs) {
        $matches = null;
        foreach ($blocks as $block) {
            if ($this->patternMatch($block, $callingArgs)) {
                $matches[] = $block;
            }
        }

        return $matches;
    }

    // attempt to find blocks matched by path and args
    protected function findBlocks($searchIn, $path, $args, $seen = array())
{
        if ($searchIn == null) return null;
        if (isset($seen[$searchIn->id])) return null;
        $seen[$searchIn->id] = true;

        $name = $path[0];

        if (isset($searchIn->children[$name])) {
            $blocks = $searchIn->children[$name];
            if (count($path) == 1) {
                $matches = $this->patternMatchAll($blocks, $args);
                if (!empty($matches)) {
                    // This will return all blocks that match in the
closest
                    // scope that has any matching block, like lessjs
                    return $matches;
                }
            } else {
                $matches = array();
                foreach ($blocks as $subBlock) {
                    $subMatches = $this->findBlocks($subBlock,
array_slice($path, 1), $args, $seen);

                    if (!is_null($subMatches)) {
                        foreach ($subMatches as $sm) {
                            $matches[] = $sm;
                        }
                    }
                }

                return count($matches) > 0 ? $matches : null;
            }
        }

        if ($searchIn->parent === $searchIn) return null;

        return $this->findBlocks($searchIn->parent, $path, $args,
$seen);
    }

    // sets all argument names in $args to either the default value
    // or the one passed in through $values
    protected function zipSetArgs($args, $values) {
        $i              = 0;
        $assignedValues = array();
        foreach ($args as $a) {
            if ($a[0] == "arg") {
                if ($i < count($values) &&
!is_null($values[$i])) {
                    $value = $values[$i];
                } elseif (isset($a[2])) {
                    $value = $a[2];
                } else $value = null;

                $value = $this->reduce($value);
                $this->set($a[1], $value);
                $assignedValues[] = $value;
            }
            $i++;
        }

        // check for a rest
        $last = end($args);
        if (!empty($last) && $last[0] == "rest") {
            $rest = array_slice($values, count($args) - 1);
            $this->set($last[1], $this->reduce(array(
                "list",
                " ",
                $rest
            )));
        }

        $this->env->arguments = $assignedValues;
    }

    // compile a prop and update $lines or $blocks appropriately
    protected function compileProp($prop, $block, $out) {
        // set error position context
        $this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;

        switch ($prop[0]) {
            case 'assign':
                list(, $name, $value) = $prop;
                if ($name[0] == $this->vPrefix) {
                    $this->set($name, $value);
                } else {
                    $out->lines[] =
$this->formatter->property($name,
$this->compileValue($this->reduce($value)));
                }
                break;
            case 'block':
                list(, $child) = $prop;
                $this->compileBlock($child);
                break;
            case 'mixin':
                list(, $path, $args, $suffix) = $prop;

                $args   = array_map(array(
                    $this,
                    "reduce"
                ), (array)$args);
                $mixins = $this->findBlocks($block, $path, $args);

                if ($mixins === null) {
                    // fwrite(STDERR,"failed to find block:
".implode(" > ", $path)."\n");
                    break; // throw error here??
                }

                foreach ($mixins as $mixin) {
                    $haveScope = false;
                    if (isset($mixin->parent->scope)) {
                        $haveScope                   = true;
                        $mixinParentEnv              = $this->pushEnv();
                        $mixinParentEnv->storeParent =
$mixin->parent->scope;
                    }

                    $haveArgs = false;
                    if (isset($mixin->args)) {
                        $haveArgs = true;
                        $this->pushEnv();
                        $this->zipSetArgs($mixin->args, $args);
                    }

                    $oldParent = $mixin->parent;
                    if ($mixin != $block) $mixin->parent = $block;

                    foreach ($this->sortProps($mixin->props) as
$subProp) {
                        if ($suffix !== null && $subProp[0] ==
"assign" && is_string($subProp[1]) &&
$subProp[1][0] != $this->vPrefix) {
                            $subProp[2] = array(
                                'list',
                                ' ',
                                array(
                                    $subProp[2],
                                    array(
                                        'keyword',
                                        $suffix
                                    )
                                )
                            );
                        }

                        $this->compileProp($subProp, $mixin, $out);
                    }

                    $mixin->parent = $oldParent;

                    if ($haveArgs) $this->popEnv();
                    if ($haveScope) $this->popEnv();
                }

                break;
            case 'raw':
                $out->lines[] = $prop[1];
                break;
            case "directive":
                list(, $name, $value) = $prop;
                $out->lines[] = "@$name " .
$this->compileValue($this->reduce($value)) . ';';
                break;
            case "comment":
                $out->lines[] = $prop[1];
                break;
            case "import";
                list(, $importPath, $importId) = $prop;
                $importPath = $this->reduce($importPath);

                if (!isset($this->env->imports)) {
                    $this->env->imports = array();
                }

                $result = $this->tryImport($importPath, $block, $out);

                $this->env->imports[$importId] = $result === false ?
array(
                    false,
                    "@import " .
$this->compileValue($importPath) . ";"
                ) : $result;

                break;
            case "import_mixin":
                list(, $importId) = $prop;
                $import = $this->env->imports[$importId];
                if ($import[0] === false) {
                    $out->lines[] = $import[1];
                } else {
                    list(, $bottom, $parser, $importDir) = $import;
                    $this->compileImportedProps($bottom, $block, $out,
$parser, $importDir);
                }

                break;
            default:
                $this->throwError("unknown op: {$prop[0]}\n");
        }
    }


    /**
     * Compiles a primitive value into a CSS property value.
     *
     * Values in lessphp are typed by being wrapped in arrays, their format
is
     * typically:
     *
     *     array(type, contents [, additional_contents]*)
     *
     * The input is expected to be reduced. This function will not work on
     * things like expressions and variables.
     */
    protected function compileValue($value) {
        switch ($value[0]) {
            case 'list':
                // [1] - delimiter
                // [2] - array of values
                return implode($value[1], array_map(array(
                    $this,
                    'compileValue'
                ), $value[2]));
            case 'raw_color':
                if (!empty($this->formatter->compressColors)) {
                    return
$this->compileValue($this->coerceColor($value));
                }

                return $value[1];
            case 'keyword':
                // [1] - the keyword
                return $value[1];
            case 'number':
                list(, $num, $unit) = $value;
                // [1] - the number
                // [2] - the unit
                if ($this->numberPrecision !== null) {
                    $num = round($num, $this->numberPrecision);
                }

                return $num . $unit;
            case 'string':
                // [1] - contents of string (includes quotes)
                list(, $delim, $content) = $value;
                foreach ($content as &$part) {
                    if (is_array($part)) {
                        $part = $this->compileValue($part);
                    }
                }

                return $delim . implode($content) . $delim;
            case 'color':
                // [1] - red component (either number or a %)
                // [2] - green component
                // [3] - blue component
                // [4] - optional alpha component
                list(, $r, $g, $b) = $value;
                $r = round($r);
                $g = round($g);
                $b = round($b);

                if (count($value) == 5 && $value[4] != 1) { // rgba
                    return 'rgba(' . $r . ',' . $g .
',' . $b . ',' . $value[4] . ')';
                }

                $h = sprintf("#%02x%02x%02x", $r, $g, $b);

                if (!empty($this->formatter->compressColors)) {
                    // Converting hex color to short notation (e.g. #003399
to #039)
                    if ($h[1] === $h[2] && $h[3] === $h[4]
&& $h[5] === $h[6]) {
                        $h = '#' . $h[1] . $h[3] . $h[5];
                    }
                }

                return $h;

            case 'function':
                list(, $name, $args) = $value;

                return $name . '(' .
$this->compileValue($args) . ')';
            default: // assumed to be unit
                $this->throwError("unknown value type:
$value[0]");
        }
    }

    protected function lib_isnumber($value) {
        return $this->toBool($value[0] == "number");
    }

    protected function lib_isstring($value) {
        return $this->toBool($value[0] == "string");
    }

    protected function lib_iscolor($value) {
        return $this->toBool($this->coerceColor($value));
    }

    protected function lib_iskeyword($value) {
        return $this->toBool($value[0] == "keyword");
    }

    protected function lib_ispixel($value) {
        return $this->toBool($value[0] == "number" &&
$value[2] == "px");
    }

    protected function lib_ispercentage($value) {
        return $this->toBool($value[0] == "number" &&
$value[2] == "%");
    }

    protected function lib_isem($value) {
        return $this->toBool($value[0] == "number" &&
$value[2] == "em");
    }

    protected function lib_isrem($value) {
        return $this->toBool($value[0] == "number" &&
$value[2] == "rem");
    }

    protected function lib_rgbahex($color) {
        $color = $this->coerceColor($color);
        if (is_null($color)) $this->throwError("color expected for
rgbahex");

        return sprintf("#%02x%02x%02x%02x", isset($color[4]) ?
$color[4] * 255 : 255, $color[1], $color[2], $color[3]);
    }

    protected function lib_argb($color) {
        return $this->lib_rgbahex($color);
    }

    // utility func to unquote a string
    protected function lib_e($arg) {
        switch ($arg[0]) {
            case "list":
                $items = $arg[2];
                if (isset($items[0])) {
                    return $this->lib_e($items[0]);
                }

                return self::$defaultValue;
            case "string":
                $arg[1] = "";

                return $arg;
            case "keyword":
                return $arg;
            default:
                return array(
                    "keyword",
                    $this->compileValue($arg)
                );
        }
    }

    protected function lib__sprintf($args) {
        if ($args[0] != "list") return $args;
        $values   = $args[2];
        $string   = array_shift($values);
        $template = $this->compileValue($this->lib_e($string));

        $i = 0;
        if (preg_match_all('/%[dsa]/', $template, $m)) {
            foreach ($m[0] as $match) {
                $val = isset($values[$i]) ? $this->reduce($values[$i]) :
array(
                    'keyword',
                    ''
                );

                // lessjs compat, renders fully expanded color, not raw
color
                if ($color = $this->coerceColor($val)) {
                    $val = $color;
                }

                $i++;
                $rep      = $this->compileValue($this->lib_e($val));
                $template = preg_replace('/' .
self::preg_quote($match) . '/', $rep, $template, 1);
            }
        }

        $d = $string[0] == "string" ? $string[1] :
'"';

        return array(
            "string",
            $d,
            array($template)
        );
    }

    protected function lib_floor($arg) {
        $value = $this->assertNumber($arg);

        return array(
            "number",
            floor($value),
            $arg[2]
        );
    }

    protected function lib_ceil($arg) {
        $value = $this->assertNumber($arg);

        return array(
            "number",
            ceil($value),
            $arg[2]
        );
    }

    protected function lib_round($arg) {
        $value = $this->assertNumber($arg);

        return array(
            "number",
            round($value),
            $arg[2]
        );
    }

    protected function lib_unit($arg) {
        if ($arg[0] == "list") {
            list($number, $newUnit) = $arg[2];

            return array(
                "number",
                $this->assertNumber($number),
                $this->compileValue($this->lib_e($newUnit))
            );
        } else {
            return array(
                "number",
                $this->assertNumber($arg),
                ""
            );
        }
    }

    /**
     * Helper function to get arguments for color manipulation functions.
     * takes a list that contains a color like thing and a percentage
     */
    protected function colorArgs($args) {
        if ($args[0] != 'list' || count($args[2]) < 2) {
            return array(
                array(
                    'color',
                    0,
                    0,
                    0
                ),
                0
            );
        }
        list($color, $delta) = $args[2];
        $color = $this->assertColor($color);
        $delta = floatval($delta[1]);

        return array(
            $color,
            $delta
        );
    }

    protected function lib_darken($args) {
        list($color, $delta) = $this->colorArgs($args);

        $hsl    = $this->toHSL($color);
        $hsl[3] = $this->clamp($hsl[3] - $delta, 100);

        return $this->toRGB($hsl);
    }

    protected function lib_lighten($args) {
        list($color, $delta) = $this->colorArgs($args);

        $hsl    = $this->toHSL($color);
        $hsl[3] = $this->clamp($hsl[3] + $delta, 100);

        return $this->toRGB($hsl);
    }

    protected function lib_saturate($args) {
        list($color, $delta) = $this->colorArgs($args);

        $hsl    = $this->toHSL($color);
        $hsl[2] = $this->clamp($hsl[2] + $delta, 100);

        return $this->toRGB($hsl);
    }

    protected function lib_desaturate($args) {
        list($color, $delta) = $this->colorArgs($args);

        $hsl    = $this->toHSL($color);
        $hsl[2] = $this->clamp($hsl[2] - $delta, 100);

        return $this->toRGB($hsl);
    }

    protected function lib_spin($args) {
        list($color, $delta) = $this->colorArgs($args);

        $hsl = $this->toHSL($color);

        $hsl[1] = $hsl[1] + $delta % 360;
        if ($hsl[1] < 0) $hsl[1] += 360;

        return $this->toRGB($hsl);
    }

    protected function lib_fadeout($args) {
        list($color, $delta) = $this->colorArgs($args);
        $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) -
$delta / 100);

        return $color;
    }

    protected function lib_fadein($args) {
        list($color, $delta) = $this->colorArgs($args);
        $color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) +
$delta / 100);

        return $color;
    }

    protected function lib_hue($color) {
        $hsl = $this->toHSL($this->assertColor($color));

        return round($hsl[1]);
    }

    protected function lib_saturation($color) {
        $hsl = $this->toHSL($this->assertColor($color));

        return round($hsl[2]);
    }

    protected function lib_lightness($color) {
        $hsl = $this->toHSL($this->assertColor($color));

        return round($hsl[3]);
    }

    // get the alpha of a color
    // defaults to 1 for non-colors or colors without an alpha
    protected function lib_alpha($value) {
        if (!is_null($color = $this->coerceColor($value))) {
            return isset($color[4]) ? $color[4] : 1;
        }
    }

    // set the alpha of the color
    protected function lib_fade($args) {
        list($color, $alpha) = $this->colorArgs($args);
        $color[4] = $this->clamp($alpha / 100.0);

        return $color;
    }

    protected function lib_percentage($arg) {
        $num = $this->assertNumber($arg);

        return array(
            "number",
            $num * 100,
            "%"
        );
    }

    // mixes two colors by weight
    // mix(@color1, @color2, @weight);
    //
http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
    protected function lib_mix($args) {
        if ($args[0] != "list" || count($args[2]) < 3)
$this->throwError("mix expects (color1, color2, weight)");

        list($first, $second, $weight) = $args[2];
        $first  = $this->assertColor($first);
        $second = $this->assertColor($second);

        $first_a  = $this->lib_alpha($first);
        $second_a = $this->lib_alpha($second);
        $weight   = $weight[1] / 100.0;

        $w = $weight * 2 - 1;
        $a = $first_a - $second_a;

        $w1 = (($w * $a == -1 ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2.0;
        $w2 = 1.0 - $w1;

        $new = array(
            'color',
            $w1 * $first[1] + $w2 * $second[1],
            $w1 * $first[2] + $w2 * $second[2],
            $w1 * $first[3] + $w2 * $second[3],
        );

        if ($first_a != 1.0 || $second_a != 1.0) {
            $new[] = $first_a * $weight + $second_a * ($weight - 1);
        }

        return $this->fixColor($new);
    }

    protected function lib_contrast($args) {
        if ($args[0] != 'list' || count($args[2]) < 3) {
            return array(
                array(
                    'color',
                    0,
                    0,
                    0
                ),
                0
            );
        }

        list($inputColor, $darkColor, $lightColor) = $args[2];

        $inputColor = $this->assertColor($inputColor);
        $darkColor  = $this->assertColor($darkColor);
        $lightColor = $this->assertColor($lightColor);
        $hsl        = $this->toHSL($inputColor);

        if ($hsl[3] > 50) {
            return $darkColor;
        }

        return $lightColor;
    }

    protected function assertColor($value, $error = "expected color
value") {
        $color = $this->coerceColor($value);
        if (is_null($color)) $this->throwError($error);

        return $color;
    }

    protected function assertNumber($value, $error = "expecting
number") {
        if ($value[0] == "number") return $value[1];
        $this->throwError($error);
    }

    protected function toHSL($color) {
        if ($color[0] == 'hsl') return $color;

        $r = $color[1] / 255;
        $g = $color[2] / 255;
        $b = $color[3] / 255;

        $min = min($r, $g, $b);
        $max = max($r, $g, $b);

        $L = ($min + $max) / 2;
        if ($min == $max) {
            $S = $H = 0;
        } else {
            if ($L < 0.5) $S = ($max - $min) / ($max + $min); else
                $S = ($max - $min) / (2.0 - $max - $min);

            if ($r == $max) $H = ($g - $b) / ($max - $min); elseif ($g ==
$max) $H = 2.0 + ($b - $r) / ($max - $min);
            elseif ($b == $max) $H = 4.0 + ($r - $g) / ($max - $min);

        }

        $out = array(
            'hsl',
            ($H < 0 ? $H + 6 : $H) * 60,
            $S * 100,
            $L * 100,
        );

        if (count($color) > 4) $out[] = $color[4]; // copy alpha

        return $out;
    }

    protected function toRGB_helper($comp, $temp1, $temp2) {
        if ($comp < 0) $comp += 1.0; elseif ($comp > 1) $comp -= 1.0;

        if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 *
$comp;
        if (2 * $comp < 1) return $temp2;
        if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1) * ((2 / 3)
- $comp) * 6;

        return $temp1;
    }

    /**
     * Converts a hsl array into a color value in rgb.
     * Expects H to be in range of 0 to 360, S and L in 0 to 100
     */
    protected function toRGB($color) {
        if ($color == 'color') return $color;

        $H = $color[1] / 360;
        $S = $color[2] / 100;
        $L = $color[3] / 100;

        if ($S == 0) {
            $r = $g = $b = $L;
        } else {
            $temp2 = $L < 0.5 ? $L * (1.0 + $S) : $L + $S - $L * $S;

            $temp1 = 2.0 * $L - $temp2;

            $r = $this->toRGB_helper($H + 1 / 3, $temp1, $temp2);
            $g = $this->toRGB_helper($H, $temp1, $temp2);
            $b = $this->toRGB_helper($H - 1 / 3, $temp1, $temp2);
        }

        // $out = array('color', round($r*255), round($g*255),
round($b*255));
        $out = array(
            'color',
            $r * 255,
            $g * 255,
            $b * 255
        );
        if (count($color) > 4) $out[] = $color[4]; // copy alpha

        return $out;
    }

    protected function clamp($v, $max = 1, $min = 0) {
        return min($max, max($min, $v));
    }

    /**
     * Convert the rgb, rgba, hsl color literals of function type
     * as returned by the parser into values of color type.
     */
    protected function funcToColor($func) {
        $fname = $func[1];
        if ($func[2][0] != 'list') return false; // need a list
of arguments
        $rawComponents = $func[2][2];

        if ($fname == 'hsl' || $fname == 'hsla') {
            $hsl = array('hsl');
            $i   = 0;
            foreach ($rawComponents as $c) {
                $val = $this->reduce($c);
                $val = isset($val[1]) ? floatval($val[1]) : 0;

                if ($i == 0) $clamp = 360; elseif ($i < 3) $clamp = 100;
                else $clamp = 1;

                $hsl[] = $this->clamp($val, $clamp);
                $i++;
            }

            while (count($hsl) < 4) $hsl[] = 0;

            return $this->toRGB($hsl);

        } elseif ($fname == 'rgb' || $fname == 'rgba')
{
            $components = array();
            $i          = 1;
            foreach ($rawComponents as $c) {
                $c = $this->reduce($c);
                if ($i < 4) {
                    if ($c[0] == "number" && $c[2] ==
"%") {
                        $components[] = 255 * ($c[1] / 100);
                    } else {
                        $components[] = floatval($c[1]);
                    }
                } elseif ($i == 4) {
                    if ($c[0] == "number" && $c[2] ==
"%") {
                        $components[] = 1.0 * ($c[1] / 100);
                    } else {
                        $components[] = floatval($c[1]);
                    }
                } else break;

                $i++;
            }
            while (count($components) < 3) $components[] = 0;
            array_unshift($components, 'color');

            return $this->fixColor($components);
        }

        return false;
    }

    protected function reduce($value, $forExpression = false) {
        switch ($value[0]) {
            case "interpolate":
                $reduced = $this->reduce($value[1]);
                $var     = $this->compileValue($reduced);
                $res     = $this->reduce(array(
                    "variable",
                    $this->vPrefix . $var
                ));

                if (empty($value[2])) $res = $this->lib_e($res);

                return $res;
            case "variable":
                $key = $value[1];
                if (is_array($key)) {
                    $key = $this->reduce($key);
                    $key = $this->vPrefix .
$this->compileValue($this->lib_e($key));
                }

                $seen =& $this->env->seenNames;

                if (!empty($seen[$key])) {
                    $this->throwError("infinite loop detected:
$key");
                }

                $seen[$key] = true;
                $out        = $this->reduce($this->get($key,
self::$defaultValue));
                $seen[$key] = false;

                return $out;
            case "list":
                foreach ($value[2] as &$item) {
                    $item = $this->reduce($item, $forExpression);
                }

                return $value;
            case "expression":
                return $this->evaluate($value);
            case "string":
                foreach ($value[2] as &$part) {
                    if (is_array($part)) {
                        $strip = $part[0] == "variable";
                        $part  = $this->reduce($part);
                        if ($strip) $part = $this->lib_e($part);
                    }
                }

                return $value;
            case "escape":
                list(, $inner) = $value;

                return $this->lib_e($this->reduce($inner));
            case "function":
                $color = $this->funcToColor($value);
                if ($color) return $color;

                list(, $name, $args) = $value;
                if ($name == "%") $name = "_sprintf";
                $f = isset($this->libFunctions[$name]) ?
$this->libFunctions[$name] : array(
                    $this,
                    'lib_' . $name
                );

                if (is_callable($f)) {
                    if ($args[0] == 'list') $args =
self::compressList($args[2], $args[1]);

                    $ret = call_user_func($f, $this->reduce($args,
true), $this);

                    if (is_null($ret)) {
                        return array(
                            "string",
                            "",
                            array(
                                $name,
                                "(",
                                $args,
                                ")"
                            )
                        );
                    }

                    // convert to a typed value if the result is a php
primitive
                    if (is_numeric($ret)) $ret = array(
                        'number',
                        $ret,
                        ""
                    ); elseif (!is_array($ret)) $ret = array(
                        'keyword',
                        $ret
                    );

                    return $ret;
                }

                // plain function, reduce args
                $value[2] = $this->reduce($value[2]);

                return $value;
            case "unary":
                list(, $op, $exp) = $value;
                $exp = $this->reduce($exp);

                if ($exp[0] == "number") {
                    switch ($op) {
                        case "+":
                            return $exp;
                        case "-":
                            $exp[1] *= -1;

                            return $exp;
                    }
                }

                return array(
                    "string",
                    "",
                    array(
                        $op,
                        $exp
                    )
                );
        }

        if ($forExpression) {
            switch ($value[0]) {
                case "keyword":
                    if ($color = $this->coerceColor($value)) {
                        return $color;
                    }
                    break;
                case "raw_color":
                    return $this->coerceColor($value);
            }
        }

        return $value;
    }


    // coerce a value for use in color operation
    protected function coerceColor($value) {
        switch ($value[0]) {
            case 'color':
                return $value;
            case 'raw_color':
                $c        = array(
                    "color",
                    0,
                    0,
                    0
                );
                $colorStr = substr($value[1], 1);
                $num      = hexdec($colorStr);
                $width    = strlen($colorStr) == 3 ? 16 : 256;

                for ($i = 3; $i > 0; $i--) { // 3 2 1
                    $t   = $num % $width;
                    $num /= $width;

                    $c[$i] = $t * (256 / $width) + $t * floor(16 / $width);
                }

                return $c;
            case 'keyword':
                $name = $value[1];
                if (isset(self::$cssColors[$name])) {
                    $rgba = explode(',',
self::$cssColors[$name]);

                    if (isset($rgba[3])) return array(
                        'color',
                        $rgba[0],
                        $rgba[1],
                        $rgba[2],
                        $rgba[3]
                    );

                    return array(
                        'color',
                        $rgba[0],
                        $rgba[1],
                        $rgba[2]
                    );
                }

                return null;
        }
    }

    // make something string like into a string
    protected function coerceString($value) {
        switch ($value[0]) {
            case "string":
                return $value;
            case "keyword":
                return array(
                    "string",
                    "",
                    array($value[1])
                );
        }

        return null;
    }

    // turn list of length 1 into value type
    protected function flattenList($value) {
        if ($value[0] == "list" && count($value[2]) == 1)
{
            return $this->flattenList($value[2][0]);
        }

        return $value;
    }

    protected function toBool($a) {
        if ($a) return self::$TRUE; else return self::$FALSE;
    }

    // evaluate an expression
    protected function evaluate($exp) {
        list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;

        $left  = $this->reduce($left, true);
        $right = $this->reduce($right, true);

        if ($leftColor = $this->coerceColor($left)) {
            $left = $leftColor;
        }

        if ($rightColor = $this->coerceColor($right)) {
            $right = $rightColor;
        }

        $ltype = $left[0];
        $rtype = $right[0];

        // operators that work on all types
        if ($op == "and") {
            return $this->toBool($left == self::$TRUE && $right
== self::$TRUE);
        }

        if ($op == "=") {
            return $this->toBool($this->eq($left, $right));
        }

        if ($op == "+" && !is_null($str =
$this->stringConcatenate($left, $right))) {
            return $str;
        }

        // type based operators
        $fname = "op_${ltype}_${rtype}";
        if (is_callable(array(
            $this,
            $fname
        ))) {
            $out = $this->$fname($op, $left, $right);
            if (!is_null($out)) return $out;
        }

        // make the expression look it did before being parsed
        $paddedOp = $op;
        if ($whiteBefore) $paddedOp = " " . $paddedOp;
        if ($whiteAfter) $paddedOp .= " ";

        return array(
            "string",
            "",
            array(
                $left,
                $paddedOp,
                $right
            )
        );
    }

    protected function stringConcatenate($left, $right) {
        if ($strLeft = $this->coerceString($left)) {
            if ($right[0] == "string") {
                $right[1] = "";
            }
            $strLeft[2][] = $right;

            return $strLeft;
        }

        if ($strRight = $this->coerceString($right)) {
            array_unshift($strRight[2], $left);

            return $strRight;
        }
    }


    // make sure a color's components don't go out of bounds
    protected function fixColor($c) {
        foreach (range(1, 3) as $i) {
            if ($c[$i] < 0) $c[$i] = 0;
            if ($c[$i] > 255) $c[$i] = 255;
        }

        return $c;
    }

    protected function op_number_color($op, $lft, $rgt) {
        if ($op == '+' || $op == '*') {
            return $this->op_color_number($op, $rgt, $lft);
        }
    }

    protected function op_color_number($op, $lft, $rgt) {
        if ($rgt[0] == '%') $rgt[1] /= 100;

        return $this->op_color_color($op, $lft, array_fill(1,
count($lft) - 1, $rgt[1]));
    }

    protected function op_color_color($op, $left, $right) {
        $out = array('color');
        $max = count($left) > count($right) ? count($left) :
count($right);
        foreach (range(1, $max - 1) as $i) {
            $lval = isset($left[$i]) ? $left[$i] : 0;
            $rval = isset($right[$i]) ? $right[$i] : 0;
            switch ($op) {
                case '+':
                    $out[] = $lval + $rval;
                    break;
                case '-':
                    $out[] = $lval - $rval;
                    break;
                case '*':
                    $out[] = $lval * $rval;
                    break;
                case '%':
                    $out[] = $lval % $rval;
                    break;
                case '/':
                    if ($rval == 0) $this->throwError("evaluate
error: can't divide by zero");
                    $out[] = $lval / $rval;
                    break;
                default:
                    $this->throwError('evaluate error: color op
number failed on op ' . $op);
            }
        }

        return $this->fixColor($out);
    }

    function lib_red($color) {
        $color = $this->coerceColor($color);
        if (is_null($color)) {
            $this->throwError('color expected for red()');
        }

        return $color[1];
    }

    function lib_green($color) {
        $color = $this->coerceColor($color);
        if (is_null($color)) {
            $this->throwError('color expected for green()');
        }

        return $color[2];
    }

    function lib_blue($color) {
        $color = $this->coerceColor($color);
        if (is_null($color)) {
            $this->throwError('color expected for blue()');
        }

        return $color[3];
    }


    // operator on two numbers
    protected function op_number_number($op, $left, $right) {
        $unit = empty($left[2]) ? $right[2] : $left[2];

        $value = 0;
        switch ($op) {
            case '+':
                $value = $left[1] + $right[1];
                break;
            case '*':
                $value = $left[1] * $right[1];
                break;
            case '-':
                $value = $left[1] - $right[1];
                break;
            case '%':
                $value = $left[1] % $right[1];
                break;
            case '/':
                if ($right[1] == 0) $this->throwError('parse error:
divide by zero');
                $value = $left[1] / $right[1];
                break;
            case '<':
                return $this->toBool($left[1] < $right[1]);
            case '>':
                return $this->toBool($left[1] > $right[1]);
            case '>=':
                return $this->toBool($left[1] >= $right[1]);
            case '=<':
                return $this->toBool($left[1] <= $right[1]);
            default:
                $this->throwError('parse error: unknown number
operator: ' . $op);
        }

        return array(
            "number",
            $value,
            $unit
        );
    }


    /* environment functions */

    protected function makeOutputBlock($type, $selectors = null) {
        $b            = new stdClass;
        $b->lines     = array();
        $b->children  = array();
        $b->selectors = $selectors;
        $b->type      = $type;
        $b->parent    = $this->scope;

        return $b;
    }

    // the state of execution
    protected function pushEnv($block = null) {
        $e         = new stdclass;
        $e->parent = $this->env;
        $e->store  = array();
        $e->block  = $block;

        $this->env = $e;

        return $e;
    }

    // pop something off the stack
    protected function popEnv() {
        $old       = $this->env;
        $this->env = $this->env->parent;

        return $old;
    }

    // set something in the current env
    protected function set($name, $value) {
        $this->env->store[$name] = $value;
    }


    // get the highest occurrence entry for a name
    protected function get($name, $default = null) {
        $current = $this->env;

        $isArguments = $name == $this->vPrefix . 'arguments';
        while ($current) {
            if ($isArguments && isset($current->arguments)) {
                return array(
                    'list',
                    ' ',
                    $current->arguments
                );
            }

            if (isset($current->store[$name])) return
$current->store[$name]; else {
                $current = isset($current->storeParent) ?
$current->storeParent : $current->parent;
            }
        }

        return $default;
    }

    // inject array of unparsed strings into environment as variables
    protected function injectVariables($args) {
        $this->pushEnv();
        $parser = new LessParser($this, __METHOD__);
        foreach ($args as $name => $strValue) {
            if ($name[0] != '@') $name = '@' . $name;
            $parser->count  = 0;
            $parser->buffer = (string)$strValue;
            if (!$parser->propertyValue($value)) {
                throw new Exception("failed to parse passed in
variable $name: $strValue");
            }

            $this->set($name, $value);
        }
    }

    /**
     * Initialize any static state, can initialize parser for a file
     * $opts isn't used yet
     */
    public function __construct($fname = null) {
        if ($fname !== null) {
            // used for deprecated parse method
            $this->_parseFile = $fname;
        }
    }

    public function compile($string, $name = null) {
        $locale = setlocale(LC_NUMERIC, 0);
        setlocale(LC_NUMERIC, "C");

        $this->parser = $this->makeParser($name);
        $root         = $this->parser->parse($string);

        $this->env   = null;
        $this->scope = null;

        $this->formatter = $this->newFormatter();

        if (!empty($this->registeredVars)) {
            $this->injectVariables($this->registeredVars);
        }

        $this->sourceParser = $this->parser; // used for error
messages
        $this->compileBlock($root);

        $out = $this->formatter->block($this->scope);

        setlocale(LC_NUMERIC, $locale);

        return $out;
    }

    public function compileFile($fname, $outFname = null) {
        if (!is_readable($fname)) {
            throw new Exception('load error: failed to find ' .
$fname);
        }

        $pi = pathinfo($fname);

        $oldImport = $this->importDir;

        $this->importDir   = (array)$this->importDir;
        $this->importDir[] = $pi['dirname'] . '/';

        $this->allParsedFiles = array();
        $this->addParsedFile($fname);

        $out = $this->compile(file_get_contents($fname), $fname);

        $this->importDir = $oldImport;

        if ($outFname !== null) {
            return file_put_contents($outFname, $out);
        }

        return $out;
    }

    // compile only if changed input has changed or output doesn't
exist
    public function checkedCompile($in, $out) {
        if (!is_file($out) || filemtime($in) > filemtime($out)) {
            $this->compileFile($in, $out);

            return true;
        }

        return false;
    }

    /**
     * Execute lessphp on a .less file or a lessphp cache structure
     *
     * The lessphp cache structure contains information about a specific
     * less file having been parsed. It can be used as a hint for future
     * calls to determine whether or not a rebuild is required.
     *
     * The cache structure contains two important keys that may be used
     * externally:
     *
     * compiled: The final compiled CSS
     * updated: The time (in seconds) the CSS was last compiled
     *
     * The cache structure is a plain-ol' PHP associative array and
can
     * be serialized and unserialized without a hitch.
     *
     * @param mixed $in    Input
     * @param bool  $force Force rebuild?
     *
     * @return array lessphp cache structure
     */
    public function cachedCompile($in, $force = false) {
        // assume no root
        $root = null;

        if (is_string($in)) {
            $root = $in;
        } elseif (is_array($in) and isset($in['root'])) {
            if ($force or !isset($in['files'])) {
                // If we are forcing a recompile or if for some reason the
                // structure does not contain any file information we
should
                // specify the root to trigger a rebuild.
                $root = $in['root'];
            } elseif (isset($in['files']) and
is_array($in['files'])) {
                foreach ($in['files'] as $fname => $ftime) {
                    if (!file_exists($fname) or filemtime($fname) >
$ftime) {
                        // One of the files we knew about previously has
changed
                        // so we should look at our incoming root again.
                        $root = $in['root'];
                        break;
                    }
                }
            }
        } else {
            // TODO: Throw an exception? We got neither a string nor
something
            // that looks like a compatible lessphp cache structure.
            return null;
        }

        if ($root !== null) {
            // If we have a root value which means we should rebuild.
            $out             = array();
            $out['root']     = $root;
            $out['compiled'] = $this->compileFile($root);
            $out['files']    = $this->allParsedFiles();
            $out['updated']  = time();

            return $out;
        } else {
            // No changes, pass back the structure
            // we were given initially.
            return $in;
        }

    }

    // parse and compile buffer
    // This is deprecated
    public function parse($str = null, $initialVariables = null) {
        if (is_array($str)) {
            $initialVariables = $str;
            $str              = null;
        }

        $oldVars = $this->registeredVars;
        if ($initialVariables !== null) {
            $this->setVariables($initialVariables);
        }

        if ($str == null) {
            if (empty($this->_parseFile)) {
                throw new Exception("nothing to parse");
            }

            $out = $this->compileFile($this->_parseFile);
        } else {
            $out = $this->compile($str);
        }

        $this->registeredVars = $oldVars;

        return $out;
    }

    protected function makeParser($name) {
        $parser                = new LessParser($this, $name);
        $parser->writeComments = $this->preserveComments;

        return $parser;
    }

    public function setFormatter($name) {
        $this->formatterName = $name;
    }

    /**
     * @return Classic
     */
    protected function newFormatter() {
        return new Compressed();
    }

    public function setPreserveComments($preserve) {
        $this->preserveComments = $preserve;
    }

    public function registerFunction($name, $func) {
        $this->libFunctions[$name] = $func;
    }

    public function unregisterFunction($name) {
        unset($this->libFunctions[$name]);
    }

    public function setVariables($variables) {
        $this->registeredVars = array_merge($this->registeredVars,
$variables);
    }

    /**
     * @return array
     */
    public function getVariables() {
        return $this->registeredVars;
    }

    public function unsetVariable($name) {
        unset($this->registeredVars[$name]);
    }

    public function setImportDir($dirs) {
        $this->importDir = (array)$dirs;
    }

    public function addImportDir($dir) {
        $this->importDir   = (array)$this->importDir;
        $this->importDir[] = $dir;
    }

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

    protected function addParsedFile($file) {
        $this->allParsedFiles[Filesystem::realpath($file)] =
filemtime($file);
    }

    /**
     * Uses the current value of $this->count to show line and line
number
     */
    protected function throwError($msg = null) {
        if ($this->sourceLoc >= 0) {
            $this->sourceParser->throwError($msg,
$this->sourceLoc);
        }
        throw new Exception($msg);
    }

    // compile file $in to file $out if $in is newer than $out
    // returns true when it compiles, false otherwise
    public static function ccompile($in, $out, $less = null) {
        if ($less === null) {
            $less = new self;
        }

        return $less->checkedCompile($in, $out);
    }

    public static function cexecute($in, $force = false, $less = null) {
        if ($less === null) {
            $less = new self;
        }

        return $less->cachedCompile($in, $force);
    }

    static protected $cssColors = array(
        'aliceblue'            => '240,248,255',
        'antiquewhite'         => '250,235,215',
        'aqua'                 => '0,255,255',
        'aquamarine'           => '127,255,212',
        'azure'                => '240,255,255',
        'beige'                => '245,245,220',
        'bisque'               => '255,228,196',
        'black'                => '0,0,0',
        'blanchedalmond'       => '255,235,205',
        'blue'                 => '0,0,255',
        'blueviolet'           => '138,43,226',
        'brown'                => '165,42,42',
        'burlywood'            => '222,184,135',
        'cadetblue'            => '95,158,160',
        'chartreuse'           => '127,255,0',
        'chocolate'            => '210,105,30',
        'coral'                => '255,127,80',
        'cornflowerblue'       => '100,149,237',
        'cornsilk'             => '255,248,220',
        'crimson'              => '220,20,60',
        'cyan'                 => '0,255,255',
        'darkblue'             => '0,0,139',
        'darkcyan'             => '0,139,139',
        'darkgoldenrod'        => '184,134,11',
        'darkgray'             => '169,169,169',
        'darkgreen'            => '0,100,0',
        'darkgrey'             => '169,169,169',
        'darkkhaki'            => '189,183,107',
        'darkmagenta'          => '139,0,139',
        'darkolivegreen'       => '85,107,47',
        'darkorange'           => '255,140,0',
        'darkorchid'           => '153,50,204',
        'darkred'              => '139,0,0',
        'darksalmon'           => '233,150,122',
        'darkseagreen'         => '143,188,143',
        'darkslateblue'        => '72,61,139',
        'darkslategray'        => '47,79,79',
        'darkslategrey'        => '47,79,79',
        'darkturquoise'        => '0,206,209',
        'darkviolet'           => '148,0,211',
        'deeppink'             => '255,20,147',
        'deepskyblue'          => '0,191,255',
        'dimgray'              => '105,105,105',
        'dimgrey'              => '105,105,105',
        'dodgerblue'           => '30,144,255',
        'firebrick'            => '178,34,34',
        'floralwhite'          => '255,250,240',
        'forestgreen'          => '34,139,34',
        'fuchsia'              => '255,0,255',
        'gainsboro'            => '220,220,220',
        'ghostwhite'           => '248,248,255',
        'gold'                 => '255,215,0',
        'goldenrod'            => '218,165,32',
        'gray'                 => '128,128,128',
        'green'                => '0,128,0',
        'greenyellow'          => '173,255,47',
        'grey'                 => '128,128,128',
        'honeydew'             => '240,255,240',
        'hotpink'              => '255,105,180',
        'indianred'            => '205,92,92',
        'indigo'               => '75,0,130',
        'ivory'                => '255,255,240',
        'khaki'                => '240,230,140',
        'lavender'             => '230,230,250',
        'lavenderblush'        => '255,240,245',
        'lawngreen'            => '124,252,0',
        'lemonchiffon'         => '255,250,205',
        'lightblue'            => '173,216,230',
        'lightcoral'           => '240,128,128',
        'lightcyan'            => '224,255,255',
        'lightgoldenrodyellow' => '250,250,210',
        'lightgray'            => '211,211,211',
        'lightgreen'           => '144,238,144',
        'lightgrey'            => '211,211,211',
        'lightpink'            => '255,182,193',
        'lightsalmon'          => '255,160,122',
        'lightseagreen'        => '32,178,170',
        'lightskyblue'         => '135,206,250',
        'lightslategray'       => '119,136,153',
        'lightslategrey'       => '119,136,153',
        'lightsteelblue'       => '176,196,222',
        'lightyellow'          => '255,255,224',
        'lime'                 => '0,255,0',
        'limegreen'            => '50,205,50',
        'linen'                => '250,240,230',
        'magenta'              => '255,0,255',
        'maroon'               => '128,0,0',
        'mediumaquamarine'     => '102,205,170',
        'mediumblue'           => '0,0,205',
        'mediumorchid'         => '186,85,211',
        'mediumpurple'         => '147,112,219',
        'mediumseagreen'       => '60,179,113',
        'mediumslateblue'      => '123,104,238',
        'mediumspringgreen'    => '0,250,154',
        'mediumturquoise'      => '72,209,204',
        'mediumvioletred'      => '199,21,133',
        'midnightblue'         => '25,25,112',
        'mintcream'            => '245,255,250',
        'mistyrose'            => '255,228,225',
        'moccasin'             => '255,228,181',
        'navajowhite'          => '255,222,173',
        'navy'                 => '0,0,128',
        'oldlace'              => '253,245,230',
        'olive'                => '128,128,0',
        'olivedrab'            => '107,142,35',
        'orange'               => '255,165,0',
        'orangered'            => '255,69,0',
        'orchid'               => '218,112,214',
        'palegoldenrod'        => '238,232,170',
        'palegreen'            => '152,251,152',
        'paleturquoise'        => '175,238,238',
        'palevioletred'        => '219,112,147',
        'papayawhip'           => '255,239,213',
        'peachpuff'            => '255,218,185',
        'peru'                 => '205,133,63',
        'pink'                 => '255,192,203',
        'plum'                 => '221,160,221',
        'powderblue'           => '176,224,230',
        'purple'               => '128,0,128',
        'red'                  => '255,0,0',
        'rosybrown'            => '188,143,143',
        'royalblue'            => '65,105,225',
        'saddlebrown'          => '139,69,19',
        'salmon'               => '250,128,114',
        'sandybrown'           => '244,164,96',
        'seagreen'             => '46,139,87',
        'seashell'             => '255,245,238',
        'sienna'               => '160,82,45',
        'silver'               => '192,192,192',
        'skyblue'              => '135,206,235',
        'slateblue'            => '106,90,205',
        'slategray'            => '112,128,144',
        'slategrey'            => '112,128,144',
        'snow'                 => '255,250,250',
        'springgreen'          => '0,255,127',
        'steelblue'            => '70,130,180',
        'tan'                  => '210,180,140',
        'teal'                 => '0,128,128',
        'thistle'              => '216,191,216',
        'tomato'               => '255,99,71',
        'transparent'          => '0,0,0,0',
        'turquoise'            => '64,224,208',
        'violet'               => '238,130,238',
        'wheat'                => '245,222,179',
        'white'                => '255,255,255',
        'whitesmoke'           => '245,245,245',
        'yellow'               => '255,255,0',
        'yellowgreen'          => '154,205,50'
    );
}



Asset/Css/Less/LessParser.php000064400000124776151161172410012075
0ustar00<?php


namespace Nextend\Framework\Asset\Css\Less;

use Exception;
use stdClass;

class LessParser {

    static protected $nextBlockId = 0; // used to uniquely identify blocks

    static protected $precedence = array(
        '=<' => 0,
        '>=' => 0,
        '='  => 0,
        '<'  => 0,
        '>'  => 0,

        '+' => 1,
        '-' => 1,
        '*' => 2,
        '/' => 2,
        '%' => 2,
    );

    static protected $whitePattern;
    static protected $commentMulti;

    static protected $commentSingle = "//";
    static protected $commentMultiLeft = "/*";
    static protected $commentMultiRight = "*/";

    // regex string to match any of the operators
    static protected $operatorString;

    // these properties will supress division unless it's inside
parenthases
    static protected $supressDivisionProps = array(
        '/border-radius$/i',
        '/^font$/i'
    );

    protected $blockDirectives = array(
        "font-face",
        "keyframes",
        "page",
        "-moz-document"
    );
    protected $lineDirectives = array("charset");

    /**
     * if we are in parens we can be more liberal with whitespace around
     * operators because it must evaluate to a single value and thus is
less
     * ambiguous.
     *
     * Consider:
     *     property1: 10 -5; // is two numbers, 10 and -5
     *     property2: (10 -5); // should evaluate to 5
     */
    protected $inParens = false;

    // caches preg escaped literals
    static protected $literalCache = array();

    public function __construct($lessc, $sourceName = null) {
        $this->eatWhiteDefault = true;
        // reference to less needed for vPrefix, mPrefix, and
parentSelector
        $this->lessc = $lessc;

        $this->sourceName = $sourceName; // name used for error messages

        $this->writeComments = false;

        if (!self::$operatorString) {
            self::$operatorString = '(' . implode('|',
array_map(array(
                    LessCompiler::class,
                    'preg_quote'
                ), array_keys(self::$precedence))) . ')';

            $commentSingle     =
LessCompiler::preg_quote(self::$commentSingle);
            $commentMultiLeft  =
LessCompiler::preg_quote(self::$commentMultiLeft);
            $commentMultiRight =
LessCompiler::preg_quote(self::$commentMultiRight);

            self::$commentMulti = $commentMultiLeft . '.*?' .
$commentMultiRight;
            self::$whitePattern = '/' . $commentSingle .
'[^\n]*\s*|(' . self::$commentMulti . ')\s*|\s+/Ais';
        }
    }

    public function parse($buffer) {
        $this->count = 0;
        $this->line  = 1;

        $this->env    = null; // block stack
        $this->buffer = $this->writeComments ? $buffer :
$this->removeComments($buffer);
        $this->pushSpecialBlock("root");
        $this->eatWhiteDefault = true;
        $this->seenComments    = array();

        // trim whitespace on head
        // if (preg_match('/^\s+/', $this->buffer, $m)) {
        // 	$this->line += substr_count($m[0], "\n");
        // 	$this->buffer = ltrim($this->buffer);
        // }
        $this->whitespace();

        // parse the entire file
        $lastCount = $this->count;
        while (false !== $this->parseChunk()) ;

        if ($this->count != strlen($this->buffer))
$this->throwError();

        // TODO report where the block was opened
        if (!is_null($this->env->parent)) throw new
Exception('parse error: unclosed block');

        return $this->env;
    }

    /**
     * Parse a single chunk off the head of the buffer and append it to the
     * current parse environment.
     * Returns false when the buffer is empty, or when there is an error.
     *
     * This function is called repeatedly until the entire document is
     * parsed.
     *
     * This parser is most similar to a recursive descent parser. Single
     * functions represent discrete grammatical rules for the language, and
     * they are able to capture the text that represents those rules.
     *
     * Consider the function lessc::keyword(). (all parse functions are
     * structured the same)
     *
     * The function takes a single reference argument. When calling the
     * function it will attempt to match a keyword on the head of the
buffer.
     * If it is successful, it will place the keyword in the referenced
     * argument, advance the position in the buffer, and return true. If it
     * fails then it won't advance the buffer and it will return
false.
     *
     * All of these parse functions are powered by lessc::match(), which
behaves
     * the same way, but takes a literal regular expression. Sometimes it
is
     * more convenient to use match instead of creating a new function.
     *
     * Because of the format of the functions, to parse an entire string of
     * grammatical rules, you can chain them together using &&.
     *
     * But, if some of the rules in the chain succeed before one fails,
then
     * the buffer position will be left at an invalid state. In order to
     * avoid this, lessc::seek() is used to remember and set buffer
positions.
     *
     * Before parsing a chain, use $s = $this->seek() to remember the
current
     * position into $s. Then if a chain fails, use $this->seek($s) to
     * go back where we started.
     */
    protected function parseChunk() {
        if (empty($this->buffer)) return false;
        $s = $this->seek();

        // setting a property
        if ($this->keyword($key) && $this->assign()
&& $this->propertyValue($value, $key) &&
$this->end()) {
            $this->append(array(
                'assign',
                $key,
                $value
            ), $s);

            return true;
        } else {
            $this->seek($s);
        }


        // look for special css blocks
        if ($this->literal('@', false)) {
            $this->count--;

            // media
            if ($this->literal('@media')) {
                if (($this->mediaQueryList($mediaQueries) || true)
&& $this->literal('{')) {
                    $media          =
$this->pushSpecialBlock("media");
                    $media->queries = is_null($mediaQueries) ? array() :
$mediaQueries;

                    return true;
                } else {
                    $this->seek($s);

                    return false;
                }
            }

            if ($this->literal("@", false) &&
$this->keyword($dirName)) {
                if ($this->isDirective($dirName,
$this->blockDirectives)) {
                    if (($this->openString("{", $dirValue,
null, array(";")) || true) &&
$this->literal("{")) {
                        $dir       =
$this->pushSpecialBlock("directive");
                        $dir->name = $dirName;
                        if (isset($dirValue)) $dir->value = $dirValue;

                        return true;
                    }
                } elseif ($this->isDirective($dirName,
$this->lineDirectives)) {
                    if ($this->propertyValue($dirValue) &&
$this->end()) {
                        $this->append(array(
                            "directive",
                            $dirName,
                            $dirValue
                        ));

                        return true;
                    }
                }
            }

            $this->seek($s);
        }

        // setting a variable
        if ($this->variable($var) && $this->assign()
&& $this->propertyValue($value) && $this->end()) {
            $this->append(array(
                'assign',
                $var,
                $value
            ), $s);

            return true;
        } else {
            $this->seek($s);
        }

        if ($this->import($importValue)) {
            $this->append($importValue, $s);

            return true;
        }

        // opening parametric mixin
        if ($this->tag($tag, true) &&
$this->argumentDef($args, $isVararg) &&
($this->guards($guards) || true) &&
$this->literal('{')) {
            $block           =
$this->pushBlock($this->fixTags(array($tag)));
            $block->args     = $args;
            $block->isVararg = $isVararg;
            if (!empty($guards)) $block->guards = $guards;

            return true;
        } else {
            $this->seek($s);
        }

        // opening a simple block
        if ($this->tags($tags) &&
$this->literal('{')) {
            $tags = $this->fixTags($tags);
            $this->pushBlock($tags);

            return true;
        } else {
            $this->seek($s);
        }

        // closing a block
        if ($this->literal('}', false)) {
            try {
                $block = $this->pop();
            } catch (Exception $e) {
                $this->seek($s);
                $this->throwError($e->getMessage());
            }

            $hidden = false;
            if (is_null($block->type)) {
                $hidden = true;
                if (!isset($block->args)) {
                    foreach ($block->tags as $tag) {
                        if (!is_string($tag) || $tag[0] !=
$this->lessc->mPrefix) {
                            $hidden = false;
                            break;
                        }
                    }
                }

                foreach ($block->tags as $tag) {
                    if (is_string($tag)) {
                        $this->env->children[$tag][] = $block;
                    }
                }
            }

            if (!$hidden) {
                $this->append(array(
                    'block',
                    $block
                ), $s);
            }

            // this is done here so comments aren't bundled into he
block that
            // was just closed
            $this->whitespace();

            return true;
        }

        // mixin
        if ($this->mixinTags($tags) &&
($this->argumentValues($argv) || true) &&
($this->keyword($suffix) || true) && $this->end()) {
            $tags = $this->fixTags($tags);
            $this->append(array(
                'mixin',
                $tags,
                $argv,
                $suffix
            ), $s);

            return true;
        } else {
            $this->seek($s);
        }

        // spare ;
        if ($this->literal(';')) return true;

        return false; // got nothing, throw error
    }

    protected function isDirective($dirname, $directives) {
        // TODO: cache pattern in parser
        $pattern = implode("|", array_map(array(
            LessCompiler::class,
            "preg_quote"
        ), $directives));
        $pattern = '/^(-[a-z-]+-)?(' . $pattern .
')$/i';

        return preg_match($pattern, $dirname);
    }

    protected function fixTags($tags) {
        // move @ tags out of variable namespace
        foreach ($tags as &$tag) {
            if ($tag[0] == $this->lessc->vPrefix) $tag[0] =
$this->lessc->mPrefix;
        }

        return $tags;
    }

    // a list of expressions
    protected function expressionList(&$exps) {
        $values = array();

        while ($this->expression($exp)) {
            $values[] = $exp;
        }

        if (count($values) == 0) return false;

        $exps = LessCompiler::compressList($values, ' ');

        return true;
    }

    /**
     * Attempt to consume an expression.
     *
     * @link
http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
     */
    protected function expression(&$out) {
        if ($this->value($lhs)) {
            $out = $this->expHelper($lhs, 0);

            // look for / shorthand
            if (!empty($this->env->supressedDivision)) {
                unset($this->env->supressedDivision);
                $s = $this->seek();
                if ($this->literal("/") &&
$this->value($rhs)) {
                    $out = array(
                        "list",
                        "",
                        array(
                            $out,
                            array(
                                "keyword",
                                "/"
                            ),
                            $rhs
                        )
                    );
                } else {
                    $this->seek($s);
                }
            }

            return true;
        }

        return false;
    }

    /**
     * recursively parse infix equation with $lhs at precedence $minP
     */
    protected function expHelper($lhs, $minP) {
        $this->inExp = true;
        $ss          = $this->seek();

        while (true) {
            $whiteBefore = isset($this->buffer[$this->count - 1])
&& preg_match('/^\\s+$/',
$this->buffer[$this->count - 1]);

            // If there is whitespace before the operator, then we require
            // whitespace after the operator for it to be an expression
            $needWhite = $whiteBefore && !$this->inParens;

            if ($this->match(self::$operatorString . ($needWhite ?
'\s' : ''), $m) && self::$precedence[$m[1]]
>= $minP) {
                if (!$this->inParens &&
isset($this->env->currentProperty) && $m[1] == "/"
&& empty($this->env->supressedDivision)) {
                    foreach (self::$supressDivisionProps as $pattern) {
                        if (preg_match($pattern,
$this->env->currentProperty)) {
                            $this->env->supressedDivision = true;
                            break 2;
                        }
                    }
                }


                $whiteAfter = isset($this->buffer[$this->count - 1])
&& preg_match('/^\\s+$/',
$this->buffer[$this->count - 1]);

                if (!$this->value($rhs)) break;

                // peek for next operator to see what to do with rhs
                if ($this->peek(self::$operatorString, $next) &&
self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
                    $rhs = $this->expHelper($rhs,
self::$precedence[$next[1]]);
                }

                $lhs = array(
                    'expression',
                    $m[1],
                    $lhs,
                    $rhs,
                    $whiteBefore,
                    $whiteAfter
                );
                $ss  = $this->seek();

                continue;
            }

            break;
        }

        $this->seek($ss);

        return $lhs;
    }

    // consume a list of values for a property
    public function propertyValue(&$value, $keyName = null) {
        $values = array();

        if ($keyName !== null) $this->env->currentProperty =
$keyName;

        $s = null;
        while ($this->expressionList($v)) {
            $values[] = $v;
            $s        = $this->seek();
            if (!$this->literal(',')) break;
        }

        if ($s) $this->seek($s);

        if ($keyName !== null) unset($this->env->currentProperty);

        if (count($values) == 0) return false;

        $value = LessCompiler::compressList($values, ', ');

        return true;
    }

    protected function parenValue(&$out) {
        $s = $this->seek();

        // speed shortcut
        if (isset($this->buffer[$this->count]) &&
$this->buffer[$this->count] != "(") {
            return false;
        }

        $inParens = $this->inParens;
        if ($this->literal("(") && ($this->inParens
= true) && $this->expression($exp) &&
$this->literal(")")) {
            $out            = $exp;
            $this->inParens = $inParens;

            return true;
        } else {
            $this->inParens = $inParens;
            $this->seek($s);
        }

        return false;
    }

    // a single value
    protected function value(&$value) {
        $s = $this->seek();

        // speed shortcut
        if (isset($this->buffer[$this->count]) &&
$this->buffer[$this->count] == "-") {
            // negation
            if ($this->literal("-", false) &&
(($this->variable($inner) && $inner = array(
                            "variable",
                            $inner
                        )) || $this->unit($inner) ||
$this->parenValue($inner))) {
                $value = array(
                    "unary",
                    "-",
                    $inner
                );

                return true;
            } else {
                $this->seek($s);
            }
        }

        if ($this->parenValue($value)) return true;
        if ($this->unit($value)) return true;
        if ($this->color($value)) return true;
        if ($this->func($value)) return true;
        if ($this->_string($value)) return true;

        if ($this->keyword($word)) {
            $value = array(
                'keyword',
                $word
            );

            return true;
        }

        // try a variable
        if ($this->variable($var)) {
            $value = array(
                'variable',
                $var
            );

            return true;
        }

        // unquote string (should this work on any type?
        if ($this->literal("~") &&
$this->_string($str)) {
            $value = array(
                "escape",
                $str
            );

            return true;
        } else {
            $this->seek($s);
        }

        // css hack: \0
        if ($this->literal('\\') &&
$this->match('([0-9]+)', $m)) {
            $value = array(
                'keyword',
                '\\' . $m[1]
            );

            return true;
        } else {
            $this->seek($s);
        }

        return false;
    }

    // an import statement
    protected function import(&$out) {
        $s = $this->seek();
        if (!$this->literal('@import')) return false;

        // @import "something.css" media;
        // @import url("something.css") media;
        // @import url(something.css) media;

        if ($this->propertyValue($value)) {
            $out = array(
                "import",
                $value
            );

            return true;
        }
    }

    protected function mediaQueryList(&$out) {
        if ($this->genericList($list, "mediaQuery",
",", false)) {
            $out = $list[2];

            return true;
        }

        return false;
    }

    protected function mediaQuery(&$out) {
        $s = $this->seek();

        $expressions = null;
        $parts       = array();

        if (($this->literal("only") && ($only = true)
|| $this->literal("not") && ($not = true) || true)
&& $this->keyword($mediaType)) {
            $prop = array("mediaType");
            if (isset($only)) $prop[] = "only";
            if (isset($not)) $prop[] = "not";
            $prop[]  = $mediaType;
            $parts[] = $prop;
        } else {
            $this->seek($s);
        }


        if (!empty($mediaType) &&
!$this->literal("and")) {
            // ~
        } else {
            $this->genericList($expressions,
"mediaExpression", "and", false);
            if (is_array($expressions)) $parts = array_merge($parts,
$expressions[2]);
        }

        if (count($parts) == 0) {
            $this->seek($s);

            return false;
        }

        $out = $parts;

        return true;
    }

    protected function mediaExpression(&$out) {
        $s     = $this->seek();
        $value = null;
        if ($this->literal("(") &&
$this->keyword($feature) && ($this->literal(":")
&& $this->expression($value) || true) &&
$this->literal(")")) {
            $out = array(
                "mediaExp",
                $feature
            );
            if ($value) $out[] = $value;

            return true;
        } elseif ($this->variable($variable)) {
            $out = array(
                'variable',
                $variable
            );

            return true;
        }

        $this->seek($s);

        return false;
    }

    // an unbounded string stopped by $end
    protected function openString($end, &$out, $nestingOpen = null,
$rejectStrs = null) {
        $oldWhite              = $this->eatWhiteDefault;
        $this->eatWhiteDefault = false;

        $stop = array(
            "'",
            '"',
            "@{",
            $end
        );
        $stop = array_map(array(
            LessCompiler::class,
            "preg_quote"
        ), $stop);
        // $stop[] = self::$commentMulti;

        if (!is_null($rejectStrs)) {
            $stop = array_merge($stop, $rejectStrs);
        }

        $patt = '(.*?)(' . implode("|", $stop) .
')';

        $nestingLevel = 0;

        $content = array();
        while ($this->match($patt, $m, false)) {
            if (!empty($m[1])) {
                $content[] = $m[1];
                if ($nestingOpen) {
                    $nestingLevel += substr_count($m[1], $nestingOpen);
                }
            }

            $tok = $m[2];

            $this->count -= strlen($tok);
            if ($tok == $end) {
                if ($nestingLevel == 0) {
                    break;
                } else {
                    $nestingLevel--;
                }
            }

            if (($tok == "'" || $tok == '"')
&& $this->_string($str)) {
                $content[] = $str;
                continue;
            }

            if ($tok == "@{" &&
$this->interpolation($inter)) {
                $content[] = $inter;
                continue;
            }

            if (!empty($rejectStrs) && in_array($tok, $rejectStrs))
{
                $ount = null;
                break;
            }

            $content[]   = $tok;
            $this->count += strlen($tok);
        }

        $this->eatWhiteDefault = $oldWhite;

        if (count($content) == 0) return false;

        // trim the end
        if (is_string(end($content))) {
            $content[count($content) - 1] = rtrim(end($content));
        }

        $out = array(
            "string",
            "",
            $content
        );

        return true;
    }

    protected function _string(&$out) {
        $s = $this->seek();
        if ($this->literal('"', false)) {
            $delim = '"';
        } elseif ($this->literal("'", false)) {
            $delim = "'";
        } else {
            return false;
        }

        $content = array();

        // look for either ending delim , escape, or string interpolation
        $patt = '([^\n]*?)(@\{|\\\\|' .
LessCompiler::preg_quote($delim) . ')';

        $oldWhite              = $this->eatWhiteDefault;
        $this->eatWhiteDefault = false;

        while ($this->match($patt, $m, false)) {
            $content[] = $m[1];
            if ($m[2] == "@{") {
                $this->count -= strlen($m[2]);
                if ($this->interpolation($inter)) {
                    $content[] = $inter;
                } else {
                    $this->count += strlen($m[2]);
                    $content[]   = "@{"; // ignore it
                }
            } elseif ($m[2] == '\\') {
                $content[] = $m[2];
                if ($this->literal($delim, false)) {
                    $content[] = $delim;
                }
            } else {
                $this->count -= strlen($delim);
                break; // delim
            }
        }

        $this->eatWhiteDefault = $oldWhite;

        if ($this->literal($delim)) {
            $out = array(
                "string",
                $delim,
                $content
            );

            return true;
        }

        $this->seek($s);

        return false;
    }

    protected function interpolation(&$out) {
        $oldWhite              = $this->eatWhiteDefault;
        $this->eatWhiteDefault = true;

        $s = $this->seek();
        if ($this->literal("@{") &&
$this->openString("}", $interp, null, array(
                "'",
                '"',
                ";"
            )) && $this->literal("}", false)) {
            $out                   = array(
                "interpolate",
                $interp
            );
            $this->eatWhiteDefault = $oldWhite;
            if ($this->eatWhiteDefault) $this->whitespace();

            return true;
        }

        $this->eatWhiteDefault = $oldWhite;
        $this->seek($s);

        return false;
    }

    protected function unit(&$unit) {
        // speed shortcut
        if (isset($this->buffer[$this->count])) {
            $char = $this->buffer[$this->count];
            if (!preg_match('/^[0-9]+$/', $char) && $char
!= ".") return false;
        }

        if
($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?',
$m)) {
            $unit = array(
                "number",
                $m[1],
                empty($m[2]) ? "" : $m[2]
            );

            return true;
        }

        return false;
    }

    // a # color
    protected function color(&$out) {
        if
($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))',
$m)) {
            if (strlen($m[1]) > 7) {
                $out = array(
                    "string",
                    "",
                    array($m[1])
                );
            } else {
                $out = array(
                    "raw_color",
                    $m[1]
                );
            }

            return true;
        }

        return false;
    }

    // consume a list of property values delimited by ; and wrapped in ()
    protected function argumentValues(&$args, $delim = ',') {
        $s = $this->seek();
        if (!$this->literal('(')) return false;

        $values = array();
        while (true) {
            if ($this->expressionList($value)) $values[] = $value;
            if (!$this->literal($delim)) break; else {
                if ($value == null) $values[] = null;
                $value = null;
            }
        }

        if (!$this->literal(')')) {
            $this->seek($s);

            return false;
        }

        $args = $values;

        return true;
    }

    // consume an argument definition list surrounded by ()
    // each argument is a variable name with optional value
    // or at the end a ... or a variable named followed by ...
    protected function argumentDef(&$args, &$isVararg, $delim =
',') {
        $s = $this->seek();
        if (!$this->literal('(')) return false;

        $values = array();

        $isVararg = false;
        while (true) {
            if ($this->literal("...")) {
                $isVararg = true;
                break;
            }

            if ($this->variable($vname)) {
                $arg = array(
                    "arg",
                    $vname
                );
                $ss  = $this->seek();
                if ($this->assign() &&
$this->expressionList($value)) {
                    $arg[] = $value;
                } else {
                    $this->seek($ss);
                    if ($this->literal("...")) {
                        $arg[0]   = "rest";
                        $isVararg = true;
                    }
                }
                $values[] = $arg;
                if ($isVararg) break;
                continue;
            }

            if ($this->value($literal)) {
                $values[] = array(
                    "lit",
                    $literal
                );
            }

            if (!$this->literal($delim)) break;
        }

        if (!$this->literal(')')) {
            $this->seek($s);

            return false;
        }

        $args = $values;

        return true;
    }

    // consume a list of tags
    // this accepts a hanging delimiter
    protected function tags(&$tags, $simple = false, $delim =
',') {
        $tags = array();
        while ($this->tag($tt, $simple)) {
            $tags[] = $tt;
            if (!$this->literal($delim)) break;
        }
        if (count($tags) == 0) return false;

        return true;
    }

    // list of tags of specifying mixin path
    // optionally separated by > (lazy, accepts extra >)
    protected function mixinTags(&$tags) {
        $s    = $this->seek();
        $tags = array();
        while ($this->tag($tt, true)) {
            $tags[] = $tt;
            $this->literal(">");
        }

        if (count($tags) == 0) return false;

        return true;
    }

    // a bracketed value (contained within in a tag definition)
    protected function tagBracket(&$value) {
        // speed shortcut
        if (isset($this->buffer[$this->count]) &&
$this->buffer[$this->count] != "[") {
            return false;
        }

        $s = $this->seek();
        if ($this->literal('[') &&
$this->to(']', $c, true) &&
$this->literal(']', false)) {
            $value = '[' . $c . ']';
            // whitespace?
            if ($this->whitespace()) $value .= " ";

            // escape parent selector, (yuck)
            $value = str_replace($this->lessc->parentSelector,
"$&$", $value);

            return true;
        }

        $this->seek($s);

        return false;
    }

    protected function tagExpression(&$value) {
        $s = $this->seek();
        if ($this->literal("(") &&
$this->expression($exp) && $this->literal(")")) {
            $value = array(
                'exp',
                $exp
            );

            return true;
        }

        $this->seek($s);

        return false;
    }

    // a space separated list of selectors
    protected function tag(&$tag, $simple = false) {
        if ($simple) $chars = '^@,:;{}\][>\(\) "\'';
else
            $chars = '^@,;{}["\'';

        $s = $this->seek();

        if (!$simple && $this->tagExpression($tag)) {
            return true;
        }

        $hasExpression = false;
        $parts         = array();
        while ($this->tagBracket($first)) $parts[] = $first;

        $oldWhite              = $this->eatWhiteDefault;
        $this->eatWhiteDefault = false;

        while (true) {
            if ($this->match('([' . $chars . '0-9]['
. $chars . ']*)', $m)) {
                $parts[] = $m[1];
                if ($simple) break;

                while ($this->tagBracket($brack)) {
                    $parts[] = $brack;
                }
                continue;
            }

            if (isset($this->buffer[$this->count]) &&
$this->buffer[$this->count] == "@") {
                if ($this->interpolation($interp)) {
                    $hasExpression = true;
                    $interp[2]     = true; // don't unescape
                    $parts[]       = $interp;
                    continue;
                }

                if ($this->literal("@")) {
                    $parts[] = "@";
                    continue;
                }
            }

            if ($this->unit($unit)) { // for keyframes
                $parts[] = $unit[1];
                $parts[] = $unit[2];
                continue;
            }

            break;
        }

        $this->eatWhiteDefault = $oldWhite;
        if (!$parts) {
            $this->seek($s);

            return false;
        }

        if ($hasExpression) {
            $tag = array(
                "exp",
                array(
                    "string",
                    "",
                    $parts
                )
            );
        } else {
            $tag = trim(implode($parts));
        }

        $this->whitespace();

        return true;
    }

    // a css function
    protected function func(&$func) {
        $s = $this->seek();

        if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m)
&& $this->literal('(')) {
            $fname = $m[1];

            $sPreArgs = $this->seek();

            $args = array();
            while (true) {
                $ss = $this->seek();
                // this ugly nonsense is for ie filter properties
                if ($this->keyword($name) &&
$this->literal('=') &&
$this->expressionList($value)) {
                    $args[] = array(
                        "string",
                        "",
                        array(
                            $name,
                            "=",
                            $value
                        )
                    );
                } else {
                    $this->seek($ss);
                    if ($this->expressionList($value)) {
                        $args[] = $value;
                    }
                }

                if (!$this->literal(',')) break;
            }
            $args = array(
                'list',
                ',',
                $args
            );

            if ($this->literal(')')) {
                $func = array(
                    'function',
                    $fname,
                    $args
                );

                return true;
            } elseif ($fname == 'url') {
                // couldn't parse and in url? treat as string
                $this->seek($sPreArgs);
                if ($this->openString(")", $string) &&
$this->literal(")")) {
                    $func = array(
                        'function',
                        $fname,
                        $string
                    );

                    return true;
                }
            }
        }

        $this->seek($s);

        return false;
    }

    // consume a less variable
    protected function variable(&$name) {
        $s = $this->seek();
        if ($this->literal($this->lessc->vPrefix, false)
&& ($this->variable($sub) || $this->keyword($name))) {
            if (!empty($sub)) {
                $name = array(
                    'variable',
                    $sub
                );
            } else {
                $name = $this->lessc->vPrefix . $name;
            }

            return true;
        }

        $name = null;
        $this->seek($s);

        return false;
    }

    /**
     * Consume an assignment operator
     * Can optionally take a name that will be set to the current property
name
     */
    protected function assign($name = null) {
        if ($name) $this->currentProperty = $name;

        return $this->literal(':') ||
$this->literal('=');
    }

    // consume a keyword
    protected function keyword(&$word) {
        if ($this->match('([\w_\-\*!"][\w\-_"]*)',
$m)) {
            $word = $m[1];

            return true;
        }

        return false;
    }

    // consume an end of statement delimiter
    protected function end() {
        if ($this->literal(';')) {
            return true;
        } elseif ($this->count == strlen($this->buffer) ||
$this->buffer[$this->count] == '}') {
            // if there is end of file or a closing block next then we
don't need a ;
            return true;
        }

        return false;
    }

    protected function guards(&$guards) {
        $s = $this->seek();

        if (!$this->literal("when")) {
            $this->seek($s);

            return false;
        }

        $guards = array();

        while ($this->guardGroup($g)) {
            $guards[] = $g;
            if (!$this->literal(",")) break;
        }

        if (count($guards) == 0) {
            $guards = null;
            $this->seek($s);

            return false;
        }

        return true;
    }

    // a bunch of guards that are and'd together
    // TODO rename to guardGroup
    protected function guardGroup(&$guardGroup) {
        $s          = $this->seek();
        $guardGroup = array();
        while ($this->guard($guard)) {
            $guardGroup[] = $guard;
            if (!$this->literal("and")) break;
        }

        if (count($guardGroup) == 0) {
            $guardGroup = null;
            $this->seek($s);

            return false;
        }

        return true;
    }

    protected function guard(&$guard) {
        $s      = $this->seek();
        $negate = $this->literal("not");

        if ($this->literal("(") &&
$this->expression($exp) && $this->literal(")")) {
            $guard = $exp;
            if ($negate) $guard = array(
                "negate",
                $guard
            );

            return true;
        }

        $this->seek($s);

        return false;
    }

    /* raw parsing functions */

    protected function literal($what, $eatWhitespace = null) {
        if ($eatWhitespace === null) $eatWhitespace =
$this->eatWhiteDefault;

        // shortcut on single letter
        if (!isset($what[1]) &&
isset($this->buffer[$this->count])) {
            if ($this->buffer[$this->count] == $what) {
                if (!$eatWhitespace) {
                    $this->count++;

                    return true;
                }
                // goes below...
            } else {
                return false;
            }
        }

        if (!isset(self::$literalCache[$what])) {
            self::$literalCache[$what] = LessCompiler::preg_quote($what);
        }

        return $this->match(self::$literalCache[$what], $m,
$eatWhitespace);
    }

    protected function genericList(&$out, $parseItem, $delim =
"", $flatten = true) {
        $s     = $this->seek();
        $items = array();
        while ($this->$parseItem($value)) {
            $items[] = $value;
            if ($delim) {
                if (!$this->literal($delim)) break;
            }
        }

        if (count($items) == 0) {
            $this->seek($s);

            return false;
        }

        if ($flatten && count($items) == 1) {
            $out = $items[0];
        } else {
            $out = array(
                "list",
                $delim,
                $items
            );
        }

        return true;
    }


    // advance counter to next occurrence of $what
    // $until - don't include $what in advance
    // $allowNewline, if string, will be used as valid char set
    protected function to($what, &$out, $until = false, $allowNewline =
false) {
        if (is_string($allowNewline)) {
            $validChars = $allowNewline;
        } else {
            $validChars = $allowNewline ? "." :
"[^\n]";
        }
        if (!$this->match('(' . $validChars . '*?)'
. LessCompiler::preg_quote($what), $m, !$until)) return false;
        if ($until) $this->count -= strlen($what); // give back $what
        $out = $m[1];

        return true;
    }

    // try to match something on head of buffer
    protected function match($regex, &$out, $eatWhitespace = null) {
        if ($eatWhitespace === null) $eatWhitespace =
$this->eatWhiteDefault;

        $r = '/' . $regex . ($eatWhitespace &&
!$this->writeComments ? '\s*' : '') .
'/Ais';
        if (preg_match($r, $this->buffer, $out, null, $this->count))
{
            $this->count += strlen($out[0]);
            if ($eatWhitespace && $this->writeComments)
$this->whitespace();

            return true;
        }

        return false;
    }

    // match some whitespace
    protected function whitespace() {
        if ($this->writeComments) {
            $gotWhite = false;
            while (preg_match(self::$whitePattern, $this->buffer, $m,
null, $this->count)) {
                if (isset($m[1]) &&
empty($this->commentsSeen[$this->count])) {
                    $this->append(array(
                        "comment",
                        $m[1]
                    ));
                    $this->commentsSeen[$this->count] = true;
                }
                $this->count += strlen($m[0]);
                $gotWhite    = true;
            }

            return $gotWhite;
        } else {
            $this->match("", $m);

            return strlen($m[0]) > 0;
        }
    }

    // match something without consuming it
    protected function peek($regex, &$out = null, $from = null) {
        if (is_null($from)) $from = $this->count;
        $r      = '/' . $regex . '/Ais';
        $result = preg_match($r, $this->buffer, $out, null, $from);

        return $result;
    }

    // seek to a spot in the buffer or return where we are on no argument
    protected function seek($where = null) {
        if ($where === null) return $this->count; else $this->count =
$where;

        return true;
    }

    /* misc functions */

    public function throwError($msg = "parse error", $count =
null) {
        $count = is_null($count) ? $this->count : $count;

        $line = $this->line + substr_count(substr($this->buffer, 0,
$count), "\n");

        if (!empty($this->sourceName)) {
            $loc = "$this->sourceName on line $line";
        } else {
            $loc = "line: $line";
        }

        // TODO this depends on $this->count
        if ($this->peek("(.*?)(\n|$)", $m, $count)) {
            throw new Exception("$msg: failed at `$m[1]`
$loc<br>FILE:
<strong>{$this->lessc->sourceParser->sourceName}</strong>");
        } else {
            throw new Exception("$msg: $loc<br>FILE:
<strong>{$this->lessc->sourceParser->sourceName}</strong>");
        }
    }

    protected function pushBlock($selectors = null, $type = null) {
        $b         = new stdclass;
        $b->parent = $this->env;

        $b->type = $type;
        $b->id   = self::$nextBlockId++;

        $b->isVararg = false; // TODO: kill me from here
        $b->tags     = $selectors;

        $b->props    = array();
        $b->children = array();

        $this->env = $b;

        return $b;
    }

    // push a block that doesn't multiply tags
    protected function pushSpecialBlock($type) {
        return $this->pushBlock(null, $type);
    }

    // append a property to the current block
    protected function append($prop, $pos = null) {
        if ($pos !== null) $prop[-1] = $pos;
        $this->env->props[] = $prop;
    }

    // pop something off the stack
    protected function pop() {
        $old       = $this->env;
        $this->env = $this->env->parent;

        return $old;
    }

    // remove comments from $text
    // todo: make it work for all functions, not just url
    protected function removeComments($text) {
        $look = array(
            'url(',
            '//',
            '/*',
            '"',
            "'"
        );

        $out = '';
        $min = null;
        while (true) {
            // find the next item
            foreach ($look as $token) {
                $pos = strpos($text, $token);
                if ($pos !== false) {
                    if (!isset($min) || $pos < $min[1]) $min = array(
                        $token,
                        $pos
                    );
                }
            }

            if (is_null($min)) break;

            $count    = $min[1];
            $skip     = 0;
            $newlines = 0;
            switch ($min[0]) {
                case 'url(':
                    if (preg_match('/url\(.*?\)/', $text, $m, 0,
$count)) $count += strlen($m[0]) - strlen($min[0]);
                    break;
                case '"':
                case "'":
                    if (preg_match('/' . $min[0] .
'.*?' . $min[0] . '/', $text, $m, 0, $count)) $count +=
strlen($m[0]) - 1;
                    break;
                case '//':
                    $skip = strpos($text, "\n", $count);
                    if ($skip === false) $skip = strlen($text) - $count;
else $skip -= $count;
                    break;
                case '/*':
                    if (preg_match('/\/\*.*?\*\//s', $text, $m,
0, $count)) {
                        $skip     = strlen($m[0]);
                        $newlines = substr_count($m[0], "\n");
                    }
                    break;
            }

            if ($skip == 0) $count += strlen($min[0]);

            $out  .= substr($text, 0, $count) . str_repeat("\n",
$newlines);
            $text = substr($text, $count + $skip);

            $min = null;
        }

        return $out . $text;
    }


}Asset/Fonts/Google/Asset.php000064400000003146151161172410011723
0ustar00<?php


namespace Nextend\Framework\Asset\Fonts\Google;


use Nextend\Framework\Asset\AbstractAsset;
use Nextend\Framework\Asset\Css\Css;
use Nextend\Framework\Url\UrlHelper;

class Asset extends AbstractAsset {

    public function getLoadedFamilies() {
        return array_keys($this->files);
    }

    function addSubset($subset = 'latin') {
        if (!in_array($subset, $this->inline)) {
            $this->inline[] = $subset;
        }
    }

    function addFont($family, $style = '400') {
        $style = (string)$style;
        if (!isset($this->files[$family])) {
            $this->files[$family] = array();
        }
        if (!in_array($style, $this->files[$family])) {
            $this->files[$family][] = $style;
        }
    }

    public function loadFonts() {

        if (!empty($this->files)) {
           
//https://fonts.googleapis.com/css?display=swap&family=Montserrat:400%7CRoboto:100italic,300,400&subset=latin,greek-ext

            $families = array();
            foreach ($this->files as $name => $styles) {
                if (count($styles) && !in_array($name,
Google::$excludedFamilies)) {
                    $families[] = $name . ':' .
implode(',', $styles);
                }
            }

            if (count($families)) {
                $params = array(
                    'display' => 'swap',
                    'family'  => implode('|',
$families),
                    'subset'  => implode(',',
$this->inline)
                );

                Css::addUrl(UrlHelper::add_query_arg($params,
'https://fonts.googleapis.com/css'));
            }

        }

        return true;
    }
}Asset/Fonts/Google/Google.php000064400000001270151161172410012054
0ustar00<?php


namespace Nextend\Framework\Asset\Fonts\Google;


use Nextend\Framework\Asset\AssetManager;

class Google {

    public static $enabled = false;

    public static $excludedFamilies = array();

    public static function addSubset($subset = 'latin') {
        AssetManager::$googleFonts->addSubset($subset);
    }

    public static function addFont($family, $style = '400') {
        AssetManager::$googleFonts->addFont($family, $style);
    }

    public static function addFontExclude($family) {
        self::$excludedFamilies[] = $family;
    }

    public static function build() {
        if (self::$enabled) {
            AssetManager::$googleFonts->loadFonts();
        }
    }
}Asset/Image/Asset.php000064400000001277151161172410010443 0ustar00<?php

namespace Nextend\Framework\Asset\Image;

class Asset {

    protected $images = array();

    public function add($images) {
        if (!is_array($images)) {
            $images = array($images);
        }

        $this->images = array_unique(array_merge($this->images,
$images));
    }

    public function get() {
        return $this->images;
    }

    public function match($url) {
        return in_array($url, $this->images);
    }

    public function serialize() {
        return array(
            'images' => $this->images
        );
    }

    public function unSerialize($array) {
        if (!empty($array['images'])) {
            $this->add($array['images']);
        }
    }
}Asset/Js/Asset.php000064400000007502151161172410007772 0ustar00<?php


namespace Nextend\Framework\Asset\Js;

use Nextend\Framework\Asset\AbstractAsset;
use Nextend\Framework\Localization\Localization;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Plugin;
use Nextend\Framework\Settings;
use Nextend\Framework\Url\Url;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\SmartSlider3Info;

class Asset extends AbstractAsset {

    public function __construct() {
        $this->cache = new Cache();
    }

    public function getOutput() {

        $output = "";

        $needProtocol = !Settings::get('protocol-relative',
'1');

        $globalInline = $this->getGlobalInlineScripts();
        if (!empty($globalInline)) {
            $output .= Html::script(self::minify_js($globalInline .
"\n"));
        }

        $async            = !Platform::isAdmin();
        $scriptAttributes = array();
        if ($async) {
            $scriptAttributes['defer'] = 1;
            $scriptAttributes['async'] = 1;
        }

        foreach ($this->urls as $url) {
            $output .= Html::scriptFile($this->filterSrc($url),
$scriptAttributes) . "\n";
        }

        foreach ($this->getFiles() as $file) {
            if (substr($file, 0, 2) == '//') {
                $output .= Html::scriptFile($this->filterSrc($file),
$scriptAttributes) . "\n";
            } else {
                $output .=
Html::scriptFile($this->filterSrc(Url::pathToUri($file, $needProtocol) .
'?ver=' . SmartSlider3Info::$revisionShort), $scriptAttributes) .
"\n";
            }
        }

        $output .= Html::script(self::minify_js(Localization::toJS() .
"\n" . $this->getInlineScripts() . "\n"));

        return $output;
    }

    private function filterSrc($src) {
        return Plugin::applyFilters('n2_script_loader_src',
$src);
    }

    public function get() {
        return array(
            'url'          => $this->urls,
            'files'        => $this->getFiles(),
            'inline'       => $this->getInlineScripts(),
            'globalInline' =>
$this->getGlobalInlineScripts()
        );
    }

    public function getAjaxOutput() {

        $output = $this->getInlineScripts();

        return $output;
    }

    private function getGlobalInlineScripts() {
        return implode('', $this->globalInline);
    }

    private function getInlineScripts() {
        $scripts = '';

        foreach ($this->firstCodes as $script) {
            $scripts .= $script . "\n";
        }

        foreach ($this->inline as $script) {
            $scripts .= $script . "\n";
        }

        return $this->serveJquery($scripts);
    }

    public static function serveJquery($script) {
        if (empty($script)) {
            return "";
        }
        $inline = "_N2.r('documentReady',
function(){\n";
        $inline .= $script;
        $inline .= "});\n";

        return $inline;
    }

    public static function minify_js($input) {
        if (trim($input) === "") return $input;

        return preg_replace(array(
            // Remove comment(s)
           
'#\s*("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')\s*|\s*\/\*(?!\!|@cc_on)(?>[\s\S]*?\*\/)\s*|\s*(?<![\:\=])\/\/.*(?=[\n\r]|$)|^\s*|\s*$#',
            // Remove white-space(s) outside the string and regex
           
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/)|\/(?!\/)[^\n\r]*?\/(?=[\s.,;]|[gimuy]|$))|\s*([!%&*\(\)\-=+\[\]\{\}|;:,.<>?\/])\s*#s',
            // Remove the last semicolon
            '#;+\}#',
            // Minify object attribute(s) except JSON attribute(s). From
`{'foo':'bar'}` to `{foo:'bar'}`
           
'#([\{,])([\'])(\d+|[a-z_][a-z0-9_]*)\2(?=\:)#i',
            // --ibid. From `foo['bar']` to `foo.bar`
           
'#([a-z0-9_\)\]])\[([\'"])([a-z_][a-z0-9_]*)\2\]#i'
        ), array(
            '$1',
            '$1$2',
            '}',
            '$1$3',
            '$1.$3'
        ), $input);
    }
}Asset/Js/Cache.php000064400000001160151161172410007710 0ustar00<?php

namespace Nextend\Framework\Asset\Js;

use Nextend\Framework\Asset\AbstractCache;
use Nextend\Framework\Cache\Manifest;

class Cache extends AbstractCache {

    public $outputFileType = "js";

    /**
     * @param Manifest $cache
     *
     * @return string
     */
    public function getCachedContent($cache) {

        $content =
'(function(){this._N2=this._N2||{_r:[],_d:[],r:function(){this._r.push(arguments)},d:function(){this._d.push(arguments)}}}).call(window);';
        $content .= parent::getCachedContent($cache);
        $content .= "_N2.d('" . $this->group .
"');";

        return $content;
    }
}Asset/Js/Js.php000064400000003441151161172410007265 0ustar00<?php

namespace Nextend\Framework\Asset\Js;

use Nextend\Framework\Asset\AssetManager;
use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Settings;
use Nextend\SmartSlider3\Application\Frontend\ApplicationTypeFrontend;

class Js {

    public static function addFile($pathToFile, $group) {
        AssetManager::$js->addFile($pathToFile, $group);
    }

    public static function addFiles($path, $files, $group) {
        AssetManager::$js->addFiles($path, $files, $group);
    }

    public static function addStaticGroup($file, $group) {
        AssetManager::$js->addStaticGroup($file, $group);
    }

    public static function addCode($code, $group) {
        AssetManager::$js->addCode($code, $group);
    }

    public static function addUrl($url) {
        AssetManager::$js->addUrl($url);
    }

    public static function addFirstCode($code, $unshift = false) {
        AssetManager::$js->addFirstCode($code, $unshift);
    }

    public static function addInline($code, $unshift = false) {
        AssetManager::$js->addInline($code, null, $unshift);
    }

    public static function addGlobalInline($code, $unshift = false) {
        AssetManager::$js->addGlobalInline($code, $unshift);
    }

    public static function addInlineFile($path, $unshift = false) {
        static $loaded = array();
        if (!isset($loaded[$path])) {
            AssetManager::$js->addInline(Filesystem::readFile($path),
null, $unshift);
            $loaded[$path] = 1;
        }
    }

    public static function addGlobalInlineFile($path, $unshift = false) {
        static $loaded = array();
        if (!isset($loaded[$path])) {
           
AssetManager::$js->addGlobalInline(Filesystem::readFile($path),
$unshift);
            $loaded[$path] = 1;
        }
    }

}Asset/Predefined.php000064400000007215151161172410010405 0ustar00<?php

namespace Nextend\Framework\Asset;


use Nextend\Framework\Asset\Css\Css;
use Nextend\Framework\Asset\Fonts\Google\Google;
use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Font\FontSources;
use Nextend\Framework\Form\Form;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Plugin;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\SmartSlider3\Application\Frontend\ApplicationTypeFrontend;
use Nextend\SmartSlider3\Settings;

class Predefined {

    public static function backend($force = false) {
        static $once;
        if ($once != null && !$force) {
            return;
        }
        $once = true;
        \JHtml::_('jquery.framework');
    
        $jQueryFallback =
'https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js';
    

        Js::addGlobalInline('_N2._jQueryFallback=\'' .
$jQueryFallback . '\';');

        $family = n2_x('Montserrat', 'Default Google font
family for admin');
        foreach (explode(',', n2_x('latin',
'Default Google font charset for admin')) as $subset) {
            Google::addSubset($subset);
        }
        Google::addFont($family);

       
Js::addFirstCode("_N2.r(['AjaxHelper'],function(){_N2.AjaxHelper.addAjaxArray("
. json_encode(Form::tokenizeUrl()) . ");});");

        Plugin::addAction('afterApplicationContent', array(
            FontSources::class,
            'onFontManagerLoadBackend'
        ));
    }

    public static function frontend($force = false) {
        static $once;
        if ($once != null && !$force) {
            return;
        }
        $once = true;
        AssetManager::getInstance();
        if (Platform::isAdmin()) {
            Js::addGlobalInline('window.N2GSAP=' . N2GSAP .
';');
            Js::addGlobalInline('window.N2PLATFORM="' .
Platform::getName() . '";');
        }
    
       
Js::addGlobalInline('(function(){this._N2=this._N2||{_r:[],_d:[],r:function(){this._r.push(arguments)},d:function(){this._d.push(arguments)}}}).call(window);');
        /**
         * WebP browser support detection
         */
        /*
        !function (ua, match, version, r) {
            match = ua.match(/(Chrome|Firefox|Safari)\/(\d+)\./);
            if (match) {
                if ("Chrome" == match[1]) {
                    r = +match[2] >= 32;
                } else if ("Firefox" == match[1]) {
                    r = +match[2] >= 65;
                } else if ("Safari" == match[1]) {
                    version = ua.match(/Version\/(\d+)/) ||
ua.match(/(\d+)[0-9_ ]+ like Mac/);
                    if (version) {
                        r = +version[1] >= 14;
                    }
                }

                if (r) {
                   
document.documentElement.classList.add("n2webp")
                }
            }
        }(navigator.userAgent);
        */
       
Js::addGlobalInline('!function(e,i,o,r){(i=e.match(/(Chrome|Firefox|Safari)\/(\d+)\./))&&("Chrome"==i[1]?r=+i[2]>=32:"Firefox"==i[1]?r=+i[2]>=65:"Safari"==i[1]&&(o=e.match(/Version\/(\d+)/)||e.match(/(\d+)[0-9_
]+ like
Mac/))&&(r=+o[1]>=14),r&&document.documentElement.classList.add("n2webp"))}(navigator.userAgent);');
    

        Js::addStaticGroup(ApplicationTypeFrontend::getAssetsPath() .
"/dist/n2.min.js", 'n2');

        FontSources::onFontManagerLoad($force);
    }

    public static function loadLiteBox() {

       
Css::addStaticGroup(ResourceTranslator::toPath('$ss3-pro-frontend$/dist/litebox.min.css'),
'litebox');

       
Js::addStaticGroup(ResourceTranslator::toPath('$ss3-pro-frontend$/dist/litebox.min.js'),
'litebox');

        Js::addInline('n2const.lightboxMobileNewTab=' .
intval(Settings::get('lightbox-mobile-new-tab', 1)) .
';');
    
    }
}

Browse/Block/BrowseManager/BlockBrowseManager.php000064400000000774151161172410016022
0ustar00<?php


namespace Nextend\Framework\Browse\Block\BrowseManager;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Localization\Localization;
use Nextend\Framework\View\AbstractBlock;
use Nextend\SmartSlider3\Application\Admin\TraitAdminUrl;

class BlockBrowseManager extends AbstractBlock {

    use TraitAdminUrl;

    public function display() {

        Js::addFirstCode("new _N2.NextendBrowse('" .
$this->getAjaxUrlBrowse() . "', " .
(defined('N2_IMAGE_UPLOAD_DISABLE') ? 0 : 1) . ");");
    }
}Browse/BrowseManager.php000064400000000557151161172410011260
0ustar00<?php


namespace Nextend\Framework\Browse;


use Nextend\Framework\Browse\Block\BrowseManager\BlockBrowseManager;
use Nextend\Framework\Pattern\VisualManagerTrait;

class BrowseManager {

    use VisualManagerTrait;

    public function display() {

        $fontManagerBlock = new BlockBrowseManager($this->MVCHelper);
        $fontManagerBlock->display();
    }

}Browse/BulletProof/BulletProof.php000064400000026401151161172410013212
0ustar00<?php

namespace Nextend\Framework\Browse\BulletProof;

use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Image\ImageEdit;

/**
 * BULLETPROOF,
 *
 * This is a one-file solution for a quick and safe way of
 * uploading, watermarking, cropping and resizing images
 * during and after uploads with PHP with best security.
 *
 * This class is heavily commented, to be as much friendly as possible.
 * Please help out by posting out some bugs/flaws if you encounter any.
Thanks!
 *
 * @category    Image uploader
 * @package     BulletProof
 * @version     1.4.0
 * @author      samayo
 * @link        https://github.com/samayo/BulletProof
 * @license     Luke 3:11 ( Free )
 */
class BulletProof {

    /*
   
|--------------------------------------------------------------------------
    | Image Upload Properties
   
\--------------------------------------------------------------------------*/

    /**
     * Set a group of default image types to upload.
     *
     * @var array
     */
    protected $imageType = array(
        "jpg",
        "jpeg",
        "png",
        "gif",
        "webp",
        "svg"
    );

    /**
     * Set a default file size to upload. Values are in bytes. Remember:
1kb ~ 1000 bytes.
     *
     * @var array
     */
    protected $imageSize = array(
        "min" => 1,
        "max" => 20000000
    );

    /**
     * Set a default min & maximum height & width for image to
upload.
     *
     * @var array
     */
    protected $imageDimension = array(
        "height" => 10000,
        "width"  => 10000
    );

    /**
     * Set a default folder to upload images, if it does not exist, it will
be created.
     *
     * @var string
     */
    protected $uploadDir = "uploads";

    /**
     * To get the real image/mime type. i.e gif, jpeg, png, ....
     *
     * @var string
     */
    protected $getMimeType;

    /*
   
|--------------------------------------------------------------------------
    | Image Upload Methods
   
\--------------------------------------------------------------------------*/

    /**
     * Stores image types to upload
     *
     * @param array $fileTypes -  ex: ['jpg', 'doc',
'txt'].
     *
     * @return $this
     */
    public function fileTypes(array $fileTypes) {
        $this->imageType = $fileTypes;

        return $this;
    }

    /**
     * Minimum and Maximum allowed image size for upload (in bytes),
     *
     * @param array $fileSize - ex: ['min'=>500,
'max'=>1000]
     *
     * @return $this
     */
    public function limitSize(array $fileSize) {
        $this->imageSize = $fileSize;

        return $this;
    }

    /**
     * Default & maximum allowed height and width image to download.
     *
     * @param array $dimensions
     *
     * @return $this
     */
    public function limitDimension(array $dimensions) {
        $this->imageDimension = $dimensions;

        return $this;
    }

    /**
     * Get the real image's Extension/mime type
     *
     * @param $imageName
     *
     * @return mixed
     * @throws Exception
     */
    protected function getMimeType($imageName) {
        if (!file_exists($imageName)) {
            throw new Exception("Image " . $imageName . "
does not exist");
        }

        $listOfMimeTypes = array(
            1 => "gif",
            "jpeg",
            "png",
            "swf",
            "psd",
            "bmp",
            "tiff",
            "tiff",
            "jpc",
            "jp2",
            "jpx",
            "jb2",
            "swc",
            "iff",
            "wbmp",
            "xmb",
            "ico",
            "webp",
            "svg"
        );

        $imageType = ImageEdit::exif_imagetype($imageName);
        if (isset($listOfMimeTypes[$imageType])) {
            return $listOfMimeTypes[$imageType];
        }

        return false;
    }

    /**
     * Handy method for getting image dimensions (W & H) in pixels.
     *
     * @param $getImage - The image name
     *
     * @return array
     */
    protected function getPixels($getImage) {
        list($width, $height) = getImageSize($getImage);

        return array(
            "width"  => $width,
            "height" => $height
        );
    }

    /**
     * Rename file either from method or by generating a random one.
     *
     * @param $isNameProvided - A new name for the file.
     *
     * @return string
     */
    protected function imageRename($isNameProvided) {
        if ($isNameProvided) {
            return $isNameProvided . "." . $this->getMimeType;
        }

        return uniqid(true) . "_" .
str_shuffle(implode(range("E", "Q"))) . "." .
$this->getMimeType;
    }

    /**
     * Get the specified upload dir, if it does not exist, create a new
one.
     *
     * @param $directoryName - directory name where you want your files to
be uploaded
     *
     * @return $this
     * @throws Exception
     */
    public function uploadDir($directoryName) {
        if (!file_exists($directoryName) &&
!is_dir($directoryName)) {

            $createFolder = Filesystem::createFolder("" .
$directoryName);
            if (!$createFolder) {
                throw new Exception("Folder " . $directoryName .
" could not be created");
            }
        }
        $this->uploadDir = $directoryName;

        return $this;
    }

    /**
     * For getting common error messages from FILES[] array during upload.
     *
     * @return array
     */
    protected function commonUploadErrors($key) {
        $uploadErrors = array(
            UPLOAD_ERR_OK         => "...",
            UPLOAD_ERR_INI_SIZE   => "File is larger than the
specified amount set by the server",
            UPLOAD_ERR_FORM_SIZE  => "File is larger than the
specified amount specified by browser",
            UPLOAD_ERR_PARTIAL    => "File could not be fully
uploaded. Please try again later",
            UPLOAD_ERR_NO_FILE    => "File is not found",
            UPLOAD_ERR_NO_TMP_DIR => "Can't write to disk, due
to server configuration ( No tmp dir found )",
            UPLOAD_ERR_CANT_WRITE => "Failed to write file to disk.
Please check you file permissions",
            UPLOAD_ERR_EXTENSION  => "A PHP extension has halted
this file upload process"
        );

        return $uploadErrors[$key];
    }

    /**
     * Simple file check and delete wrapper.
     *
     * @param $fileToDelete
     *
     * @return bool
     * @throws Exception
     */
    public function deleteFile($fileToDelete) {
        if (file_exists($fileToDelete) && !unlink($fileToDelete)) {
            throw new Exception("File may have been deleted or does
not exist");
        }

        return true;
    }

    /**
     * Final image uploader method, to check for errors and upload
     *
     * @param      $fileToUpload
     * @param null $isNameProvided
     *
     * @return string
     * @throws Exception
     */
    public function upload($fileToUpload, $isNameProvided = null) {

        $isMedia = false;
        // Check if any errors are thrown by the FILES[] array
        if ($fileToUpload["error"]) {
            throw new
Exception($this->commonUploadErrors($fileToUpload["error"]));
        }

        if (function_exists("mime_content_type")) {
            $rawMime =
mime_content_type($fileToUpload["tmp_name"]);
        } else {
            $path_parts =
pathinfo($_FILES["image"]["name"]);
            switch ($path_parts['extension']) {
                case 'mp4':
                    $rawMime = 'video/mp4';
                    break;
                case 'mp3':
                    $rawMime = 'audio/mpeg';
                    break;
                default:
                    $rawMime = '';
                    break;
            }
        }

        switch ($rawMime) {
            case 'video/mp4':
                $this->getMimeType = 'mp4';
                $isMedia           = true;
                break;
            case 'audio/mpeg':
                $this->getMimeType = 'mp3';
                $isMedia           = true;
                break;
        }

        if (!$isMedia) {
            // First get the real file extension
            $this->getMimeType =
$this->getMimeType($fileToUpload["tmp_name"]);

            $specialImage = false;
            if ($this->getMimeType === false) {
                if (isset($fileToUpload["type"]) &&
strpos($fileToUpload["type"], 'image/') !== false) {
                    $this->getMimeType = str_replace(array(
                        'image/',
                        'svg+xml'
                    ), array(
                        '',
                        'svg'
                    ), $fileToUpload["type"]);
                    $specialImage      = true;
                }
            }

            // Check if this file type is allowed for upload
            if (!in_array($this->getMimeType, $this->imageType)) {
                throw new Exception(" This is not allowed file type!
             Please only upload ( " . implode(", ",
$this->imageType) . " ) file types");
            }

            //Check if size (in bytes) of the image are above or below of
defined in 'limitSize()'
            if ($fileToUpload["size"] <
$this->imageSize["min"] || $fileToUpload["size"]
> $this->imageSize["max"]) {
                throw new Exception("File sizes must be between "
. implode(" to ", $this->imageSize) . " bytes");
            }

            // check if image is valid pixel-wise.
            if (!$specialImage) {
                $pixel =
$this->getPixels($fileToUpload["tmp_name"]);

                if ($pixel["width"] < 4 ||
$pixel["height"] < 4) {
                    throw new Exception("This file is either too small
or corrupted to be an image");
                }

                if ($pixel["height"] >
$this->imageDimension["height"] || $pixel["width"]
> $this->imageDimension["width"]) {
                    throw new Exception("Image pixels/size must be
below " . implode(", ", $this->imageDimension) . "
pixels");
                }
            }
        }

        // create upload directory if it does not exist
        $this->uploadDir($this->uploadDir);

        $i           = '';
        $newFileName = $this->imageRename($isNameProvided);

        while (file_exists($this->uploadDir . "/" .
$newFileName)) {
            // The file already uploaded, nothing to do here
            if (self::isFilesIdentical($this->uploadDir . "/"
. $newFileName, $fileToUpload["tmp_name"])) {
                return $this->uploadDir . "/" . $newFileName;
            }
            $i++;
            $newFileName = $this->imageRename($isNameProvided . $i);
        }

        // Upload the file
        $moveUploadedFile =
$this->moveUploadedFile($fileToUpload["tmp_name"],
$this->uploadDir . "/" . $newFileName);

        if ($moveUploadedFile) {
            return $this->uploadDir . "/" . $newFileName;
        } else {
            throw new Exception(" File could not be uploaded. Unknown
error occurred. ");
        }
    }

    public function moveUploadedFile($uploaded_file, $new_file) {
        if (!is_uploaded_file($uploaded_file)) {
            return copy($uploaded_file, $new_file);
        }

        return move_uploaded_file($uploaded_file, $new_file);
    }

    private static function isFilesIdentical($fn1, $fn2) {
        if (filetype($fn1) !== filetype($fn2)) return FALSE;

        if (filesize($fn1) !== filesize($fn2)) return FALSE;

        if (sha1_file($fn1) != sha1_file($fn2)) return false;

        return true;
    }
}Browse/BulletProof/Exception.php000064400000000141151161172410012704
0ustar00<?php


namespace Nextend\Framework\Browse\BulletProof;


class Exception extends \Exception {

}Browse/ControllerAjaxBrowse.php000064400000011716151161172410012634
0ustar00<?php

namespace Nextend\Framework\Browse;

use Exception;
use Nextend\Framework\Browse\BulletProof\BulletProof;
use Nextend\Framework\Controller\Admin\AdminAjaxController;
use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Image\Image;
use Nextend\Framework\Notification\Notification;
use Nextend\Framework\Request\Request;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;

class ControllerAjaxBrowse extends AdminAjaxController {

    public function actionIndex() {
        $this->validateToken();
        $root =
Filesystem::convertToRealDirectorySeparator(Filesystem::getImagesFolder());
        $path = Filesystem::realpath($root . '/' .
ltrim(rtrim(Request::$REQUEST->getVar('path', ''),
'/'), '/'));
        if (strpos($path, $root) !== 0) {
            $path = $root;
        }
        $_directories = glob($path . '/*', GLOB_ONLYDIR);
        $directories  = array();
        for ($i = 0; $i < count($_directories); $i++) {
            $directories[basename($_directories[$i])] =
Filesystem::toLinux($this->relative($_directories[$i], $root));
        }

        $extensions = array(
            'jpg',
            'jpeg',
            'png',
            'gif',
            'mp4',
            'mp3',
            'svg',
            'webp'
        );
        $_files     = scandir($path);
        $files      = array();
        for ($i = 0; $i < count($_files); $i++) {
            $_files[$i] = $path . DIRECTORY_SEPARATOR . $_files[$i];
            $ext        = strtolower(pathinfo($_files[$i],
PATHINFO_EXTENSION));
            if (self::check_utf8($_files[$i]) && in_array($ext,
$extensions)) {
                $files[basename($_files[$i])] =
ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($_files[$i]));
            }
        }
        $relativePath = Filesystem::toLinux($this->relative($path,
$root));
        if (!$relativePath) {
            $relativePath = '';
        }
        $this->response->respond(array(
            'fullPath'    => $path,
            'path'        => $relativePath,
            'directories' => (object)$directories,
            'files'       => (object)$files
        ));
    }

    private static function check_utf8($str) {
        $len = strlen($str);
        for ($i = 0; $i < $len; $i++) {
            $c = ord($str[$i]);
            if ($c > 128) {
                if (($c > 247)) return false; elseif ($c > 239)
$bytes = 4;
                elseif ($c > 223) $bytes = 3;
                elseif ($c > 191) $bytes = 2;
                else return false;
                if (($i + $bytes) > $len) return false;
                while ($bytes > 1) {
                    $i++;
                    $b = ord($str[$i]);
                    if ($b < 128 || $b > 191) return false;
                    $bytes--;
                }
            }
        }

        return true;
    }

    public function actionUpload() {
        if (defined('N2_IMAGE_UPLOAD_DISABLE')) {
            Notification::error(n2_('You are not allowed to
upload!'));
            $this->response->error();
        }

        $this->validateToken();

        $root   = Filesystem::getImagesFolder();
        $folder =
ltrim(rtrim(Request::$REQUEST->getVar('path', ''),
'/'), '/');
        $path   = Filesystem::realpath($root . '/' . $folder);

        if ($path === false || $path == '') {
            $folder = preg_replace("/[^A-Za-z0-9]/",
'', $folder);
            if (empty($folder)) {
                Notification::error(n2_('Folder is missing!'));
                $this->response->error();
            } else {
                Filesystem::createFolder($root . '/' . $folder);
                $path = Filesystem::realpath($root . '/' .
$folder);
            }
        }

        $relativePath = Filesystem::toLinux($this->relative($path,
$root));
        if (!$relativePath) {
            $relativePath = '';
        }
        $response = array(
            'path' => $relativePath
        );
        try {
            if (isset($_FILES) && isset($_FILES['image'])
&& isset($_FILES['image']['name'])) {
                $info     =
pathinfo($_FILES['image']['name']);
                $fileName = preg_replace('/[^a-zA-Z0-9_-]/',
'', $info['filename']);
                if (strlen($fileName) == 0) {
                    $fileName = '';
                }

                $upload           = new BulletProof();
                $file             = $upload->uploadDir($path)
                                          
->upload($_FILES['image'], $fileName);
                $response['name'] = basename($file);
                $response['url']  =
ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($file));

                Image::onImageUploaded($file);
            }
        } catch (Exception $e) {
            Notification::error($e->getMessage());
            $this->response->error();
        }


        $this->response->respond($response);
    }

    private function relative($path, $root) {
        return substr(Filesystem::convertToRealDirectorySeparator($path),
strlen($root));
    }
}
Cache/AbstractCache.php000064400000004436151161172410010755
0ustar00<?php

namespace Nextend\Framework\Cache;


use Nextend\Framework\Cache\Storage\AbstractStorage;

abstract class AbstractCache {

    protected $group = '';
    protected $isAccessible = false;

    /** @var AbstractStorage */
    public $storage;

    protected $_storageEngine = 'filesystem';

    /**
     * @param string $engine
     *
     * @return AbstractStorage
     */
    public static function getStorage($engine = "filesystem") {
        static $storage = null;
        if ($storage === null) {
            $storage = array(
                'filesystem' => new  Storage\Filesystem(),
                'database'   => new Storage\Database()
            );
        }

        return $storage[$engine];
    }

    public static function clearAll() {
        self::getStorage('filesystem')
            ->clearAll();
        self::getStorage('filesystem')
            ->clearAll('web');
    }

    public static function clearGroup($group) {
        self::getStorage('filesystem')
            ->clear($group);
        self::getStorage('filesystem')
            ->clear($group, 'web');
        self::getStorage('database')
            ->clear($group);
        self::getStorage('database')
            ->clear($group, 'web');
    }

    public function __construct($group, $isAccessible = false) {
        $this->group        = $group;
        $this->isAccessible = $isAccessible;
        $this->storage      =
self::getStorage($this->_storageEngine);
    }

    protected function clearCurrentGroup() {
        $this->storage->clear($this->group, $this->getScope());
    }

    protected function getScope() {
        if ($this->isAccessible) {
            return 'web';
        }

        return 'notweb';
    }

    protected function exists($key) {
        return $this->storage->exists($this->group, $key,
$this->getScope());
    }

    protected function get($key) {
        return $this->storage->get($this->group, $key,
$this->getScope());
    }

    protected function set($key, $value) {
        $this->storage->set($this->group, $key, $value,
$this->getScope());
    }

    protected function getPath($key) {
        return $this->storage->getPath($this->group, $key,
$this->getScope());
    }

    protected function remove($key) {
        return $this->storage->remove($this->group, $key,
$this->getScope());
    }
}Cache/CacheImage.php000064400000007123151161172410010230 0ustar00<?php

namespace Nextend\Framework\Cache;

use DateTime;

class CacheImage extends AbstractCache {

    protected $_storageEngine = 'filesystem';

    protected $lazy = false;

    public function __construct($group) {
        parent::__construct($group, true);
    }

    protected function getScope() {
        return 'image';
    }

    public function setLazy($lazy) {
        $this->lazy = $lazy;
    }

    /**
     * @param          $fileExtension
     * @param callable $callable
     * @param array    $parameters
     * @param bool     $hash
     *
     * @return mixed
     */
    public function makeCache($fileExtension, $callable, $parameters =
array(), $hash = false) {

        if (!$hash) {
            $hash = $this->generateHash($fileExtension, $callable,
$parameters);
        }

        if (strpos($parameters[1], '?') !== false) {
            $fileNameParts = explode('?', $parameters[1]);
            $keepFileName  = pathinfo($fileNameParts[0],
PATHINFO_FILENAME);
        } else {
            $keepFileName = pathinfo($parameters[1], PATHINFO_FILENAME);
        }

        $fileName              = $hash . (!empty($keepFileName) ?
'/' . $keepFileName : '');
        $fileNameWithExtension = $fileName . '.' .
$fileExtension;

        $isCached = $this->exists($fileNameWithExtension);
        if ($isCached) {
            if (!$this->testManifestFile($fileName, $parameters[1])) {
                $isCached = false;
            }
        }

        if (!$isCached) {
            if ($this->lazy) {
                return $parameters[1];
            }

            array_unshift($parameters,
$this->getPath($fileNameWithExtension));
            call_user_func_array($callable, $parameters);

            $this->createManifestFile($fileName, $parameters[2]);
        }

        return $this->getPath($fileNameWithExtension);
    }

    private function generateHash($fileExtension, $callable, $parameters) {
        return md5(json_encode(array(
            $fileExtension,
            $callable,
            $parameters
        )));
    }

    protected function testManifestFile($fileName, $originalFile) {
        $manifestKey = $this->getManifestKey($fileName);
        if ($this->exists($manifestKey)) {

            $manifestData = json_decode($this->get($manifestKey), true);

            $newManifestData = $this->getManifestData($originalFile);
            if ($manifestData['mtime'] ==
$newManifestData['mtime']) {
                return true;
            }
        } else {
            // Backward compatibility
            $this->createManifestFile($fileName, $originalFile);

            return true;
        }

        return false;
    }

    protected function createManifestFile($fileName, $originalFile) {

        $this->set($this->getManifestKey($fileName),
json_encode($this->getManifestData($originalFile)));
    }

    private function getManifestData($originalFile) {
        $manifestData = array();
        if (strpos($originalFile, '//') !== false) {
            $manifestData['mtime'] =
$this->getRemoteMTime($originalFile);
        } else {
            $manifestData['mtime'] = filemtime($originalFile);
        }

        return $manifestData;
    }

    private function getRemoteMTime($url) {
        $h = get_headers($url, 1);
        if (!$h || strpos($h[0], '200') !== false) {
            foreach ($h as $k => $v) {
                if (strtolower(trim($k)) == "last-modified") {
                    return (new DateTime($v))->getTimestamp();
                }
            }
        }

        return 0;
    }

    protected function getManifestKey($fileName) {
        return $fileName . '.manifest';
    }
}Cache/Manifest.php000064400000004761151161172420010036 0ustar00<?php

namespace Nextend\Framework\Cache;

class Manifest extends AbstractCache {

    private $isRaw = false;

    private $manifestData;

    public function __construct($group, $isAccessible = false, $isRaw =
false) {
        parent::__construct($group, $isAccessible);
        $this->isRaw = $isRaw;
    }

    protected function decode($data) {
        return $data;
    }

    /**
     * @param          $fileName
     * @param          $hash
     * @param callback $callable
     *
     * @return bool
     */
    public function makeCache($fileName, $hash, $callable) {
        if (!$this->isCached($fileName, $hash)) {

            $return = call_user_func($callable, $this);
            if ($return === false) {
                return false;
            }

            return $this->createCacheFile($fileName, $hash, $return);
        }
        if ($this->isAccessible) {
            return $this->getPath($fileName);
        }

        return $this->decode($this->get($fileName));
    }

    private function isCached($fileName, $hash) {


        $manifestKey = $this->getManifestKey($fileName);
        if ($this->exists($manifestKey)) {

            $this->manifestData =
json_decode($this->get($manifestKey), true);

            if (!$this->isCacheValid($this->manifestData) ||
$this->manifestData['hash'] != $hash ||
!$this->exists($fileName)) {
                $this->clean($fileName);

                return false;
            }

            return true;
        }

        return false;
    }

    protected function createCacheFile($fileName, $hash, $content) {

        $this->manifestData = array();

        $this->manifestData['hash'] = $hash;
        $this->addManifestData($this->manifestData);

        $this->set($this->getManifestKey($fileName),
json_encode($this->manifestData));

        $this->set($fileName, $this->isRaw ? $content :
json_encode($content));

        if ($this->isAccessible) {
            return $this->getPath($fileName);
        }

        return $content;
    }

    protected function isCacheValid(&$manifestData) {
        return true;
    }

    protected function addManifestData(&$manifestData) {

    }

    public function clean($fileName) {

        $this->remove($this->getManifestKey($fileName));
        $this->remove($fileName);
    }

    protected function getManifestKey($fileName) {
        return $fileName . '.manifest';
    }

    public function getData($key, $default = 0) {
        return isset($this->manifestData[$key]) ?
$this->manifestData[$key] : $default;
    }
}Cache/Storage/AbstractStorage.php000064400000001233151161172420012753
0ustar00<?php


namespace Nextend\Framework\Cache\Storage;


abstract class AbstractStorage {

    protected $paths = array();

    public function isFilesystem() {
        return false;
    }

    public abstract function clearAll($scope = 'notweb');

    public abstract function clear($group, $scope = 'notweb');

    public abstract function exists($group, $key, $scope =
'notweb');

    public abstract function set($group, $key, $value, $scope =
'notweb');

    public abstract function get($group, $key, $scope =
'notweb');

    public abstract function remove($group, $key, $scope =
'notweb');

    public abstract function getPath($group, $key, $scope =
'notweb');
}Cache/Storage/Database.php000064400000002507151161172420011374
0ustar00<?php

namespace Nextend\Framework\Cache\Storage;

use Nextend\Framework\Model\ApplicationSection;
use Nextend\Framework\Platform\Platform;

class Database extends AbstractStorage {

    protected $db;

    public function __construct() {

        $this->paths['web']    = 'web';
        $this->paths['notweb'] = 'notweb';
        $this->paths['image']  = 'image';

        $this->db = new  ApplicationSection('cache');
    }

    public function clearAll($scope = 'notweb') {

    }

    public function clear($group, $scope = 'notweb') {

        $this->db->delete($scope . '/' . $group);
    }

    public function exists($group, $key, $scope = 'notweb') {

        if ($this->db->get($scope . '/' . $group, $key)) {
            return true;
        }

        return false;
    }

    public function set($group, $key, $value, $scope = 'notweb')
{

        $this->db->set($scope . '/' . $group, $key,
$value);
    }

    public function get($group, $key, $scope = 'notweb') {
        return $this->db->get($scope . '/' . $group, $key);
    }

    public function remove($group, $key, $scope = 'notweb') {
        $this->db->delete($scope . '/' . $group, $key);
    }

    public function getPath($group, $key, $scope = 'notweb') {

        return Platform::getSiteUrl() . '?nextendcache=1&g='
. urlencode($group) . '&k=' . urlencode($key);
    }
}Cache/Storage/Filesystem.php000064400000004266151161172420012020
0ustar00<?php


namespace Nextend\Framework\Cache\Storage;


class Filesystem extends AbstractStorage {

    public function __construct() {
        $this->paths['web']    =
\Nextend\Framework\Filesystem\Filesystem::getWebCachePath();
        $this->paths['notweb'] =
\Nextend\Framework\Filesystem\Filesystem::getNotWebCachePath();
        $this->paths['image']  =
\Nextend\Framework\Filesystem\Filesystem::getImagesFolder();
    }

    public function isFilesystem() {
        return true;
    }

    public function clearAll($scope = 'notweb') {
        if
(\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope]))
{
           
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope]);
        }
    }

    public function clear($group, $scope = 'notweb') {

        if
(\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope]
. '/' . $group)) {
           
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope]
. '/' . $group);
        }
    }

    public function exists($group, $key, $scope = 'notweb') {
        if
(\Nextend\Framework\Filesystem\Filesystem::existsFile($this->paths[$scope]
. '/' . $group . '/' . $key)) {
            return true;
        }

        return false;
    }

    public function set($group, $key, $value, $scope = 'notweb')
{
        $path = $this->paths[$scope] . '/' . $group .
'/' . $key;
        $dir  = dirname($path);
        if (!\Nextend\Framework\Filesystem\Filesystem::existsFolder($dir))
{
            \Nextend\Framework\Filesystem\Filesystem::createFolder($dir);
        }
        \Nextend\Framework\Filesystem\Filesystem::createFile($path,
$value);
    }

    public function get($group, $key, $scope = 'notweb') {
        return
\Nextend\Framework\Filesystem\Filesystem::readFile($this->paths[$scope]
. '/' . $group . '/' . $key);
    }

    public function remove($group, $key, $scope = 'notweb') {
        if ($this->exists($group, $key, $scope)) {
            @unlink($this->paths[$scope] . '/' . $group .
'/' . $key);
        }
    }

    public function getPath($group, $key, $scope = 'notweb') {
        return $this->paths[$scope] . DIRECTORY_SEPARATOR . $group .
DIRECTORY_SEPARATOR . $key;
    }
}Cache/StoreImage.php000064400000001603151161172420010317 0ustar00<?php

namespace Nextend\Framework\Cache;

class StoreImage extends AbstractCache {

    protected $_storageEngine = 'filesystem';

    protected function getScope() {
        return 'image';
    }

    public function makeCache($fileName, $content) {
        if (!$this->isImage($fileName)) {
            return false;
        }

        if (!$this->exists($fileName)) {
            $this->set($fileName, $content);
        }

        return $this->getPath($fileName);
    }

    private function isImage($fileName) {
        $supported_image = array(
            'gif',
            'jpg',
            'jpeg',
            'png',
            'mp4',
            'mp3',
            'webp',
            'svg'
        );

        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        if (in_array($ext, $supported_image)) {
            return true;
        }

        return false;
    }
}Cast.php000064400000000425151161172420006150 0ustar00<?php


namespace Nextend\Framework;


class Cast {

    /**
     * @param $number
     *
     * @return string the JavaScript float representation of the string
     */
    public static function floatToString($number) {

        return json_encode(floatval($number));
    }
}Content/AbstractPlatformContent.php000064400000001171151161172420013472
0ustar00<?php

namespace Nextend\Framework\Content;

abstract class AbstractPlatformContent {

    /**
     * @param $keyword
     *
     * @return array links
     * $links[] = array(
     * 'title'       => '',
     * 'link'        => '',
     * 'info'        => ''
     * );
     */
    abstract public function searchLink($keyword);


    /**
     * @param $keyword
     *
     * @return array links
     * $links[] = array(
     * 'title'       => '',
     * 'description' => '',
     * 'image'       => '',
     * 'link'        => '',
     * 'info'        => ''
     * );
     */
    abstract public function searchContent($keyword);
}Content/Content.php000064400000001157151161172420010305 0ustar00<?php

namespace Nextend\Framework\Content;

use Nextend\Framework\Content\Joomla\JoomlaContent;
use Nextend\Framework\Content\WordPress\WordPressContent;

class Content {

    /**
     * @var AbstractPlatformContent
     */
    private static $platformContent;

    public function __construct() {
        self::$platformContent = new JoomlaContent();
    
    }

    public static function searchLink($keyword) {
        return self::$platformContent->searchLink($keyword);
    }

    public static function searchContent($keyword) {
        return self::$platformContent->searchContent($keyword);
    }
}

new
Content();Content/ControllerAjaxContent.php000064400000001162151161172420013151
0ustar00<?php


namespace Nextend\Framework\Content;


use Nextend\Framework\Controller\Admin\AdminAjaxController;
use Nextend\Framework\Request\Request;

class ControllerAjaxContent extends AdminAjaxController {

    public function actionSearchLink() {
        $this->validateToken();

        $keyword = Request::$REQUEST->getVar('keyword',
'');
        $this->response->respond(Content::searchLink($keyword));
    }

    public function actionSearchContent() {
        $this->validateToken();

        $keyword = Request::$REQUEST->getVar('keyword',
'');
        $this->response->respond(Content::searchContent($keyword));
    }
}Content/Joomla/JoomlaContent.php000064400000014513151161172430012671
0ustar00<?php

namespace Nextend\Framework\Content\Joomla;

use ContentHelperRoute;
use JFactory;
use Joomla\Component\Content\Administrator\Model\ArticlesModel;
use JUri;
use Nextend\Framework\Content\AbstractPlatformContent;
use Nextend\Framework\Data\Data;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\SmartSlider3\Platform\Joomla\JoomlaShim;

class JoomlaContent extends AbstractPlatformContent {

    public function searchContent($keyword = '') {

        $result = array();

        JoomlaShim::loadComContentRoute();

        if (JoomlaShim::$isJoomla4) {
            $a = new ArticlesModel();
        } else {
            require_once(JPATH_ADMINISTRATOR .
'/components/com_content/models/articles.php');
            $a = new \ContentModelArticles();
        }

        $db    = $a->getDbo();
        $query = $db->getQuery(true);
        // Select the required fields from the table.
        $query->select($a->getState('list.select',
'a.id, a.title, a.introtext, a.images, a.alias, a.catid,
a.language'));
        $query->from('#__content AS a');

        // Join over the categories.
        $query->select('c.title AS category_title')
              ->join('LEFT', '#__categories AS c ON c.id
= a.catid');

        if (!empty($keyword)) {
            if (stripos($keyword, 'id:') === 0) {
                $query->where('a.id = ' .
(int)substr($keyword, 3));
            } elseif (stripos($keyword, 'author:') === 0) {
                $keyword2 = $db->quote('%' .
$db->escape(substr($keyword, 7), true) . '%');
                $query->where('(ua.name LIKE ' . $keyword2 .
' OR ua.username LIKE ' . $keyword2 . ')');
            } else {
                $keyword2 = $db->quote('%' .
str_replace(' ', '%', $db->escape(trim($keyword),
true) . '%'));
                $query->where('(a.title LIKE ' . $keyword2 .
' OR a.alias LIKE ' . $keyword2 . ')');
            }
        }

        $db->setQuery($query, 0, 10);
        $articles = $db->loadAssocList();

        foreach ($articles as $article) {
            $images = new Data($article['images'], true);
            $image  = $images->get('image_fulltext',
$images->get('image_intro', ''));
            if (!empty($image) && substr($image, 0, 2) !=
'//' && substr($image, 0, 4) != 'http') {
                $image = JUri::root(false) . $image;
            }

            $result[] = array(
                'title'       => $article['title'],
                'description' =>
$article['introtext'],
                'image'       =>
ResourceTranslator::urlToResource($image),
                'link'        =>
ContentHelperRoute::getArticleRoute($article['id'],
$article['catid'], $article['language']),
                'info'        =>
$article['category_title']
            );
        }

        if (count($result) == 0 && !empty($keyword)) {
            /**
             * Try to show all post when no matches
             */
            return $this->searchContent();
        }

        return $result;
    }

    public function searchLink($keyword = '') {
        $result = array();

        JoomlaShim::loadComContentRoute();

        if (JoomlaShim::$isJoomla4) {
            $a = new ArticlesModel();
        } else {
            require_once(JPATH_ADMINISTRATOR .
'/components/com_content/models/articles.php');
            $a = new \ContentModelArticles();
        }

        $db    = $a->getDbo();
        $query = $db->getQuery(true);
        // Select the required fields from the table.
        $query->select($a->getState('list.select',
'a.id, a.title, a.alias, a.catid, a.language'));
        $query->from('#__content AS a');

        // Join over the categories.
        $query->select('c.title AS category_title')
              ->join('LEFT', '#__categories AS c ON c.id
= a.catid');

        if (!empty($keyword)) {
            if (stripos($keyword, 'id:') === 0) {
                $query->where('a.id = ' .
(int)substr($keyword, 3));
            } elseif (stripos($keyword, 'author:') === 0) {
                $keyword2 = $db->quote('%' .
$db->escape(substr($keyword, 7), true) . '%');
                $query->where('(ua.name LIKE ' . $keyword2 .
' OR ua.username LIKE ' . $keyword2 . ')');
            } else {
                $keyword2 = $db->quote('%' .
str_replace(' ', '%', $db->escape(trim($keyword),
true) . '%'));
                $query->where('(a.title LIKE ' . $keyword2 .
' OR a.alias LIKE ' . $keyword2 . ')');
            }
        }


        $db->setQuery($query, 0, 10);
        $articles = $db->loadAssocList();

        foreach ($articles as $article) {
            $result[] = array(
                'title' => $article['title'],
                'link'  =>
ContentHelperRoute::getArticleRoute($article['id'],
$article['catid'], $article['language']),
                'info'  =>
$article['category_title']
            );
        }


        $db = JFactory::getDbo();
        $db->setQuery('SELECT * FROM #__menu WHERE title LIKE
' . $db->quote('%' . str_replace(' ',
'%', $db->escape(trim($keyword), true) . '%')) .
' AND client_id = 0 AND menutype != "" LIMIT 0,10');
        $menuItems = $db->loadAssocList();

        foreach ($menuItems as $mi) {
            $link = $mi['link'];
            if ($link && strpos($link, 'index.php') ===
0) {
                $link = 'index.php?Itemid=' .
$mi['id'];

                if (isset($mi['language'])) {
                    $link .= self::getLangauge($mi['language']);
                }
            }


            $result[] = array(
                'title' => $mi['title'] . '
[' . $mi['menutype'] . ']',
                'link'  => $link,
                'info'  => n2_('Menu item')
            );
        }
        if (count($result) == 0 && !empty($keyword)) {
            return $this->searchLink();
        }

        return $result;
    }

    private function getLangauge($language) {
        $db    = JFactory::getDBO();
        $query = $db->getQuery(true);

        $link = '';

        if (is_object($query)) {
            $query->select('a.sef AS sef');
            $query->select('a.lang_code AS lang_code');
            $query->from('#__languages AS a');
            $db->setQuery($query);
            $langs = $db->loadObjectList();

            foreach ($langs as $lang) {
                if ($language == $lang->lang_code) {
                    $language = $lang->sef;
                    $link     .= '&lang=' . $language;
                }
            }
        }

        return $link;
    }
}Controller/AbstractController.php000064400000011710151161172430013210
0ustar00<?php


namespace Nextend\Framework\Controller;


use Exception;
use Nextend\Framework\Acl\Acl;
use Nextend\Framework\Application\AbstractApplication;
use Nextend\Framework\Application\AbstractApplicationType;
use Nextend\Framework\Asset\AssetManager;
use Nextend\Framework\Asset\Predefined;
use Nextend\Framework\Form\Form;
use Nextend\Framework\Notification\Notification;
use Nextend\Framework\Pattern\GetPathTrait;
use Nextend\Framework\Pattern\MVCHelperTrait;
use Nextend\Framework\Plugin;
use Nextend\Framework\Request\Request;
use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;

abstract class AbstractController {

    use GetPathTrait;
    use MVCHelperTrait;

    /**
     * @var AbstractApplicationType
     */
    protected $applicationType;

    /** @var callback[] */
    protected $externalActions = array();

    /**
     * AbstractController constructor.
     *
     * @param AbstractApplicationType $applicationType
     */
    public function __construct($applicationType) {

       
//PluggableController\Nextend\SmartSlider3\Application\Admin\Slider\ControllerSlider
        Plugin::doAction('PluggableController\\' .
get_class($this), array($this));


        $this->applicationType = $applicationType;
        $this->setMVCHelper($this->applicationType);

        AssetManager::getInstance();

        $this->initialize();
    }

    /**
     * @param          $actionName
     * @param callback $callable
     */
    public function addExternalAction($actionName, $callable) {

        $this->externalActions[$actionName] = $callable;
    }

    /**
     * @return AbstractApplication
     */
    public function getApplication() {
        return $this->applicationType->getApplication();
    }

    /**
     * @return AbstractApplicationType
     */
    public function getApplicationType() {
        return $this->applicationType;
    }

    public function getRouter() {
        return $this->applicationType->getRouter();
    }

    /**
     * @param       $actionName
     * @param array $args
     *
     * @throws Exception
     */
    final public function doAction($actionName, $args = array()) {

        $originalActionName = $actionName;

        if (method_exists($this, 'action' . $actionName)) {

            call_user_func_array(array(
                $this,
                'action' . $actionName
            ), $args);

        } else if (isset($this->externalActions[$actionName]) &&
is_callable($this->externalActions[$actionName])) {

            call_user_func_array($this->externalActions[$actionName],
$args);

        } else {

            $actionName = $this->missingAction($this, $actionName);

            if (method_exists($this, 'action' . $actionName)) {

                call_user_func_array(array(
                    $this,
                    'action' . $actionName
                ), $args);

            } else {
                throw new Exception(sprintf('Missing action (%s) for
controller (%s)', $originalActionName, static::class));
            }

        }
    }

    protected function missingAction($controllerName, $actionName) {

        return 'index';
    }

    public function initialize() {
        Predefined::frontend();
    }

    /**
     * Check ACL permissions
     *
     * @param      $action
     *
     * @return bool
     */
    public function canDo($action) {
        return Acl::canDo($action, $this);
    }

    public function redirect($url, $statusCode = 302, $terminate = true) {
        Request::redirect($url, $statusCode, $terminate);
    }

    public function validatePermission($permission) {

        if (!$this->canDo($permission)) {
            Notification::error(n2_('You are not authorised to view
this resource.'));

            ApplicationSmartSlider3::getInstance()
                                   ->getApplicationTypeAdmin()
                                   ->process('sliders',
'index');

            return false;
        }

        return true;
    }

    public function validateVariable($condition, $property) {

        if (!$condition) {
            Notification::error(sprintf(n2_('Missing parameter:
%s'), $property));

            ApplicationSmartSlider3::getInstance()
                                   ->getApplicationTypeAdmin()
                                   ->process('sliders',
'index');

            return false;
        }

        return true;
    }

    public function validateDatabase($condition, $showError = true) {
        if (!$condition) {
            if ($showError) {
                Notification::error(n2_('Database error'));

                ApplicationSmartSlider3::getInstance()
                                       ->getApplicationTypeAdmin()
                                       ->process('sliders',
'index');
            }

            return false;
        }

        return true;
    }

    public function validateToken() {
        if (!Form::checkToken()) {
            Notification::error(n2_('Security token mismatch'));

            return false;
        }

        return true;
    }
}Controller/Admin/AbstractAdminController.php000064400000001052151161172430015207
0ustar00<?php


namespace Nextend\Framework\Controller\Admin;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Asset\Predefined;
use Nextend\Framework\Controller\AbstractController;

abstract class AbstractAdminController extends AbstractController {

    public function initialize() {
        // Prevent browser from cache on backward button.
        header("Cache-Control: no-store");

        Js::addGlobalInline('window.N2DISABLESCHEDULER=1;');

        parent::initialize();

        Predefined::frontend();
        Predefined::backend();
    }
}Controller/Admin/AdminAjaxController.php000064400000000237151161172430014333
0ustar00<?php


namespace Nextend\Framework\Controller\Admin;


use Nextend\Framework\Controller\AjaxController;

class AdminAjaxController extends AjaxController {

}Controller/Admin/AdminVisualManagerAjaxController.php000064400000011313151161172430017007
0ustar00<?php


namespace Nextend\Framework\Controller\Admin;

use Nextend\Framework\Notification\Notification;
use Nextend\Framework\Request\Request;
use Nextend\Framework\Visual\ModelVisual;

abstract class AdminVisualManagerAjaxController extends AdminAjaxController
{

    protected $type = '';

    /**
     * @return ModelVisual
     */
    public abstract function getModel();

    public function actionCreateSet() {
        $this->validateToken();

        $this->validatePermission('smartslider_edit');

        $name = Request::$REQUEST->getVar('name');
        $this->validateVariable(!empty($name), 'set name');

        $model = $this->getModel();
        if (($set = $model->createSet($name))) {
            $this->response->respond(array(
                'set' => $set
            ));
        }

        Notification::error(n2_('Unexpected error'));
        $this->response->error();
    }

    public function actionRenameSet() {
        $this->validateToken();

        $this->validatePermission('smartslider_edit');

        $setId = Request::$REQUEST->getInt('setId');
        $this->validateVariable($setId > 0, 'set');

        $name = Request::$REQUEST->getVar('name');
        $this->validateVariable(!empty($name), 'set name');

        $model = $this->getModel();

        if (($set = $model->renameSet($setId, $name))) {
            $this->response->respond(array(
                'set' => $set
            ));
        }

        Notification::error(n2_('Set is not editable'));
        $this->response->error();
    }

    public function actionDeleteSet() {
        $this->validateToken();

        $this->validatePermission('smartslider_delete');

        $setId = Request::$REQUEST->getInt('setId');
        $this->validateVariable($setId > 0, 'set');

        $model = $this->getModel();

        if (($set = $model->deleteSet($setId))) {
            $this->response->respond(array(
                'set' => $set
            ));
        }

        Notification::error(n2_('Set is not editable'));
        $this->response->error();
    }

    public function actionLoadVisualsForSet() {
        $this->validateToken();


        $setId = Request::$REQUEST->getInt('setId');
        $this->validateVariable($setId > 0, 'set');

        $model   = $this->getModel();
        $visuals = $model->getVisuals($setId);
        if (is_array($visuals)) {
            $this->response->respond(array(
                'visuals' => $visuals
            ));
        }

        Notification::error(n2_('Unexpected error'));
        $this->response->error();
    }

    public function actionLoadSetByVisualId() {
        $this->validateToken();

        $visualId = Request::$REQUEST->getInt('visualId');
        $this->validateVariable($visualId > 0, 'visual');

        $model = $this->getModel();

        $set = $model->getSetByVisualId($visualId);

        if (is_array($set) && is_array($set['visuals']))
{
            $this->response->respond(array(
                'set' => $set
            ));
        }

        Notification::error(n2_('Visual do not exists'));
        $this->response->error();
    }

    public function actionAddVisual() {
        $this->validateToken();

        $this->validatePermission('smartslider_edit');

        $setId = Request::$REQUEST->getInt('setId');
        $this->validateVariable($setId > 0, 'set');

        $model = $this->getModel();

        if (($visual = $model->addVisual($setId,
Request::$REQUEST->getVar('value')))) {
            $this->response->respond(array(
                'visual' => $visual
            ));
        }

        Notification::error(n2_('Not editable'));
        $this->response->error();
    }

    public function actionDeleteVisual() {
        $this->validateToken();

        $this->validatePermission('smartslider_delete');

        $visualId = Request::$REQUEST->getInt('visualId');
        $this->validateVariable($visualId > 0, 'visual');

        $model = $this->getModel();

        if (($visual = $model->deleteVisual($visualId))) {
            $this->response->respond(array(
                'visual' => $visual
            ));
        }

        Notification::error(n2_('Not editable'));
        $this->response->error();
    }

    public function actionChangeVisual() {
        $this->validateToken();

        $this->validatePermission('smartslider_edit');

        $visualId = Request::$REQUEST->getInt('visualId');
        $this->validateVariable($visualId > 0, 'visual');

        $model = $this->getModel();

        if (($visual = $model->changeVisual($visualId,
Request::$REQUEST->getVar('value')))) {
            $this->response->respond(array(
                'visual' => $visual
            ));
        }

        Notification::error(n2_('Unexpected error'));
        $this->response->error();
    }

}Controller/AjaxController.php000064400000003177151161172430012340
0ustar00<?php

namespace Nextend\Framework\Controller;

use Nextend\Framework\Form\Form;
use Nextend\Framework\Notification\Notification;
use Nextend\Framework\PageFlow;
use Nextend\Framework\Response\ResponseAjax;

class AjaxController extends AbstractController {

    /** @var ResponseAjax */
    protected $response;

    public function __construct($applicationType) {
        PageFlow::cleanOutputBuffers();

        $this->response = new ResponseAjax($applicationType);
        parent::__construct($applicationType);
    }

    /**
     * @return ResponseAjax
     */
    public function getResponse() {
        return $this->response;
    }

    public function validateToken() {

        if (!Form::checkToken()) {
            Notification::error(n2_('Security token mismatch. Please
refresh the page!'));
            $this->response->error();
        }
    }

    public function validatePermission($permission) {

        if (!$this->canDo($permission)) {

            Notification::error(n2_('You are not authorised to view
this resource.'));

            $this->response->error();
        }
    }

    public function validateVariable($condition, $property) {

        if (!$condition) {
            Notification::error(sprintf(n2_('Missing parameter:
%s'), $property));
            $this->response->error();
        }
    }

    public function validateDatabase($condition, $showError = true) {
        if (!$condition) {
            Notification::error(n2_('Database error'));
            $this->response->error();
        }
    }

    public function redirect($url, $statusCode = 302, $terminate = true) {
        $this->response->redirect($url);
    }

}Data/Data.php000064400000003623151161172430007004 0ustar00<?php

namespace Nextend\Framework\Data;


class Data {

    /**
     * @var array
     */
    public $_data = array();

    public function __construct($data = null, $json = false) {

        if ($data) {
            if (is_array($data)) {
                $this->loadArray($data);
            } else {
                $this->loadJSON($data);
            }
        }
    }

    /**
     * @param $json
     */
    public function loadJSON($json) {
        $array = json_decode($json, true);
        if (is_array($array)) $this->_data =
array_merge($this->_data, $array);
    }

    /**
     * @param $array
     */
    public function loadArray($array) {
        if (!$this->_data) $this->_data = array();
        if (is_array($array)) $this->_data =
array_merge($this->_data, $array);
    }

    /**
     * @return mixed|string
     */
    public function toJSON() {
        return json_encode($this->_data);
    }

    /**
     * @return array
     */
    public function toArray() {
        return (array)$this->_data;
    }

    public function has($key) {

        return isset($this->_data[$key]);
    }

    /**
     * @param string $key
     * @param string $default
     *
     * @return mixed
     */
    public function get($key, $default = '') {
        if (isset($this->_data[$key])) return $this->_data[$key];

        return $default;
    }

    public function getIfEmpty($key, $default = '') {
        if (isset($this->_data[$key]) &&
!empty($this->_data[$key])) return $this->_data[$key];

        return $default;
    }

    /**
     * @param string $key
     * @param mixed  $value
     */
    public function set($key, $value) {
        $this->_data[$key] = $value;
    }

    public function un_set($key) {
        if (isset($this->_data[$key])) {
            unset($this->_data[$key]);
        }
    }

    public function fillDefault($defaults) {
        $this->_data = array_merge($defaults, $this->_data);
    }
}Database/AbstractPlatformConnector.php000064400000002415151161172430014107
0ustar00<?php

namespace Nextend\Framework\Database;

abstract class AbstractPlatformConnector {

    protected $_prefixJoker = '#__';

    protected $_prefix = '';

    public function getPrefix() {
        return $this->_prefix;
    }

    public function parsePrefix($query) {
        return str_replace($this->_prefixJoker, $this->_prefix,
$query);
    }

    abstract public function insertId();

    abstract public function query($query, $attributes = false);

    /**
     * Return with one row by query string
     *
     * @param string     $query
     * @param array|bool $attributes for parameter binding
     *
     * @return mixed
     */
    abstract public function queryRow($query, $attributes = false);

    abstract public function queryAll($query, $attributes = false, $type =
"assoc", $key = null);


    /**
     * @param string $text
     * @param bool   $escape
     *
     * @return string
     */
    abstract public function quote($text, $escape = true);

    /**
     * @param string $name
     * @param null   $as
     *
     * @return mixed
     */
    abstract public function quoteName($name, $as = null);

    public function checkError($result) {
        return $result;
    }

    /**
     * @return string
     */
    abstract public function getCharsetCollate();
}Database/AbstractPlatformConnectorTable.php000064400000003710151161172430015056
0ustar00<?php


namespace Nextend\Framework\Database;


abstract class AbstractPlatformConnectorTable {

    protected $primaryKeyColumn = "id";

    /** @var AbstractPlatformConnector */
    protected static $connector;

    protected $tableName;

    public function __construct($tableName) {

        $this->tableName = self::$connector->getPrefix() .
$tableName;
    }

    public function getTableName() {
        return $this->tableName;
    }

    abstract public function findByPk($primaryKey);

    abstract public function findByAttributes(array $attributes, $fields =
false, $order = false);

    abstract public function findAll($order = false);

    /**
     * Return with all row by attributes
     *
     * @param array       $attributes
     * @param bool|array  $fields
     * @param bool|string $order
     *
     * @return mixed
     */
    abstract public function findAllByAttributes(array $attributes, $fields
= false, $order = false);

    /**
     * Insert new row
     *
     * @param array $attributes
     *
     * @return mixed|void
     */
    abstract public function insert(array $attributes);

    abstract public function insertId();

    /**
     * Update row(s) by param(s)
     *
     * @param array $attributes
     * @param array $conditions
     *
     * @return mixed
     */
    abstract public function update(array $attributes, array $conditions);

    /**
     * Update one row by primary key with $attributes
     *
     * @param mixed $primaryKey
     * @param array $attributes
     *
     * @return mixed
     */
    abstract public function updateByPk($primaryKey, array $attributes);

    /**
     * Delete one with by primary key
     *
     * @param mixed $primaryKey
     *
     * @return mixed
     */
    abstract public function deleteByPk($primaryKey);

    /**
     * Delete all rows by attributes
     *
     * @param array $conditions
     *
     * @return mixed
     */
    abstract public function deleteByAttributes(array $conditions);
}Database/Database.php000064400000004550151161172430010472 0ustar00<?php

namespace Nextend\Framework\Database;

use Nextend\Framework\Database\Joomla\JoomlaConnector;
use Nextend\Framework\Database\Joomla\JoomlaConnectorTable;
use Nextend\Framework\Database\WordPress\WordPressConnector;
use Nextend\Framework\Database\WordPress\WordPressConnectorTable;
use Nextend\Framework\Pattern\SingletonTrait;

class Database {

    use SingletonTrait;

    /**
     * @var AbstractPlatformConnector
     */
    private static $platformConnector;

    protected function init() {
        self::$platformConnector = new JoomlaConnector();
    
    }

    /**
     * @param $tableName
     *
     * @return AbstractPlatformConnectorTable
     */
    public static function getTable($tableName) {
        return new JoomlaConnectorTable($tableName);
    
    }

    public static function getPrefix() {
        return self::$platformConnector->getPrefix();
    }

    public static function parsePrefix($query) {
        return self::$platformConnector->parsePrefix($query);
    }

    public static function insertId() {

        return self::$platformConnector->insertId();
    }

    public static function query($query, $attributes = false) {

        return self::$platformConnector->query($query, $attributes);
    }

    /**
     * Return with one row by query string
     *
     * @param string     $query
     * @param array|bool $attributes for parameter binding
     *
     * @return mixed
     */
    public static function queryRow($query, $attributes = false) {

        return self::$platformConnector->queryRow($query, $attributes);
    }

    public static function queryAll($query, $attributes = false, $type =
"assoc", $key = null) {

        return self::$platformConnector->queryAll($query, $attributes,
$type, $key);
    }


    /**
     * @param string $text
     * @param bool   $escape
     *
     * @return string
     */
    public static function quote($text, $escape = true) {

        return self::$platformConnector->quote($text, $escape);
    }

    /**
     * @param string $name
     * @param null   $as
     *
     * @return mixed
     */
    public static function quoteName($name, $as = null) {

        return self::$platformConnector->quoteName($name, $as);
    }

    /**
     * @return string
     */
    public static function getCharsetCollate() {

        return self::$platformConnector->getCharsetCollate();
    }
}

Database::getInstance();Database/Joomla/JoomlaConnector.php000064400000005032151161172430013277
0ustar00<?php

namespace Nextend\Framework\Database\Joomla;

use JDatabaseDriver;
use JFactory;
use Nextend\Framework\Database\AbstractPlatformConnector;

class JoomlaConnector extends AbstractPlatformConnector {

    /**
     * @var JDatabaseDriver
     */
    private $db;


    public function __construct() {
        $this->db      = JFactory::getDbo();
        $this->_prefix = $this->db->getPrefix();

        JoomlaConnectorTable::init($this, $this->db);
    }

    public function insertId() {
        return $this->db->insertid();
    }

    public function query($query, $attributes = false) {
        if ($attributes) {
            foreach ($attributes as $key => $value) {
                $replaceTo = is_numeric($value) ? $value :
$this->db->quote($value);
                $query     = str_replace($key, $replaceTo, $query);
            }
        }
        $this->db->setQuery($query);

        return $this->db->execute();
    }


    public function queryRow($query, $attributes = false) {
        if ($attributes) {
            foreach ($attributes as $key => $value) {
                $replaceTo = is_numeric($value) ? $value :
$this->db->quote($value);
                $query     = str_replace($key, $replaceTo, $query);
            }
        }
        $nextend = $this->db->setQuery($query);

        return $nextend->loadAssoc();
    }

    public function queryAll($query, $attributes = false, $type =
"assoc", $key = null) {
        if ($attributes) {
            foreach ($attributes as $key => $value) {
                $replaceTo = is_numeric($value) ? $value :
$this->db->quote($value);
                $query     = str_replace($key, $replaceTo, $query);
            }
        }

        $nextend = $this->db->setQuery($query);

        if ($type == "assoc") {
            return $nextend->loadAssocList($key);
        } else {
            return $nextend->loadObjectList($key);
        }

    }

    /**
     * @param string $text
     * @param bool   $escape
     *
     * @return string
     */
    public function quote($text, $escape = true) {
        return $this->db->quote($text, $escape);
    }

    /**
     * @param string $name
     * @param null   $as
     *
     * @return mixed
     */
    public function quoteName($name, $as = null) {
        return $this->db->quoteName($name, $as);
    }

    public function getCharsetCollate() {

        if ($this->db->hasUTF8mb4Support()) {

            return 'DEFAULT CHARSET=utf8mb4 DEFAULT
COLLATE=utf8mb4_unicode_ci';
        }

        return 'DEFAULT CHARSET=utf8 DEFAULT
COLLATE=utf8_unicode_ci';
    }
}Database/Joomla/JoomlaConnectorTable.php000064400000013373151161172430014256
0ustar00<?php


namespace Nextend\Framework\Database\Joomla;


use JDatabaseDriver;
use Nextend\Framework\Database\AbstractPlatformConnector;
use Nextend\Framework\Database\AbstractPlatformConnectorTable;
use stdClass;

class JoomlaConnectorTable extends AbstractPlatformConnectorTable {

    /** @var JDatabaseDriver */
    protected static $db;

    /**
     * @param AbstractPlatformConnector $connector
     * @param JDatabaseDriver           $db
     */
    public static function init($connector, $db) {
        self::$connector = $connector;
        self::$db        = $db;
    }

    public function findByPk($primaryKey) {
        $query = self::$db->getQuery(true);

        $query->select('*');
       
$query->from(self::$connector->quoteName($this->tableName));
       
$query->where(self::$connector->quoteName($this->primaryKeyColumn)
. ' = ' . (is_numeric($primaryKey) ? $primaryKey :
self::$db->quote($primaryKey)));

        // Reset the query using our newly populated query object.
        self::$db->setQuery($query);

        // Load the results as a list of stdClass objects (see later for
more options on retrieving data).
        return self::$db->loadAssoc();
    }


    public function findByAttributes(array $attributes, $fields = false,
$order = false) {
        $query = self::$db->getQuery(true);
        if ($fields) {
            $query->select(self::$connector->quoteName($fields));
        } else {
            $query->select(array('*'));
        }
       
$query->from(self::$connector->quoteName($this->tableName));
        foreach ($attributes as $key => $val) {
            $query->where(self::$connector->quoteName($key) . '
= ' . (is_numeric($val) ? $val : self::$connector->quote($val)));
        }

        if ($order) {
            $query->order($order);
        }

        self::$db->setQuery($query);

        return self::$db->loadAssoc();
    }

    public function findAll($order = false) {
        $query = self::$db->getQuery(true);
        $query->select('*');
        $query->from(self::$db->quoteName($this->tableName));

        if ($order) {
            $query->order($order);
        }

        self::$db->setQuery($query);

        return self::$db->loadAssocList();
    }

    public function findAllByAttributes(array $attributes, $fields = false,
$order = false) {
        $query = self::$db->getQuery(true);
        if ($fields) {
            $query->select(self::$connector->quoteName($fields));
        } else {
            $query->select('*');
        }
        $query->from(self::$db->quoteName($this->tableName));
        foreach ($attributes as $key => $val) {
            $query->where(self::$db->quoteName($key) . ' =
' . (is_numeric($val) ? $val : self::$db->quote($val)));
        }

        if ($order) {
            $query->order($order);
        }

        self::$db->setQuery($query);

        return self::$db->loadAssocList();
    }

    public function insert(array $attributes) {
        $object = new stdClass();
        foreach ($attributes as $key => $value) {
            $object->$key = $value;
        }

        // Insert the object into the user profile table.
        try {
            return self::$db->insertObject($this->tableName,
$object);
        } catch (\Exception $e) {
            return false;
        }
    }

    public function insertId() {
        return self::$db->insertid();
    }

    public function update(array $attributes, array $conditions) {
        $query = self::$db->getQuery(true);

        $fields = array();

        foreach ($attributes as $akey => $avalue) {
            $fields[] = self::$connector->quoteName($akey) . ' =
' . (is_numeric($avalue) ? intval($avalue) :
self::$connector->quote($avalue));
        }

        $where = array();
        foreach ($conditions as $ckey => $cvalue) {
            $where[] = self::$connector->quoteName($ckey) . ' =
' . (is_numeric($cvalue) ? intval($cvalue) :
self::$connector->quote($cvalue));
        }

       
$query->update(self::$connector->quoteName($this->tableName))
              ->set($fields)
              ->where($where);

        self::$db->setQuery($query);

        return self::$db->execute();
    }

    public function updateByPk($primaryKey, array $attributes) {
        $query = self::$db->getQuery(true);

        $fields = array();

        foreach ($attributes as $akey => $avalue) {
            $fields[] = self::$connector->quoteName($akey) . ' =
' . (is_numeric($avalue) ? intval($avalue) :
self::$connector->quote($avalue));
        }

        $conditions =
self::$connector->quoteName($this->primaryKeyColumn) . ' =
' . (is_numeric($primaryKey) ? $primaryKey :
self::$connector->quote($primaryKey));

       
$query->update(self::$connector->quoteName($this->tableName))
              ->set($fields)
              ->where($conditions);

        self::$db->setQuery($query);

        return self::$db->execute();
    }

    public function deleteByPk($primaryKey) {
        $query = self::$db->getQuery(true);

        $conditions =
array(self::$connector->quoteName($this->primaryKeyColumn) . ' =
' . (is_numeric($primaryKey) ? $primaryKey :
self::$connector->quote($primaryKey)));

       
$query->delete(self::$connector->quoteName($this->tableName));
        $query->where($conditions);

        self::$db->setQuery($query);

        return self::$db->execute();
    }

    public function deleteByAttributes(array $conditions) {
        $query = self::$db->getQuery(true);

        $where = array();
        foreach ($conditions as $ckey => $cvalue) {
            $where[] = self::$connector->quoteName($ckey) . ' =
' . (is_numeric($cvalue) ? intval($cvalue) :
self::$connector->quote($cvalue));
        }

       
$query->delete(self::$connector->quoteName($this->tableName));
        $query->where($where);

        self::$db->setQuery($query);

        return self::$db->execute();
    }
}FastImageSize/FastImageSize.php000064400000016025151161172430012450
0ustar00<?php

/**
 * fast-image-size base class
 *
 * @package       fast-image-size
 * @copyright (c) Marc Alexander <admin@m-a-styles.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nextend\Framework\FastImageSize;

use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;

class FastImageSize {

    use SingletonTrait;

    private static $cache = array();

    /**
     * @param string $image
     * @param array  $attributes
     */
    public static function initAttributes($image, &$attributes) {

        $size = self::getSize($image);

        if ($size) {
            $attributes['width']  = $size['width'];
            $attributes['height'] = $size['height'];
        }
    }

    public static function getWidth($image) {

        $size = self::getSize($image);

        if ($size) {
            return $size['width'];
        }

        return 0;
    }

    public static function getSize($image) {
        $imagePath = ResourceTranslator::toPath($image);

        if (!isset(self::$cache[$imagePath])) {
            if (empty($imagePath)) {
                self::$cache[$imagePath] = false;
            } else {
                self::$cache[$imagePath] = self::getInstance()
                                              
->getImageSize($imagePath);
            }
        }

        return self::$cache[$imagePath];
    }

    /** @var array Size info that is returned */
    protected $size = array();

    /** @var string Data retrieved from remote */
    protected $data = '';

    /** @var array List of supported image types and associated image types
*/
    protected $supportedTypes = array(
        'png'  => array('png'),
        'gif'  => array('gif'),
        'jpeg' => array(
            'jpeg',
            'jpg'
        ),
        'webp' => array(
            'webp',
        ),
        'svg'  => array(
            'svg',
        )
    );

    /** @var array Class map that links image extensions/mime types to
class */
    protected $classMap;

    /** @var array An array containing the classes of supported image types
*/
    protected $type;

    /**
     * Get image dimensions of supplied image
     *
     * @param string $file Path to image that should be checked
     * @param string $type Mimetype of image
     *
     * @return array|bool Array with image dimensions if successful, false
if not
     */
    public function getImageSize($file, $type = '') {
        // Reset values
        $this->resetValues();

        // Treat image type as unknown if extension or mime type is unknown
        if (!preg_match('/\.([a-z0-9]+)$/i', $file, $match)
&& empty($type)) {
            $this->getImagesizeUnknownType($file);
        } else {
            $extension = (empty($type) && isset($match[1])) ?
$match[1] : preg_replace('/.+\/([a-z0-9-.]+)$/i', '$1',
$type);

            $this->getImageSizeByExtension($file, $extension);
        }

        return sizeof($this->size) > 1 ? $this->size : false;
    }

    /**
     * Get dimensions of image if type is unknown
     *
     * @param string $filename Path to file
     */
    protected function getImagesizeUnknownType($filename) {
        // Grab the maximum amount of bytes we might need
        $data = $this->getImage($filename, 0,
Type\TypeJpeg::JPEG_MAX_HEADER_SIZE, false);

        if ($data !== false) {
            $this->loadAllTypes();
            foreach ($this->type as $imageType) {
                $imageType->getSize($filename);

                if (sizeof($this->size) > 1) {
                    break;
                }
            }
        }
    }

    /**
     * Get image size by file extension
     *
     * @param string $file      Path to image that should be checked
     * @param string $extension Extension/type of image
     */
    protected function getImageSizeByExtension($file, $extension) {
        $extension = strtolower($extension);
        $this->loadExtension($extension);
        if (isset($this->classMap[$extension])) {
            $this->classMap[$extension]->getSize($file);
        }
    }

    /**
     * Reset values to default
     */
    protected function resetValues() {
        $this->size = array();
        $this->data = '';
    }

    /**
     * Set mime type based on supplied image
     *
     * @param int $type Type of image
     */
    public function setImageType($type) {
        $this->size['type'] = $type;
    }

    /**
     * Set size info
     *
     * @param array $size Array containing size info for image
     */
    public function setSize($size) {
        $this->size = $size;
    }

    /**
     * Get image from specified path/source
     *
     * @param string $filename    Path to image
     * @param int    $offset      Offset at which reading of the image
should start
     * @param int    $length      Maximum length that should be read
     * @param bool   $forceLength True if the length needs to be the
specified
     *                            length, false if not. Default: true
     *
     * @return false|string Image data or false if result was empty
     */
    public function getImage($filename, $offset, $length, $forceLength =
true) {
        if (empty($this->data)) {
            $this->data = @file_get_contents($filename, null, null,
$offset, $length);
        }

        // Force length to expected one. Return false if data length
        // is smaller than expected length
        if ($forceLength === true) {
            return (strlen($this->data) < $length) ? false :
substr($this->data, $offset, $length);
        }

        return empty($this->data) ? false : $this->data;
    }

    /**
     * Get return data
     *
     * @return array|bool Size array if dimensions could be found, false if
not
     */
    protected function getReturnData() {
        return sizeof($this->size) > 1 ? $this->size : false;
    }

    /**
     * Load all supported types
     */
    protected function loadAllTypes() {
        foreach ($this->supportedTypes as $imageType => $extension) {
            $this->loadType($imageType);
        }
    }

    /**
     * Load an image type by extension
     *
     * @param string $extension Extension of image
     */
    protected function loadExtension($extension) {
        if (isset($this->classMap[$extension])) {
            return;
        }
        foreach ($this->supportedTypes as $imageType => $extensions)
{
            if (in_array($extension, $extensions, true)) {
                $this->loadType($imageType);
            }
        }
    }

    /**
     * Load an image type
     *
     * @param string $imageType Mimetype
     */
    protected function loadType($imageType) {
        if (isset($this->type[$imageType])) {
            return;
        }

        $className = '\\' . __NAMESPACE__ .
'\Type\Type' . ucfirst($imageType);

        $this->type[$imageType] = new $className($this);

        // Create class map
        foreach ($this->supportedTypes[$imageType] as $ext) {
            /** @var Type\TypeInterface */
            $this->classMap[$ext] = $this->type[$imageType];
        }
    }
}
FastImageSize/Type/TypeBase.php000064400000001310151161172430012401
0ustar00<?php

/**
 * fast-image-size image type base
 *
 * @package       fast-image-size
 * @copyright (c) Marc Alexander <admin@m-a-styles.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nextend\Framework\FastImageSize\Type;

use Nextend\Framework\FastImageSize\FastImageSize;

abstract class TypeBase implements TypeInterface {

    /** @var FastImageSize */
    protected $fastImageSize;

    /**
     * Base constructor for image types
     *
     * @param FastImageSize $fastImageSize
     */
    public function __construct(FastImageSize $fastImageSize) {
        $this->fastImageSize = $fastImageSize;
    }
}
FastImageSize/Type/TypeGif.php000064400000002413151161172430012241
0ustar00<?php

/**
 * fast-image-size image type gif
 *
 * @package       fast-image-size
 * @copyright (c) Marc Alexander <admin@m-a-styles.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nextend\Framework\FastImageSize\Type;

class TypeGif extends TypeBase {

    /** @var string GIF87a header */
    const GIF87A_HEADER = "\x47\x49\x46\x38\x37\x61";

    /** @var string GIF89a header */
    const GIF89A_HEADER = "\x47\x49\x46\x38\x39\x61";

    /** @var int GIF header size */
    const GIF_HEADER_SIZE = 6;

    /**
     * {@inheritdoc}
     */
    public function getSize($filename) {
        // Get data needed for reading image dimensions as outlined by
GIF87a
        // and GIF89a specifications
        $data = $this->fastImageSize->getImage($filename, 0,
self::GIF_HEADER_SIZE + self::SHORT_SIZE * 2);

        $type = substr($data, 0, self::GIF_HEADER_SIZE);
        if ($type !== self::GIF87A_HEADER && $type !==
self::GIF89A_HEADER) {
            return;
        }

        $size = unpack('vwidth/vheight', substr($data,
self::GIF_HEADER_SIZE, self::SHORT_SIZE * 2));

        $this->fastImageSize->setSize($size);
        $this->fastImageSize->setImageType(IMAGETYPE_GIF);
    }
}
FastImageSize/Type/TypeInterface.php000064400000001222151161172430013431
0ustar00<?php

/**
 * fast-image-size image type interface
 *
 * @package       fast-image-size
 * @copyright (c) Marc Alexander <admin@m-a-styles.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nextend\Framework\FastImageSize\Type;

interface TypeInterface {

    /** @var int 4-byte long size */
    const LONG_SIZE = 4;

    /** @var int 2-byte short size */
    const SHORT_SIZE = 2;

    /**
     * Get size of supplied image
     *
     * @param string $filename File name of image
     *
     * @return null
     */
    public function getSize($filename);
}
FastImageSize/Type/TypeJpeg.php000064400000011636151161172430012430
0ustar00<?php

/**
 * fast-image-size image type jpeg
 *
 * @package       fast-image-size
 * @copyright (c) Marc Alexander <admin@m-a-styles.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nextend\Framework\FastImageSize\Type;

class TypeJpeg extends TypeBase {

    /** @var int JPEG max header size. Headers can be bigger, but
we'll abort
     *            going through the header after this */
    const JPEG_MAX_HEADER_SIZE = 786432; // = 768 kiB

    /** @var string JPEG header */
    const JPEG_HEADER = "\xFF\xD8";

    /** @var string Start of frame marker */
    const SOF_START_MARKER = "\xFF";

    /** @var string End of image (EOI) marker */
    const JPEG_EOI_MARKER = "\xD9";

    /** @var array JPEG SOF markers */
    protected $sofMarkers = array(
        "\xC0",
        "\xC1",
        "\xC2",
        "\xC3",
        "\xC5",
        "\xC6",
        "\xC7",
        "\xC9",
        "\xCA",
        "\xCB",
        "\xCD",
        "\xCE",
        "\xCF"
    );

    /** @var string|bool JPEG data stream */
    protected $data = '';

    /** @var int Data length */
    protected $dataLength = 0;

    /**
     * {@inheritdoc}
     */
    public function getSize($filename) {
        // Do not force the data length
        $this->data = $this->fastImageSize->getImage($filename, 0,
self::JPEG_MAX_HEADER_SIZE, false);

        // Check if file is jpeg
        if ($this->data === false || substr($this->data, 0,
self::SHORT_SIZE) !== self::JPEG_HEADER) {
            return;
        }

        // Look through file for SOF marker
        $size = $this->getSizeInfo();

        $this->fastImageSize->setSize($size);
        $this->fastImageSize->setImageType(IMAGETYPE_JPEG);
    }

    /**
     * Get size info from image data
     *
     * @return array An array with the image's size info or an empty
array if
     *        size info couldn't be found
     */
    protected function getSizeInfo() {
        $size = array();
        // since we check $i + 1 we need to stop one step earlier
        $this->dataLength = strlen($this->data) - 1;

        $sofStartRead = true;

        // Look through file for SOF marker
        for ($i = 2; $i < $this->dataLength; $i++) {
            $marker = $this->getNextMarker($i, $sofStartRead);

            if (in_array($marker, $this->sofMarkers)) {
                // Extract size info from SOF marker
                return $this->extractSizeInfo($i);
            } else {
                // Extract length only
                $markerLength = $this->extractMarkerLength($i);

                if ($markerLength < 2) {
                    return $size;
                }

                $i += $markerLength - 1;
                continue;
            }
        }

        return $size;
    }

    /**
     * Extract marker length from data
     *
     * @param int $i Current index
     *
     * @return int Length of current marker
     */
    protected function extractMarkerLength($i) {
        // Extract length only
        list(, $unpacked) = unpack("H*", substr($this->data,
$i, self::LONG_SIZE));

        // Get width and height from unpacked size info
        $markerLength = hexdec(substr($unpacked, 0, 4));

        return $markerLength;
    }

    /**
     * Extract size info from data
     *
     * @param int $i Current index
     *
     * @return array Size info of current marker
     */
    protected function extractSizeInfo($i) {
        // Extract size info from SOF marker
        list(, $unpacked) = unpack("H*", substr($this->data,
$i - 1 + self::LONG_SIZE, self::LONG_SIZE));

        // Get width and height from unpacked size info
        $size = array(
            'width'  => hexdec(substr($unpacked, 4, 4)),
            'height' => hexdec(substr($unpacked, 0, 4)),
        );

        return $size;
    }

    /**
     * Get next JPEG marker in file
     *
     * @param int  $i            Current index
     * @param bool $sofStartRead Flag whether SOF start padding was already
read
     *
     * @return string Next JPEG marker in file
     */
    protected function getNextMarker(&$i, &$sofStartRead) {
        $this->skipStartPadding($i, $sofStartRead);

        do {
            if ($i >= $this->dataLength) {
                return self::JPEG_EOI_MARKER;
            }
            $marker = $this->data[$i];
            $i++;
        } while ($marker == self::SOF_START_MARKER);

        return $marker;
    }

    /**
     * Skip over any possible padding until we reach a byte without SOF
start
     * marker. Extraneous bytes might need to require proper treating.
     *
     * @param int  $i            Current index
     * @param bool $sofStartRead Flag whether SOF start padding was already
read
     */
    protected function skipStartPadding(&$i, &$sofStartRead) {
        if (!$sofStartRead) {
            while ($this->data[$i] !== self::SOF_START_MARKER) {
                $i++;
            }
        }
    }
}
FastImageSize/Type/TypePng.php000064400000002467151161172430012271
0ustar00<?php

/**
 * fast-image-size image type png
 *
 * @package       fast-image-size
 * @copyright (c) Marc Alexander <admin@m-a-styles.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nextend\Framework\FastImageSize\Type;

class TypePng extends TypeBase {

    /** @var string PNG header */
    const PNG_HEADER = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";

    /** @var int PNG IHDR offset */
    const PNG_IHDR_OFFSET = 12;

    /**
     * {@inheritdoc}
     */
    public function getSize($filename) {
        // Retrieve image data including the header, the IHDR tag, and the
        // following 2 chunks for the image width and height
        $data = $this->fastImageSize->getImage($filename, 0,
self::PNG_IHDR_OFFSET + 3 * self::LONG_SIZE);

        // Check if header fits expected format specified by RFC 2083
        if (substr($data, 0, self::PNG_IHDR_OFFSET - self::LONG_SIZE) !==
self::PNG_HEADER || substr($data, self::PNG_IHDR_OFFSET, self::LONG_SIZE)
!== 'IHDR') {
            return;
        }

        $size = unpack('Nwidth/Nheight', substr($data,
self::PNG_IHDR_OFFSET + self::LONG_SIZE, self::LONG_SIZE * 2));
        $this->fastImageSize->setSize($size);
        $this->fastImageSize->setImageType(IMAGETYPE_PNG);
    }
}
FastImageSize/Type/TypeSvg.php000064400000001746151161172430012303
0ustar00<?php

namespace Nextend\Framework\FastImageSize\Type;

class TypeSvg extends TypeBase {

    /**
     * {@inheritdoc}
     */
    public function getSize($filename) {

        $data = $this->fastImageSize->getImage($filename, 0, 100);

        preg_match('/width="([0-9]+)"/', $data,
$matches);
        if ($matches && $matches[1] > 0) {
            $size          = array();
            $size['width'] = $matches[1];

            preg_match('/height="([0-9]+)"/', $data,
$matches);
            if ($matches && $matches[1] > 0) {
                $size['height'] = $matches[1];
                $this->fastImageSize->setSize($size);

                return;
            }
        }

        preg_match('/viewBox=["\']([0-9]+) ([0-9]+) ([0-9]+)
([0-9]+)["\']/i', $data, $matches);

        if ($matches) {
            $this->fastImageSize->setSize(array(
                'width'  => $matches[3] - $matches[1],
                'height' => $matches[4] - $matches[2],
            ));
        }

    }
}
FastImageSize/Type/TypeWebp.php000064400000010211151161172430012424
0ustar00<?php

/**
 * fast-image-size image type webp
 *
 * @package       fast-image-size
 * @copyright (c) Marc Alexander <admin@m-a-styles.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nextend\Framework\FastImageSize\Type;

use Nextend\Framework\FastImageSize\FastImageSize;

class TypeWebp extends TypeBase {

    /** @var string RIFF header */
    const WEBP_RIFF_HEADER = "RIFF";

    /** @var string Webp header */
    const WEBP_HEADER = "WEBP";

    /** @var string VP8 chunk header */
    const VP8_HEADER = "VP8";

    /** @var string Simple(lossy) webp format */
    const WEBP_FORMAT_SIMPLE = ' ';

    /** @var string Lossless webp format */
    const WEBP_FORMAT_LOSSLESS = 'L';

    /** @var string Extended webp format */
    const WEBP_FORMAT_EXTENDED = 'X';

    /** @var int WEBP header size needed for retrieving image size */
    const WEBP_HEADER_SIZE = 30;

    /** @var array Size info array */
    protected $size;

    /**
     * Constructor for webp image type. Adds missing constant if necessary.
     *
     * @param FastImageSize $fastImageSize
     */
    public function __construct(FastImageSize $fastImageSize) {
        parent::__construct($fastImageSize);

        if (!defined('IMAGETYPE_WEBP')) {
            define('IMAGETYPE_WEBP', 18);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getSize($filename) {
        // Do not force length of header
        $data = $this->fastImageSize->getImage($filename, 0,
self::WEBP_HEADER_SIZE);

        $this->size = array();

        $webpFormat = substr($data, 15, 1);

        if (!$this->hasWebpHeader($data) ||
!$this->isValidFormat($webpFormat)) {
            return;
        }

        $data = substr($data, 16, 14);

        $this->getWebpSize($data, $webpFormat);

        $this->fastImageSize->setSize($this->size);
        $this->fastImageSize->setImageType(IMAGETYPE_WEBP);
    }

    /**
     * Check if $data has valid WebP header
     *
     * @param string $data Image data
     *
     * @return bool True if $data has valid WebP header, false if not
     */
    protected function hasWebpHeader($data) {
        $riffSignature = substr($data, 0, self::LONG_SIZE);
        $webpSignature = substr($data, 8, self::LONG_SIZE);
        $vp8Signature  = substr($data, 12, self::SHORT_SIZE + 1);

        return !empty($data) && $riffSignature ===
self::WEBP_RIFF_HEADER && $webpSignature === self::WEBP_HEADER
&& $vp8Signature === self::VP8_HEADER;
    }

    /**
     * Check if $format is a valid WebP format
     *
     * @param string $format Format string
     *
     * @return bool True if format is valid WebP format, false if not
     */
    protected function isValidFormat($format) {
        return in_array($format, array(
            self::WEBP_FORMAT_SIMPLE,
            self::WEBP_FORMAT_LOSSLESS,
            self::WEBP_FORMAT_EXTENDED
        ));
    }

    /**
     * Get webp size info depending on format type and set size array
values
     *
     * @param string $data   Data string
     * @param string $format Format string
     */
    protected function getWebpSize($data, $format) {
        switch ($format) {
            case self::WEBP_FORMAT_SIMPLE:
                $this->size = unpack('vwidth/vheight',
substr($data, 10, 4));
                break;

            case self::WEBP_FORMAT_LOSSLESS:
                // Lossless uses 14-bit values so we'll have to use
bitwise shifting
                $this->size = array(
                    'width'  => ord($data[5]) +
((ord($data[6]) & 0x3F) << 8) + 1,
                    'height' => (ord($data[6]) >> 6) +
(ord($data[7]) << 2) + ((ord($data[8]) & 0xF) << 10) + 1,
                );
                break;

            case self::WEBP_FORMAT_EXTENDED:
                // Extended uses 24-bit values cause 14-bit for lossless
wasn't weird enough
                $this->size = array(
                    'width'  => ord($data[8]) + (ord($data[9])
<< 8) + (ord($data[10]) << 16) + 1,
                    'height' => ord($data[11]) +
(ord($data[12]) << 8) + (ord($data[13]) << 16) + 1,
                );
                break;
        }
    }
}
Filesystem/AbstractPlatformFilesystem.php000064400000021371151161172430014723
0ustar00<?php

namespace Nextend\Framework\Filesystem;

use Nextend\Framework\Url\Url;

if (!defined('NEXTEND_RELATIVE_CACHE_WEB')) {
    define('NEXTEND_RELATIVE_CACHE_WEB',
'/cache/nextend/web');
    define('NEXTEND_CUSTOM_CACHE', 0);
} else {
    define('NEXTEND_CUSTOM_CACHE', 1);
}
if (!defined('NEXTEND_RELATIVE_CACHE_NOTWEB')) {
    define('NEXTEND_RELATIVE_CACHE_NOTWEB',
'/cache/nextend/notweb');
}

abstract class AbstractPlatformFilesystem {

    public $paths = array();

    /**
     * @var string Absolute path which match to the baseuri. It must not
end with /
     * @example /asd/xyz/wordpress
     */
    protected $_basepath;

    protected $dirPermission = 0777;

    protected $filePermission = 0666;


    protected $translate = array();

    public function init() {

    }

    public function getPaths() {

        return $this->paths;
    }

    public function check($base, $folder) {
        static $checked = array();
        if (!isset($checked[$base . '/' . $folder])) {
            $cacheFolder = $base . '/' . $folder;
            if (!$this->existsFolder($cacheFolder)) {
                if ($this->is_writable($base)) {
                    $this->createFolder($cacheFolder);
                } else {
                    die('<div
style="position:fixed;background:#fff;width:100%;height:100%;top:0;left:0;z-index:100000;">'
. sprintf('<h2><b>%s</b> is not
writable.</h2>', $base) . '</div>');
                }
            } else if (!$this->is_writable($cacheFolder)) {
                die('<div
style="position:fixed;background:#fff;width:100%;height:100%;top:0;left:0;z-index:100000;">'
. sprintf('<h2><b>%s</b> is not
writable.</h2>', $cacheFolder) . '</div>');
            }
            $checked[$base . '/' . $folder] = true;
        }
    }

    public function measurePermission($testDir) {
        while ('.' != $testDir && !is_dir($testDir)) {
            $testDir = dirname($testDir);
        }

        if ($stat = @stat($testDir)) {
            $this->dirPermission  = $stat['mode'] &
0007777;
            $this->filePermission = $this->dirPermission &
0000666;
        }
    }

    /**
     * @param $path
     *
     * @return mixed
     */
    public function toLinux($path) {
        return str_replace(DIRECTORY_SEPARATOR, '/', $path);
    }

    /**
     * @return string
     */
    public function getBasePath() {

        return $this->_basepath;
    }

    /**
     * @param $path
     */
    public function setBasePath($path) {

        $this->_basepath = $path;
    }

    public function getWebCachePath() {

        return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_WEB;
    }

    public function getNotWebCachePath() {
        return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_NOTWEB;
    }

    /**
     * @param $path
     *
     * @return string
     */
    public function pathToAbsoluteURL($path) {
        return Url::pathToUri($path);
    }

    /**
     * @param $path
     *
     * @return string
     */
    public function pathToRelativePath($path) {

        return preg_replace('/^' .
preg_quote($this->_basepath, '/') . '/',
'', str_replace('/', DIRECTORY_SEPARATOR, $path));
    }

    /**
     * @param $path
     *
     * @return string
     */
    public function pathToAbsolutePath($path) {

        return $this->_basepath . str_replace('/',
DIRECTORY_SEPARATOR, $path);
    }

    /**
     * @param $url
     *
     * @return string
     */
    public function absoluteURLToPath($url) {

        $fullUri = Url::getFullUri();
        if (substr($url, 0, strlen($fullUri)) == $fullUri) {

            return str_replace($fullUri, $this->_basepath, $url);
        }

        return $url;
    }

    /**
     * @param $file
     *
     * @return bool
     */
    public function fileexists($file) {
        return is_file($file);
    }

    /**
     * @param $file
     *
     * @return bool
     */
    public function safefileexists($file) {
        return realpath($file) && is_file($file);
    }

    /**
     *
     * @param $dir
     *
     * @return array Folder names without trailing slash
     */
    public function folders($dir) {
        if (!is_dir($dir)) {
            return array();
        }
        $folders = array();
        foreach (scandir($dir) as $file) {
            if ($file == '.' || $file == '..')
continue;
            if (is_dir($dir . DIRECTORY_SEPARATOR . $file)) $folders[] =
$file;
        }

        return $folders;
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public function is_writable($path) {
        return is_writable($path);
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public function createFolder($path) {

        return mkdir($path, $this->dirPermission, true);
    }

    public function deleteFolder($dir) {
        if (!is_dir($dir) || is_link($dir)) return unlink($dir);
        foreach (scandir($dir) as $file) {
            if ($file == '.' || $file == '..')
continue;
            if (!$this->deleteFolder($dir . DIRECTORY_SEPARATOR .
$file)) {
                chmod($dir . DIRECTORY_SEPARATOR . $file,
$this->dirPermission);
                if (!$this->deleteFolder($dir . DIRECTORY_SEPARATOR .
$file)) return false;
            }
        }

        return rmdir($dir);
    }

    public function existsFolder($path) {
        return is_dir($path);
    }

    public function files($path) {
        $files = array();
        if (is_dir($path)) {
            if ($dh = opendir($path)) {
                while (($file = readdir($dh)) !== false) {
                    if ($file[0] != ".") {
                        $files[] = $file;
                    }
                }
                closedir($dh);
            }
        }

        return $files;
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public function existsFile($path) {

        return file_exists($path);
    }

    /**
     * @param $path
     * @param $buffer
     *
     * @return int
     */
    public function createFile($path, $buffer) {
        return file_put_contents($path, $buffer);
    }

    /**
     * @param $path
     *
     * @return string
     */
    public function readFile($path) {
        return file_get_contents($path);
    }

    /**
     * convert dir alias to normal format
     *
     * @param $pathName
     *
     * @return mixed
     */
    public function dirFormat($pathName) {
        return str_replace(".", DIRECTORY_SEPARATOR, $pathName);
    }

    public function getImagesFolder() {
        return '';
    }

    public function realpath($path) {
        return rtrim(realpath($path), '/\\');
    }

    public function registerTranslate($from, $to) {
        $this->translate[$from] = $to;
    }

    protected function trailingslashit($string) {
        return $this->untrailingslashit($string) . '/';
    }

    protected function untrailingslashit($string) {
        return rtrim($string, '/\\');
    }

    public function convertToRealDirectorySeparator($path) {
        return str_replace(DIRECTORY_SEPARATOR == '/' ?
'\\' : '/', DIRECTORY_SEPARATOR, $path);
    }

    public function get_temp_dir() {
        static $temp = '';
        if (defined('SS_TEMP_DIR')) return
$this->trailingslashit(SS_TEMP_DIR);

        if ($temp) return $this->trailingslashit($temp);

        if (function_exists('sys_get_temp_dir')) {
            $temp = sys_get_temp_dir();
            if (@is_dir($temp) && $this->is_writable($temp))
return $this->trailingslashit($temp);
        }

        $temp = ini_get('upload_tmp_dir');
        if (@is_dir($temp) && $this->is_writable($temp)) return
$this->trailingslashit($temp);

        $temp = $this->getNotWebCachePath() . '/';
        if (is_dir($temp) && $this->is_writable($temp)) return
$temp;

        return '/tmp/';
    }

    public function tempnam($filename = '', $dir = '')
{
        if (empty($dir)) {
            $dir = $this->get_temp_dir();
        }

        if (empty($filename) || '.' == $filename || '/'
== $filename || '\\' == $filename) {
            $filename = time();
        }

        // Use the basename of the given file without the extension as the
name for the temporary directory
        $temp_filename = basename($filename);
        $temp_filename = preg_replace('|\.[^.]*$|', '',
$temp_filename);

        // If the folder is falsey, use its parent directory name instead.
        if (!$temp_filename) {
            return $this->tempnam(dirname($filename), $dir);
        }

        // Suffix some random data to avoid filename conflicts
        $temp_filename .= '-' . md5(uniqid(rand() . time()));
        $temp_filename .= '.tmp';
        $temp_filename = $dir . $temp_filename;

        $fp = @fopen($temp_filename, 'x');
        if (!$fp && is_writable($dir) &&
file_exists($temp_filename)) {
            return $this->tempnam($filename, $dir);
        }
        if ($fp) {
            fclose($fp);
        }

        return $temp_filename;
    }
}Filesystem/Filesystem.php000064400000012601151161172430011526
0ustar00<?php

namespace Nextend\Framework\Filesystem;

use Nextend\Framework\Filesystem\Joomla\JoomlaFilesystem;
use Nextend\Framework\Filesystem\WordPress\WordPressFilesystem;

class Filesystem {

    /**
     * @var AbstractPlatformFilesystem
     */
    private static $platformFilesystem;

    public function __construct() {
        self::$platformFilesystem = new JoomlaFilesystem();
    

        self::$platformFilesystem->init();
    }

    /**
     * @return AbstractPlatformFilesystem
     */
    public static function get() {

        return self::$platformFilesystem;
    }

    public static function getPaths() {

        return self::$platformFilesystem->getPaths();
    }

    public static function check($base, $folder) {

        self::$platformFilesystem->check($base, $folder);
    }

    public static function measurePermission($testDir) {

        self::$platformFilesystem->measurePermission($testDir);
    }

    /**
     * @param $path
     *
     * @return string
     */
    public static function toLinux($path) {

        return self::$platformFilesystem->toLinux($path);
    }

    /**
     * @return string
     */
    public static function getBasePath() {

        return self::$platformFilesystem->getBasePath();
    }

    /**
     * @param $path
     */
    public static function setBasePath($path) {

        self::$platformFilesystem->setBasePath($path);
    }

    public static function getWebCachePath() {

        return self::$platformFilesystem->getWebCachePath();
    }

    public static function getNotWebCachePath() {

        return self::$platformFilesystem->getNotWebCachePath();
    }

    /**
     * @param $path
     *
     * @return string
     */
    public static function pathToAbsoluteURL($path) {

        return self::$platformFilesystem->pathToAbsoluteURL($path);
    }

    /**
     * @param $path
     *
     * @return string
     */
    public static function pathToRelativePath($path) {

        return self::$platformFilesystem->pathToRelativePath($path);
    }

    /**
     * @param $path
     *
     * @return string
     */
    public static function pathToAbsolutePath($path) {

        return self::$platformFilesystem->pathToAbsolutePath($path);
    }

    /**
     * @param $url
     *
     * @return string
     */
    public static function absoluteURLToPath($url) {

        return self::$platformFilesystem->absoluteURLToPath($url);
    }

    /**
     * @param $file
     *
     * @return bool
     */
    public static function fileexists($file) {

        return self::$platformFilesystem->fileexists($file);
    }

    /**
     * @param $file
     *
     * @return bool
     */
    public static function safefileexists($file) {

        return self::$platformFilesystem->safefileexists($file);
    }

    /**
     *
     * @param $dir
     *
     * @return array Folder names without trailing slash
     */
    public static function folders($dir) {

        return self::$platformFilesystem->folders($dir);
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public static function is_writable($path) {

        return self::$platformFilesystem->is_writable($path);
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public static function createFolder($path) {

        return self::$platformFilesystem->createFolder($path);
    }

    /**
     * @param $dir
     *
     * @return bool
     */
    public static function deleteFolder($dir) {

        return self::$platformFilesystem->deleteFolder($dir);
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public static function existsFolder($path) {

        return self::$platformFilesystem->existsFolder($path);
    }

    /**
     * @param $path
     *
     * @return array
     */
    public static function files($path) {

        return self::$platformFilesystem->files($path);
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public static function existsFile($path) {

        return self::$platformFilesystem->existsFile($path);
    }

    /**
     * @param $path
     * @param $buffer
     *
     * @return int
     */
    public static function createFile($path, $buffer) {

        return self::$platformFilesystem->createFile($path, $buffer);
    }

    /**
     * @param $path
     *
     * @return string
     */
    public static function readFile($path) {

        return self::$platformFilesystem->readFile($path);
    }

    /**
     * convert dir alias to normal format
     *
     * @param $pathName
     *
     * @return mixed
     */
    public static function dirFormat($pathName) {

        return self::$platformFilesystem->dirFormat($pathName);
    }

    public static function getImagesFolder() {

        return self::$platformFilesystem->getImagesFolder();
    }

    public static function realpath($path) {

        return self::$platformFilesystem->realpath($path);
    }

    public static function registerTranslate($from, $to) {

        self::$platformFilesystem->registerTranslate($from, $to);
    }

    public static function convertToRealDirectorySeparator($path) {

        return
self::$platformFilesystem->convertToRealDirectorySeparator($path);
    }

    public static function get_temp_dir() {

        return self::$platformFilesystem->get_temp_dir();
    }

    public static function tempnam($filename = '', $dir =
'') {

        return self::$platformFilesystem->tempnam($filename =
'', $dir = '');
    }
}

new
Filesystem();Filesystem/Joomla/JoomlaFilesystem.php000064400000004537151161172430014122
0ustar00<?php

namespace Nextend\Framework\Filesystem\Joomla;

use JFile;
use JFolder;
use Nextend\Framework\Filesystem\AbstractPlatformFilesystem;

class JoomlaFilesystem extends AbstractPlatformFilesystem {

    public function init() {
        $this->_basepath = realpath(JPATH_SITE == '' ?
DIRECTORY_SEPARATOR : JPATH_SITE . DIRECTORY_SEPARATOR);
        if ($this->_basepath == DIRECTORY_SEPARATOR) {
            $this->_basepath = '';
        }
        $this->_cachepath = realpath(JPATH_CACHE);

        $this->measurePermission($this->_basepath .
'/media/');
    }

    public function getWebCachePath() {
        return $this->getBasePath() . '/media/nextend';
    }

    public function getNotWebCachePath() {
        return JPATH_CACHE . '/nextend';
    }

    public function getImagesFolder() {
        if (defined('JPATH_NEXTEND_IMAGES')) {
            return $this->_basepath . JPATH_NEXTEND_IMAGES;
        }

        return $this->_basepath . '/images';
    }

    /**
     * Calling JFile:exists() method
     *
     * @param $file
     *
     * @return bool
     */
    public function fileexists($file) {
        return JFile::exists($file);
    }

    /**
     * @param $path
     *
     * @return mixed
     */
    public function folders($path) {
        return JFolder::folders($path);
    }

    /**
     * @param $path
     *
     * @return bool
     */
    public function is_writable($path) {
        return true;
    }

    /**
     * @param $path
     *
     * @return mixed
     */
    public function createFolder($path) {
        return JFolder::create($path, $this->dirPermission);
    }

    /**
     * @param $path
     *
     * @return mixed
     */
    public function deleteFolder($path) {
        return JFolder::delete($path);
    }

    /**
     * @param $path
     *
     * @return mixed
     */
    public function existsFolder($path) {
        return JFolder::exists($path);
    }

    /**
     * @param $path
     *
     * @return mixed
     */
    public function files($path) {
        return JFolder::files($path);
    }

    /**
     * @param $path
     *
     * @return mixed
     */
    public function existsFile($path) {
        return JFile::exists($path);
    }

    /**
     * @param $path
     * @param $buffer
     *
     * @return mixed
     */
    public function createFile($path, $buffer) {
        return JFile::write($path, $buffer);
    }

}Font/AbstractFontSource.php000064400000001026151161172430011736
0ustar00<?php


namespace Nextend\Framework\Font;


use Nextend\Framework\Form\ContainerInterface;

abstract class AbstractFontSource {

    protected $name;

    public abstract function getLabel();

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

    public function onFontManagerLoad($force = false) {

    }

    public function onFontManagerLoadBackend() {
    }

    /**
     * @param ContainerInterface $container
     */
    abstract public function renderFields($container);
}Font/Block/FontManager/BlockFontManager.php000064400000003161151161172430014574
0ustar00<?php


namespace Nextend\Framework\Font\Block\FontManager;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Font\FontRenderer;
use Nextend\Framework\Font\FontSettings;
use Nextend\Framework\Font\ModelFont;
use Nextend\Framework\Localization\Localization;
use Nextend\Framework\Visual\AbstractBlockVisual;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonApply;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonCancel;

class BlockFontManager extends AbstractBlockVisual {

    /** @var ModelFont */
    protected $model;

    /**
     * @return ModelFont
     */
    public function getModel() {
        return $this->model;
    }

    public function display() {

        $this->model = new ModelFont($this);

        $this->renderTemplatePart('Index');
    }

    public function displayTopBar() {

        $buttonCancel = new BlockButtonCancel($this);
       
$buttonCancel->addClass('n2_fullscreen_editor__cancel');
        $buttonCancel->display();

        $buttonApply = new BlockButtonApply($this);
        $buttonApply->addClass('n2_fullscreen_editor__save');
        $buttonApply->display();
    }

    public function displayContent() {
        $model = $this->getModel();

        Js::addFirstCode("
            _N2.CSSRendererFont.defaultFamily = " .
json_encode(FontSettings::getDefaultFamily()) . ";
            _N2.CSSRendererFont.rendererModes = " .
json_encode(FontRenderer::$mode) . ";
            _N2.CSSRendererFont.pre = " .
json_encode(FontRenderer::$pre) . ";
            new _N2.NextendFontManager();
        ");

        $model->renderForm();
    }
}Font/Block/FontManager/Index.php000064400000001474151161172430012474
0ustar00<?php

namespace Nextend\Framework\Font\Block\FontManager;

/**
 * @var BlockFontManager $this
 */
?>
<div id="n2-lightbox-font"
class="n2_fullscreen_editor">
    <div class="n2_fullscreen_editor__overlay"></div>
    <div class="n2_fullscreen_editor__window">
        <div class="n2_fullscreen_editor__nav_bar">
            <div
class="n2_fullscreen_editor__nav_bar_label">
                <?php n2_e('Font manager'); ?>
            </div>
            <div
class="n2_fullscreen_editor__nav_bar_actions">
                <?php $this->displayTopBar(); ?>
            </div>
        </div>
        <div class="n2_fullscreen_editor__content">
            <div class="n2_fullscreen_editor__content_content
n2_container_scrollable">
                <?php $this->displayContent(); ?>
            </div>
        </div>
    </div>
</div>Font/ControllerAjaxFont.php000064400000000446151161172430011746
0ustar00<?php

namespace Nextend\Framework\Font;

use Nextend\Framework\Controller\Admin\AdminVisualManagerAjaxController;

class ControllerAjaxFont extends AdminVisualManagerAjaxController {

    protected $type = 'font';

    public function getModel() {

        return new ModelFont($this);
    }
}Font/FontManager.php000064400000000540151161172430010364 0ustar00<?php

namespace Nextend\Framework\Font;

use Nextend\Framework\Font\Block\FontManager\BlockFontManager;
use Nextend\Framework\Pattern\VisualManagerTrait;

class FontManager {

    use VisualManagerTrait;

    public function display() {

        $fontManagerBlock = new BlockFontManager($this->MVCHelper);
        $fontManagerBlock->display();
    }
}Font/FontParser.php000064400000002427151161172430010254 0ustar00<?php


namespace Nextend\Framework\Font;


use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Model\Section;

class FontParser {

    /**
     * @param $data
     *
     * @return string
     */
    public static function parse($data) {
        if (empty($data)) {
            return '';
        } else if (is_numeric($data)) {
            /**
             * Linked font
             */

            $font = Section::getById($data, 'font');

            if (!$font) {
                /**
                 * Linked font not exists anymore
                 */
                return '';
            }


            if (is_string($font['value'])) {
                /**
                 * Old format when value stored as Base64
                 */
                $decoded = $font['value'];
                if ($decoded[0] != '{') {
                    $decoded = Base64::decode($decoded);
                }

                return $decoded;
            }

            /**
             * Value stored as array
             */
            $value = json_encode($font['value']);
            if ($value == false) {
                return '';
            }

            return $value;
        } else if ($data[0] != '{') {
            return Base64::decode($data);
        }

        return $data;
    }
}Font/FontRenderer.php000064400000024377151161172430010576 0ustar00<?php

namespace Nextend\Framework\Font;

use Nextend\Framework\Settings;

class FontRenderer {

    public static $defaultFont = 'Montserrat';

    public static $pre = '';

    /**
     * @var FontStyle
     */
    public static $style;

    public static $mode;

    public static function setDefaultFont($fontFamily) {
        self::$defaultFont = $fontFamily;
    }

    public static function render($font, $mode, $pre = '',
$fontSize = false) {
        self::$pre = $pre;

        if (!empty($font)) {
            $value = json_decode($font, true);
            if ($value) {
                $selector = 'n2-font-' . md5($font) .
'-' . $mode;

                return array(
                    $selector . ' ',
                    self::renderFont($mode, $pre, $selector,
$value['data'], $fontSize)
                );
            }
        }

        return false;
    }

    private static function renderFont($mode, $pre, $selector, $tabs,
$fontSize) {
        $search  = array(
            '@pre',
            '@selector'
        );
        $replace = array(
            $pre,
            '.' . $selector
        );
        $tabs[0] = array_merge(array(
            'afont'         => self::$defaultFont,
            'color'         => '000000ff',
            'size'          => '14||px',
            'tshadow'       =>
'0|*|0|*|0|*|000000ff',
            'lineheight'    => '1.5',
            'bold'          => 0,
            'italic'        => 0,
            'underline'     => 0,
            'align'         => 'left',
            'letterspacing' => "normal",
            'wordspacing'   => "normal",
            'texttransform' => "none",
            'extra'         => ''
        ), $tabs[0]);

        if
(self::$mode[$mode]['renderOptions']['combined']) {
            for ($i = 1; $i < count($tabs); $i++) {
                $tabs[$i] = array_merge($tabs[$i - 1], $tabs[$i]);
                if ($tabs[$i]['size'] ==
$tabs[0]['size']) {
                    $tabs[$i]['size'] = '100||%';
                } else {
                    $size1 = explode('||',
$tabs[0]['size']);
                    $size2 = explode('||',
$tabs[$i]['size']);
                    if (isset($size1[1]) && isset($size2[1])
&& $size1[1] == 'px' && $size2[1] ==
'px') {
                        $tabs[$i]['size'] = round($size2[0] /
$size1[0] * 100) . '||%';
                    }
                }
            }
        }
        foreach ($tabs AS $k => $tab) {
            $search[]            = '@tab' . $k;
            FontStyle::$fontSize = $fontSize;
            $replace[]           = self::$style->style($tab);
        }

        $template = '';
        foreach (self::$mode[$mode]['selectors'] AS $s =>
$style) {
            $key = array_search($style, $search);
            if (is_numeric($key) && !empty($replace[$key])) {
                $template .= $s . "{" . $style . "}";
            }
        }

        return str_replace($search, $replace, $template);
    }
}

$frontendAccessibility =
intval(Settings::get('frontend-accessibility', 1));

FontRenderer::$mode = array(
    '0'                   => array(
        'id'            => '0',
        'label'         => n2_('Text'),
        'tabs'          => array(
            n2_('Text')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '<div
class="{fontClassName}">Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.</div>',
        'selectors'     => array(
            '@pre@selector' => '@tab0'
        )
    ),
    'simple'              => array(
        'id'            => 'simple',
        'label'         => n2_('Text'),
        'tabs'          => array(
            n2_('Text')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '<div
class="{fontClassName}">Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.</div>',
        'selectors'     => array(
            '@pre@selector' => '@tab0'
        )
    ),
    'hover'               => array(
        'id'            => 'hover',
        'label'         => n2_('Hover'),
        'tabs'          => array(
            n2_('Text'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '<div
class="{fontClassName}">' . n2_('Heading') .
'</div>',
        'selectors'     => $frontendAccessibility ? array(
            '@pre@selector'                                      
           => '@tab0',
            '@pre@selector:HOVER, @pre@selector:ACTIVE,
@pre@selector:FOCUS' => '@tab1'
        ) : array(
            '@pre@selector, @pre@selector:FOCUS'        =>
'@tab0',
            '@pre@selector:HOVER, @pre@selector:ACTIVE' =>
'@tab1'
        )
    ),
    'link'                => array(
        'id'            => 'link',
        'label'         => n2_('Link'),
        'tabs'          => array(
            n2_('Text'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '<div
class="{fontClassName}"><a href="#"
onclick="return false;">' . n2_('Button') .
'</a></div>',
        'selectors'     => $frontendAccessibility ? array(
            '@pre@selector a'                                    
                 => '@tab0',
            '@pre@selector a:HOVER, @pre@selector a:ACTIVE,
@pre@selector a:FOCUS' => '@tab1'
        ) : array(
            '@pre@selector a, @pre@selector a:FOCUS'        =>
'@tab0',
            '@pre@selector a:HOVER, @pre@selector a:ACTIVE' =>
'@tab1'
        )
    ),
    'paragraph'           => array(
        'id'            => 'paragraph',
        'label'         => n2_('Paragraph'),
        'tabs'          => array(
            n2_('Text'),
            n2_('Link'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div
class="{fontClassName}">Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed do <a href="#">test
link</a> incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
ea commodo consequat. Duis aute irure dolor in <a
href="#">test link</a> velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat <a
href="#">test link</a>, sunt in culpa qui officia
deserunt mollit anim id est laborum.</div>',
        'selectors'     => array(
            '@pre@selector'                                 =>
'@tab0',
            '@pre@selector a, @pre@selector a:FOCUS'        =>
'@tab1',
            '@pre@selector a:HOVER, @pre@selector a:ACTIVE' =>
'@tab2'
        )
    ),
    'input'               => array(
        'id'            => 'input',
        'label'         => 'Input',
        'tabs'          => array(
            n2_('Text'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '<div
class="{fontClassName}">Excepteur sint
occaecat</div>',
        'selectors'     => array(
            '@pre@selector'                            =>
'@tab0',
            '@pre@selector:HOVER, @pre@selector:FOCUS' =>
'@tab2'
        )
    ),
    'dot'                 => array(
        'id'            => 'dot',
        'label'         => n2_('Dot'),
        'tabs'          => array(
            n2_('Text'),
            n2_('Active')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '',
        'selectors'     => array(
            '@pre@selector, @pre@selector:FOCUS'                 
               => '@tab0',
            '@pre@selector.n2-active, @pre@selector:HOVER,
@pre@selector:ACTIVE' => '@tab1'
        )
    ),
    'list'                => array(
        'id'            => 'list',
        'label'         => n2_('List'),
        'tabs'          => array(
            n2_('Text'),
            n2_('Link'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '',
        'selectors'     => array(
            '@pre@selector li'                                   
=> '@tab0',
            '@pre@selector li a, @pre@selector li a:FOCUS'       
=> '@tab1',
            '@pre@selector li a:HOVER, @pre@selector li a:ACTIVE'
=> '@tab2'
        )
    ),
    'highlight'           => array(
        'id'            => 'highlight',
        'label'         => n2_('Highlight'),
        'tabs'          => array(
            n2_('Text'),
            n2_('Highlight'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div
class="{fontClassName}">' . n2_('Button') .
'</div>',
        'selectors'     => $frontendAccessibility ? array(
            '@pre@selector'                                      
                                                           =>
'@tab0',
            '@pre@selector .n2-highlighted'                      
                                                           =>
'@tab1',
            '@pre@selector .n2-highlighted:HOVER, @pre@selector
.n2-highlighted:ACTIVE, @pre@selector .n2-highlighted:FOCUS' =>
'@tab2'
        ) : array(
            '@pre@selector'                                      
                      => '@tab0',
            '@pre@selector .n2-highlighted, @pre@selector
.n2-highlighted:FOCUS'        => '@tab1',
            '@pre@selector .n2-highlighted:HOVER, @pre@selector
.n2-highlighted:ACTIVE' => '@tab2'
        )
    ),
);

FontRenderer::$style = new
FontStyle();Font/FontSettings.php000064400000006666151161172430010631
0ustar00<?php


namespace Nextend\Framework\Font;


use Nextend\Framework\Data\Data;
use Nextend\Framework\Model\Section;

class FontSettings {

    /**
     * @var Data
     */
    private static $data;

    /**
     * @var Data
     */
    private static $pluginsData;

    public function __construct() {
        self::load();
       
FontRenderer::setDefaultFont(self::$data->get('default-family'));
    }

    public static function load() {

        self::$data = new Data(array(
            'default-family'  =>
n2_x('Roboto,Arial', 'Default font'),
            'preset-families' => n2_x(implode("\n",
array(
                "Abel",
                "Arial",
                "Arimo",
                "Average",
                "Bevan",
                "Bitter",
                "'Bree Serif'",
                "Cabin",
                "Calligraffitti",
                "Chewy",
                "Comfortaa",
                "'Covered By Your Grace'",
                "'Crafty Girls'",
                "'Dancing Script'",
                "'Noto Sans'",
                "'Noto Serif'",
                "'Francois One'",
                "'Fredoka One'",
                "'Gloria Hallelujah'",
                "'Happy Monkey'",
                "'Josefin Slab'",
                "Lato",
                "Lobster",
                "'Luckiest Guy'",
                "Montserrat",
                "'Nova Square'",
                "Nunito",
                "'Open Sans'",
                "Oswald",
                "Oxygen",
                "Pacifico",
                "'Permanent Marker'",
                "'Playfair Display'",
                "'PT Sans'",
                "'Poiret One'",
                "Raleway",
                "Roboto",
                "'Rock Salt'",
                "Quicksand",
                "Satisfy",
                "'Squada One'",
                "'The Girl Next Door'",
                "'Titillium Web'",
                "'Varela Round'",
                "Vollkorn",
                "'Walter Turncoat'"
            )), 'Default font family list'),
            'plugins'         => array()
        ));

        foreach (Section::getAll('system', 'fonts') AS
$data) {
            self::$data->set($data['referencekey'],
$data['value']);
        }

        self::$pluginsData = new
Data(self::$data->get('plugins'), true);
    }

    public static function store($data) {
        if (is_array($data)) {
            foreach ($data as $key => $value) {
                if (self::$data->has($key)) {
                    self::$data->set($key, $value);
                    Section::set('system', 'fonts',
$key, $value, 1, 1);
                    unset($data[$key]);
                }
            }
            if (count($data)) {
                self::$pluginsData = new Data($data);
                Section::set('system', 'fonts',
'plugins', self::$pluginsData->toJSON(), 1, 1);

            }

            return true;
        }

        return false;
    }

    /**
     * @return Data
     */
    public static function getData() {

        return self::$data;
    }

    /**
     * @return Data
     */
    public static function getPluginsData() {

        return self::$pluginsData;
    }

    public static function getDefaultFamily() {
        return self::$data->get('default-family');
    }

    /**
     * @return array
     */
    public static function getPresetFamilies() {
        return array_filter(explode("\n",
self::$data->get('preset-families')));
    }
}

new FontSettings();Font/FontSources.php000064400000002357151161172430010445
0ustar00<?php


namespace Nextend\Framework\Font;


use Nextend\Framework\Filesystem\Filesystem;

class FontSources {

    /** @var AbstractFontSource[] */
    private static $fontSources = array();

    public function __construct() {
        $dir = dirname(__FILE__) . '/Sources/';
        foreach (Filesystem::folders($dir) AS $folder) {
            $file = $dir . $folder . '/' . $folder .
'.php';
            if (Filesystem::fileexists($file)) {
                require_once($file);
            }
        }
    }

    /**
     * @param string $class
     */
    public static function registerSource($class) {

        /** @var AbstractFontSource $source */
        $source = new $class();

        self::$fontSources[$source->getName()] = $source;
    }

    /**
     * @return AbstractFontSource[]
     */
    public static function getFontSources() {
        return self::$fontSources;
    }

    public static function onFontManagerLoad($force = false) {
        foreach (self::$fontSources AS $source) {
            $source->onFontManagerLoad($force);
        }
    }

    public static function onFontManagerLoadBackend() {
        foreach (self::$fontSources AS $source) {
            $source->onFontManagerLoadBackend();
        }
    }
}

new FontSources();Font/FontStorage.php000064400000004441151161172430010422
0ustar00<?php


namespace Nextend\Framework\Font;

use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\Plugin;

class FontStorage {

    use SingletonTrait;

    private $sets = array();

    private $fonts = array();

    private $fontsBySet = array();

    private $fontsById = array();

    protected function init() {

        Plugin::addAction('systemfontset', array(
            $this,
            'fontSet'
        ));
        Plugin::addAction('systemfont', array(
            $this,
            'fonts'
        ));
        Plugin::addAction('font', array(
            $this,
            'font'
        ));
    }

    private function load() {
        static $loaded;
        if (!$loaded) {
            Plugin::doAction('fontStorage', array(
                &$this->sets,
                &$this->fonts
            ));

            for ($i = 0; $i < count($this->fonts); $i++) {
                if
(!isset($this->fontsBySet[$this->fonts[$i]['referencekey']]))
{
                   
$this->fontsBySet[$this->fonts[$i]['referencekey']] =
array();
                }
               
$this->fontsBySet[$this->fonts[$i]['referencekey']][] =
&$this->fonts[$i];
                $this->fontsById[$this->fonts[$i]['id']]   
          = &$this->fonts[$i];
            }
            $loaded = true;
        }
    }

    public function fontSet($referenceKey, &$sets) {

        $this->load();

        for ($i = count($this->sets) - 1; $i >= 0; $i--) {
            $this->sets[$i]['system']   = 1;
            $this->sets[$i]['editable'] = 0;
            array_unshift($sets, $this->sets[$i]);
        }

    }

    public function fonts($referenceKey, &$fonts) {

        $this->load();

        if (isset($this->fontsBySet[$referenceKey])) {
            $_fonts = &$this->fontsBySet[$referenceKey];
            for ($i = count($_fonts) - 1; $i >= 0; $i--) {
                $_fonts[$i]['system']   = 1;
                $_fonts[$i]['editable'] = 0;
                array_unshift($fonts, $_fonts[$i]);
            }

        }
    }

    public function font($id, &$font) {

        $this->load();

        if (isset($this->fontsById[$id])) {
            $this->fontsById[$id]['system']   = 1;
            $this->fontsById[$id]['editable'] = 0;
            $font                             = $this->fontsById[$id];
        }
    }
}Font/FontStyle.php000064400000010243151161172430010113 0ustar00<?php


namespace Nextend\Framework\Font;


use Nextend\Framework\Parser\Color;
use Nextend\Framework\Parser\Common;
use Nextend\Framework\Plugin;
use Nextend\Framework\Sanitize;

class FontStyle {

    public static $fontSize = false;

    /**
     * @param string $tab
     *
     * @return string
     */
    public function style($tab) {
        $style = '';
        $extra = '';
        if (isset($tab['extra'])) {
            $extra = $tab['extra'];
            unset($tab['extra']);
        }
        foreach ($tab AS $k => $v) {
            $style .= $this->parse($k, $v);
        }
        $style .= $this->parse('extra', $extra);

        return $style;
    }

    /**
     * @param $property
     * @param $value
     *
     * @return mixed
     */
    public function parse($property, $value) {
        $fn = 'parse' . $property;

        return $this->$fn($value);
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseColor($v) {
        $hex = Color::hex82hex($v);
        if ($hex[1] == 'ff') {
            return 'color: #' . $hex[0] . ';';
        }

        $rgba = Color::hex2rgba($v);

        return 'color: RGBA(' . $rgba[0] . ',' .
$rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127,
2) . ');';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseSize($v) {
        if (self::$fontSize) {
            $fontSize = Common::parse($v);
            if ($fontSize[1] == 'px') {
                return 'font-size:' . ($fontSize[0] /
self::$fontSize * 100) . '%;';
            }
        }

        return 'font-size:' . Common::parse($v, '') .
';';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseTshadow($v) {
        $v    = Common::parse($v);
        $rgba = Color::hex2rgba($v[3]);
        if ($v[0] == 0 && $v[1] == 0 && $v[2] == 0) return
'text-shadow: none;';

        return 'text-shadow: ' . $v[0] . 'px ' . $v[1]
. 'px ' . $v[2] . 'px RGBA(' . $rgba[0] . ','
. $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] /
127, 2) . ');';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseAfont($v) {
        return 'font-family: ' .
Sanitize::esc_css_value($this->loadFont($v)) . ';';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseLineheight($v) {
        if ($v == '') return '';

        return 'line-height: ' . $v . ';';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseBold($v) {
        return $this->parseWeight($v);
    }

    public function parseWeight($v) {
        if ($v == '1') return 'font-weight: bold;';
        if ($v > 1) return 'font-weight: ' . intval($v) .
';';

        return 'font-weight: normal;';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseItalic($v) {
        if ($v == '1') return 'font-style: italic;';

        return 'font-style: normal;';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseUnderline($v) {
        if ($v == '1') return 'text-decoration:
underline;';

        return 'text-decoration: none;';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseAlign($v) {
        return 'text-align: ' . $v . ';';
    }

    public function parseLetterSpacing($v) {
        return 'letter-spacing: ' . $v . ';';
    }

    public function parseWordSpacing($v) {
        return 'word-spacing: ' . $v . ';';
    }

    public function parseTextTransform($v) {
        return 'text-transform: ' . $v . ';';
    }

    public function parseExtra($v) {
        return $v;
    }

    /**
     * @param $families
     *
     * @return mixed
     */
    public function loadFont($families) {
        $families = explode(',', $families);
        for ($i = 0; $i < count($families); $i++) {
            if ($families[$i] != "inherit") {
                $families[$i] =
$this->getFamily(trim(trim($families[$i]), '\'"'));
            }
        }

        return implode(',', $families);
    }

    private function getFamily($family) {
        return "'" .
Plugin::applyFilters('fontFamily', $family) . "'";
    }
}Font/ModelFont.php000064400000006715151161172430010064 0ustar00<?php

namespace Nextend\Framework\Font;

use Nextend\Framework\Form\Container\ContainerTable;
use Nextend\Framework\Form\Element\Button;
use Nextend\Framework\Form\Element\Decoration;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\Radio\TextAlign;
use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Form\Element\Select\FontWeight;
use Nextend\Framework\Form\Element\Tab;
use Nextend\Framework\Form\Element\Text\Color;
use Nextend\Framework\Form\Element\Text\Family;
use Nextend\Framework\Form\Element\Text\TextAutoComplete;
use Nextend\Framework\Form\Element\Textarea;
use Nextend\Framework\Form\Form;
use Nextend\Framework\Visual\ModelVisual;

class ModelFont extends ModelVisual {

    protected $type = 'font';

    public function renderForm() {

        $form = new Form($this, 'n2-font-editor');

        $table = new ContainerTable($form->getContainer(),
'font', n2_('Font settings'));

        $table->setFieldsetPositionEnd();

        new Button($table->getFieldsetLabel(),
'font-clear-tab', false, n2_('Clear tab'));

        new Tab($table->getFieldsetLabel(), 'font-state');

        $row1 = $table->createRow('font-row-1');
        new Family($row1, 'family', n2_('Family'),
'Arial, Helvetica', array(
            'style' => 'width:150px;'
        ));
        new Color($row1, 'color', n2_('Color'),
'000000FF', array(
            'alpha' => true
        ));

        new MixedField\FontSize($row1, 'size',
n2_('Size'), '14|*|px');

        new FontWeight($row1, 'weight', n2_('Font
weight'), '');
        new Decoration($row1, 'decoration',
n2_('Decoration'));
        new TextAutoComplete($row1, 'lineheight', n2_('Line
height'), '18px', array(
            'values' => array(
                'normal',
                '1',
                '1.2',
                '1.5',
                '1.8',
                '2'
            ),
            'style'  => 'width:70px;'
        ));
        new TextAlign($row1, 'textalign', n2_('Text
align'), 'inherit');

        $row2 = $table->createRow('font-row-2');

        new TextAutoComplete($row2, 'letterspacing',
n2_('Letter spacing'), 'normal', array(
            'values' => array(
                'normal',
                '1px',
                '2px',
                '5px',
                '10px',
                '15px'
            ),
            'style'  => 'width:50px;'
        ));
        new TextAutoComplete($row2, 'wordspacing', n2_('Word
spacing'), 'normal', array(
            'values' => array(
                'normal',
                '2px',
                '5px',
                '10px',
                '15px'
            ),
            'style'  => 'width:50px;'
        ));
        new Select($row2, 'texttransform',
n2_('Transform'), 'none', array(
            'options' => array(
                'none'       => n2_('None'),
                'capitalize' => n2_('Capitalize'),
                'uppercase'  => n2_('Uppercase'),
                'lowercase'  => n2_('Lowercase')
            )
        ));

        new MixedField\TextShadow($row2, 'tshadow',
n2_('Text shadow'), '0|*|0|*|1|*|000000FF');

        new Textarea($row2, 'extracss', 'CSS',
'', array(
            'width'  => 200,
            'height' => 26
        ));

        $previewTable = new ContainerTable($form->getContainer(),
'font-preview', n2_('Preview'));

        $previewTable->setFieldsetPositionEnd();

        new Color($previewTable->getFieldsetLabel(),
'preview-background', false, 'ced3d5');

        $form->render();
    }
}Font/Sources/GoogleFonts/families.csv000064400000025704151161172430013642
0ustar00ABeeZee
Abel
Abhaya Libre
Abril Fatface
Aclonica
Acme
Actor
Adamina
Advent Pro
Aguafina Script
Akronim
Aladin
Alata
Alatsi
Aldrich
Alef
Alegreya
Alegreya Sans
Alegreya Sans SC
Alegreya SC
Aleo
Alex Brush
Alfa Slab One
Alice
Alike
Alike Angular
Allan
Allerta
Allerta Stencil
Allura
Almarai
Almendra
Almendra Display
Almendra SC
Amarante
Amaranth
Amatic SC
Amatica SC
Amethysta
Amiko
Amiri
Amita
Anaheim
Andada
Andika
Angkor
Annie Use Your Telescope
Anonymous Pro
Antic
Antic Didone
Antic Slab
Anton
Arapey
Arbutus
Arbutus Slab
Architects Daughter
Archivo
Archivo Black
Archivo Narrow
Aref Ruqaa
Arima Madurai
Arimo
Arizonia
Armata
Arsenal
Artifika
Arvo
Arya
Asap
Asap Condensed
Asar
Asset
Assistant
Astloch
Asul
Athiti
Atma
Atomic Age
Aubrey
Audiowide
Autour One
Average
Average Sans
Averia Gruesa Libre
Averia Libre
Averia Sans Libre
Averia Serif Libre
B612
B612 Mono
Bad Script
Bahiana
Bahianita
Bai Jamjuree
Baloo
Baloo 2
Baloo Bhai
Baloo Bhai 2
Baloo Bhaijaan
Baloo Bhaina
Baloo Bhaina 2
Baloo Chettan
Baloo Chettan 2
Baloo Da
Baloo Da 2
Baloo Paaji
Baloo Paaji 2
Baloo Tamma
Baloo Tamma 2
Baloo Tammudu
Baloo Tammudu 2
Baloo Thambi
Baloo Thambi 2
Balsamiq Sans
Balthazar
Bangers
Barlow
Barlow Condensed
Barlow Semi Condensed
Barriecito
Barrio
Basic
Baskervville
Battambang
Baumans
Bayon
Be Vietnam
Bebas Neue
Belgrano
Bellefair
Belleza
Bellota
Bellota Text
BenchNine
Bentham
Berkshire Swash
Beth Ellen
Bevan
Big Shoulders Display
Big Shoulders Text
Bigelow Rules
Bigshot One
Bilbo
Bilbo Swash Caps
BioRhyme
BioRhyme Expanded
Biryani
Bitter
Black And White Picture
Black Han Sans
Black Ops One
Blinker
Bokor
Bonbon
Boogaloo
Bowlby One
Bowlby One SC
Brawler
Bree Serif
Bubblegum Sans
Bubbler One
Buda
Buenard
Bungee
Bungee Hairline
Bungee Inline
Bungee Outline
Bungee Shade
Butcherman
Butterfly Kids
Cabin
Cabin Condensed
Cabin Sketch
Caesar Dressing
Cagliostro
Cairo
Caladea
Calistoga
Calligraffitti
Cambay
Cambo
Candal
Cantarell
Cantata One
Cantora One
Capriola
Cardo
Carme
Carrois Gothic
Carrois Gothic SC
Carter One
Catamaran
Caudex
Caveat
Caveat Brush
Cedarville Cursive
Ceviche One
Chakra Petch
Changa
Changa One
Chango
Charm
Charmonman
Chathura
Chau Philomene One
Chela One
Chelsea Market
Chenla
Cherry Cream Soda
Cherry Swash
Chewy
Chicle
Chilanka
Chivo
Chonburi
Cinzel
Cinzel Decorative
Clicker Script
Coda
Coda Caption
Codystar
Coiny
Combo
Comfortaa
Comic Neue
Coming Soon
Concert One
Condiment
Content
Contrail One
Convergence
Cookie
Copse
Corben
Cormorant
Cormorant Garamond
Cormorant Infant
Cormorant SC
Cormorant Unicase
Cormorant Upright
Courgette
Courier Prime
Cousine
Coustard
Covered By Your Grace
Crafty Girls
Creepster
Crete Round
Crimson Pro
Crimson Text
Croissant One
Crushed
Cuprum
Cute Font
Cutive
Cutive Mono
Damion
Dancing Script
Dangrek
Darker Grotesque
David Libre
Dawning of a New Day
Days One
Dekko
Delius
Delius Swash Caps
Delius Unicase
Della Respira
Denk One
Devonshire
Dhurjati
Didact Gothic
Diplomata
Diplomata SC
DM Mono
DM Sans
DM Serif Display
DM Serif Text
Do Hyeon
Dokdo
Domine
Donegal One
Doppio One
Dorsa
Dosis
Dr Sugiyama
Droid Sans
Droid Sans Mono
Droid Serif
Duru Sans
Dynalight
Eagle Lake
East Sea Dokdo
Eater
EB Garamond
Economica
Eczar
Ek Mukta
El Messiri
Electrolize
Elsie
Elsie Swash Caps
Emblema One
Emilys Candy
Encode Sans
Encode Sans Condensed
Encode Sans Expanded
Encode Sans Semi Condensed
Encode Sans Semi Expanded
Engagement
Englebert
Enriqueta
Epilogue
Erica One
Esteban
Euphoria Script
Ewert
Exo
Exo 2
Expletus Sans
Fahkwang
Fanwood Text
Farro
Farsan
Fascinate
Fascinate Inline
Faster One
Fasthand
Fauna One
Faustina
Federant
Federo
Felipa
Fenix
Finger Paint
Fira Code
Fira Mono
Fira Sans
Fira Sans Condensed
Fira Sans Extra Condensed
Fjalla One
Fjord One
Flamenco
Flavors
Fondamento
Fontdiner Swanky
Forum
Francois One
Frank Ruhl Libre
Freckle Face
Fredericka the Great
Fredoka One
Freehand
Fresca
Frijole
Fruktur
Fugaz One
Gabriela
Gaegu
Gafata
Galada
Galdeano
Galindo
Gamja Flower
Gayathri
Gelasio
Gentium Basic
Gentium Book Basic
Geo
Geostar
Geostar Fill
Germania One
GFS Didot
GFS Neohellenic
Gidugu
Gilda Display
Girassol
Give You Glory
Glass Antiqua
Glegoo
Gloria Hallelujah
Goblin One
Gochi Hand
Gorditas
Gothic A1
Gotu
Goudy Bookletter 1911
Graduate
Grand Hotel
Gravitas One
Great Vibes
Grenze
Grenze Gotisch
Griffy
Gruppo
Gudea
Gugi
Gupter
Gurajada
Habibi
Halant
Hammersmith One
Hanalei
Hanalei Fill
Handlee
Hanuman
Happy Monkey
Harmattan
Headland One
Heebo
Henny Penny
Hepta Slab
Herr Von Muellerhoff
Hi Melody
Hind
Hind Guntur
Hind Madurai
Hind Siliguri
Hind Vadodara
Holtwood One SC
Homemade Apple
Homenaje
Ibarra Real Nova
IBM Plex Mono
IBM Plex Sans
IBM Plex Sans Condensed
IBM Plex Serif
Iceberg
Iceland
IM Fell Double Pica
IM Fell Double Pica SC
IM Fell DW Pica
IM Fell DW Pica SC
IM Fell English
IM Fell English SC
IM Fell French Canon
IM Fell French Canon SC
IM Fell Great Primer
IM Fell Great Primer SC
Imprima
Inconsolata
Inder
Indie Flower
Inika
Inknut Antiqua
Inria Sans
Inria Serif
Inter
Irish Grover
Istok Web
Italiana
Italianno
Itim
Jacques Francois
Jacques Francois Shadow
Jaldi
Jim Nightshade
Jockey One
Jolly Lodger
Jomhuria
Jomolhari
Josefin Sans
Josefin Slab
Jost
Joti One
Jua
Judson
Julee
Julius Sans One
Junge
Jura
Just Another Hand
Just Me Again Down Here
K2D
Kadwa
Kalam
Kameron
Kanit
Kantumruy
Karla
Karma
Katibeh
Kaushan Script
Kavivanar
Kavoon
Kdam Thmor
Keania One
Kelly Slab
Kenia
Khand
Khmer
Khula
Kirang Haerang
Kite One
Knewave
Kodchasan
KoHo
Kosugi
Kosugi Maru
Kotta One
Koulen
Kranky
Kreon
Kristi
Krona One
Krub
Kulim Park
Kumar One
Kumar One Outline
Kurale
La Belle Aurore
Lacquer
Laila
Lakki Reddy
Lalezar
Lancelot
Lateef
Lato
League Script
Leckerli One
Ledger
Lekton
Lemon
Lemonada
Lexend Deca
Lexend Exa
Lexend Giga
Lexend Mega
Lexend Peta
Lexend Tera
Lexend Zetta
Libre Barcode 128
Libre Barcode 128 Text
Libre Barcode 39
Libre Barcode 39 Extended
Libre Barcode 39 Extended Text
Libre Barcode 39 Text
Libre Baskerville
Libre Caslon Display
Libre Caslon Text
Libre Franklin
Life Savers
Lilita One
Lily Script One
Limelight
Linden Hill
Literata
Liu Jian Mao Cao
Livvic
Lobster
Lobster Two
Londrina Outline
Londrina Shadow
Londrina Sketch
Londrina Solid
Long Cang
Lora
Love Ya Like A Sister
Loved by the King
Lovers Quarrel
Luckiest Guy
Lusitana
Lustria
M PLUS 1p
M PLUS Rounded 1c
Ma Shan Zheng
Macondo
Macondo Swash Caps
Mada
Magra
Maiden Orange
Maitree
Major Mono Display
Mako
Mali
Mallanna
Mandali
Manjari
Manrope
Mansalva
Manuale
Marcellus
Marcellus SC
Marck Script
Margarine
Markazi Text
Marko One
Marmelad
Martel
Martel Sans
Marvel
Mate
Mate SC
Maven Pro
McLaren
Meddon
MedievalSharp
Medula One
Meera Inimai
Megrim
Meie Script
Merienda
Merienda One
Merriweather
Merriweather Sans
Metal
Metal Mania
Metamorphous
Metrophobic
Michroma
Milonga
Miltonian
Miltonian Tattoo
Mina
Miniver
Miriam Libre
Mirza
Miss Fajardose
Mitr
Modak
Modern Antiqua
Mogra
Molengo
Molle
Monda
Monofett
Monoton
Monsieur La Doulaise
Montaga
Montez
Montserrat
Montserrat Alternates
Montserrat Subrayada
Moul
Moulpali
Mountains of Christmas
Mouse Memoirs
Mr Bedfort
Mr Dafoe
Mr De Haviland
Mrs Saint Delafield
Mrs Sheppards
Mukta
Mukta Mahee
Mukta Malar
Mukta Vaani
Muli
Mulish
MuseoModerno
Mystery Quest
Nanum Brush Script
Nanum Gothic
Nanum Gothic Coding
Nanum Myeongjo
Nanum Pen Script
Neucha
Neuton
New Rocker
News Cycle
Niconne
Niramit
Nixie One
Nobile
Nokora
Norican
Nosifer
Notable
Nothing You Could Do
Noticia Text
Noto Sans
Noto Sans HK
Noto Sans JP
Noto Sans KR
Noto Sans SC
Noto Sans TC
Noto Serif
Noto Serif JP
Noto Serif KR
Noto Serif SC
Noto Serif TC
Nova Cut
Nova Flat
Nova Mono
Nova Oval
Nova Round
Nova Script
Nova Slim
Nova Square
NTR
Numans
Nunito
Nunito Sans
Odibee Sans
Odor Mean Chey
Offside
Old Standard TT
Oldenburg
Oleo Script
Oleo Script Swash Caps
Open Sans
Open Sans Condensed
Oranienbaum
Orbitron
Oregano
Orienta
Original Surfer
Oswald
Over the Rainbow
Overlock
Overlock SC
Overpass
Overpass Mono
Ovo
Oxanium
Oxygen
Oxygen Mono
Pacifico
Padauk
Palanquin
Palanquin Dark
Pangolin
Paprika
Parisienne
Passero One
Passion One
Pathway Gothic One
Patrick Hand
Patrick Hand SC
Pattaya
Patua One
Pavanam
Paytone One
Peddana
Peralta
Permanent Marker
Petit Formal Script
Petrona
Philosopher
Piedra
Pinyon Script
Pirata One
Plaster
Play
Playball
Playfair Display
Playfair Display SC
Podkova
Poiret One
Poller One
Poly
Pompiere
Pontano Sans
Poor Story
Poppins
Port Lligat Sans
Port Lligat Slab
Pragati Narrow
Prata
Preahvihear
Press Start 2P
Pridi
Princess Sofia
Prociono
Prompt
Prosto One
Proza Libre
PT Mono
PT Sans
PT Sans Caption
PT Sans Narrow
PT Serif
PT Serif Caption
Public Sans
Puritan
Purple Purse
Quando
Quantico
Quattrocento
Quattrocento Sans
Questrial
Quicksand
Quintessential
Qwigley
Racing Sans One
Radley
Rajdhani
Rakkas
Raleway
Raleway Dots
Ramabhadra
Ramaraja
Rambla
Rammetto One
Ranchers
Rancho
Ranga
Rasa
Rationale
Ravi Prakash
Red Hat Display
Red Hat Text
Redressed
Reem Kufi
Reenie Beanie
Revalia
Rhodium Libre
Ribeye
Ribeye Marrow
Righteous
Risque
Roboto
Roboto Condensed
Roboto Mono
Roboto Slab
Rochester
Rock Salt
Rokkitt
Romanesco
Ropa Sans
Rosario
Rosarivo
Rouge Script
Rowdies
Rozha One
Rubik
Rubik Mono One
Rubik One
Ruda
Rufina
Ruge Boogie
Ruluko
Rum Raisin
Ruslan Display
Russo One
Ruthie
Rye
Sacramento
Sahitya
Sail
Saira
Saira Condensed
Saira Extra Condensed
Saira Semi Condensed
Saira Stencil One
Salsa
Sanchez
Sancreek
Sansita
Sansita One
Sarabun
Sarala
Sarina
Sarpanch
Satisfy
Sawarabi Gothic
Sawarabi Mincho
Scada
Scheherazade
Schoolbell
Scope One
Seaweed Script
Secular One
Sedgwick Ave
Sedgwick Ave Display
Sen
Sevillana
Seymour One
Shadows Into Light
Shadows Into Light Two
Shanti
Share
Share Tech
Share Tech Mono
Shojumaru
Short Stack
Shrikhand
Siemreap
Sigmar One
Signika
Signika Negative
Simonetta
Single Day
Sintony
Sirin Stencil
Six Caps
Skranji
Slabo 13px
Slabo 27px
Slackey
Smokum
Smythe
Sniglet
Snippet
Snowburst One
Sofadi One
Sofia
Solway
Song Myung
Sonsie One
Sora
Sorts Mill Goudy
Source Code Pro
Source Sans Pro
Source Serif Pro
Space Mono
Spartan
Special Elite
Spectral
Spectral SC
Spicy Rice
Spinnaker
Spirax
Squada One
Sree Krushnadevaraya
Sriracha
Srisakdi
Staatliches
Stalemate
Stalinist One
Stardos Stencil
Stint Ultra Condensed
Stint Ultra Expanded
Stoke
Strait
Stylish
Sue Ellen Francisco
Suez One
Sulphur Point
Sumana
Sunflower
Sunshiney
Supermercado One
Sura
Suranna
Suravaram
Suwannaphum
Swanky and Moo Moo
Syncopate
Tajawal
Tangerine
Taprom
Tauri
Taviraj
Teko
Telex
Tenali Ramakrishna
Tenor Sans
Text Me One
Thasadith
The Girl Next Door
Tienne
Tillana
Timmana
Tinos
Titan One
Titillium Web
Tomorrow
Trade Winds
Trirong
Trocchi
Trochut
Trykker
Tulpen One
Turret Road
Ubuntu
Ubuntu Condensed
Ubuntu Mono
Ultra
Uncial Antiqua
Underdog
Unica One
UnifrakturCook
UnifrakturMaguntia
Unkempt
Unlock
Unna
Vampiro One
Varela
Varela Round
Varta
Vast Shadow
Vesper Libre
Viaoda Libre
Vibes
Vibur
Vidaloka
Viga
Voces
Volkhov
Vollkorn
Vollkorn SC
Voltaire
VT323
Waiting for the Sunrise
Wallpoet
Walter Turncoat
Warnes
Wellfleet
Wendy One
Wire One
Work Sans
Yanone Kaffeesatz
Yantramanav
Yatra One
Yellowtail
Yeon Sung
Yeseva One
Yesteryear
Yrsa
ZCOOL KuaiLe
ZCOOL QingKe HuangYou
ZCOOL XiaoWei
Zeyad
Zeyada
Zhi Mang Xing
Zilla Slab
Zilla Slab
HighlightFont/Sources/GoogleFonts/GoogleFonts.php000064400000020241151161172430014262
0ustar00<?php


namespace Nextend\Framework\Font\Sources\GoogleFonts;

use Nextend\Framework\Asset\AssetManager;
use Nextend\Framework\Asset\Fonts\Google\Google;
use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Font\AbstractFontSource;
use Nextend\Framework\Font\FontSettings;
use Nextend\Framework\Font\FontSources;
use Nextend\Framework\Form\Container\ContainerRowGroup;
use Nextend\Framework\Form\Element\OnOff;
use Nextend\Framework\Form\Fieldset\FieldsetRow;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Plugin;


/*
jQuery.getJSON('https://www.googleapis.com/webfonts/v1/webfonts?sort=alpha&key=AIzaSyBIzBtder0-ef5a6kX-Ri9IfzVwFu21PGw').done(function(data){
var f = [];
for(var i = 0; i < data.items.length; i++){
f.push(data.items[i].family);
}
console.log(JSON.stringify(f));
});
*/

class GoogleFonts extends AbstractFontSource {

    protected $name = 'google';

    private static $fonts = array();

    private static $styles = array();
    private static $subsets = array();

    public function __construct() {
        $lines = file(dirname(__FILE__) . '/families.csv',
FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        for ($i = 0; $i < count($lines); $i++) {
            self::$fonts[strtolower($lines[$i])] = $lines[$i];
        }
        self::$fonts['droid sans']      = 'Noto Sans';
        self::$fonts['droid sans mono'] = 'Roboto
Mono';
        self::$fonts['droid serif']     = 'Noto Serif';
    }

    public function getLabel() {
        return 'Google';
    }

    public function renderFields($container) {

        $row1 = new FieldsetRow($container, 'fonts-google-1');
        new OnOff($row1, 'google-enabled',
n2_('Frontend'), 1, array(
            'tipLabel'       => n2_('Frontend'),
            'tipDescription' => n2_('You can load Google
Fonts on the frontend.')
        ));
        new OnOff($row1, 'google-enabled-backend',
n2_('Backend'), 1, array(
            'tipLabel'       => n2_('Backend'),
            'tipDescription' => n2_('You can load Google
Fonts in the backend.')
        ));

        $rowGroupStyle = new ContainerRowGroup($container,
'fonts-google-style', n2_('Style'));
        $rowStyle      =
$rowGroupStyle->createRow('fonts-google-style');
        new OnOff($rowStyle, 'google-style-100', '100',
0);
        new OnOff($rowStyle, 'google-style-100italic', '100
' . n2_x('Italic', "Font style"), 0);
        new OnOff($rowStyle, 'google-style-200', '200',
0);
        new OnOff($rowStyle, 'google-style-200italic', '200
' . n2_x('Italic', "Font style"), 0);
        new OnOff($rowStyle, 'google-style-300', '300',
1);
        new OnOff($rowStyle, 'google-style-300italic', '300
' . n2_x('Italic', "Font style"), 0);
        new OnOff($rowStyle, 'google-style-400',
n2_('Normal'), 1);
        new OnOff($rowStyle, 'google-style-400italic',
n2_('Normal') . ' ' . n2_x('Italic',
"Font style"), 0);
        new OnOff($rowStyle, 'google-style-500', '500',
0);
        new OnOff($rowStyle, 'google-style-500italic', '500
' . n2_x('Italic', "Font style"), 0);
        new OnOff($rowStyle, 'google-style-600', '600',
0);
        new OnOff($rowStyle, 'google-style-600italic', '600
' . n2_x('Italic', "Font style"), 0);
        new OnOff($rowStyle, 'google-style-700', '700',
0);
        new OnOff($rowStyle, 'google-style-700italic', '700
' . n2_x('Italic', "Font style"), 0);
        new OnOff($rowStyle, 'google-style-800', '800',
0);
        new OnOff($rowStyle, 'google-style-800italic', '800
' . n2_x('Italic', "Font style"), 0);
        new OnOff($rowStyle, 'google-style-900', '900',
0);
        new OnOff($rowStyle, 'google-style-900italic', '900
' . n2_x('Italic', "Font style"), 0);


        $rowGroupCharacterSet = new ContainerRowGroup($container,
'fonts-google-character-set', n2_('Character set'));
        $rowCharacterSet      =
$rowGroupCharacterSet->createRow('fonts-google-character-set');
        new OnOff($rowCharacterSet, 'google-set-latin',
n2_x('Latin', "Character set"), 1);
        new OnOff($rowCharacterSet, 'google-set-latin-ext',
n2_x('Latin Extended', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-greek',
n2_x('Greek', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-greek-ext',
n2_x('Greek Extended', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-cyrillic',
n2_x('Cyrillic', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-devanagari',
n2_x('Devanagari', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-arabic',
n2_x('Arabic', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-khmer',
n2_x('Khmer', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-telugu',
n2_x('Telugu', "Character set"), 0);
        new OnOff($rowCharacterSet, 'google-set-vietnamese',
n2_x('Vietnamese', "Character set"), 0);
    }

    public static function getDefaults() {
        $defaults  = array();
        $fontsSets = explode(',', n2_x('latin',
'Default font sets'));
        for ($i = 0; $i < count($fontsSets); $i++) {
            $fontsSets[$i] = 'google-set-' . $fontsSets[$i];
        }
        $defaults += array_fill_keys($fontsSets, 1);

        return $defaults;
    }

    public function getPath() {
        return dirname(__FILE__) . DIRECTORY_SEPARATOR . 'google'
. DIRECTORY_SEPARATOR;
    }

    public function onFontManagerLoad($force = false) {
        static $loaded;
        if (!$loaded || $force) {
            $loaded     = true;
            $parameters = FontSettings::getPluginsData();

            $parameters->fillDefault(self::getDefaults());

            if ((!Platform::isAdmin() &&
$parameters->get('google-enabled', 1)) || (Platform::isAdmin()
&& $parameters->get('google-enabled-backend', 1))) {
                Google::$enabled = 1;

                for ($i = 100; $i < 1000; $i += 100) {
                    $this->addStyle($parameters, $i);
                    $this->addStyle($parameters, $i .
'italic');
                }
                if (empty(self::$styles)) {
                    self::$styles[] = '300';
                    self::$styles[] = '400';
                }

                $this->addSubset($parameters, 'latin');
                $this->addSubset($parameters, 'latin-ext');
                $this->addSubset($parameters, 'greek');
                $this->addSubset($parameters, 'greek-ext');
                $this->addSubset($parameters, 'cyrillic');
                $this->addSubset($parameters, 'devanagari');
                $this->addSubset($parameters, 'arabic');
                $this->addSubset($parameters, 'khmer');
                $this->addSubset($parameters, 'telugu');
                $this->addSubset($parameters, 'vietnamese');
                if (empty(self::$subsets)) {
                    self::$subsets[] = 'latin';
                }
                foreach (self::$subsets as $subset) {
                    Google::addSubset($subset);
                }
                Plugin::addAction('fontFamily', array(
                    $this,
                    'onFontFamily'
                ));
            }
        }
    }

    public function onFontManagerLoadBackend() {
        $parameters = FontSettings::getPluginsData();

        $parameters->fillDefault(self::getDefaults());

        if ($parameters->get('google-enabled-backend', 1)) {
            Js::addInline('new
_N2.NextendFontServiceGoogle("' . implode(',',
self::$styles) . '","' . implode(',',
self::$subsets) . '", ' . json_encode(self::$fonts) .
', ' .
json_encode(AssetManager::$googleFonts->getLoadedFamilies()) .
');');
        }
    }

    function addStyle($parameters, $weight) {
        if ($parameters->get('google-style-' . $weight, 0)) {
            self::$styles[] = $weight;
        }
    }

    function addSubset($parameters, $subset) {
        if ($parameters->get('google-set-' . $subset, 0)) {
            self::$subsets[] = $subset;
        }
    }

    function onFontFamily($family) {
        $familyLower = strtolower($family);
        if (isset(self::$fonts[$familyLower])) {
            foreach (self::$styles as $style) {
                Google::addFont(self::$fonts[$familyLower], $style);
            }

            return self::$fonts[$familyLower];
        }

        return $family;
    }
}

FontSources::registerSource(GoogleFonts::class);Form/AbstractContainer.php000064400000002751151161172430011574
0ustar00<?php


namespace Nextend\Framework\Form;


abstract class AbstractContainer implements ContainerContainedInterface {

    use TraitContainer;

    /**
     * @var ContainerContainedInterface
     */
    protected $first, $last;

    protected $controlName = '';

    /**
     * @var ContainerInterface;
     */
    private $previous, $next;

    public function getPrevious() {
        return $this->previous;
    }

    /**
     * @param ContainedInterface|null $element
     */
    public function setPrevious($element = null) {
        $this->previous = $element;
    }

    public function getNext() {
        return $this->next;
    }

    /**
     * @param ContainedInterface|null $element
     */
    public function setNext($element = null) {
        $this->next = $element;
        if ($element) {
            $element->setPrevious($this);
        }
    }

    public function remove() {
        $this->getParent()
             ->removeElement($this);
    }

    public function render() {
        $this->renderContainer();
    }

    public function renderContainer() {
        $element = $this->first;
        while ($element) {
            $element->renderContainer();
            $element = $element->getNext();
        }
    }

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

    /**
     * @param string $controlName
     */
    public function setControlName($controlName) {
        $this->controlName = $controlName;
    }
}Form/AbstractField.php000064400000017711151161172430010677
0ustar00<?php


namespace Nextend\Framework\Form;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Insert\AbstractInsert;
use Nextend\Framework\View\Html;

abstract class AbstractField implements ContainedInterface {

    /**
     * @var AbstractField;
     */
    private $previous, $next;

    public function getPrevious() {
        return $this->previous;
    }

    /**
     * @param AbstractField|null $element
     */
    public function setPrevious($element = null) {
        $this->previous = $element;
    }

    public function getNext() {
        return $this->next;
    }

    /**
     * @param AbstractField|null $element
     */
    public function setNext($element = null) {
        $this->next = $element;
        if ($element) {
            $element->setPrevious($this);
        }
    }

    public function remove() {
        $this->getParent()
             ->removeElement($this);
    }

    /**
     * @var TraitFieldset
     */
    protected $parent;

    protected $name = '';

    protected $label = '';

    protected $controlName = '';

    protected $defaultValue;

    protected $fieldID;

    private $exposeName = true;

    protected $tip = '';

    protected $tipLabel = '';

    protected $tipDescription = '';

    protected $tipLink = '';

    protected $rowClass = '';

    protected $rowAttributes = array();

    protected $class = '';

    protected $style = '';

    protected $post = '';

    protected $relatedFields = array();

    protected $relatedFieldsOff = array();

    /**
     * AbstractField constructor.
     *
     * @param TraitFieldset|AbstractInsert $insertAt
     * @param string                       $name
     * @param string                       $label
     * @param string                       $default
     * @param array                        $parameters
     */
    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {

        $this->name  = $name;
        $this->label = $label;

        if ($insertAt instanceof ContainerInterface) {
            $this->parent = $insertAt;
            $this->parent->addElement($this);
        } else if ($insertAt instanceof AbstractInsert) {
            $this->parent = $insertAt->insert($this);
        }

        $this->controlName = $this->parent->getControlName();

        $this->fieldID = $this->generateId($this->controlName .
$this->name);

        $this->defaultValue = $default;

        foreach ($parameters as $option => $value) {
            $option = 'set' . $option;
            $this->{$option}($value);
        }
    }

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

    public function setDefaultValue($defaultValue) {
        $this->defaultValue = $defaultValue;
    }

    public function setExposeName($exposeName) {
        $this->exposeName = $exposeName;
    }

    public function getPost() {
        return $this->post;
    }

    public function setPost($post) {
        $this->post = $post;
    }

    /**
     * @param string $tip
     */
    public function setTip($tip) {
        $this->tip = $tip;
    }

    /**
     * @param string $tipLabel
     */
    public function setTipLabel($tipLabel) {
        $this->tipLabel = $tipLabel;
    }

    /**
     * @param string $tipDescription
     */
    public function setTipDescription($tipDescription) {
        $this->tipDescription = $tipDescription;
    }

    /**
     * @param string $tipLink
     */
    public function setTipLink($tipLink) {
        $this->tipLink = $tipLink;
    }

    public function setRowClass($rowClass) {
        $this->rowClass .= $rowClass;
    }

    public function getRowClass() {
        return $this->rowClass;
    }

    public function getClass() {
        return $this->class;
    }

    public function setClass($class) {
        $this->class = $class;
    }

    protected function getFieldName() {
        if ($this->exposeName) {
            return $this->controlName . '[' . $this->name .
']';
        }

        return '';
    }

    public function render() {

        return array(
            $this->fetchTooltip(),
            $this->fetchElement()
        );
    }

    public function displayLabel() {

        echo $this->fetchTooltip();
    }

    public function displayElement() {

        echo $this->fetchElement();
    }

    protected function fetchTooltip() {

        if ($this->label === false || $this->label === '')
{
            return '';
        }

        $attributes = array(
            'for' => $this->fieldID
        );


        $post = '';
        if (!empty($this->tipDescription)) {
            $tipAttributes = array(
                'class'                => 'ssi_16
ssi_16--info',
                'data-tip-description' =>
$this->tipDescription
            );
            if (!empty($this->tipLabel)) {
                $tipAttributes['data-tip-label'] =
$this->tipLabel;
            }
            if (!empty($this->tipLink)) {
                $tipAttributes['data-tip-link'] =
$this->tipLink;
            }
            $post .= Html::tag('i', $tipAttributes);
        }

        return Html::tag('label', $attributes, $this->label) .
$post;
    }

    protected function fetchNoTooltip() {
        return "";
    }

    /**
     * @return string
     */
    abstract protected function fetchElement();

    public function getValue() {
        return $this->getForm()
                    ->get($this->name, $this->defaultValue);
    }

    public function setValue($value) {
        $this->parent->getForm()
                     ->set($this->name, $value);
    }

    /**
     * @param array $rowAttributes
     */
    public function setRowAttributes($rowAttributes) {
        $this->rowAttributes = $rowAttributes;
    }

    /**
     * @return array
     */
    public function getRowAttributes() {
        return $this->rowAttributes;
    }

    public function setStyle($style) {
        $this->style = $style;
    }

    protected function getStyle() {
        return $this->style;
    }

    /**
     * @param string $relatedFields
     */
    public function setRelatedFields($relatedFields) {
        $this->relatedFields = $relatedFields;
    }

    public function setRelatedFieldsOff($relatedFieldsOff) {
        $this->relatedFieldsOff = $relatedFieldsOff;
    }

    protected function renderRelatedFields() {
        if (!empty($this->relatedFields) ||
!empty($this->relatedFieldsOff)) {
            $options = array(
                'relatedFieldsOn'  => $this->relatedFields,
                'relatedFieldsOff' =>
$this->relatedFieldsOff
            );
            Js::addInline('new _N2.FormRelatedFields("' .
$this->fieldID . '", ' . json_encode($options) .
');');
        }
    }

    /**
     * @param $name
     *
     * @return string
     */
    protected function generateId($name) {

        return str_replace(array(
            '[',
            ']',
            ' '
        ), array(
            '',
            '',
            ''
        ), $name);
    }

    public function getLabelClass() {
        if ($this->label === false) {
            return 'n2_field--label-none';
        } else if ($this->label === '') {
            return 'n2_field--label-placeholder';
        }

        return '';
    }

    /**
     * @return bool
     */
    public function hasLabel() {
        return !empty($this->label);
    }

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

    /**
     * @return Form
     */
    public function getForm() {
        return $this->parent->getForm();
    }

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

    /**
     * @param string $controlName
     */
    public function setControlName($controlName) {
        $this->controlName = $controlName;
    }

    /**
     * @return TraitFieldset
     */
    public function getParent() {
        return $this->parent;
    }

    public function getPath() {
        return $this->parent->getPath() . '/' .
$this->name;
    }
}Form/AbstractFieldset.php000064400000005644151161172430011415
0ustar00<?php


namespace Nextend\Framework\Form;

use Nextend\Framework\Form\Insert\AbstractInsert;

abstract class AbstractFieldset implements ContainerContainedInterface {

    use TraitFieldset;

    /**
     * @var ContainedInterface;
     */
    private $previous, $next;

    public function getPrevious() {
        return $this->previous;
    }

    public function setPrevious($element = null) {
        $this->previous = $element;
    }

    public function getNext() {
        return $this->next;
    }

    public function setNext($element = null) {
        $this->next = $element;
        if ($element) {
            $element->setPrevious($this);
        }
    }

    public function remove() {
        $this->getParent()
             ->removeElement($this);
    }

    /**
     * @var ContainerInterface
     */
    protected $parent;

    protected $name = '';

    protected $label = '';

    protected $controlName = '';

    protected $class = '';

    /**
     * Container constructor.
     *
     * @param ContainerInterface|AbstractInsert $insertAt
     * @param                                   $name
     * @param boolean|string                    $label
     * @param array                             $parameters
     */
    public function __construct($insertAt, $name, $label = false,
$parameters = array()) {

        $this->name  = $name;
        $this->label = $label;

        if ($insertAt instanceof ContainerInterface) {
            $this->parent = $insertAt;
            $this->parent->addElement($this);
        } else if ($insertAt instanceof AbstractInsert) {
            $this->parent = $insertAt->insert($this);
        }

        $this->controlName = $this->parent->getControlName();

        foreach ($parameters AS $option => $value) {
            $option = 'set' . $option;
            $this->{$option}($value);
        }

    }

    public function render() {
        $this->renderContainer();
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        ob_start();

        $element->displayElement();

        return ob_get_clean();
    }

    /**
     * @return bool
     */
    public function hasLabel() {
        return !empty($this->label);
    }

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

    /**
     * @return Form
     */
    public function getForm() {
        return $this->parent->getForm();
    }

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

    /**
     * @param string $controlName
     */
    public function setControlName($controlName) {
        $this->controlName = $controlName;
    }

    public function hasFields() {

        return !empty($this->flattenElements);
    }

    /**
     * @param string $class
     */
    public function setClass($class) {
        $this->class = $class;
    }
}Form/AbstractFormManager.php000064400000000540151161172430012042
0ustar00<?php


namespace Nextend\Framework\Form;


use Nextend\Framework\Pattern\MVCHelperTrait;

abstract class AbstractFormManager {

    use MVCHelperTrait;

    /**
     * AbstractFormManager constructor.
     *
     * @param MVCHelperTrait $MVCHelper
     */
    public function __construct($MVCHelper) {

        $this->setMVCHelper($MVCHelper);
    }
}Form/Base/PlatformFormBase.php000064400000000402151161172430012232
0ustar00<?php


namespace Nextend\Framework\Form\Base;

class PlatformFormBase {

    public function tokenize() {
        return '';
    }

    public function tokenizeUrl() {
        return '';
    }

    public function checkToken() {
        return true;
    }
}Form/ContainedInterface.php000064400000001266151161172430011713
0ustar00<?php


namespace Nextend\Framework\Form;


interface ContainedInterface {

    /**
     * @return ContainedInterface|null
     */
    public function getPrevious();

    /**
     * @param ContainedInterface|null $element
     */
    public function setPrevious($element = null);

    /**
     * @return ContainedInterface|null
     */
    public function getNext();

    /**
     * @param ContainedInterface|null $element
     */
    public function setNext($element = null);

    public function remove();

    /**
     * @return ContainerInterface
     */
    public function getParent();

    /**
     * @return string
     */
    public function getPath();

    public function render();
}Form/Container/ContainerAlternative.php000064400000000313151161172430014221
0ustar00<?php


namespace Nextend\Framework\Form\Container;


use Nextend\Framework\Form\ContainerGeneral;

class ContainerAlternative extends ContainerGeneral {

    public function renderContainer() {

    }
}Form/Container/ContainerRowGroup.php000064400000001562151161172430013536
0ustar00<?php


namespace Nextend\Framework\Form\Container;


use Nextend\Framework\Form\ContainerGeneral;
use Nextend\Framework\Form\Fieldset\FieldsetRow;

class ContainerRowGroup extends ContainerGeneral {

    public function renderContainer() {
        echo '<div class="n2_form__table_row_group"
data-field="table-row-group-' . $this->name .
'">';
        if ($this->label !== false) {
            echo '<div
class="n2_form__table_row_group_label">';
            echo $this->label;
            echo '</div>';
        }

        echo '<div class="n2_form__table_row_group_rows"
data-field="table-row-group-rows-' . $this->name .
'">';
        parent::renderContainer();
        echo '</div>';
        echo '</div>';
    }

    /**
     * @param $name
     *
     * @return FieldsetRow
     */
    public function createRow($name) {

        return new FieldsetRow($this, $name);
    }
}Form/Container/ContainerSubform.php000064400000000675151161172430013373
0ustar00<?php


namespace Nextend\Framework\Form\Container;


use Nextend\Framework\Form\ContainerGeneral;

class ContainerSubform extends ContainerGeneral {

    public function renderContainer() {
        echo '<div id="' . $this->getId() .
'" class="n2_form__subform">';
        parent::renderContainer();
        echo '</div>';
    }

    public function getId() {
        return 'n2_form__subform_' . $this->controlName .
'_' . $this->name;
    }
}Form/Container/ContainerTab.php000064400000001062151161172430012453
0ustar00<?php


namespace Nextend\Framework\Form\Container;


use Nextend\Framework\Form\ContainerGeneral;

class ContainerTab extends ContainerGeneral {

    public function renderContainer() {
        echo '<div class="n2_form__tab"
data-related-form="' . $this->getForm()
                                                                   
->getId() . '" data-tab="' . $this->getId() .
'">';
        parent::renderContainer();
        echo '</div>';
    }

    public function getId() {
        return 'n2_form__tab_' . $this->controlName .
'_' . $this->name;
    }
}Form/Container/ContainerTable.php000064400000004173151161172430013002
0ustar00<?php


namespace Nextend\Framework\Form\Container;

use Nextend\Framework\Form\ContainerGeneral;
use Nextend\Framework\Form\Fieldset\FieldsetRow;
use Nextend\Framework\Form\Fieldset\FieldsetTableLabel;

class ContainerTable extends ContainerGeneral {

    /**
     * @var FieldsetTableLabel
     */
    protected $fieldsetLabel;

    protected $fieldsetLabelPosition = 'start';

    public function __construct($insertAt, $name, $label = false,
$parameters = array()) {
        parent::__construct($insertAt, $name, $label, $parameters);

        $labelContainer      = new ContainerAlternative($this, $name .
'-container-label');
        $this->fieldsetLabel = new FieldsetTableLabel($labelContainer,
$name . '-label', false);
    }

    public function renderContainer() {
        echo '<div class="n2_form__table"
data-field="table-' . $this->name . '">';
        echo '<div
class="n2_form__table_label">';
        echo '<div
class="n2_form__table_label_title">';
        echo $this->label;
        echo '</div>';
        if ($this->fieldsetLabel->hasFields()) {
            echo '<div class="n2_form__table_label_fields
n2_form__table_label_fields--' . $this->fieldsetLabelPosition .
'">';
            $this->fieldsetLabel->renderContainer();
            echo '</div>';
        }
        echo '</div>';

        if ($this->first) {
            echo '<div class="n2_form__table_rows"
data-field="table-rows-' . $this->name .
'">';
            parent::renderContainer();
            echo '</div>';
        }
        echo '</div>';
    }

    /**
     * @param $name
     *
     * @return FieldsetRow
     */
    public function createRow($name) {

        return new FieldsetRow($this, $name);
    }

    /**
     * @param        $name
     * @param string $label
     *
     * @return ContainerRowGroup
     */
    public function createRowGroup($name, $label) {

        return new ContainerRowGroup($this, $name, $label);
    }

    /**
     * @return FieldsetTableLabel
     */
    public function getFieldsetLabel() {
        return $this->fieldsetLabel;
    }

    public function setFieldsetPositionEnd() {
        $this->fieldsetLabelPosition = 'end';
    }

}Form/Container/LayerWindow/ContainerAnimation.php000064400000002107151161172430016131
0ustar00<?php


namespace Nextend\Framework\Form\Container\LayerWindow;


use Nextend\Framework\Form\ContainerGeneral;

class ContainerAnimation extends ContainerGeneral {

    /**
     * @param $name
     * @param $label
     *
     * @return ContainerAnimationTab
     */
    public function createTab($name, $label) {
        return new ContainerAnimationTab($this, $name, $label);
    }

    public function renderContainer() {
        echo '<div class="n2_container_animation"
data-field="animation-' . $this->name .
'">';
        echo '<div
class="n2_container_animation__buttons">';

        $element = $this->first;
        while ($element) {

            if ($element instanceof ContainerAnimationTab) {
                echo '<div
class="n2_container_animation__button"
data-related-tab="' . $element->getName() .
'">' . $element->getLabel() .
'</div>';
            }

            $element = $element->getNext();
        }

        echo '</div>';
        echo '<div
class="n2_container_animation__tabs">';
        parent::renderContainer();
        echo '</div>';
        echo '</div>';
    }
}Form/Container/LayerWindow/ContainerAnimationTab.php000064400000000552151161172430016562
0ustar00<?php


namespace Nextend\Framework\Form\Container\LayerWindow;


use Nextend\Framework\Form\ContainerGeneral;

class ContainerAnimationTab extends ContainerGeneral {

    public function renderContainer() {
        echo '<div class="n2_container_animation__tab"
data-tab="' . $this->name . '">';
        parent::renderContainer();
        echo '</div>';
    }
}Form/Container/LayerWindow/ContainerDesign.php000064400000002042151161172430015421
0ustar00<?php


namespace Nextend\Framework\Form\Container\LayerWindow;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\ContainerGeneral;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\View\Html;

class ContainerDesign extends ContainerGeneral {

    public function __construct(ContainerInterface $insertAt, $name) {
        parent::__construct($insertAt, $name);
    }

    public function renderContainer() {

        $id = 'n2_css_' . $this->name;

        echo Html::openTag('div', array(
            'id'    => $id,
            'class' => 'n2_ss_design_' .
$this->name
        ));

        $element = $this->first;
        while ($element) {
            $element->renderContainer();
            $element = $element->getNext();
        }

        echo Html::closeTag('div');

        $options = array(
            'ajaxUrl' => $this->getForm()
                              ->createAjaxUrl('css/index')
        );

        Js::addInline('new _N2.BasicCSS(' . json_encode($id) .
', ' . json_encode($options) . ');');
    }
}Form/Container/LayerWindow/ContainerSettings.php000064400000001101151161172450016005
0ustar00<?php


namespace Nextend\Framework\Form\Container\LayerWindow;


use Nextend\Framework\Form\ContainerGeneral;
use Nextend\Framework\Form\ContainerInterface;

class ContainerSettings extends ContainerGeneral {

    public function __construct(ContainerInterface $insertAt, $name,
$parameters = array()) {
        parent::__construct($insertAt, $name, false, $parameters);
    }

    public function renderContainer() {
        echo '<div class="n2_ss_layer_window__tab_panel"
data-panel="' . $this->name . '">';
        parent::renderContainer();
        echo '</div>';
    }
}Form/ContainerContainedInterface.php000064400000000205151161172450013550
0ustar00<?php


namespace Nextend\Framework\Form;


interface ContainerContainedInterface extends ContainerInterface,
ContainedInterface {

}Form/ContainerGeneral.php000064400000005213151161172450011404
0ustar00<?php

namespace Nextend\Framework\Form;

use Nextend\Framework\Form\Insert\AbstractInsert;

class ContainerGeneral extends AbstractContainer {

    /**
     * @var ContainerInterface
     */
    protected $parent;

    protected $name = '';

    protected $label = '';

    protected $class = '';

    /**
     * Container constructor.
     *
     * @param ContainerInterface|AbstractInsert $insertAt
     * @param string                            $name
     * @param boolean|string                    $label
     * @param array                             $parameters
     */
    public function __construct($insertAt, $name, $label = false,
$parameters = array()) {

        $this->name  = $name;
        $this->label = $label;

        if ($insertAt instanceof ContainerInterface) {
            $this->parent = $insertAt;
            $this->parent->addElement($this);
        } else if ($insertAt instanceof AbstractInsert) {
            $this->parent = $insertAt->insert($this);
        }

        $this->controlName = $this->parent->getControlName();

        foreach ($parameters AS $option => $value) {
            $option = 'set' . $option;
            $this->{$option}($value);
        }

    }

    public function removeElement($element) {
        $previous = $element->getPrevious();
        $next     = $element->getNext();

        if ($this->first === $element) {
            $this->first = $next;
        }

        if ($this->last === $element) {
            $this->last = $previous;
        }

        if ($previous) {
            $previous->setNext($next);
        } else {
            $next->setPrevious();
        }
    }

    /**
     * @return ContainerInterface
     */
    public function getParent() {
        return $this->parent;
    }

    public function getPath() {
        return $this->parent->getPath() . '/' .
$this->name;
    }

    /**
     * @param string $class
     */
    public function setClass($class) {
        $this->class = $class;
    }

    /**
     * @return bool
     */
    public function hasLabel() {
        return !empty($this->label);
    }

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

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

    /**
     * @return Form
     */
    public function getForm() {
        return $this->parent->getForm();
    }

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

    /**
     * @param string $controlName
     */
    public function setControlName($controlName) {
        $this->controlName = $controlName;
    }
}Form/ContainerInterface.php000064400000002022151161172450011722
0ustar00<?php


namespace Nextend\Framework\Form;


interface ContainerInterface {

    /**
     * @param ContainedInterface $element
     */
    public function addElement($element);

    /**
     * @param ContainedInterface $element
     * @param ContainedInterface $target
     */
    public function insertElementBefore($element, $target);

    /**
     * @param ContainedInterface $element
     * @param ContainedInterface $target
     */
    public function insertElementAfter($element, $target);

    /**
     * @param ContainedInterface $element
     */
    public function removeElement($element);

    /**
     * @param $path
     *
     * @return ContainedInterface
     */
    public function getElement($path);

    /**
     * @return string
     */
    public function getPath();

    /**
     * @return Form
     */
    public function getForm();

    /**
     * @return string
     */
    public function getName();

    /**
     * @return string
     */
    public function getControlName();

    public function renderContainer();
}Form/ContainerMain.php000064400000003074151161172450010716
0ustar00<?php


namespace Nextend\Framework\Form;


use Nextend\Framework\Form\Fieldset\FieldsetHidden;

class ContainerMain extends AbstractContainer {

    /**
     * @var Form
     */
    protected $form;

    /**
     * @var FieldsetHidden
     */
    protected $fieldsetHidden;

    /**
     * ContainerMain constructor.
     *
     * @param Form $form
     */
    public function __construct($form) {
        $this->form        = $form;
        $this->controlName = $form->getControlName();

        $this->fieldsetHidden = new FieldsetHidden($this);
    }

    public function removeElement($element) {
        $previous = $element->getPrevious();
        $next     = $element->getNext();

        if ($this->first === $element) {
            $this->first = $next;
        }

        if ($this->last === $element) {
            $this->last = $previous;
        }

        if ($previous) {
            $previous->setNext($next);
        } else {
            $next->setPrevious();
        }
    }

    public function getParent() {
        return false;
    }

    public function getPath() {
        return '';
    }

    /**
     * @return Form
     */
    public function getForm() {
        return $this->form;
    }

    /**
     * @return string
     */
    public function getName() {
        return 'ContainerMain';
    }

    /**
     * @return FieldsetHidden
     */
    public function getFieldsetHidden() {
        return $this->fieldsetHidden;
    }

    /**
     *
     * @return ContainerContainedInterface
     */
    public function getFirst() {
        return $this->first;
    }
}Form/Element/AbstractChooser.php000064400000003177151161172450012652
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Localization\Localization;
use Nextend\Framework\View\Html;

abstract class AbstractChooser extends AbstractFieldHidden {

    protected $hasClear = true;

    protected $class = '';

    protected $width;

    abstract protected function addScript();

    protected function fetchElement() {

        $this->addScript();

        $this->renderRelatedFields();

        return Html::tag('div', array(
            'class' => 'n2_field_chooser ' .
$this->class
        ), $this->pre() . parent::fetchElement() . $this->field() .
$this->post());
    }

    protected function pre() {

    }

    protected function field() {
        $style = '';
        if ($this->width) {
            $style = 'width: ' . $this->width .
'px;';
        }

        return '<div class="n2_field_chooser__label"
style="' . $style . '"></div>';
    }

    protected function post() {

        $html = '';
        if ($this->hasClear) {
            $html .= Html::tag('a', array(
                'href'  => '#',
                'class' => 'n2_field_chooser__clear'
            ), Html::tag('i', array('class' =>
'ssi_16 ssi_16--circularremove'), ''));
        }

        $html .= Html::tag('a', array(
            'href'  => '#',
            'class' => 'n2_field_chooser__choose'
        ), '<i class="ssi_16
ssi_16--plus"></i>');

        return $html;
    }

    /**
     * @param bool $hasClear
     */
    public function setHasClear($hasClear) {
        $this->hasClear = $hasClear;
    }

    /**
     * @param int $width
     */
    public function setWidth($width) {
        $this->width = $width;
    }
}Form/Element/AbstractChooserText.php000064400000004136151161172450013513
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\View\Html;

abstract class AbstractChooserText extends AbstractFieldHidden {

    protected $hasClear = true;

    protected $width = 130;

    protected $class = '';

    protected $type = 'text';

    abstract protected function addScript();

    protected function fetchElement() {

        $this->addScript();

        $this->renderRelatedFields();

        return Html::tag('div', array(
            'class' => 'n2_field_text' .
$this->class
        ), $this->pre() . $this->field() . $this->post());
    }

    protected function pre() {

    }

    protected function field() {

        if ($this->type === 'hidden') {
            return Html::tag('input', array(
                'type'     => 'text',
                'style'    => 'width: ' .
$this->width . 'px;',
                'disabled' => 'disabled'
            ), false, false);
        }

        return Html::tag('input', array(
            'id'           => $this->fieldID,
            'name'         => $this->getFieldName(),
            'value'        => $this->getValue(),
            'type'         => $this->type,
            'style'        => 'width: ' .
$this->width . 'px;',
            'autocomplete' => 'off'
        ), false, false);

    }

    protected function post() {

        $html = '';
        if ($this->hasClear) {
            $html .= Html::tag('a', array(
                'href'     => '#',
                'class'    =>
'n2_field_text__clear',
                'tabindex' => -1
            ), Html::tag('i', array('class' =>
'ssi_16 ssi_16--circularremove'), ''));
        }

        $html .= Html::tag('a', array(
            'href'       => '#',
            'class'      => 'n2_field_text__choose',
            'aria-label' => n2_('Choose')
        ), '<i class="ssi_16
ssi_16--plus"></i>');

        return $html;
    }

    /**
     * @param bool $hasClear
     */
    public function setHasClear($hasClear) {
        $this->hasClear = $hasClear;
    }

    /**
     * @param int $width
     */
    public function setWidth($width) {
        $this->width = $width;
    }
}Form/Element/AbstractFieldHidden.php000064400000001723151161172450013402
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\View\Html;

class AbstractFieldHidden extends AbstractField {

    protected $hasTooltip = true;

    protected $type = 'hidden';

    public function __construct($insertAt, $name = '', $label =
false, $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);
    }

    protected function fetchTooltip() {
        if ($this->hasTooltip) {
            return parent::fetchTooltip();
        } else {
            return $this->fetchNoTooltip();
        }
    }

    protected function fetchElement() {

        return Html::tag('input', array(
            'id'           => $this->fieldID,
            'name'         => $this->getFieldName(),
            'value'        => $this->getValue(),
            'type'         => $this->type,
            'autocomplete' => 'off'
        ), false, false);
    }
}Form/Element/Breakpoint.php000064400000007015151161172450011655
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\TraitFieldset;
use Nextend\Framework\View\Html;

class Breakpoint extends AbstractField implements ContainerInterface {

    use TraitFieldset;

    protected $fields = array();

    protected $enables = false;

    protected $global = false;

    public function __construct($insertAt, $name = '', $fields =
array(), $enables = false, $global = false) {

        $this->fields  = $fields;
        $this->enables = $enables;
        $this->global  = $global;

        parent::__construct($insertAt, $name, false, '');
    }

    public function getLabelClass() {

        return parent::getLabelClass() . ' n2_field--raw';
    }

    protected function fetchElement() {

        $orientation = new Tab($this, $this->name .
'-orientation', n2_('Orientation'),
'portrait', array(
            'options' => array(
                'portrait'  => n2_('Portrait'),
                'landscape' => n2_('Landscape')
            )
        ));
        $devices = array(
            array(
                'id'    => 'mobileportrait',
                'icon'  => 'ssi_16
ssi_16--mobileportrait',
                'label' => n2_('Mobile')
            ),
            array(
                'id'    => 'mobilelandscape',
                'icon'  => 'ssi_16
ssi_16--mobileportraitlarge',
                'label' => n2_('Large mobile')
            ),
            array(
                'id'    => 'tabletportrait',
                'icon'  => 'ssi_16
ssi_16--tabletportrait',
                'label' => n2_('Tablet')
            ),
            array(
                'id'    => 'tabletlandscape',
                'icon'  => 'ssi_16
ssi_16--tabletportraitlarge',
                'label' => n2_('Large tablet')
            ),
            array(
                'id'    => 'desktopportrait',
                'icon'  => 'ssi_16
ssi_16--desktopportrait',
                'label' => n2_('Desktop')
            ),
            array(
                'id'    => 'desktoplandscape',
                'icon'  => 'ssi_16
ssi_16--desktoplandscape',
                'label' => n2_('Large desktop')
            )
        );

        $preHtml = '';
        $element = $this->first;
        while ($element) {
            $preHtml .= $this->decorateElement($element);

            $element = $element->getNext();
        }

        $html = '';

        for ($i = 0; $i < count($devices); $i++) {
            $html .= Html::tag('div', array(
                'data-id' => $devices[$i]['id'],
                'class'   =>
'n2_field_breakpoint__device'
            ), '<div
class="n2_field_breakpoint__device_enable"
data-n2tip="' . $devices[$i]['label'] .
'"><i class="' . $devices[$i]['icon'] .
'"></i></div>');
        }

        $options = array(
            'orientation' => $orientation->getID(),
            'fields'      => $this->fields,
            'enables'     => $this->enables,
            'global'      => $this->global
        );

        Js::addInline('new _N2.FormElementBreakpoint("' .
$this->fieldID . '", ' . json_encode($options) .
');');


        return '<div id="' . $this->getID() .
'" class="n2_field_breakpoint"><div
class="n2_field_breakpoint__pre_fields">' . $preHtml .
'</div><div
class="n2_field_breakpoint__breakpoint_container"
data-orientation="portrait">' . $html .
'</div></div>';
    }

    public function decorateElement($element) {
        return $this->parent->decorateElement($element);
    }

}Form/Element/Button/ButtonIcon.php000064400000001442151161172450013114
0ustar00<?php


namespace Nextend\Framework\Form\Element\Button;


use Nextend\Framework\Form\Element\Button;

class ButtonIcon extends Button {

    protected $hoverTip = '';

    public function __construct($insertAt, $name = '', $label =
'', $icon = '', $parameters = array()) {

        $this->classes[] = 'n2_field_button--icon';
        parent::__construct($insertAt, $name, $label, '<i
class="' . $icon . '"></i>',
$parameters);
    }

    protected function getAttributes() {
        $attributes = parent::getAttributes();

        if (!empty($this->hoverTip)) {
            $attributes['data-n2tip'] = $this->hoverTip;
        }

        return $attributes;
    }

    /**
     * @param string $hoverTip
     */
    public function setHoverTip($hoverTip) {
        $this->hoverTip = $hoverTip;
    }
}Form/Element/Button/ButtonMoreLess.php000064400000001431151161172450013753
0ustar00<?php


namespace Nextend\Framework\Form\Element\Button;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\Button;

class ButtonMoreLess extends Button {

    public function __construct($insertAt, $name, $label = '',
$parameters = array()) {
        parent::__construct($insertAt, $name, $label,
n2_('More'), $parameters);
    }

    protected function fetchElement() {

        $options = array(
            'labelMore' => n2_('More'),
            'labelLess' => n2_('Less')
        );

        if (!empty($this->relatedFields)) {
            $options['relatedFields'] = $this->relatedFields;
        }

        Js::addInline('new _N2.FormElementButtonMoreLess("'
. $this->fieldID . '", ' . json_encode($options) .
');');

        return parent::fetchElement();
    }
}Form/Element/Button/ButtonRecordViewer.php000064400000001450151161172450014623
0ustar00<?php


namespace Nextend\Framework\Form\Element\Button;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\Button;

class ButtonRecordViewer extends Button {

    public function __construct($insertAt, $name = '',
$parameters = array()) {
        parent::__construct($insertAt, $name, '', n2_('View
records'), $parameters);


        $this->addClass('n2_field_button--blue');
    }

    protected function fetchElement() {

        $ajaxRecordUrl = $this->getForm()
                              ->createAjaxUrl(array(
                                  'generator/recordstable'
                              ));
        Js::addInline('new _N2.FieldRecordViewer(' .
json_encode($this->fieldID) . ',' .
json_encode($ajaxRecordUrl) . ');');


        return parent::fetchElement();
    }
}Form/Element/Button.php000064400000002646151161172450011037
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\View\Html;

class Button extends AbstractField {

    protected $url = '';

    protected $target = '';

    protected $buttonLabel = '';

    protected $classes = array('n2_field_button');

    public function __construct($insertAt, $name = '', $label =
'', $buttonLabel = '', $parameters = array()) {
        $this->buttonLabel = $buttonLabel;
        parent::__construct($insertAt, $name, $label, '',
$parameters);
    }

    protected function fetchElement() {

        return Html::tag('a', $this->getAttributes(),
$this->buttonLabel);
    }

    /**
     * @param $className
     */
    public function addClass($className) {
        $this->classes[] = $className;
    }

    /**
     * @return array
     */
    protected function getAttributes() {
        $attributes = array(
            'id'    => $this->fieldID,
            'class' => implode(' ',
$this->classes)
        );

        if (!empty($this->url)) {
            $attributes['href'] = $this->url;
            if (!empty($this->target)) {
                $attributes['target'] = $this->target;
            }
        } else {
            $attributes['href'] = '#';
        }

        return $attributes;
    }

    public function setUrl($url) {
        $this->url = $url;
    }

    public function setTarget($target) {
        $this->target = $target;
    }
}Form/Element/CheckboxOnOff.php000064400000003212151161172450012230
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class CheckboxOnOff extends AbstractFieldHidden {

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

    protected $invert = false;

    protected $checkboxTip;

    public function __construct($insertAt, $name, $label, $icon, $default =
0, $parameters = array()) {

        $this->icon = $icon;

        parent::__construct($insertAt, $name, $label, $default,
$parameters);
    }

    protected function fetchElement() {

        $options = array(
            'invert'        => $this->invert,
            'relatedFields' => $this->relatedFields
        );

        Js::addInline('new _N2.FormElementCheckboxOnOff("' .
$this->fieldID . '", ' . json_encode($options) .
');');

        $attr = array(
            'class' => 'n2_field_checkbox_onoff' .
($this->isActive() ? ' n2_field_checkbox_onoff--active' :
'')
        );

        if (!empty($this->checkboxTip)) {
            $attr['data-n2tip'] = $this->checkboxTip;
        }

        return Html::tag('div', $attr, '<i
class="' . $this->icon . '"></i>' .
parent::fetchElement());
    }

    protected function isActive() {

        $value = $this->getValue();

        if (!$this->invert && $value) {
            return true;
        } else if ($this->invert && !$value) {
            return true;
        }

        return false;
    }

    /**
     * @param bool $invert
     */
    public function setInvert($invert) {
        $this->invert = $invert;
    }

    /**
     * @param string $tip
     */
    public function setCheckboxTip($tip) {
        $this->checkboxTip = $tip;
    }

}Form/Element/Connected.php000064400000001052151161172450011454
0ustar00<?php

namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Form\AbstractField;

class Connected extends MixedField {

    protected $rowClass = 'n2_field_connected ';

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        $elementHtml = $element->render();

        return $elementHtml[1];
    }

    protected function decorate($html) {

        return '<div
class="n2_field_connected__container" style="' .
$this->style . '">' . $html .
'</div>';
    }
}Form/Element/Decoration.php000064400000003357151161172450011653
0ustar00<?php


namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class Decoration extends AbstractFieldHidden {

    protected $value = null;

    protected $options = array(
        'italic'    => 'ssi_16 ssi_16--italic',
        'underline' => 'ssi_16 ssi_16--underline'
    );

    protected $style = '';

    protected function fetchElement() {

        $this->value = explode('||', $this->getValue());

        $html = Html::tag('div', array(
            'class' => 'n2_field_decoration',
            'style' => $this->style
        ), $this->renderOptions() . parent::fetchElement());

        Js::addInline('new _N2.FormElementDecoration("' .
$this->fieldID . '", ' .
json_encode(array_keys($this->options)) . ');');

        return $html;
    }

    /**
     *
     * @return string
     */
    protected function renderOptions() {

        $length = count($this->options) - 1;

        $html = '';
        $i    = 0;
        foreach ($this->options AS $value => $class) {

            $html .= Html::tag('div', array(
                'class'      =>
'n2_field_decoration__option ' . ($this->isSelected($value) ?
' n2_field_decoration__option--selected' : ''),
                'data-value' => $value
            ), Html::tag('i', array('class' =>
$class)));
            $i++;
        }

        return $html;
    }

    function isSelected($value) {
        if (in_array($value, $this->value)) {
            return true;
        }

        return false;
    }

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

    /**
     * @param string $style
     */
    public function setStyle($style) {
        $this->style = $style;
    }
}Form/Element/Devices.php000064400000003034151161172450011136
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class Devices extends AbstractFieldHidden {

    private $values = array();

    protected function fetchElement() {

        $html = Html::tag('div', array(
            'id'    => $this->fieldID,
            'class' => 'n2_field_radio_icon'
        ), $this->generateOptions());

        Js::addInline('new _N2.FormElementDevices("' .
$this->fieldID . '", ' . json_encode($this->values) .
');');

        return $html;
    }

    function generateOptions() {
        $options = array(
            'desktop-landscape' => 'ssi_16
ssi_16--desktoplandscape',
            'desktop-portrait'  => 'ssi_16
ssi_16--desktopportrait',
            'tablet-landscape'  => 'ssi_16
ssi_16--tabletportraitlarge',
            'tablet-portrait'   => 'ssi_16
ssi_16--tabletportrait',
            'mobile-landscape'  => 'ssi_16
ssi_16--mobileportraitlarge',
            'mobile-portrait'   => 'ssi_16
ssi_16--mobileportrait'
        );

        $html = '';
        $i    = 0;
        foreach ($options as $value => $class) {
            $this->values[] = $value;

            $html .= Html::tag('div', array(
                'class' => 'n2_field_radio__option'
            ), Html::tag('i', array(
                    'class' => $class
                )) . Html::tag('input', array(
                    'type' => 'hidden',
                    'id'   => $this->fieldID .
'-' . $value
                )));
            $i++;
        }

        return $html;
    }
}Form/Element/EmptyArea.php000064400000000457151161172450011451
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\View\Html;

class EmptyArea extends AbstractField {

    protected function fetchElement() {

        return Html::tag('div', array(
            'id' => $this->fieldID
        ));
    }
}Form/Element/Font.php000064400000003017151161172450010463 0ustar00<?php

namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Font\FontManager;
use Nextend\Framework\Font\FontParser;
use Nextend\Framework\View\Html;

class Font extends AbstractFieldHidden {

    protected $mode = '';

    protected $css = '';

    protected $style2 = '';

    protected $preview = '';


    protected function addScript() {

        FontManager::enqueue($this->getForm());

        Js::addInline('new _N2.FormElementFont("' .
$this->fieldID . '", {
            mode: "' . $this->mode . '",
            label: "' . $this->label . '",
            style: "' . $this->style . '",
            style2: "' . $this->style2 . '",
            preview: ' . json_encode($this->preview) . '
        });');
    }

    protected function fetchElement() {

        $this->addScript();

        return Html::tag('div', array(
            'class' => 'n2_field_font'
        ), n2_('Font') . parent::fetchElement());
    }

    public function getValue() {

        return FontParser::parse(parent::getValue());
    }

    /**
     * @param string $mode
     */
    public function setMode($mode) {
        $this->mode = $mode;
    }

    /**
     * @param string $css
     */
    public function setCss($css) {
        $this->css = $css;
    }

    /**
     * @param string $style2
     */
    public function setStyle2($style2) {
        $this->style2 = $style2;
    }

    /**
     * @param string $preview
     */
    public function setPreview($preview) {
        $this->preview = $preview;
    }

}Form/Element/Group/GroupCheckboxOnOff.php000064400000000550151161172450014343
0ustar00<?php


namespace Nextend\Framework\Form\Element\Group;


use Nextend\Framework\Form\Element\Grouping;
use Nextend\Framework\View\Html;

class GroupCheckboxOnOff extends Grouping {

    protected function fetchElement() {
        return Html::tag('div', array(
            'class' =>
'n2_field_group_checkbox_onoff'
        ), parent::fetchElement());
    }

}Form/Element/Grouping.php000064400000001555151161172450011354
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\TraitFieldset;

class Grouping extends AbstractField implements ContainerInterface {

    use TraitFieldset;

    protected $rowClass = 'n2_field__grouping';

    public function __construct($insertAt, $name = '', $label =
false, $parameters = array()) {
        parent::__construct($insertAt, $name, $label, '',
$parameters);
    }

    protected function fetchElement() {

        $html = '';

        $element = $this->first;
        while ($element) {
            $html .= $this->decorateElement($element);

            $element = $element->getNext();
        }

        return $html;
    }

    public function decorateElement($element) {

        return $this->parent->decorateElement($element);
    }
}Form/Element/Hidden/HiddenFont.php000064400000001356151161172450012776
0ustar00<?php

namespace Nextend\Framework\Form\Element\Hidden;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Font\FontManager;
use Nextend\Framework\Form\Element\AbstractFieldHidden;

class HiddenFont extends AbstractFieldHidden {

    protected $rowClass = 'n2_form_element--hidden';

    protected $mode = '';

    protected function fetchElement() {

        FontManager::enqueue($this->getForm());

        Js::addInline('new _N2.FormElementFontHidden("' .
$this->fieldID . '", {
            mode: "' . $this->mode . '",
            label: "' . $this->label . '"
        });');

        return parent::fetchElement();
    }

    /**
     * @param string $mode
     */
    public function setMode($mode) {
        $this->mode = $mode;
    }
}Form/Element/Hidden/HiddenOnOff.php000064400000000300151161172450013063
0ustar00<?php


namespace Nextend\Framework\Form\Element\Hidden;


use Nextend\Framework\Form\Element\OnOff;

class HiddenOnOff extends OnOff {

    protected $rowClass = 'n2_form_element--hidden';

}Form/Element/Hidden/HiddenStyle.php000064400000001363151161172450013166
0ustar00<?php

namespace Nextend\Framework\Form\Element\Hidden;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\AbstractFieldHidden;
use Nextend\Framework\Style\StyleManager;

class HiddenStyle extends AbstractFieldHidden {

    protected $rowClass = 'n2_form_element--hidden';

    protected $mode = '';

    protected function fetchElement() {

        StyleManager::enqueue($this->getForm());

        Js::addInline('new _N2.FormElementStyleHidden("' .
$this->fieldID . '", {
            mode: "' . $this->mode . '",
            label: "' . $this->label . '"
        });');

        return parent::fetchElement();
    }

    /**
     * @param string $mode
     */
    public function setMode($mode) {
        $this->mode = $mode;
    }
}Form/Element/Hidden.php000064400000000614151161172450010750
0ustar00<?php


namespace Nextend\Framework\Form\Element;


class Hidden extends AbstractFieldHidden {

    protected $hasTooltip = false;

    public function __construct($insertAt, $name = '', $default =
'', $parameters = array()) {
        parent::__construct($insertAt, $name, false, $default,
$parameters);
    }

    public function getRowClass() {
        return 'n2_form_element--hidden';
    }
}Form/Element/Icon.php000064400000001030151161172450010436 0ustar00<?php
/**
 * @required N2SSPRO
 */

namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;

class Icon extends AbstractChooser {

    protected $hasClear = false;

    protected $class = ' n2_field_icon';

    protected function addScript() {

        \Nextend\Framework\Icon\Icon::serveAdmin();

        Js::addInline('
            new _N2.FormElementIcon2Manager("' .
$this->fieldID . '");
        ');
    }

    protected function field() {
        return '<div
class="n2_field_icon__preview"></div>';
    }
}Form/Element/IconTab.php000064400000005146151161172450011101
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class IconTab extends AbstractFieldHidden {

    protected $options = array();
    protected $relatedValueFields = array();
    protected $relatedAttribute = '';
    protected $tooltips = array();

    protected function fetchElement() {

        $value = $this->getValue();
        if (!empty($value)) {
            $this->defaultValue = $value;
        } else if (empty($this->defaultValue)) {
            $this->defaultValue = array_keys($this->options)[0];
        }

        $html = Html::openTag("div", array(
            "id"    => $this->fieldID .
"_icon_tab",
            "class" => "n2_field_icon_tab",
            "style" => $this->style
        ));

        $html .= $this->renderOptions();

        $html .= Html::closeTag("div");

        $html .= parent::fetchElement();

        if (!empty($this->relatedAttribute)) {
            $options['relatedAttribute'] =
$this->relatedAttribute;
        }

        $options = array();

        if (!empty($this->relatedValueFields)) {
            $options['relatedValueFields'] =
$this->relatedValueFields;
        }

        Js::addInline('new _N2.FormElementIconTab("' .
$this->fieldID . '", ' . json_encode($options) .
');');

        return $html;
    }

    /**
     * @param array $options
     */
    public function setOptions($options) {

        $this->options = $options;
    }

    /**
     * @param array $tooltips
     */
    public function setTooltips($tooltips) {

        $this->tooltips = $tooltips;
    }

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

    public function renderOptions() {
        $html = '';
        foreach ($this->options AS $option => $icon) {
            $class = 'n2_field_icon_tab__option';
            if ($option == $this->defaultValue) {
                $class .= ' n2_field_icon_tab__option--selected';
            }

            $element = array(
                "class"       => $class,
                "data-ssoption" => $option
            );

            if (isset($this->tooltips[$option])) {
                $element += array(
                    "data-n2tip" =>
$this->tooltips[$option]
                );

            }
            $html .= Html::openTag("div", $element);
            $html .= Html::openTag("i", array(
                "class" => $icon
            ));
            $html .= Html::closeTag("i");
            $html .= Html::closeTag("div");
        }

        return $html;
    }
}Form/Element/LayerWindowFocus.php000064400000003143151161172450013021
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;

class LayerWindowFocus extends AbstractField {

    /**
     * @var AbstractField
     */
    protected $fieldImage;

    /**
     * @var AbstractField
     */
    protected $fieldFocusX;

    /**
     * @var AbstractField
     */
    protected $fieldFocusY;


    /**
     * LayerWindowFocus constructor.
     *
     * @param               $insertAt
     * @param               $name
     * @param               $label
     * @param array         $parameters
     */
    public function __construct($insertAt, $name, $label, $parameters =
array()) {

        parent::__construct($insertAt, $name, $label, '',
$parameters);
    }

    /**
     * @param AbstractField $fieldImage
     * @param AbstractField $fieldFocusX
     * @param AbstractField $fieldFocusY
     */
    public function setFields($fieldImage, $fieldFocusX, $fieldFocusY) {

        $this->fieldImage  = $fieldImage;
        $this->fieldFocusX = $fieldFocusX;
        $this->fieldFocusY = $fieldFocusY;
    }

    protected function fetchElement() {

        Js::addInline('new
_N2.FormElementLayerWindowFocus("' . $this->fieldID .
'", ' . json_encode(array(
                'image'  => $this->fieldImage->getID(),
                'focusX' => $this->fieldFocusX->getID(),
                'focusY' => $this->fieldFocusY->getID(),
            )) . ');');

        return '<div id="' . $this->fieldID .
'" class="n2_field_layer_window_focus"
style="width:314px;"><img
class="n2_field_layer_window_focus__image"
alt="Error"></div>';
    }

}Form/Element/MarginPadding.php000064400000004141151161172450012260
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\TraitFieldset;

class MarginPadding extends AbstractFieldHidden implements
ContainerInterface {

    use TraitFieldset;

    private static $separator = '|*|';

    protected $unit = false;

    protected function fetchElement() {
        $default = explode(self::$separator, $this->defaultValue);
        $value   = explode(self::$separator, $this->getValue());
        $value   = $value + $default;

        $html = "<div class='n2_field_margin_padding'
style='" . $this->style . "'>";

        $html        .= '<div
class="n2_field_margin_padding__pre_label"><i
class="ssi_16 ssi_16--unlink"></i></div>';
        $subElements = array();
        $i           = 0;

        $element = $this->first;
        while ($element) {
            $element->setExposeName(false);
            if (isset($value[$i])) {
                $element->setDefaultValue($value[$i]);
            }

            $html            .= $this->decorateElement($element);
            $subElements[$i] = $element->getID();
            $i++;

            $element = $element->getNext();
        }

        if ($this->unit) {
            $html .= '<div
class="n2_field_unit"><div
class="n2_field_unit__current_unit">' . $this->unit .
'</div></div>';
        }

        $html .= parent::fetchElement();
        $html .= "</div>";

        Js::addInline('new _N2.FormElementMarginPadding("' .
$this->fieldID . '", ' . json_encode($subElements) .
', "' . self::$separator . '");');

        $this->renderRelatedFields();

        return $html;
    }

    /**
     * @param string $unit
     */
    public function setUnit($unit) {
        $this->unit = $unit;
    }

    public function getControlName() {
        return $this->name . $this->controlName;
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        $elementHtml = $element->render();

        return $elementHtml[1];
    }
}Form/Element/Message/Notice.php000064400000000526151161172450012364
0ustar00<?php


namespace Nextend\Framework\Form\Element\Message;


use Nextend\Framework\Form\Element\Message;

class Notice extends Message {

    public function __construct($insertAt, $name, $label, $description) {
        $this->classes[] = 'n2_field_message--notice';
        parent::__construct($insertAt, $name, $label, $description);
    }
}Form/Element/Message/Warning.php000064400000001013151161172450012540
0ustar00<?php


namespace Nextend\Framework\Form\Element\Message;

use Nextend\Framework\Form\Element\Message;

class Warning extends Message {

    protected $description = '';

    public function __construct($insertAt, $name, $description) {
        $this->classes[] = 'n2_field_message--warning';
        parent::__construct($insertAt, $name, n2_('Warning'),
$description);
    }

    protected function fetchElement() {
        echo '<div class="' . implode(' ',
$this->classes) . '">' . $this->description .
'</div>';
    }
}Form/Element/Message.php000064400000001053151161172450011137
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Form\AbstractField;

abstract class Message extends AbstractField {

    protected $description = '';

    protected $classes = array('n2_field_message');

    public function __construct($insertAt, $name, $label, $description) {
        $this->description = $description;
        parent::__construct($insertAt, $name, $label);
    }

    protected function fetchElement() {
        echo '<div class="' . implode(' ',
$this->classes) . '">' . $this->description .
'</div>';
    }
}Form/Element/MixedField/Border.php000064400000004252151161172460013007
0ustar00<?php


namespace Nextend\Framework\Form\Element\MixedField;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Form\Element\Text\Color;
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;
use Nextend\Framework\View\Html;

class Border extends MixedField {

    protected $rowClass = 'n2_field_mixed_border ';

    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        new NumberAutoComplete($this, $this->name . '-1',
false, '', array(
            'values'        => array(
                0,
                1,
                3,
                5
            ),
            'min'           => 0,
            'wide'          => 3,
            'unit'          => 'px',
            'relatedFields' => array(
                $this->generateId($this->getControlName() .
$this->name . '-2'),
                $this->generateId($this->getControlName() .
$this->name . '-3')
            )
        ));

        new Select($this, $this->name . '-2', false,
'', array(
            'options' => array(
                'none'   => n2_('None'),
                'dotted' => n2_('Dotted'),
                'dashed' => n2_('Dashed'),
                'solid'  => n2_('Solid'),
                'double' => n2_('Double'),
                'groove' => n2_('Groove'),
                'ridge'  => n2_('Ridge'),
                'inset'  => n2_('Inset'),
                'outset' => n2_('Outset')
            )
        ));

        new Color($this, $this->name . '-3', false,
'', array(
            'alpha' => true
        ));
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        $elementHtml = $element->render();

        return Html::tag('div', array(
            'data-field' => $element->getID()
        ), $elementHtml[1]);
    }

    protected function decorate($html) {

        return '<div
class="n2_field_mixed_border__container" style="' .
$this->style . '">' . $html .
'</div>';
    }
}Form/Element/MixedField/BoxShadow.php000064400000002266151161172460013473
0ustar00<?php


namespace Nextend\Framework\Form\Element\MixedField;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\Text\Color;
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;

class BoxShadow extends MixedField {

    protected $rowClass = 'n2_field_mixed_box_shadow ';

    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        for ($i = 1; $i < 5; $i++) {
            new NumberAutoComplete($this, $this->name . '-' .
$i, false, 0, array(
                'wide' => 3
            ));
        }
        new Color($this, $this->name . '-5', false,
'', array(
            'alpha' => true
        ));
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        $elementHtml = $element->render();

        return $elementHtml[1];
    }

    protected function decorate($html) {

        return '<div
class="n2_field_mixed_box_shadow__container" style="' .
$this->style . '">' . $html .
'</div>';
    }
}Form/Element/MixedField/FontSize.php000064400000003062151161172460013331
0ustar00<?php


namespace Nextend\Framework\Form\Element\MixedField;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\Text\NumberSlider;
use Nextend\Framework\Form\Element\Unit;

class FontSize extends MixedField {

    protected $rowClass = 'n2_field_mixed_font_size ';

    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        new NumberSlider($this, $this->name . '-1', false,
'', array(
            'min'       => 1,
            'max'       => 10000,
            'sliderMax' => 100,
            'units'     => array(
                'pxMin'       => 1,
                'pxMax'       => 10000,
                'pxSliderMax' => 100,
                '%Min'        => 1,
                '%Max'        => 10000,
                '%SliderMax'  => 600
            ),
            'style'     => 'width: 22px;'
        ));
        new Unit($this, $this->name . '-2', false,
'', array(
            'units' => array(
                'px' => 'px',
                '%'  => '%'
            )
        ));
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        $elementHtml = $element->render();

        return $elementHtml[1];
    }

    protected function decorate($html) {

        return '<div
class="n2_field_mixed_font_size__container" style="' .
$this->style . '">' . $html .
'</div>';
    }
}Form/Element/MixedField/GeneratorOrder.php000064400000002117151161172460014512
0ustar00<?php


namespace Nextend\Framework\Form\Element\MixedField;


use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\Radio;
use Nextend\Framework\Form\Element\Select;

class GeneratorOrder extends MixedField {

    protected $rowClass = 'n2_field_mixed_generator_order ';

    protected $options = array();

    public function __construct($insertAt, $name = '', $default =
'', $parameters = array()) {
        parent::__construct($insertAt, $name, false, $default,
$parameters);

        new Select($this, $name . '-1', n2_('Field'),
'', $this->options);

        new Radio($this, $name . '-2', n2_('Order'),
'', array(
            'options' => array(
                'asc'  => n2_('Ascending'),
                'desc' => n2_('Descending')
            )
        ));
    }

    protected function decorate($html) {

        return '<div
class="n2_field_mixed_generator_order__container"
style="' . $this->style . '">' . $html .
'</div>';
    }

    protected function setOptions($options) {
        $this->options = array(
            'options' => $options
        );
    }
}Form/Element/MixedField/TextShadow.php000064400000002271151161172460013663
0ustar00<?php


namespace Nextend\Framework\Form\Element\MixedField;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\Text\Color;
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;

class TextShadow extends MixedField {

    protected $rowClass = 'n2_field_mixed_text_shadow ';

    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        for ($i = 1; $i < 4; $i++) {
            new NumberAutoComplete($this, $this->name . '-' .
$i, false, 0, array(
                'wide' => 3
            ));
        }
        new Color($this, $this->name . '-4', false,
'', array(
            'alpha' => true
        ));
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        $elementHtml = $element->render();

        return $elementHtml[1];
    }

    protected function decorate($html) {

        return '<div
class="n2_field_mixed_text_shadow__container" style="'
. $this->style . '">' . $html .
'</div>';
    }
}Form/Element/MixedField.php000064400000003572151161172460011576
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\TraitFieldset;

class MixedField extends AbstractFieldHidden implements ContainerInterface
{

    use TraitFieldset;

    private $separator = '|*|';

    protected $style = '';

    protected $rowClass = 'n2_field_mixed ';

    protected function fetchElement() {

        $default = explode($this->separator, $this->defaultValue);
        $value   = explode($this->separator, $this->getValue());
        $value   = $value + $default;

        $html        = '';
        $subElements = array();
        $i           = 0;


        $element = $this->first;
        while ($element) {
            $element->setExposeName(false);
            if (isset($value[$i])) {
                $element->setDefaultValue($value[$i]);
            }

            $html .= $this->decorateElement($element);

            $subElements[$i] = $element->getID();
            $i++;

            $element = $element->getNext();
        }

        $html .= parent::fetchElement();

        Js::addInline('new _N2.FormElementMixed("' .
$this->fieldID . '", ' . json_encode($subElements) .
', "' . $this->separator . '");');

        return $this->decorate($html);
    }

    /**
     * @param string $style
     */
    public function setStyle($style) {
        $this->style = $style;
    }

    public function getControlName() {
        return $this->name . $this->controlName;
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        return $this->parent->decorateElement($element);
    }

    protected function decorate($html) {

        return '<div class="n2_field_mixed__container"
style="' . $this->style . '">' . $html .
'</div>';
    }
}Form/Element/OnOff.php000064400000005235151161172460010571
0ustar00<?php

namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Asset\Js\Js;

class OnOff extends AbstractFieldHidden {

    protected $relatedFieldsOn = array();

    protected $relatedAttribute = '';

    protected $values = array(
        0 => 0,
        1 => 1
    );

    protected $customValues = false;

    protected function fetchElement() {

        $html = '<div class="n2_field_onoff' .
$this->isOn() . '" role="switch"
aria-checked="false" tabindex="0"
aria-label="' . $this->label . '">' .
parent::fetchElement() . '<div
class="n2_field_onoff__slider"><div
class="n2_field_onoff__slider_bullet"></div></div><div
class="n2_field_onoff__labels"><div
class="n2_field_onoff__label n2_field_onoff__label_off">'
. n2_('Off') . '</div><div
class="n2_field_onoff__label n2_field_onoff__label_on">'
. n2_('On') . '</div></div></div>';

        $options = array();

        if ($this->customValues) {
            $options['values'] = $this->customValues;
        }
        if (!empty($this->relatedFieldsOff)) {
            $options['relatedFieldsOff'] =
$this->relatedFieldsOff;
        }
        if (!empty($this->relatedFieldsOn)) {
            $options['relatedFieldsOn'] =
$this->relatedFieldsOn;
        }
        if (!empty($this->relatedAttribute)) {
            $options['relatedAttribute'] =
$this->relatedAttribute;
        }

        Js::addInline('new _N2.FormElementOnoff("' .
$this->fieldID . '", ' . json_encode($options) .
');');

        return $html;
    }

    private function isOn() {
        $value = $this->getValue();
        if (($this->customValues &&
$this->customValues[$value]) || (!$this->customValues &&
$value)) {
            return ' n2_field_onoff--on';
        }

        return '';
    }

    /**
     * @param array $relatedFields
     */
    public function setRelatedFieldsOn($relatedFields) {
        $this->relatedFieldsOn = $relatedFields;
    }

    /**
     * @param array $relatedFields
     */
    public function setRelatedFieldsOff($relatedFields) {
        $this->relatedFieldsOff = $relatedFields;
    }

    public function setRelatedAttribute($relatedAttribute) {
        $this->relatedAttribute = $relatedAttribute;
    }

    public function setCustomValues($offValue = 0, $onValue = 1) {

        if ($offValue === 0 && $onValue === 1) {
            $this->customValues = false;
        } else {
            $this->customValues            = array();
            $this->customValues[$offValue] = 0;
            $this->customValues[$onValue]  = 1;
        }
    }

    public function setInvert($isInvert) {
        if ($isInvert) {
            $this->setCustomValues(1, 0);
        } else {
            $this->setCustomValues(0, 1);
        }
    }
}Form/Element/Radio/AbstractRadioIcon.php000064400000001216151161172460014146
0ustar00<?php


namespace Nextend\Framework\Form\Element\Radio;


use Nextend\Framework\Form\Element\Radio;
use Nextend\Framework\View\Html;

abstract class AbstractRadioIcon extends Radio {

    protected $class = 'n2_field_radio_icon';

    protected function renderOptions() {

        $html = '';
        $i    = 0;
        foreach ($this->options AS $value => $class) {

            $html .= Html::tag('div', array(
                'class' => 'n2_field_radio__option'
. ($this->isSelected($value) ? '
n2_field_radio__option--selected' : '')
            ), Html::tag('i', array('class' =>
$class)));
            $i++;
        }

        return $html;
    }
}Form/Element/Radio/ImageList.php000064400000004312151161172460012471
0ustar00<?php


namespace Nextend\Framework\Form\Element\Radio;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\AbstractFieldHidden;
use Nextend\Framework\Localization\Localization;
use Nextend\Framework\Url\Url;
use Nextend\Framework\View\Html;

abstract class ImageList extends AbstractFieldHidden {

    protected $hasDisabled = true;

    protected $width = 44;

    protected $column = 5;

    protected $options = array();

    protected function fetchElement() {

        $jsParameters = array(
            'width' => $this->width
        );

        if ($this->hasDisabled) {
            $jsParameters['hasDisabled'] = true;
        }

        $html = Html::openTag("div", array(
            'class' => 'n2_field_image_list',
            'style' => $this->style
        ));

        $html .= parent::fetchElement();
        $html .= '<div
class="n2_field_image_list__preview">';

        $html .= '</div>';
        $html .= '<i class="n2_field_image_list__arrow ssi_16
ssi_16--selectarrow"></i>';

        $html .= $this->postHTML();

        $html .= Html::closeTag('div');

        $frontendOptions = array();
        foreach ($this->options as $key => $option) {
            $frontendOptions[$key] = array(
                'url' =>
Url::pathToUri($option['path'])
            );

            if (!empty($option['label'])) {
                $frontendOptions[$key]['label'] =
$option['label'];
            }
        }

        $jsParameters['column']  = min($this->column,
count($this->options) + ($this->hasDisabled ? 1 : 0));
        $jsParameters['options'] = $frontendOptions;

        Js::addInline('new _N2.FormElementImageList("' .
$this->fieldID . '", ' . json_encode($jsParameters) .
', ' . json_encode($this->relatedFields) . ');');

        return $html;
    }

    /**
     * @param bool $hasDisabled
     */
    public function setHasDisabled($hasDisabled) {
        $this->hasDisabled = $hasDisabled;
    }

    /**
     * @param int $width
     */
    public function setWidth($width) {
        $this->width = $width;
    }

    /**
     * @param int $column
     */
    public function setColumn($column) {
        $this->column = $column;
    }

    protected function postHTML() {
        return '';
    }
}Form/Element/Radio/ImageListFromFolder.php000064400000005553151161172460014461
0ustar00<?php

namespace Nextend\Framework\Form\Element\Radio;

use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\TraitFieldset;

class ImageListFromFolder extends ImageList implements ContainerInterface {

    use TraitFieldset;

    protected $folder = '';

    protected $filenameOnly = false;

    protected function fetchElement() {

        $this->initOptions();

        return parent::fetchElement();
    }

    private function initOptions() {

        $value        = $this->getValue();
        $currentValue = basename($value);
        if ($value !== $currentValue) {
            $this->setValue($currentValue);
        }


        $files = Filesystem::files($this->folder);
        for ($i = 0; $i < count($files); $i++) {
            $ext        = pathinfo($files[$i], PATHINFO_EXTENSION);
            $extensions = array(
                'jpg',
                'jpeg',
                'png',
                'svg',
                'gif',
                'webp'
            );
            if (in_array($ext, $extensions)) {

                $path = $this->folder . $files[$i];

                if ($this->filenameOnly) {
                    $value = pathinfo($files[$i], PATHINFO_FILENAME);
                } else {
                    $value = basename($files[$i]);
                }

                $this->options[$value] = array(
                    'path' => $path
                );
            }
        }

        if (!isset($this->options[$currentValue])) {
            foreach ($this->options AS $value => $option) {
                if (pathinfo($value, PATHINFO_FILENAME) == $currentValue) {
                    $currentValue = $value;
                    $this->setValue($currentValue);
                }
            }
        }
    }

    protected function postHTML() {
        if ($this->first) {
            $html = '<div
class="n2_field_image_list__fields">';

            $element = $this->first;
            while ($element) {
                $html .= $this->decorateElement($element);

                $element = $element->getNext();
            }

            $html .= '</div>';

            return $html;
        }

        return '';
    }

    public function setFolder($folder) {
        $this->folder = $folder;
    }

    public function setFilenameOnly($value) {
        $this->filenameOnly = $value;
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {
        $html = '<div class="n2_field">';
        $html .= '<div class="n2_field__label">';
        $html .= $element->fetchTooltip();
        $html .= '</div>';
        $html .= '<div
class="n2_field__element">';
        $html .= $element->fetchElement();
        $html .= '</div>';
        $html .= '</div>';

        return $html;
    }
}Form/Element/Radio/TextAlign.php000064400000001215151161172460012511
0ustar00<?php

namespace Nextend\Framework\Form\Element\Radio;

class TextAlign extends AbstractRadioIcon {

    protected $options = array(
        'inherit' => 'ssi_16 ssi_16--none',
        'left'    => 'ssi_16 ssi_16--textleft',
        'center'  => 'ssi_16 ssi_16--textcenter',
        'right'   => 'ssi_16 ssi_16--textright',
        'justify' => 'ssi_16 ssi_16--textjustify'
    );

    /**
     * @param $excluded array
     */
    public function setExcludeOptions($excluded) {
        foreach ($excluded AS $exclude) {
            if (isset($this->options[$exclude])) {
                unset($this->options[$exclude]);
            }

        }
    }
}Form/Element/Radio.php000064400000003416151161172460010617
0ustar00<?php


namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class Radio extends AbstractFieldHidden {

    protected $options = array();

    protected $class = 'n2_field_radio';

    protected $style = '';

    protected $value;

    protected function addScript() {
        Js::addInline('new _N2.FormElementRadio("' .
$this->fieldID . '", ' .
json_encode(array_keys($this->options)) . ', ' .
json_encode($this->relatedFields) . ');');
    }

    protected function fetchElement() {

        $this->value = $this->getValue();

        $html = Html::tag('div', array(
            'class' => $this->class,
            'style' => $this->style
        ), $this->renderOptions() . parent::fetchElement());

        $this->addScript();

        return $html;
    }

    /**
     * @return string
     */
    protected function renderOptions() {

        $html = '';
        $i    = 0;
        foreach ($this->options AS $value => $label) {
            $html .= Html::tag('div', array(
                'class' => 'n2_field_radio__option'
. ($this->isSelected($value) ? '
n2_field_radio__option--selected' : '')
            ), Html::tag('div', array(
                    'class' =>
'n2_field_radio__option_marker'
                ), '<i class="ssi_16
ssi_16--check"></i>') . '<div
class="n2_field_radio__option_label">' . $label .
'</div>');
            $i++;
        }

        return $html;
    }

    function isSelected($value) {
        if ((string)$value == $this->value) {
            return true;
        }

        return false;
    }

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

    public function setStyle($style) {
        $this->style = $style;
    }
}Form/Element/RichTextarea.php000064400000003324151161172460012142
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\View\Html;

class RichTextarea extends AbstractField {

    protected $fieldStyle = '';

    protected function fetchElement() {

        Js::addInline('new _N2.FormElementRichText("' .
$this->fieldID . '");');

        $tools = array(
            Html::tag('div', array(
                'class'       =>
'n2_field_textarea_rich__button',
                'data-action' => 'bold'
            ), Html::tag('I', array('class' =>
'ssi_16 ssi_16--bold'))),
            Html::tag('div', array(
                'class'       =>
'n2_field_textarea_rich__button',
                'data-action' => 'italic'
            ), Html::tag('I', array('class' =>
'ssi_16 ssi_16--italic'))),
            Html::tag('div', array(
                'class'       =>
'n2_field_textarea_rich__button',
                'data-action' => 'link'
            ), Html::tag('I', array('class' =>
'ssi_16 ssi_16--link')))
        );

        $buttons = Html::tag('div', array(
            'class' =>
'n2_field_textarea_rich__buttons'
        ), implode('', $tools));

        return Html::tag('div', array(
            'class' => 'n2_field_textarea_rich',
            'style' => $this->style
        ), $buttons . Html::tag('textarea', array(
                'id'           => $this->fieldID,
                'name'         => $this->getFieldName(),
                'autocomplete' => 'off',
                'style'        => $this->fieldStyle
            ), $this->getValue()));
    }

    /**
     * @param string $fieldStyle
     */
    public function setFieldStyle($fieldStyle) {
        $this->fieldStyle = $fieldStyle;
    }
}Form/Element/Select/Easing.php000064400000002755151161172460012213
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Form\Element\Select;

class Easing extends Select {

    protected $options = array(
        "linear"           => "Linear",
        "easeInQuad"       => "Quad In",
        "easeOutQuad"      => "Quad Out",
        "easeInOutQuad"    => "Quad In Out",
        "easeInCubic"      => "Cubic In",
        "easeOutCubic"     => "Cubic Out",
        "easeInOutCubic"   => "Cubic In Out",
        "easeInQuart"      => "Quart In",
        "easeOutQuart"     => "Quart Out",
        "easeInOutQuart"   => "Quart In Out",
        "easeInQuint"      => "Quint In",
        "easeOutQuint"     => "Quint Out",
        "easeInOutQuint"   => "Quint In Out",
        "easeInSine"       => "Sine In",
        "easeOutSine"      => "Sine Out",
        "easeInOutSine"    => "Sine In Out",
        "easeInExpo"       => "Expo In",
        "easeOutExpo"      => "Expo Out",
        "easeInOutExpo"    => "Expo In Out",
        "easeInCirc"       => "Circ In",
        "easeOutCirc"      => "Circ Out",
        "easeInOutCirc"    => "Circ In Out",
        "easeInElastic"    => "Elastic In",
        "easeOutElastic"   => "Elastic Out",
        "easeInOutElastic" => "Elastic In Out",
        "easeInBack"       => "Back In",
        "easeOutBack"      => "Back Out",
        "easeInOutBack"    => "Back In Out",
        "easeInBounce"     => "Bounce In",
        "easeOutBounce"    => "Bounce Out",
        "easeInOutBounce"  => "Bounce In Out"
    );
}Form/Element/Select/FillMode.php000064400000001456151161172460012475
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;

use Nextend\Framework\Form\Element\Select;

class FillMode extends Select {

    protected $useGlobal = false;

    protected function fetchElement() {

        $this->options = array(
            'fill'    => n2_('Fill'),
            'blurfit' => n2_('Blur fit'),
            'fit'     => n2_('Fit'),
            'stretch' => n2_('Stretch'),
            'center'  => n2_('Center')
        );

        if ($this->useGlobal) {
            $this->options = array_merge(array(
                'default' => n2_('Slider\'s
default')
            ), $this->options);
        }

        return parent::fetchElement();
    }

    /**
     * @param bool $useGlobal
     */
    public function setUseGlobal($useGlobal) {
        $this->useGlobal = $useGlobal;
    }
}Form/Element/Select/Filter.php000064400000001032151161172460012215
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Form\Element\Select;

class Filter extends Select {

    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        $no_label = strtolower($this->label);

        $this->options = array(
            '0'  => n2_('All'),
            '1'  => $this->label,
            '-1' => sprintf(n2_('Not %s'),
$no_label)
        );
    }
}Form/Element/Select/FontWeight.php000064400000001465151161172460013060
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Form\Element\Select;

class FontWeight extends Select {

    public function __construct($insertAt, $name = '', $label =
false, $default = '', $parameters = array()) {
        $this->options = array(
            '0'   => n2_('Normal'),
            '1'   => n2_('Bold'),
            '100' => '100',
            '200' => '200 - ' . n2_('Extra
light'),
            '300' => '300 - ' .
n2_('Light'),
            '400' => '400 - ' .
n2_('Normal'),
            '500' => '500',
            '600' => '600 - ' . n2_('Semi
bold'),
            '700' => '700 - ' .
n2_('Bold'),
            '800' => '800 - ' . n2_('Extra
bold'),
            '900' => '900'
        );
        parent::__construct($insertAt, $name, $label, $default,
$parameters);
    }
}Form/Element/Select/Gradient.php000064400000001066151161172460012534
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Form\Element\Select;

class Gradient extends Select {

    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        $this->options = array(
            'off'        => n2_('Off'),
            'vertical'   => '&darr;',
            'horizontal' => '&rarr;',
            'diagonal1'  => '&#8599;',
            'diagonal2'  => '&#8600;'
        );
    }
}Form/Element/Select/LinkTarget.php000064400000001031151161172460013033
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Form\Element\Select;

class LinkTarget extends Select {

    public function __construct($insertAt, $name = '', $label =
'', $default = '_self', array $parameters = array()) {
        $this->options = array(
            '_self'   => n2_('Self'),
            '_blank'  => n2_('New'),
            '_parent' => n2_('Parent'),
            '_top'    => n2_('Top')
        );

        parent::__construct($insertAt, $name, $label, $default,
$parameters);
    }
}Form/Element/Select/SelectFile.php000064400000002075151161172460013017
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Platform\Platform;

class SelectFile extends Select {

    /**
     * File constructor.
     *
     * @param        $insertAt
     * @param string $name
     * @param string $label
     * @param string $default
     * @param string $extension
     * @param array  $parameters
     *
     */
    public function __construct($insertAt, $name = '', $label =
'', $default = '', $extension = '',
$parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        $dir             = Platform::getPublicDirectory();
        $files           = scandir($dir);
        $validated_files = array();

        foreach ($files as $file) {
            if (strtolower(pathinfo($file, PATHINFO_EXTENSION)) ==
$extension) {
                $validated_files[] = $file;
            }
        }

        $this->options[''] = n2_('Choose');

        foreach ($validated_files AS $f) {
            $this->options[$f] = $f;
        }
    }
}Form/Element/Select/Skin.php000064400000002111151161172460011673
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Localization\Localization;

class Skin extends Select {

    protected $fixed = false;

    protected function fetchElement() {

        $html = parent::fetchElement();

        Js::addInline('new _N2.FormElementSkin("' .
$this->fieldID . '", "' .
str_replace($this->name, '', $this->fieldID) .
'", ' . json_encode($this->options) . ', ' .
json_encode($this->fixed) . ');');

        return $html;
    }

    protected function renderOptions($options) {
        $html = '';
        if (!$this->fixed) {
            $html .= '<option value="0"
selected="selected">' . n2_('Choose') .
'</option>';
        }
        foreach ($options as $value => $option) {
            $html .= '<option ' . $this->isSelected($value)
. ' value="' . $value . '">' .
$option['label'] . '</option>';
        }

        return $html;
    }

    /**
     * @param bool $fixed
     */
    public function setFixed($fixed) {
        $this->fixed = $fixed;
    }
}Form/Element/Select/SubFormIcon.php000064400000006011151161172460013160
0ustar00<?php


namespace Nextend\Framework\Form\Element\Select;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Container\ContainerSubform;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\Element\AbstractFieldHidden;
use Nextend\Framework\Form\TraitFieldset;
use Nextend\Framework\View\Html;

abstract class SubFormIcon extends AbstractFieldHidden {

    protected $ajaxUrl = '';

    /**
     * @var ContainerSubform
     */
    protected $containerSubform;

    protected $plugins = array();

    protected $options = array();

    /**
     * SubFormIcon constructor.
     *
     * @param TraitFieldset      $insertAt
     * @param string             $name
     * @param ContainerInterface $container
     * @param string             $ajaxUrl
     * @param string             $default
     * @param array              $parameters
     */
    public function __construct($insertAt, $name, $container, $ajaxUrl,
$default = '', $parameters = array()) {

        $this->ajaxUrl = $ajaxUrl;

        parent::__construct($insertAt, $name, '', $default,
$parameters);

        $this->loadOptions();

        $this->containerSubform = new ContainerSubform($container, $name
. '-subform');

        $this->getCurrentPlugin($this->getValue())
             ->renderFields($this->containerSubform);
    }

    protected function fetchElement() {

        $currentValue = $this->getValue();

        Js::addInline('
            new _N2.FormElementSubformIcon(
               "' . $this->fieldID . '",
              "' . $this->ajaxUrl . '",
               "' . $this->containerSubform->getId() .
'",
               "' . $currentValue . '"
            );
        ');
        $html = Html::openTag('div', array(
            'class' => 'n2_field_subform_icon'
        ));
        foreach ($this->options AS $value => $option) {
            $html .= Html::tag('div', array(
                'class'      =>
'n2_field_subform_icon__option' . ($value == $currentValue ?
' n2_field_subform_icon__option--selected' : ''),
                'data-value' => $value
            ), Html::tag('div', array(
                    'class' =>
'n2_field_subform_icon__option_icon'
                ), '<i class="' .
$option['icon'] . '"></i>') .
Html::tag('div', array(
                    'class' =>
'n2_field_subform_icon__option_label'
                ), $option['label']));
        }

        $html .= parent::fetchElement() . '</div>';

        return $html;
    }

    protected abstract function loadOptions();


    protected function getCurrentPlugin($value) {

        if (!isset($this->plugins[$value])) {
            list($value) = array_keys($this->plugins);
            $this->setValue($value);
        }

        return $this->plugins[$value];
    }

    /**
     * @param string $option
     */
    public function removeOption($option) {
        if (isset($this->options[$option])) {
            unset($this->options[$option]);

            if ($this->getValue() === $option) {
                $this->setValue($this->defaultValue);
            }
        }
    }
}Form/Element/Select.php000064400000011030151161172460010767
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class Select extends AbstractFieldHidden {

    public $value;

    protected $values = array();
    protected $options = array();
    protected $optgroup = array();
    protected $isMultiple = false;
    protected $size = '';

    protected $relatedValueFields = array();
    protected $relatedAttribute = '';

    protected function fetchElement() {

        $this->values = explode('||', $this->getValue());
        if (!is_array($this->values)) {
            $this->values = array();
        }

        $html = Html::openTag("div", array(
            "class" => "n2_field_select",
            "style" => $this->style
        ));

        $selectAttributes = array(
            'id'              => $this->fieldID .
'_select',
            'name'            => 'select' .
$this->getFieldName(),
            'aria-labelledby' => $this->fieldID,
            'autocomplete'    => 'off'
        );

        if (!empty($this->size)) {
            $selectAttributes['size'] = $this->size;
        }

        if ($this->isMultiple) {
            $selectAttributes['multiple'] = 'multiple';
            $selectAttributes['class']    =
'nextend-element-hastip';
            $selectAttributes['title']    = n2_('Hold down
the ctrl (Windows) or command (MAC) button to select multiple
options.');
        }

        $html .= Html::tag('select', $selectAttributes,
$this->renderOptions($this->options) . (!empty($this->optgroup) ?
$this->renderOptgroup() : ''));

        $html .= Html::closeTag("div");

        $html .= parent::fetchElement();

        $options = array();

        if (!empty($this->relatedFields)) {
            $options['relatedFields'] = $this->relatedFields;
        }

        if (!empty($this->relatedValueFields)) {
            $options['relatedValueFields'] =
$this->relatedValueFields;
        }

        if (!empty($this->relatedAttribute)) {
            $options['relatedAttribute'] =
$this->relatedAttribute;
        }

        Js::addInline('new _N2.FormElementList("' .
$this->fieldID . '", ' . json_encode($options) .
');');

        return $html;
    }

    /**
     *
     * @return string
     */
    protected function renderOptgroup() {
        $html = '';
        foreach ($this->optgroup as $label => $options) {
            if (is_array($options)) {
                $html .= "<optgroup label='" . $label .
"'>";
                $html .= $this->renderOptions($options);
                $html .= "</optgroup>";
            } else {
                $html .= $this->renderOption($label, $options);
            }
        }

        return $html;
    }

    /**
     * @param array $options
     *
     * @return string
     */
    protected function renderOptions($options) {
        $html = '';
        foreach ($options as $value => $label) {
            $html .= $this->renderOption($value, $label);
        }

        return $html;
    }

    protected function renderOption($value, $label) {

        return '<option value="' . $value . '"
' . $this->isSelected($value) . '>' . $label .
'</option>';
    }

    protected function isSelected($value) {
        if (in_array($value, $this->values)) {
            return ' selected="selected"';
        }

        return '';
    }

    /**
     * @param array $options
     */
    public function setOptions($options) {

        $this->options = $options;
    }

    /**
     * @param array $optgroup
     */
    public function setOptgroup($optgroup) {
        $this->optgroup = $optgroup;
    }

    /**
     * @param bool $isMultiple
     */
    public function setIsMultiple($isMultiple) {
        $this->isMultiple = $isMultiple;
        $this->size       = 10;
    }

    /**
     * @param string $size
     */
    public function setSize($size) {
        $this->size = $size;
    }

    protected function createTree(&$list, &$new, $parent, $cindent
= '', $indent = '- ') {

        if (isset($new[$parent])) {
            for ($i = 0; $i < count($new[$parent]); $i++) {
                $new[$parent][$i]->treename = $cindent .
$new[$parent][$i]->name;
                $list[]                     = $new[$parent][$i];
                $this->createTree($list, $new,
$new[$parent][$i]->cat_ID, $cindent . $indent, $indent);
            }
        }

        return $list;
    }

    public function setRelatedValueFields($relatedValueFields) {
        $this->relatedValueFields = $relatedValueFields;
    }

    public function setRelatedAttribute($relatedAttribute) {
        $this->relatedAttribute = $relatedAttribute;
    }
}Form/Element/SelectIcon.php000064400000003266151161172460011614
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class SelectIcon extends AbstractFieldHidden {

    protected $options;

    public function __construct($insertAt, $name = '', $label =
false, $options = array(), $default = '', $parameters = array())
{

        $this->options = $options;

        parent::__construct($insertAt, $name, $label, $default,
$parameters);
    }


    protected function fetchElement() {

        $currentValue = $this->getValue();

        $html = Html::openTag('div', array(
            'class' => 'n2_field_select_icon'
        ));

        foreach ($this->options AS $value => $option) {

            $classes = array('n2_field_select_icon__option');
            if ($currentValue == $value) {
                $classes[] =
'n2_field_select_icon__option--selected';
            }

            $html .= Html::tag('div', array(
                'class'      => implode(' ',
$classes),
                'data-value' => $value
            ), Html::tag('div', array(
                    'class' =>
'n2_field_select_icon__option_icon'
                ), '<i class="' .
$option['icon'] . '"></i>') .
Html::tag('div', array(
                    'class' =>
'n2_field_select_icon__option_label'
                ), $option['label']) . Html::tag('div',
array(
                    'class' =>
'n2_field_select_icon__selected_marker'
                ), '<i class="ssi_16
ssi_16--check"></i>'));
        }

        $html .= Html::closeTag('div');

        $html .= parent::fetchElement();

        Js::addInline('new _N2.FormElementSelectIcon("' .
$this->fieldID . '", ' . json_encode(array()) .
');');

        return $html;
    }
}Form/Element/Style.php000064400000004256151161172460010664
0ustar00<?php

namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\Style\StyleManager;
use Nextend\Framework\Style\StyleParser;
use Nextend\Framework\View\Html;

class Style extends AbstractFieldHidden {

    protected $mode = '';

    protected $font = '';

    protected $font2 = '';

    protected $style2 = '';

    protected $preview = '';

    protected $css = '';

    protected function addScript() {

        StyleManager::enqueue($this->getForm());

        $preview =
preg_replace_callback('/url\(\'(.*?)\'\)/', array(
            $this,
            'fixPreviewImages'
        ), $this->preview);

        Js::addInline('new _N2.FormElementStyle("' .
$this->fieldID . '", {
            mode: "' . $this->mode . '",
            label: "' . $this->label . '",
            font: "' . $this->font . '",
            font2: "' . $this->font2 . '",
            style2: "' . $this->style2 . '",
            preview: ' . json_encode($preview) . '
        });');
    }

    protected function fetchElement() {

        $this->addScript();

        return Html::tag('div', array(
            'class' => 'n2_field_style'
        ), n2_('Style') . parent::fetchElement());
    }

    public function fixPreviewImages($matches) {
        return "url(" . ResourceTranslator::toUrl($matches[1]) .
")";
    }

    public function getValue() {

        return StyleParser::parse(parent::getValue());
    }

    /**
     * @param string $mode
     */
    public function setMode($mode) {
        $this->mode = $mode;
    }

    /**
     * @param string $font
     */
    public function setFont($font) {
        $this->font = $font;
    }

    /**
     * @param string $font2
     */
    public function setFont2($font2) {
        $this->font2 = $font2;
    }

    /**
     * @param string $style2
     */
    public function setStyle2($style2) {
        $this->style2 = $style2;
    }

    /**
     * @param string $preview
     */
    public function setPreview($preview) {
        $this->preview = $preview;
    }

    /**
     * @param string $css
     */
    public function setCss($css) {
        $this->css = $css;
    }
}Form/Element/Tab.php000064400000003316151161172460010266 0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class Tab extends AbstractFieldHidden {

    protected $options = array();
    protected $relatedValueFields = array();

    protected function fetchElement() {

        if (empty($this->defaultValue) &&
!empty($this->options)) {
            $this->defaultValue = array_keys($this->options)[0];
        }

        $html = Html::openTag("div", array(
            "id"    => $this->fieldID . "_tab",
            "class" => "n2_field_tab",
            "style" => $this->style
        ));

        $html .= $this->renderOptions();

        $html .= Html::closeTag("div");

        $html .= parent::fetchElement();

        Js::addInline('new _N2.FormElementTab("' .
$this->fieldID . '", ' .
json_encode($this->relatedValueFields) . ');');

        return $html;
    }

    /**
     * @param array $options
     */
    public function setOptions($options) {

        $this->options = $options;
    }

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

    public function renderOptions() {
        $html = '';
        foreach ($this->options AS $option => $label) {
            $class = 'n2_field_tab__option';
            if ($option == $this->defaultValue) {
                $class .= ' n2_field_tab__option--selected';
            }
            $html .= Html::openTag("div", array(
                "class"       => $class,
                "data-ssoption" => $option
            ));
            $html .= $label;
            $html .= Html::closeTag("div");
        }

        return $html;
    }
}Form/Element/Text/Color.php000064400000001573151161172460011565
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\Text;

class Color extends Text {

    protected $alpha = false;

    protected $class = 'n2_field_color ';

    protected function fetchElement() {

        if ($this->alpha) {
            $this->class .= 'n2_field_color--alpha ';
        }

        $html = parent::fetchElement();
        Js::addInline('new _N2.FormElementColor("' .
$this->fieldID . '", ' . intval($this->alpha) .
');');

        return $html;
    }

    protected function pre() {

        return '<div class="n2-field-color-preview
n2_checker_box"><div
class="n2-field-color-preview-inner"></div></div>';
    }

    protected function post() {
        return '';
    }

    /**
     * @param boolean $alpha
     */
    public function setAlpha($alpha) {
        $this->alpha = $alpha;
    }
}Form/Element/Text/Disabled.php000064400000000276151161172460012215
0ustar00<?php

namespace Nextend\Framework\Form\Element\Text;

use Nextend\Framework\Form\Element\Text;

class Disabled extends Text {

    protected $attributes = array('disabled' =>
'disabled');
}Form/Element/Text/Family.php000064400000001006151161172460011717
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Font\FontSettings;
use Nextend\Framework\Form\Element\Text;

class Family extends Text {

    protected $class = 'n2_field_autocomplete
n2_autocomplete_position_to';

    protected function addScript() {
        parent::addScript();

        $families = FontSettings::getPresetFamilies();
        Js::addInline('_N2.AutocompleteSimple("' .
$this->fieldID . '", ' . json_encode($families) .
');');
    }
}Form/Element/Text/FieldImage.php000064400000002767151161172460012503
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Browse\BrowseManager;
use Nextend\Framework\Form\Element\AbstractChooserText;
use Nextend\Framework\Image\Image;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\Sanitize;

class FieldImage extends AbstractChooserText {

    protected $attributes = array();

    protected $relatedAlt = '';

    protected $class = ' n2_field_text_image';

    protected function addScript() {

        $options = array();
        if (!empty($this->relatedAlt)) {
            $options['alt'] = $this->relatedAlt;
        }

        Js::addInline("new _N2.FormElementImage('" .
$this->fieldID . "', " . json_encode($options) . "
);");
    }

    protected function fetchElement() {

        BrowseManager::enqueue($this->getForm());

        $html = parent::fetchElement();

        Image::initLightbox();

        return $html;
    }

    protected function pre() {

        return '<div class="n2_field_text_image__preview"
style="' . $this->getImageStyle() .
'"></div>';
    }

    protected function getImageStyle() {
        $image = $this->getValue();
        if (empty($image) || $image[0] == '{') {
            return '';
        }

        return 'background-image:URL(' .
Sanitize::esc_attr(ResourceTranslator::toUrl($image)) . ');';
    }

    /**
     * @param string $relatedAlt
     */
    public function setRelatedAlt($relatedAlt) {
        $this->relatedAlt = $relatedAlt;
    }
}Form/Element/Text/FieldImageResponsive.php000064400000001472151161172460014551
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Image\ImageManager;
use Nextend\Framework\View\Html;

class FieldImageResponsive extends FieldImage {

    protected function fetchElement() {
        ImageManager::enqueue($this->getForm());
    

        $html = parent::fetchElement();

        $html .= Html::tag('a', array(
            'id'         => $this->fieldID .
'_manage',
            'class'      => 'n2_field_button
n2_field_button--icon n2_field_text_image__button',
            'href'       => '#',
            'data-n2tip' => n2_('Select images for
devices')
        ), '<i class="ssi_16
ssi_16--desktopportrait"></i>');

        Js::addInline('new _N2.FormElementImageManager("' .
$this->fieldID . '", {});');
    

        return $html;
    }
}Form/Element/Text/Folder.php000064400000002117151161172460011715
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Browse\BrowseManager;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\Image\Image;
use Nextend\Framework\View\Html;

class Folder extends Text {

    protected $width = 300;

    protected function addScript() {

        BrowseManager::enqueue($this->getForm());

        Image::initLightbox();

        Js::addInline("new _N2.FormElementFolders('" .
$this->fieldID . "' );");
    }

    protected function post() {

        $html = Html::tag('a', array(
            'href'     => '#',
            'class'    => 'n2_field_text__clear',
            'tabindex' => -1
        ), Html::tag('i', array('class' =>
'ssi_16 ssi_16--circularremove'), ''));

        $html .= Html::tag('a', array(
            'href'       => '#',
            'class'      => 'n2_field_text__choose',
            'aria-label' => n2_('Choose')
        ), '<i class="ssi_16
ssi_16--plus"></i>');

        return $html;
    }

    public function setWidth($width) {
        $this->width = $width;
    }
}Form/Element/Text/HiddenText.php000064400000000374151161172460012545
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Form\Element\Text;

class HiddenText extends Text {

    public $fieldType = 'hidden';

    public function getRowClass() {
        return 'n2_form_element--hidden';
    }
}Form/Element/Text/Number.php000064400000005414151161172460011735
0ustar00<?php

namespace Nextend\Framework\Form\Element\Text;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\View\Html;

class Number extends Text {

    protected $class = 'n2_field_number ';

    protected $min = false;
    protected $max = false;
    protected $sublabel = '';

    protected $units = false;

    protected function fetchElement() {

        if ($this->min === false) {
            $this->min = '-Number.MAX_VALUE';
        }

        if ($this->max === false) {
            $this->max = 'Number.MAX_VALUE';
        }

        $this->addScript();

        $this->renderRelatedFields();

        $html = Html::openTag('div', array(
            'class' => 'n2_field_text ' .
$this->getClass(),
            'style' => ($this->fieldType ==
'hidden' ? 'display: none;' : '')
        ));

        if (!empty($this->sublabel)) {
            $html .= Html::tag('div', array(
                'class' =>
'n2_field_text__pre_label'
            ), $this->sublabel);
        }

        $html .= $this->pre();

        $html .= Html::tag('input', array(
            'type'         => $this->fieldType,
            'id'           => $this->fieldID,
            'name'         => $this->getFieldName(),
            'value'        => $this->getValue(),
            'style'        => $this->getStyle(),
            'autocomplete' => 'off'
        ), false, false);

        $html .= $this->post();

        if ($this->unit) {
            $html .= Html::tag('div', array(
                'class' => 'n2_field_number__unit'
            ), $this->unit);
        }
        $html .= "</div>";

        return $html;
    }

    protected function addScript() {
        Js::addInline('new _N2.FormElementNumber("' .
$this->fieldID . '", ' . $this->min . ', ' .
$this->max . ', ' . json_encode($this->units) .
');');
    }

    public function setMin($min) {
        $this->min = $min;
    }

    /**
     * @param int $max
     */
    public function setMax($max) {
        $this->max = $max;
    }

    /**
     * @param string $sublabel
     */
    public function setSublabel($sublabel) {
        $this->sublabel = $sublabel;
    }

    /**
     * @param bool|array $units
     */
    public function setUnits($units) {
        $this->units = $units;
    }

    public function setWide($wide) {
        switch ($wide) {
            case 2:
                $this->style .= 'width:20px;';
                break;
            case 3:
                $this->style .= 'width:26px;';
                break;
            case 4:
                $this->style .= 'width:32px;';
                break;
            case 5:
                $this->style .= 'width:44px;';
                break;
            case 6:
                $this->style .= 'width:60px;';
                break;
        }
    }
}Form/Element/Text/NumberAutoComplete.php000064400000001051151161172460014250
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;

class NumberAutoComplete extends Number {

    protected $values = array();

    protected $class = 'n2_field_number n2_autocomplete_position_to
';

    protected function addScript() {
        parent::addScript();

        Js::addInline('_N2.AutocompleteSimple("' .
$this->fieldID . '", ' . json_encode($this->values) .
');');
    }

    /**
     * @param array $values
     */
    public function setValues($values) {
        $this->values = $values;
    }
}Form/Element/Text/NumberSlider.php000064400000002053151161172460013074
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;

class NumberSlider extends Number {

    protected $step = 1;

    protected $sliderMax;

    protected function fetchElement() {
        $html = parent::fetchElement();

        Js::addInline('new _N2.FormElementNumberSlider("' .
$this->fieldID . '", ' . json_encode(array(
                'min'   => floatval($this->min),
                'max'   => floatval($this->sliderMax),
                'step'  => floatval($this->step),
                'units' => $this->units
            )) . ');');

        return $html;
    }

    /**
     * @param int $step
     */
    public function setStep($step) {
        $this->step = $step;
    }

    /**
     * @param int $sliderMax
     */
    public function setSliderMax($sliderMax) {
        $this->sliderMax = $sliderMax;
    }

    /**
     * @param int $max
     */
    public function setMax($max) {
        parent::setMax($max);

        if ($this->sliderMax === null) {
            $this->sliderMax = $max;
        }
    }
}Form/Element/Text/TextAutoComplete.php000064400000001123151161172460013744
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\Text;

class TextAutoComplete extends Text {

    protected $class = 'n2_field_autocomplete
n2_autocomplete_position_to';

    protected $values = array();

    protected function addScript() {
        parent::addScript();

        Js::addInline('_N2.AutocompleteSimple("' .
$this->fieldID . '", ' . json_encode($this->values) .
');');
    }

    /**
     * @param array $values
     */
    public function setValues($values) {
        $this->values = $values;
    }
}Form/Element/Text/TextMultiAutoComplete.php000064400000001527151161172460014767
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\View\Html;

class TextMultiAutoComplete extends Text {

    protected $options = array();

    protected $class = 'n2_field_autocomplete ';

    protected function addScript() {
        Js::addInline('new _N2.FormElementAutocomplete("' .
$this->fieldID . '", ' . json_encode($this->options) .
');');
    }

    protected function post() {
        return Html::tag('a', array(
            'href'  => '#',
            'class' => 'n2_field_text__clear',
            'tabindex' => -1
        ), Html::tag('i', array('class' =>
'ssi_16 ssi_16--circularremove'), ''));
    }

    /**
     * @param array $options
     */
    public function setOptions($options) {
        $this->options = $options;
    }
}Form/Element/Text/Url.php000064400000002263151161172460011246
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Element\AbstractChooserText;
use Nextend\Framework\Localization\Localization;
use Nextend\Framework\Pattern\MVCHelperTrait;
use Nextend\Framework\Platform\Platform;

class Url extends AbstractChooserText {

    protected function addScript() {
        Js::addInline("new _N2.FormElementUrl('" .
$this->fieldID . "', " .
$this->getElementUrlParameters($this->getForm()) . " );");
    }

    /**
     * @param MVCHelperTrait $MVCHelper
     *
     * @return string
     */
    private function getElementUrlParameters($MVCHelper) {
        $params = array(
            'hasPosts' => Platform::hasPosts()
        );

        $params['url'] =
$MVCHelper->createAjaxUrl("content/searchlink");
        $params['labelButton']      = 'Joomla';
        $params['labelDescription'] = n2_(/** @lang text */
'Select article or menu item from your site.');
    

        return json_encode($params);
    }

    protected function post() {

        return parent::post();
    }

    /**
     * @param int $width
     */
    public function setWidth($width) {
        $this->width = $width;
    }

}Form/Element/Text/Video.php000064400000000452151161172460011550
0ustar00<?php


namespace Nextend\Framework\Form\Element\Text;


use Nextend\Framework\Browse\BrowseManager;

class Video extends FieldImage {

    protected function fetchElement() {

        BrowseManager::enqueue($this->getForm());

        $html = parent::fetchElement();

        return $html;
    }
}Form/Element/Text.php000064400000004473151161172460010511 0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\TraitFieldset;
use Nextend\Framework\View\Html;

class Text extends AbstractField implements ContainerInterface {

    use TraitFieldset;

    protected $attributes = array();

    public $fieldType = 'text';

    protected $unit = false;

    protected function addScript() {
        Js::addInline('new _N2.FormElementText("' .
$this->fieldID . '");');
    }

    protected function fetchElement() {

        $this->addScript();

        if ($this->getValue() === '') {
            $this->class .= 'n2_field_text--empty ';
        }

        $html = Html::openTag('div', array(
            'class' => 'n2_field_text ' .
$this->getClass(),
            'style' => ($this->fieldType ==
'hidden' ? 'display: none;' : '')
        ));

        $html .= $this->pre();
        $html .= Html::tag('input', $this->attributes + array(
                'type'         => $this->fieldType,
                'id'           => $this->fieldID,
                'name'         => $this->getFieldName(),
                'value'        => $this->getValue(),
                'style'        => $this->getStyle(),
                'autocomplete' => 'off'
            ), false, false);

        $html .= $this->post();

        if (!empty($this->unit)) {
            $html .= Html::tag('div', array(
                'class' => 'n2_field_text__unit'
            ), $this->unit);
        }
        $html .= "</div>";

        return $html;
    }

    public function setUnit($unit) {
        $this->unit = $unit;
    }

    protected function pre() {
        return '';
    }

    protected function post() {

        if ($this->first) {
            $html = '';

            $element = $this->first;
            while ($element) {

                $html .= $this->decorateElement($element);

                $element = $element->getNext();
            }

            return '<div
class="n2_field_text__post">' . $html .
'</div>';
        }

        return '';
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        list($label, $fieldHTML) = $element->render();

        return $fieldHTML;
    }
}Form/Element/Textarea/TextareaInline.php000064400000000467151161172460014255
0ustar00<?php


namespace Nextend\Framework\Form\Element\Textarea;


use Nextend\Framework\Form\Element\Textarea;

class TextareaInline extends Textarea {

    protected $width = 200;

    protected $height = 26;

    protected $classes = array(
        'n2_field_textarea',
        'n2_field_textarea--inline'
    );
}Form/Element/Textarea.php000064400000003275151161172460011341
0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Sanitize;
use Nextend\Framework\View\Html;

class Textarea extends AbstractField {

    protected $width = 200;

    protected $height = 44;

    protected $minHeight = 44;

    protected $resize = 'vertical';

    protected $classes = array(
        'n2_field_textarea'
    );

    protected function fetchElement() {

        Js::addInline('new _N2.FormElementText("' .
$this->fieldID . '");');

        return Html::tag('div', array(
            'class' => implode(' ',
$this->classes),
            'style' => $this->style
        ), Html::tag('textarea', array(
            'id'           => $this->fieldID,
            'name'         => $this->getFieldName(),
            'autocomplete' => 'off',
            'style'        => 'width:' .
$this->width . 'px;height:' . $this->height .
'px;min-height:' . $this->minHeight . 'px;resize:' .
$this->resize . ';'
        ), Sanitize::esc_textarea($this->getValue())));
    }

    /**
     * @param int $width
     */
    public function setWidth($width) {
        $this->width = $width;
    }

    /**
     * @param int $height
     */
    public function setHeight($height) {
        $this->height = $height;
        if ($this->minHeight > $height) {
            $this->minHeight = $height;
        }
    }

    /**
     * @param int $minHeight
     */
    public function setMinHeight($minHeight) {
        $this->minHeight = $minHeight;
    }

    /**
     * @param string $resize
     */
    public function setResize($resize) {
        $this->resize = $resize;
    }

    public function setFieldStyle($style) {

    }
}Form/Element/Token.php000064400000000304151161172460010632
0ustar00<?php


namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Form\Form;

class Token extends Hidden {

    protected function fetchElement() {

        return Form::tokenize();
    }
}Form/Element/Unit.php000064400000002642151161172460010500 0ustar00<?php


namespace Nextend\Framework\Form\Element;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\View\Html;

class Unit extends AbstractFieldHidden {

    protected $style = '';

    protected $units = array();

    protected function fetchElement() {

        $values = array();

        $html = "<div class='n2_field_unit'
style='" . $this->style . "'>";

        $currentValue = $this->getValue();
        $currentLabel = '';

        $html .= Html::openTag('div', array(
            'class' => 'n2_field_unit__units'
        ));
        foreach ($this->units AS $unit) {
            $values[] = $unit;

            $html .= Html::tag('div', array(
                'class' => 'n2_field_unit__unit'
            ), $unit);

            if ($currentValue == $unit) {
                $currentLabel = $unit;
            }
        }

        $html .= "</div>";

        $html .= Html::tag('div', array(
            'class' => 'n2_field_unit__current_unit'
        ), $currentLabel);

        $html .= parent::fetchElement();

        $html .= "</div>";

        Js::addInline('new _N2.FormElementUnits("' .
$this->fieldID . '", ' . json_encode($values) .
');');

        return $html;
    }

    /**
     * @param string $style
     */
    public function setStyle($style) {
        $this->style = $style;
    }

    /**
     * @param array $units
     */
    public function setUnits($units) {
        $this->units = $units;
    }
}Form/Element/Upload.php000064400000002016151161172460011000
0ustar00<?php

namespace Nextend\Framework\Form\Element;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\View\Html;

class Upload extends AbstractField {

    protected $class = 'n2-form-element-file ';

    protected function fetchElement() {

        $html = '';
        $html .= '<div
class="n2_field_chooser__label"></div>';
        $html .= Html::tag('a', array(
            'href'  => '#',
            'class' => 'n2_field_chooser__choose'
        ), '<i class="ssi_16
ssi_16--plus"></i>');

        $html .= Html::tag('input', array(
            'type'         => 'file',
            'id'           => $this->fieldID,
            'name'         => $this->getFieldName(),
            'value'        => $this->getValue(),
            'autocomplete' => 'off'
        ), false, false);

        Js::addInline('new _N2.FormElementUpload("' .
$this->fieldID . '");');

        return Html::tag('div', array(
            'class' => 'n2_field_chooser n2_field_upload
'
        ), $html);
    }
}Form/Fieldset/FieldsetHidden.php000064400000001134151161172460012575
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset;

use Nextend\Framework\Form\AbstractFieldset;

class FieldsetHidden extends AbstractFieldset {

    public function __construct($insertAt) {

        parent::__construct($insertAt, '');
    }

    public function renderContainer() {

        if ($this->first) {
            echo '<div
class="n2_form_element--hidden">';

            $element = $this->first;
            while ($element) {
                echo $this->decorateElement($element);

                $element = $element->getNext();
            }

            echo '</div>';
        }
    }

}Form/Fieldset/FieldsetRow.php000064400000003360151161172460012154
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\AbstractFieldset;
use Nextend\Framework\View\Html;

class FieldsetRow extends AbstractFieldset {

    public function __construct($insertAt, $name, $parameters = array()) {
        parent::__construct($insertAt, $name, false, $parameters);
    }

    public function renderContainer() {

        $classes = array('n2_form__table_row');
        if (!$this->isVisible) {
            $classes[] = 'n2_form__table_row--hidden';
        }

        echo Html::openTag('div', array(
            'class'      => implode(' ', $classes),
            'data-field' => 'table-row-' .
$this->name
        ));

        $element = $this->first;
        while ($element) {
            echo $this->decorateElement($element);

            $element = $element->getNext();
        }
        echo '</div>';
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        ob_start();

        $hasLabel = $element->hasLabel();

        $classes = array(
            'n2_field',
            $element->getLabelClass(),
            $element->getRowClass()
        );

        echo Html::openTag('div', array(
                'class'      => implode(' ',
array_filter($classes)),
                'data-field' => $element->getID()
            ) + $element->getRowAttributes());

        if ($hasLabel) {
            echo "<div class='n2_field__label'>";
            $element->displayLabel();
            echo "</div>";
        }

        echo "<div class='n2_field__element'>";
        $element->displayElement();
        echo "</div>";

        echo "</div>";

        return ob_get_clean();
    }
}Form/Fieldset/FieldsetRowPlain.php000064400000001307151161172470013140
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset;


use Nextend\Framework\Form\AbstractField;

class FieldsetRowPlain extends FieldsetRow {

    public function renderContainer() {
        echo '<div class="n2_form__table_row_plain"
data-field="table-row-plain-' . $this->name .
'">';

        $element = $this->first;
        while ($element) {
            echo $this->decorateElement($element);

            $element = $element->getNext();
        }

        echo '</div>';
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        ob_start();

        $element->displayElement();

        return ob_get_clean();
    }
}Form/Fieldset/FieldsetTableLabel.php000064400000001236151161172470013375
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset;


use Nextend\Framework\Form\AbstractFieldset;
use Nextend\Framework\View\Html;

class FieldsetTableLabel extends AbstractFieldset {

    public function renderContainer() {

        $element = $this->first;
        while ($element) {

            echo Html::openTag('div', array(
                    'class'      =>
'n2_form__table_label_field ' . $element->getRowClass(),
                    'data-field' => $element->getID()
                ) + $element->getRowAttributes());
            echo $this->decorateElement($element);
            echo "</div>";

            $element = $element->getNext();
        }
    }
}Form/Fieldset/FieldsetVisualSet.php000064400000002256151161172470013330
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\AbstractFieldset;
use Nextend\Framework\View\Html;

class FieldsetVisualSet extends AbstractFieldset {

    public function renderContainer() {
        echo '<div class="n2_form__visual_set"
data-field="visual-set-' . $this->name .
'">';

        echo "<div
class='n2_form__visual_set_label'>" . $this->label .
'</div>';

        $element = $this->first;
        while ($element) {
            echo $this->decorateElement($element);

            $element = $element->getNext();
        }
        echo '</div>';
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        ob_start();

        $classes = array(
            'n2_field',
            $element->getRowClass()
        );

        echo Html::openTag('div', array(
                'class'      => implode(' ',
array_filter($classes)),
                'data-field' => $element->getID()
            ) + $element->getRowAttributes());

        $element->displayElement();

        echo "</div>";

        return ob_get_clean();
    }
}Form/Fieldset/LayerWindow/FieldsetDesign.php000064400000003110151161172470015054
0ustar00<?php

namespace Nextend\Framework\Form\Fieldset\LayerWindow;

use Nextend\Framework\Form\Element\Button\ButtonIcon;
use Nextend\Framework\Form\Element\Select;

class FieldsetDesign extends FieldsetLayerWindowLabelFields {

    public function __construct($insertAt, $name, $label) {
        parent::__construct($insertAt, $name, $label);

        $this->addAttribute('data-fieldset-type',
'design');

        new ButtonIcon($this->fieldsetLabel, $name .
'-reset-to-normal', false, 'ssi_16 ssi_16--reset',
array(
            'hoverTip'      => n2_('Reset to normal
state'),
            'rowAttributes' => array(
                'data-design-feature' =>
'reset-to-normal'
            )
        ));
        new Select($this->fieldsetLabel, $name . '-element',
false, '', array(
            'rowAttributes' => array(
                'data-design-feature' => 'element'
            )
        ));
        new Select($this->fieldsetLabel, $name . '-state',
false, '', array(
            'rowAttributes' => array(
                'data-design-feature' => 'state'
            )
        ));
    }

    protected function renderTitle() {

        echo '<div
class="n2_fields_layer_window__label">' . $this->label
. '</div>';

        if ($this->fieldsetLabel->hasFields()) {
            echo '<div
class="n2_fields_layer_window__title_fields">';
            $this->fieldsetLabel->renderContainer();
            echo '</div>';
        }
    }

    /**
     * @param mixed $parentDesign
     */
    public function setParentDesign($parentDesign) {
        $this->addAttribute('data-parent-design',
$parentDesign);
    }
}Form/Fieldset/LayerWindow/FieldsetInsideLabel.php000064400000001240151161172470016020
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset\LayerWindow;


use Nextend\Framework\Form\AbstractFieldset;
use Nextend\Framework\View\Html;

class FieldsetInsideLabel extends AbstractFieldset {

    public function renderContainer() {

        $element = $this->first;
        while ($element) {

            echo Html::openTag('div', array(
                    'class'      =>
'n2_form__table_label_field ' . $element->getRowClass(),
                    'data-field' => $element->getID()
                ) + $element->getRowAttributes());
            $element->displayElement();
            echo "</div>";

            $element = $element->getNext();
        }
    }
}Form/Fieldset/LayerWindow/FieldsetLayerWindow.php000064400000004363151161172470016122
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset\LayerWindow;


use Nextend\Framework\Form\AbstractField;
use Nextend\Framework\Form\AbstractFieldset;
use Nextend\Framework\View\Html;

class FieldsetLayerWindow extends AbstractFieldset {

    protected $attributes = array();

    public function renderContainer() {

        echo Html::openTag('div', array(
                'class'      =>
'n2_fields_layer_window',
                'data-field' =>
'fieldset-layer-window-' . $this->name
            ) + $this->attributes);

        if (!empty($this->label)) {
            echo '<div
class="n2_fields_layer_window__title">';
            $this->renderTitle();
            echo '</div>';
        }

        echo '<div
class="n2_fields_layer_window__fields">';

        $element = $this->first;
        while ($element) {
            echo $this->decorateElement($element);

            $element = $element->getNext();
        }

        echo '</div>';
        echo '</div>';
    }

    protected function renderTitle() {

        echo '<div
class="n2_fields_layer_window__label">' . $this->label
. '</div>';
    }

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    public function decorateElement($element) {

        ob_start();

        $hasLabel = $element->hasLabel();

        $classes = array(
            'n2_field',
            $element->getLabelClass(),
            $element->getRowClass()
        );

        echo Html::openTag('div', array(
                'class'      => implode(' ',
array_filter($classes)),
                'data-field' => $element->getID()
            ) + $element->getRowAttributes());

        if ($hasLabel) {
            echo "<div class='n2_field__label'>";
            $element->displayLabel();
            echo "</div>";
        }

        echo "<div class='n2_field__element'>";
        $element->displayElement();
        echo "</div>";

        echo "</div>";

        return ob_get_clean();
    }

    /**
     * @param array $attributes
     */
    public function setAttributes($attributes) {
        $this->attributes = $attributes;
    }

    /**
     * @param string $name
     * @param string $value
     */
    public function addAttribute($name, $value) {
        $this->attributes[$name] = $value;
    }
}Form/Fieldset/LayerWindow/FieldsetLayerWindowLabelFields.php000064400000002114151161172470020201
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset\LayerWindow;


use Nextend\Framework\Form\Container\ContainerAlternative;

class FieldsetLayerWindowLabelFields extends FieldsetLayerWindow {

    /**
     * @var FieldsetInsideLabel
     */
    protected $fieldsetLabel;

    public function __construct($insertAt, $name, $label, $parameters =
array()) {
        parent::__construct($insertAt, $name, $label, $parameters);

        $labelContainer      = new ContainerAlternative($this->parent,
$name . '-container-label');
        $this->fieldsetLabel = new FieldsetInsideLabel($labelContainer,
$name . '-label', false);
    }

    /**
     * @return FieldsetInsideLabel
     */
    public function getFieldsetLabel() {
        return $this->fieldsetLabel;
    }

    protected function renderTitle() {
        echo '<div
class="n2_fields_layer_window__label">' . $this->label
. '</div>';

        echo '<div
class="n2_fields_layer_window__title_fields">';
        if ($this->fieldsetLabel->hasFields()) {
            $this->fieldsetLabel->renderContainer();
        }
        echo '</div>';
    }
}Form/Fieldset/LayerWindow/FieldsetLayerWindowStyleMode.php000064400000001602151161172470017741
0ustar00<?php


namespace Nextend\Framework\Form\Fieldset\LayerWindow;


use Nextend\Framework\Form\Element\Button\ButtonIcon;
use Nextend\Framework\Form\Element\Select;

class FieldsetLayerWindowStyleMode extends FieldsetLayerWindowLabelFields {

    public function __construct($insertAt, $name, $label, $modes,
$parameters = array()) {
        parent::__construct($insertAt, $name, $label, $parameters);

        $this->addAttribute('data-fieldset-type',
'style-mode');

        new ButtonIcon($this->fieldsetLabel, $name .
'-mode-reset-to-normal', false, 'ssi_16 ssi_16--reset',
array(
            'hoverTip'      => n2_('Reset to normal
state'),
            'rowAttributes' => array(
                'data-style-mode-feature' =>
'reset-to-normal'
            )
        ));

        new Select($this->fieldsetLabel, $name . '-mode',
false, '', array(
            'options' => $modes
        ));
    }
}Form/Form.php000064400000005104151161172470007070 0ustar00<?php


namespace Nextend\Framework\Form;


use Nextend\Framework\Data\Data;
use Nextend\Framework\Form\Fieldset\FieldsetHidden;
use Nextend\Framework\Pattern\MVCHelperTrait;

class Form extends Data {

    use MVCHelperTrait;

    protected static $counter = 1;

    /** @var Base\PlatformFormBase */
    private static $platformForm;

    protected $id;

    /**
     * @var Data
     */
    protected $context;

    protected $controlName = '';

    /**
     * @var ContainerMain
     */
    protected $container;

    protected $classes = array(
        'n2_form'
    );

    /**
     * Form constructor.
     *
     * @param MVCHelperTrait $MVCHelper
     * @param string         $controlName
     */
    public function __construct($MVCHelper, $controlName) {

        $this->id = 'n2_form_' . self::$counter++;

        $this->controlName = $controlName;

        $this->setMVCHelper($MVCHelper);

        $this->context = new Data();
        parent::__construct();

        $this->container = new ContainerMain($this);
    }

    /**
     * @return ContainerMain
     */
    public function getContainer() {
        return $this->container;
    }

    public function getId() {
        return $this->id;
    }

    /**
     * @return Data
     */
    public function getContext() {
        return $this->context;
    }

    /**
     * @param $path
     *
     * @return ContainerInterface|AbstractField
     */
    public function getElement($path) {

        /**
         * Remove starting / path separator
         */
        return $this->container->getElement(substr($path, 1));
    }

    public function render() {
        echo '<div class="' . implode(' ',
$this->classes) . '">';

        $this->container->renderContainer();

        echo '</div>';
    }

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

    public static function init() {
        self::$platformForm = new Joomla\PlatformForm();
    
    }

    public static function tokenize() {
        return self::$platformForm->tokenize();
    }

    public static function tokenizeUrl() {
        return self::$platformForm->tokenizeUrl();
    }

    public static function checkToken() {
        return self::$platformForm->checkToken();
    }

    /**
     * @return FieldsetHidden
     */
    public function getFieldsetHidden() {
        return $this->container->getFieldsetHidden();
    }

    public function setDark() {
        $this->classes[] = 'n2_form--dark';
    }

    public function addClass($className) {
        $this->classes[] = $className;
    }
}

Form::init();Form/FormTabbed.php000064400000003512151161172470010173
0ustar00<?php


namespace Nextend\Framework\Form;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Form\Container\ContainerTab;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Core\Header\BlockHeader;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Core\Header\MenuItem;

class FormTabbed extends Form {

    protected $classes = array(
        'n2_form',
        'n2_form_tabbed'
    );

    protected $toggleMode = false;

    protected $sessionID = '';

    /**
     * @param $name
     * @param $label
     *
     * @return ContainerTab
     */
    public function createTab($name, $label) {

        return new ContainerTab($this->container, $name, $label);
    }

    /**
     * @param BlockHeader $blockHeader
     */
    public function addTabsToHeader($blockHeader) {
        $element = $this->container->getFirst();
        while ($element) {
            if ($element instanceof ContainerTab) {

                $tab = new MenuItem($element->getLabel());
                $tab->addClass('n2_form__tab_button');
                $tab->setAttribute('data-related-form',
$this->id);
                $tab->setAttribute('data-related-tab',
$element->getId());
                $blockHeader->addMenuItem($tab);
            }

            $element = $element->getNext();
        }
    }

    public function render() {
        parent::render();

        Js::addInline('new _N2.FormTabbed("' . $this->id
. '", ' . json_encode(array(
                'toggleMode' => $this->toggleMode,
                'sessionID'  => $this->sessionID
            )) . ');');
    }

    /**
     * @param bool $toggleMode
     */
    public function setToggleMode($toggleMode) {
        $this->toggleMode = $toggleMode;
    }

    /**
     * @param string $sessionID
     */
    public function setSessionID($sessionID) {
        $this->sessionID = $sessionID;
    }
}Form/Insert/AbstractInsert.php000064400000001101151161172500012344
0ustar00<?php


namespace Nextend\Framework\Form\Insert;

use Nextend\Framework\Form\ContainedInterface;
use Nextend\Framework\Form\ContainerInterface;

abstract class AbstractInsert {

    /**
     * @var ContainedInterface
     */
    protected $at;

    /**
     * AbstractInsert constructor.
     *
     * @param ContainedInterface $at
     */
    public function __construct($at) {
        $this->at = $at;
    }

    /**
     * @param ContainedInterface $element
     *
     * @return ContainerInterface Returns the parent
     */
    public abstract function insert($element);
}Form/Insert/InsertAfter.php000064400000000412151161172500011646
0ustar00<?php


namespace Nextend\Framework\Form\Insert;


class InsertAfter extends AbstractInsert {

    public function insert($element) {
        $parent = $this->at->getParent();
        $parent->insertElementAfter($element, $this->at);

        return $parent;
    }
}Form/Insert/InsertBefore.php000064400000000414151161172500012011
0ustar00<?php


namespace Nextend\Framework\Form\Insert;


class InsertBefore extends AbstractInsert {

    public function insert($element) {
        $parent = $this->at->getParent();
        $parent->insertElementBefore($element, $this->at);

        return $parent;
    }
}Form/Joomla/Element/Select/MenuItems.php000064400000001306151161172500014116
0ustar00<?php


namespace Nextend\Framework\Form\Joomla\Element\Select;


use JMenu;
use Nextend\Framework\Form\Element\Select;

class MenuItems extends Select {

    public function __construct($insertAt, $name = '', $label =
'', $default = '', $parameters = array()) {
        parent::__construct($insertAt, $name, $label, $default,
$parameters);

        $menu      = JMenu::getInstance('site');
        $menuItems = $menu->getItems($attributes = array(), $values =
array());

        $this->options['0'] = n2_('Default');

        if (count($menuItems)) {
            foreach ($menuItems AS $item) {
                $this->options[$item->id] = '[' .
$item->id . '] ' . $item->title;
            }
        }
    }
}Form/Joomla/PlatformForm.php000064400000001054151161172500012010
0ustar00<?php

namespace Nextend\Framework\Form\Joomla;

use JSession;
use Nextend\Framework\Form\Base\PlatformFormBase;

class PlatformForm extends PlatformFormBase {

    public function tokenize() {
        return '<input type="hidden" name="' .
JSession::getFormToken() . '" value="1">';
    }

    public function tokenizeUrl() {
        $a                           = array();
        $a[JSession::getFormToken()] = 1;

        return $a;
    }

    public function checkToken() {
        return JSession::checkToken() ||
JSession::checkToken('get');
    }
}Form/TraitContainer.php000064400000005070151161172500011107
0ustar00<?php


namespace Nextend\Framework\Form;


trait TraitContainer {

    /**
     * @var ContainedInterface
     */
    protected $first, $last;

    /**
     * @var ContainedInterface[]
     */
    protected $flattenElements = array();

    /**
     * @param ContainedInterface $element
     */
    public function addElement($element) {

        if (!$this->first) {
            $this->first = $element;
        }

        if ($this->last) {
            $this->last->setNext($element);
        }

        $this->last = $element;

        $name = $element->getName();
        if ($name) {
            $this->flattenElements[$name] = $element;
        }
    }

    /**
     * @param ContainedInterface $element
     * @param ContainedInterface $target
     */
    public function insertElementBefore($element, $target) {
        $previous = $target->getPrevious();
        if ($previous) {
            $previous->setNext($element);
        } else {
            $this->first = $element;
        }

        $element->setNext($target);

        $name = $element->getName();
        if ($name) {
            $this->flattenElements[$name] = $element;
        }
    }

    /**
     * @param AbstractField $element
     * @param AbstractField $target
     */
    public function insertElementAfter($element, $target) {

        $next = $target->getNext();
        $target->setNext($element);

        if ($next) {
            $element->setNext($next);
        } else {
            $this->last = $element;
        }

        $name = $element->getName();
        if ($name) {
            $this->flattenElements[$name] = $element;
        }
    }

    /**
     * @param AbstractField $element
     */
    public function removeElement($element) {
        $previous = $element->getPrevious();
        $next     = $element->getNext();

        if ($this->first === $element) {
            $this->first = $next;
        }

        if ($this->last === $element) {
            $this->last = $previous;
        }

        if ($previous) {
            $previous->setNext($next);
        } else {
            $next->setPrevious();
        }
    }

    /**
     * @param $path
     *
     * @return AbstractField
     */
    public function getElement($path) {
        $parts   = explode('/', $path, 2);
        $element = $this->flattenElements[$parts[0]];
        if (!empty($parts[1]) && $element instanceof
ContainerInterface) {
            $element = $element->getElement($parts[1]);
        }

        return $element;
    }

    public function getElementIdentifiers() {
        return array_keys($this->flattenElements);
    }
}Form/TraitFieldset.php000064400000001603151161172500010722
0ustar00<?php

namespace Nextend\Framework\Form;

trait TraitFieldset {

    use TraitContainer;

    /**
     * @var AbstractField
     */
    protected $first, $last;

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

    public function hide() {
        $this->isVisible = false;
    }

    /**
     * @return ContainerInterface
     */
    public function getParent() {
        return $this->parent;
    }

    public function getPath() {
        return $this->getParent()
                    ->getPath() . '/' . $this->name;
    }

    public function renderContainer() {

    }

    abstract public function getControlName();

    /**
     * @return Form
     */
    abstract public function getForm();

    /**
     * @param AbstractField $element
     *
     * @return string
     */
    abstract public function decorateElement($element);

    abstract public function getName();
}Framework.php000064400000000634151161172500007214 0ustar00<?php


namespace Nextend\Framework;


use Nextend\Framework\Font\FontStorage;
use Nextend\Framework\Localization\Localization;
use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\Style\StyleStorage;

class Framework {

    use SingletonTrait;

    protected function init() {

        Localization::getInstance();

        FontStorage::getInstance();
        StyleStorage::getInstance();
    }
}Icon/Icon.php000064400000005522151161172500007040 0ustar00<?php

namespace Nextend\Framework\Icon;

use Nextend\Framework\Asset\AssetManager;
use Nextend\Framework\Asset\Css\Css;
use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\Settings;
use Nextend\Framework\Url\Url;

class Icon {

    public static $icons = array();

    public static $keys = array();

    public static function init() {

        $path      =
ResourceTranslator::toPath('$ss3-pro-frontend$/icons/');
        $iconPacks = Filesystem::folders($path);

        foreach ($iconPacks as $iconPack) {
            $manifestPath = $path . $iconPack . '/manifest.json';
            if (Filesystem::fileexists($manifestPath)) {
                self::$icons[$iconPack] =
json_decode(Filesystem::readFile($manifestPath), true);


                self::$icons[$iconPack]['path'] = $path .
$iconPack . '/dist/' . $iconPack . '.min.css';
                self::$icons[$iconPack]['css']  =
Url::pathToUri($path . $iconPack . '/dist/' . $iconPack .
'.min.css', false);

                self::$keys[self::$icons[$iconPack]['id']] =
&self::$icons[$iconPack];
            }
        }
    }

    public static function serveAdmin() {
        static $isServed = false;
        if (!$isServed) {
            Js::addInline('new _N2.Icons(' .
json_encode(self::$icons) . ');');
            $isServed = true;
        }
    }

    public static function render($key) {
        $parts = explode(':', $key);
        if (count($parts) != 2) {
            return false;
        }

        $id   = $parts[0];
        $icon = $parts[1];
        if (!isset(self::$keys[$id])) {
            return false;
        }

        $iconPack = &self::$keys[$id];
        if (!isset($iconPack['data'][$icon])) {
            return false;
        }

        if (!AssetManager::$stateStorage->get('icon-' .
$iconPack['id'] . '-loaded', 0)) {
            AssetManager::$stateStorage->set('icon-' .
$iconPack['id'] . '-loaded', 1);

            if (Platform::isAdmin() || Settings::get('icon-' .
$iconPack['id'], 1)) {
                Css::addStaticGroup($iconPack['path'],
$iconPack['id']);
            } else if (isset($iconPack['compatibility'])) {
                Css::addInline($iconPack['compatibility']);

                if ($iconPack['id'] == 'fa') {
                    $iconPack['class']  = 'fa';
                    $iconPack['prefix'] = 'fa-';
                }
            }
        }

        if ($iconPack['isLigature']) {

            return array(
                "class"    => $iconPack['class'],
                "ligature" => $icon
            );

        } else {

            return array(
                "class"    => $iconPack['class'] .
" " . $iconPack['prefix'] . $icon,
                "ligature" => ""
            );
        }

    }
}

Icon::init();Image/AbstractPlatformImage.php000064400000000270151161172500012510
0ustar00<?php

namespace Nextend\Framework\Image;

abstract class AbstractPlatformImage {

    public function initLightbox() {

    }

    public function onImageUploaded($filename) {
    }
}Image/Block/ImageManager/BlockImageManager.php000064400000002747151161172500015147
0ustar00<?php


namespace Nextend\Framework\Image\Block\ImageManager;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Image\ImageManager;
use Nextend\Framework\Image\ModelImage;
use Nextend\Framework\Visual\AbstractBlockVisual;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonApply;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonCancel;
use Nextend\SmartSlider3\Application\Admin\TraitAdminUrl;

class BlockImageManager extends AbstractBlockVisual {

    use TraitAdminUrl;

    /** @var ModelImage */
    protected $model;

    /**
     * @return ModelImage
     */
    public function getModel() {
        return $this->model;
    }

    public function display() {

        $this->model = new ModelImage($this);

        $this->renderTemplatePart('Index');
    }

    public function displayTopBar() {

        $buttonCancel = new BlockButtonCancel($this);
       
$buttonCancel->addClass('n2_fullscreen_editor__cancel');
        $buttonCancel->display();

        $buttonApply = new BlockButtonApply($this);
        $buttonApply->addClass('n2_fullscreen_editor__save');
        $buttonApply->display();
    }

    public function displayContent() {
        Js::addFirstCode("
            new _N2.NextendImageManager({
                visuals: " . json_encode(ImageManager::$loaded) .
",
                ajaxUrl: '" . $this->getAjaxUrlImage() .
"'
            });
        ");

        $this->getModel()
             ->renderForm();
    }
}Image/Block/ImageManager/Index.php000064400000001501151161172500012711
0ustar00<?php

namespace Nextend\Framework\Image\Block\ImageManager;

/**
 * @var BlockImageManager $this
 */
?>
<div id="n2-lightbox-image"
class="n2_fullscreen_editor">
    <div class="n2_fullscreen_editor__overlay"></div>
    <div class="n2_fullscreen_editor__window">
        <div class="n2_fullscreen_editor__nav_bar">
            <div
class="n2_fullscreen_editor__nav_bar_label">
                <?php n2_e('Image manager'); ?>
            </div>
            <div
class="n2_fullscreen_editor__nav_bar_actions">
                <?php $this->displayTopBar(); ?>
            </div>
        </div>
        <div class="n2_fullscreen_editor__content">
            <div class="n2_fullscreen_editor__content_content
n2_container_scrollable">
                <?php $this->displayContent(); ?>
            </div>
        </div>
    </div>
</div>Image/ControllerAjaxImage.php000064400000005131151161172500012170
0ustar00<?php


namespace Nextend\Framework\Image;


use Nextend\Framework\Controller\Admin\AdminVisualManagerAjaxController;
use Nextend\Framework\Notification\Notification;
use Nextend\Framework\Request\Request;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;

class ControllerAjaxImage extends AdminVisualManagerAjaxController {

    protected $type = 'image';

    public function actionLoadVisualForImage() {
        $this->validateToken();
        $model  = $this->getModel();
        $image  = Request::$REQUEST->getVar('image');
        $visual = $model->getVisual($image);
        if (!empty($visual)) {
            $this->response->respond(array(
                'visual' => $visual
            ));
        } else {

            if (($visual = $model->addVisual($image,
ImageStorage::$emptyImage))) {
                $this->response->respond(array(
                    'visual' => $visual
                ));
            }
        }

        Notification::error(n2_('Unexpected error'));
        $this->response->error();
    }

    public function actionAddVisual() {
        $this->validateToken();

        $image = Request::$REQUEST->getVar('image');
        $this->validateVariable(!empty($image), 'image');

        $model = $this->getModel();

        if (($visual = $model->addVisual($image,
Request::$REQUEST->getVar('value')))) {
            $this->response->respond(array(
                'visual' => $visual
            ));
        }

        Notification::error(n2_('Unexpected error'));
        $this->response->error();
    }

    public function actionDeleteVisual() {
        $this->validateToken();

        $visualId = Request::$REQUEST->getInt('visualId');
        $this->validateVariable($visualId > 0, 'image');

        $model = $this->getModel();

        if (($visual = $model->deleteVisual($visualId))) {
            $this->response->respond(array(
                'visual' => $visual
            ));
        }

        Notification::error(n2_('Not editable'));
        $this->response->error();
    }

    public function actionChangeVisual() {
        $this->validateToken();

        $visualId = Request::$REQUEST->getInt('visualId');
        $this->validateVariable($visualId > 0, 'image');

        $model = $this->getModel();

        if (($visual = $model->changeVisual($visualId,
Request::$REQUEST->getVar('value')))) {
            $this->response->respond(array(
                'visual' => $visual
            ));
        }

        Notification::error(n2_('Unexpected error'));
        $this->response->error();
    }

    public function getModel() {
        return new ModelImage($this);
    }
}Image/Image.php000064400000003567151161172500007333 0ustar00<?php

namespace Nextend\Framework\Image;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Image\Joomla\JoomlaImage;
use Nextend\Framework\Image\WordPress\WordPressImage;
use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;

class Image {

    use SingletonTrait;

    /**
     * @var AbstractPlatformImage
     */
    private static $platformImage;

    public function __construct() {
        self::$platformImage = new JoomlaImage();
    
    }

    public static function init() {

        if (!self::$platformImage) {
            new Image();
        }
    }

    public static function enqueueHelper() {
        $parameters = array(
            'siteKeywords'     =>
ResourceTranslator::getResourceIdentifierKeywords(),
            'imageUrls'        =>
ResourceTranslator::getResourceIdentifierUrls(),
            'protocolRelative' =>
ResourceTranslator::isProtocolRelative()
        );

        $parameters['placeholderImage']         =
'$ss3-frontend$/images/placeholder/image.png';
        $parameters['placeholderRepeatedImage'] =
'$ss3-frontend$/images/placeholder/image.png';

        Js::addFirstCode('new _N2.ImageHelper(' .
json_encode($parameters) . ');');
    }

    public static function initLightbox() {

        self::$platformImage->initLightbox();
    }

    public static function onImageUploaded($filename) {

        self::$platformImage->onImageUploaded($filename);
    }

    public static function SVGToBase64($image) {

        $ext = pathinfo($image, PATHINFO_EXTENSION);
        if ($ext == 'svg' &&
ResourceTranslator::isResource($image)) {
            return 'data:image/svg+xml;base64,' .
Base64::encode(Filesystem::readFile(ResourceTranslator::toPath($image)));
        }

        return ResourceTranslator::toUrl($image);
    }
}Image/ImageEdit.php000064400000053333151161172500010135 0ustar00<?php


namespace Nextend\Framework\Image;


use Exception;
use Nextend\Framework\Cache\CacheImage;
use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Parser\Color;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\Url\Url;

class ImageEdit {

    public static function resizeImage($group, $imageUrlOrPath,
$targetWidth, $targetHeight, $lazy = false, $mode = 'cover',
$backgroundColor = false, $resizeRemote = false, $quality = 100, $optimize
= false, $x = 50, $y = 50) {

        if (strpos($imageUrlOrPath, Filesystem::getBasePath()) === 0) {
            $imageUrl = Url::pathToUri($imageUrlOrPath);
        } else {
            $imageUrl = ResourceTranslator::toUrl($imageUrlOrPath);
        }

        if ($targetWidth <= 0 || $targetHeight <= 0 ||
!function_exists('imagecreatefrompng')) {
            return $imageUrl;
        }

        $quality          = max(0, min(100, $quality));
        $originalImageUrl = $imageUrl;

        if (substr($imageUrl, 0, 2) == '//') {
            $imageUrl = parse_url(Url::getFullUri(), PHP_URL_SCHEME) .
':' . $imageUrl;
        }

        $imageUrl  = Url::relativetoabsolute($imageUrl);
        $imagePath = Filesystem::absoluteURLToPath($imageUrl);

        $cache = new CacheImage($group);
        if ($lazy) {
            $cache->setLazy(true);
        }

        if ($imagePath == $imageUrl) {
            // The image is not local
            if (!$resizeRemote) {
                return $originalImageUrl;
            }

            $pathInfo  = pathinfo(parse_url($imageUrl, PHP_URL_PATH));
            $extension =
self::validateGDExtension($pathInfo['extension']);
            if (!$extension) {
                return $originalImageUrl;
            }

            $resizedPath = $cache->makeCache($extension, array(
                self::class,
                '_resizeRemoteImage'
            ), array(
                $extension,
                $imageUrl,
                $targetWidth,
                $targetHeight,
                $mode,
                $backgroundColor,
                $quality,
                $optimize,
                $x,
                $y
            ));

            if (substr($resizedPath, 0, 5) == 'http:' ||
substr($resizedPath, 0, 6) == 'https:') {
                return $resizedPath;
            }

            if ($resizedPath === $originalImageUrl) {
                return $originalImageUrl;
            }

            return Filesystem::pathToAbsoluteURL($resizedPath);

        } else {
            $extension = false;
            $imageType = @self::exif_imagetype($imagePath);
            switch ($imageType) {
                case IMAGETYPE_JPEG:
                    $extension = 'jpg';
                    break;
                case IMAGETYPE_PNG:
                    if (self::isPNG8($imagePath)) {
                        // GD cannot resize palette PNG so we return the
original image
                        return $originalImageUrl;
                    }
                    $extension = 'png';
                    break;
            }
            if (!$extension) {
                return $originalImageUrl;
            }

            return
Filesystem::pathToAbsoluteURL($cache->makeCache($extension, array(
                self::class,
                '_resizeImage'
            ), array(
                $extension,
                $imagePath,
                $targetWidth,
                $targetHeight,
                $mode,
                $backgroundColor,
                $quality,
                $optimize,
                $x,
                $y
            )));
        }
    }

    public static function _resizeRemoteImage($targetFile, $extension,
$imageUrl, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality,
$optimize, $x, $y) {
        return self::_resizeImage($targetFile, $extension, $imageUrl,
$targetWidth, $targetHeight, $mode, $backgroundColor, $quality, $optimize,
$x, $y);
    }

    public static function _resizeImage($targetFile, $extension,
$imagePath, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality
= 100, $optimize = false, $x = 50, $y = 50) {
        $targetDir = dirname($targetFile);

        $rotated = false;

        if ($extension == 'png') {
            $image = @imagecreatefrompng($imagePath);
        } else if ($extension == 'jpg') {
            $image = @imagecreatefromjpeg($imagePath);
            if (function_exists("exif_read_data")) {
                $exif = @exif_read_data($imagePath);

                $rotated = self::getOrientation($exif, $image);
                if ($rotated) {
                    imagedestroy($image);
                    $image = $rotated;
                }
            }
        }

        if (isset($image) && $image) {
            $originalWidth  = imagesx($image);
            $originalHeight = imagesy($image);

            if ($optimize) {
                if ($originalWidth <= $targetWidth || $originalHeight
<= $targetHeight) {
                    if (!Filesystem::existsFolder($targetDir)) {
                        Filesystem::createFolder($targetDir);
                    }
                    if ($extension == 'png') {
                        imagesavealpha($image, true);
                        imagealphablending($image, false);
                        imagepng($image, $targetFile);
                    } else if ($extension == 'jpg') {
                        imagejpeg($image, $targetFile, $quality);
                    }
                    imagedestroy($image);

                    return true;
                }

                if ($originalWidth / $targetWidth > $originalHeight /
$targetHeight) {
                    $targetWidth = $originalWidth / ($originalHeight /
$targetHeight);
                } else {
                    $targetHeight = $originalHeight / ($originalWidth /
$targetWidth);
                }
            }
            if ($rotated || $originalWidth != $targetWidth ||
$originalHeight != $targetHeight) {
                $newImage = imagecreatetruecolor($targetWidth,
$targetHeight);
                if ($extension == 'png') {
                    imagesavealpha($newImage, true);
                    imagealphablending($newImage, false);
                    $transparent = imagecolorallocatealpha($newImage, 255,
255, 255, 127);
                    imagefilledrectangle($image, 0, 0, $targetWidth,
$targetHeight, $transparent);
                } else if ($extension == 'jpg' &&
$backgroundColor) {
                    $rgb        = Color::hex2rgb($backgroundColor);
                    $background = imagecolorallocate($newImage, $rgb[0],
$rgb[1], $rgb[2]);
                    imagefilledrectangle($newImage, 0, 0, $targetWidth,
$targetHeight, $background);
                }

                list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h,
$src_w, $src_h) = self::imageMode($targetWidth, $targetHeight,
$originalWidth, $originalHeight, $mode, $x, $y);
                imagecopyresampled($newImage, $image, $dst_x, $dst_y,
$src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
                imagedestroy($image);

            } else {
                $newImage = $image;
            }

            if (!Filesystem::existsFolder($targetDir)) {
                Filesystem::createFolder($targetDir);
            }
            if ($extension == 'png') {
                imagepng($newImage, $targetFile);
            } else if ($extension == 'jpg') {
                imagejpeg($newImage, $targetFile, $quality);
            }
            imagedestroy($newImage);

            return true;
        }

        throw new Exception('Unable to resize image: ' .
$imagePath);
    }

    public static function scaleImage($group, $imageUrlOrPath, $scale = 1,
$resizeRemote = false, $quality = 100) {


        if (strpos($imageUrlOrPath, Filesystem::getBasePath()) === 0) {
            $imageUrl = Url::pathToUri($imageUrlOrPath);
        } else {
            $imageUrl = ResourceTranslator::toUrl($imageUrlOrPath);
        }

        if ($scale <= 0 ||
!function_exists('imagecreatefrompng')) {
            return $imageUrl;
        }

        $quality          = max(0, min(100, $quality));
        $originalImageUrl = $imageUrl;

        if (substr($imageUrl, 0, 2) == '//') {
            $imageUrl = parse_url(Url::getFullUri(), PHP_URL_SCHEME) .
':' . $imageUrl;
        }

        $imageUrl  = Url::relativetoabsolute($imageUrl);
        $imagePath = Filesystem::absoluteURLToPath($imageUrl);

        $cache = new CacheImage($group);
        if ($imagePath == $imageUrl) {
            // The image is not local
            if (!$resizeRemote) {
                return $originalImageUrl;
            }

            $pathInfo  = pathinfo(parse_url($imageUrl, PHP_URL_PATH));
            $extension =
self::validateGDExtension($pathInfo['extension']);
            if (!$extension) {
                return $originalImageUrl;
            }

            return
ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache($extension,
array(
                self::class,
                '_scaleRemoteImage'
            ), array(
                $extension,
                $imageUrl,
                $scale,
                $quality
            ))));

        } else {
            $extension = false;
            $imageType = @self::exif_imagetype($imagePath);
            switch ($imageType) {
                case IMAGETYPE_JPEG:
                    $extension = 'jpg';
                    break;
                case IMAGETYPE_PNG:
                    if (self::isPNG8($imagePath)) {
                        // GD cannot resize palette PNG so we return the
original image
                        return $originalImageUrl;
                    }
                    $extension = 'png';
                    break;
            }
            if (!$extension) {
                return $originalImageUrl;
            }

            return
ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache($extension,
array(
                self::class,
                '_scaleImage'
            ), array(
                $extension,
                $imagePath,
                $scale,
                $quality
            ))));
        }
    }

    public static function _scaleRemoteImage($targetFile, $extension,
$imageUrl, $scale, $quality) {
        return self::_scaleImage($targetFile, $extension, $imageUrl,
$scale, $quality);
    }

    public static function _scaleImage($targetFile, $extension, $imagePath,
$scale, $quality = 100) {
        $targetDir = dirname($targetFile);

        $image = false;

        if ($extension == 'png') {
            $image = @imagecreatefrompng($imagePath);
        } else if ($extension == 'jpg') {
            $image = @imagecreatefromjpeg($imagePath);
            if (function_exists("exif_read_data")) {
                $exif = @exif_read_data($imagePath);

                $rotated = self::getOrientation($exif, $image);
                if ($rotated) {
                    imagedestroy($image);
                    $image = $rotated;
                }
            }
        }

        if ($image) {
            $originalWidth  = imagesx($image);
            $originalHeight = imagesy($image);
            $targetWidth    = $originalWidth * $scale;
            $targetHeight   = $originalHeight * $scale;
            if ((isset($rotated) && $rotated) || $originalWidth !=
$targetWidth || $originalHeight != $targetHeight) {
                $newImage = imagecreatetruecolor($targetWidth,
$targetHeight);
                if ($extension == 'png') {
                    imagesavealpha($newImage, true);
                    imagealphablending($newImage, false);
                    $transparent = imagecolorallocatealpha($newImage, 255,
255, 255, 127);
                    imagefilledrectangle($image, 0, 0, $targetWidth,
$targetHeight, $transparent);
                }

                list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h,
$src_w, $src_h) = self::imageMode($targetWidth, $targetHeight,
$originalWidth, $originalHeight);
                imagecopyresampled($newImage, $image, $dst_x, $dst_y,
$src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
                imagedestroy($image);

            } else {
                $newImage = $image;
            }

            if (!Filesystem::existsFolder($targetDir)) {
                Filesystem::createFolder($targetDir);
            }
            if ($extension == 'png') {
                imagepng($newImage, $targetFile);
            } else if ($extension == 'jpg') {
                imagejpeg($newImage, $targetFile, $quality);
            }
            imagedestroy($newImage);

            return true;
        }

        throw new Exception('Unable to scale image: ' .
$imagePath);
    }

    private static function getOrientation($exif, $image) {
        if ($exif && !empty($exif['Orientation'])) {
            $rotated = false;
            switch ($exif['Orientation']) {
                case 3:
                    $rotated = imagerotate($image, 180, 0);
                    break;

                case 6:
                    $rotated = imagerotate($image, -90, 0);
                    break;

                case 8:
                    $rotated = imagerotate($image, 90, 0);
                    break;
            }

            return $rotated;
        }

        return false;
    }

    private static function imageMode($width, $height, $originalWidth,
$OriginalHeight, $mode = 'cover', $x = 50, $y = 50) {
        $dst_x           = 0;
        $dst_y           = 0;
        $src_x           = 0;
        $src_y           = 0;
        $dst_w           = $width;
        $dst_h           = $height;
        $src_w           = $originalWidth;
        $src_h           = $OriginalHeight;
        $horizontalRatio = $width / $originalWidth;
        $verticalRatio   = $height / $OriginalHeight;

        if ($horizontalRatio > $verticalRatio) {
            $new_h = $horizontalRatio * $OriginalHeight;
            $dst_y = ($height - $new_h) / 2 * $y / 50;
            $dst_h = $new_h;
        } else {
            $new_w = $verticalRatio * $originalWidth;
            $dst_x = ($width - $new_w) / 2 * $x / 50;
            $dst_w = $new_w;
        }

        return array(
            $dst_x,
            $dst_y,
            $src_x,
            $src_y,
            $dst_w,
            $dst_h,
            $src_w,
            $src_h
        );
    }

    private static function validateGDExtension($extension) {
        static $validExtensions = array(
            'png'  => 'png',
            'jpg'  => 'jpg',
            'jpeg' => 'jpg',
            'gif'  => 'gif',
            'svg'  => 'svg'
        );
        $extension = strtolower($extension);
        if (isset($validExtensions[$extension])) {
            return $validExtensions[$extension];
        }

        return false;
    }

    private static function validateExtension($extension) {
        static $validExtensions = array(
            'png'  => 'png',
            'jpg'  => 'jpg',
            'jpeg' => 'jpg',
            'gif'  => 'gif',
            'webp' => 'webp',
            'svg'  => 'svg'
        );
        $extension = strtolower($extension);
        if (isset($validExtensions[$extension])) {
            return $validExtensions[$extension];
        }

        return false;
    }

    public static function base64Transparent() {
        return
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
    }

    public static function base64($imagePath, $image) {
        $pathInfo  = pathinfo(parse_url($imagePath, PHP_URL_PATH));
        $extension =
self::validateExtension($pathInfo['extension']);
        if ($extension) {
            return 'data:image/' . $extension .
';base64,' . Base64::encode(Filesystem::readFile($imagePath));
        }

        return ResourceTranslator::toUrl($image);
    }

    public static function exif_imagetype($filename) {
        if (!function_exists('exif_imagetype')) {
            if ((list($width, $height, $type, $attr) =
getimagesize($filename)) !== false) {
                return $type;
            }

            return false;
        }

        return exif_imagetype($filename);
    }

    public static function isPNG8($path) {
        $fp = fopen($path, 'r');
        fseek($fp, 25);
        $data = fgets($fp, 2);
        fclose($fp);
        if (ord($data) == 3) {
            return true;
        }

        return false;
    }

    public static function scaleImageWebp($group, $imageUrlOrPath,
$options) {

        $options = array_merge(array(
            'mode'    => 'scale',
            'scale'   => 1,
            'quality' => 100,
            'remote'  => false
        ), $options);

        if (strpos($imageUrlOrPath, Filesystem::getBasePath()) === 0) {
            $imageUrl = Url::pathToUri($imageUrlOrPath);
        } else {
            $imageUrl = ResourceTranslator::toUrl($imageUrlOrPath);
        }

        if (!function_exists('imagecreatefrompng') ||
($options['mode'] === 'scale' &&
$options['scale'] <= 0)) {
            return Filesystem::pathToAbsoluteURL($imageUrl);
        }

        $options['quality'] = max(0, min(100,
$options['quality']));
        $originalImageUrl   = $imageUrl;


        if (substr($imageUrl, 0, 2) == '//') {
            $imageUrl = parse_url(Url::getFullUri(), PHP_URL_SCHEME) .
':' . $imageUrl;
        }

        $imageUrl  = Url::relativetoabsolute($imageUrl);
        $imagePath = Filesystem::absoluteURLToPath($imageUrl);

        $cache = new CacheImage($group);
        if ($imagePath == $imageUrl) {
            // The image is not local
            if (!$options['remote']) {
                return $originalImageUrl;
            }

            $pathInfo  = pathinfo(parse_url($imageUrl, PHP_URL_PATH));
            $extension =
self::validateGDExtension($pathInfo['extension']);
            if (!$extension) {
                return $originalImageUrl;
            }

            return
ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache('webp',
array(
                self::class,
                '_scaleRemoteImageWebp'
            ), array(
                $extension,
                $imageUrl,
                $options
            ))));

        } else {
            $extension = false;
            $imageType = @self::exif_imagetype($imagePath);
            switch ($imageType) {
                case IMAGETYPE_JPEG:
                    $extension = 'jpg';
                    break;
                case IMAGETYPE_PNG:
                    $extension = 'png';
                    break;
            }
            if (!$extension) {
                return $originalImageUrl;
            }

            return
ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache('webp',
array(
                self::class,
                '_scaleImageWebp'
            ), array(
                $extension,
                $imagePath,
                $options
            ))));
        }
    }

    public static function _scaleRemoteImageWebp($targetFile, $extension,
$imageUrl, $options) {
        return self::_scaleImageWebp($targetFile, $extension, $imageUrl,
$options);
    }

    public static function _scaleImageWebp($targetFile, $extension,
$imagePath, $options) {

        $options = array_merge(array(
            'focusX' => 50,
            'focusY' => 50,
        ), $options);

        $targetDir = dirname($targetFile);

        $image = false;

        if ($extension == 'png') {
            $image = @imagecreatefrompng($imagePath);
            if (!imageistruecolor($image)) {
                imagepalettetotruecolor($image);
                imagealphablending($image, true);
                imagesavealpha($image, true);
            }
        } else if ($extension == 'jpg') {
            $image = @imagecreatefromjpeg($imagePath);
            if (function_exists("exif_read_data")) {
                $exif = @exif_read_data($imagePath);

                $rotated = self::getOrientation($exif, $image);
                if ($rotated) {
                    imagedestroy($image);
                    $image = $rotated;
                }
            }
        }

        if ($image) {
            $originalWidth  = imagesx($image);
            $originalHeight = imagesy($image);
            switch ($options['mode']) {
                case 'scale':
                    $targetWidth  = $originalWidth *
$options['scale'];
                    $targetHeight = $originalHeight *
$options['scale'];
                    break;
                case 'resize':
                    $targetWidth  = $options['width'];
                    $targetHeight = $options['height'];
                    break;
            }
            if ((isset($rotated) && $rotated) || $originalWidth !=
$targetWidth || $originalHeight != $targetHeight) {
                $newImage = imagecreatetruecolor($targetWidth,
$targetHeight);
                if ($extension == 'png') {
                    imagesavealpha($newImage, true);
                    imagealphablending($newImage, false);
                    $transparent = imagecolorallocatealpha($newImage, 255,
255, 255, 127);
                    imagefilledrectangle($image, 0, 0, $targetWidth,
$targetHeight, $transparent);
                }

                list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h,
$src_w, $src_h) = self::imageMode($targetWidth, $targetHeight,
$originalWidth, $originalHeight, 'cover',
$options['focusX'], $options['focusY']);
                imagecopyresampled($newImage, $image, $dst_x, $dst_y,
$src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
                imagedestroy($image);

            } else {
                $newImage = $image;
            }

            if (!Filesystem::existsFolder($targetDir)) {
                Filesystem::createFolder($targetDir);
            }

            imagewebp($newImage, $targetFile,
$options['quality']);
            imagedestroy($newImage);

            return true;
        }

        throw new Exception('Unable to scale image: ' .
$imagePath);
    }
}Image/ImageManager.php000064400000003041151161172500010611
0ustar00<?php

namespace Nextend\Framework\Image;

use Nextend\Framework\Image\Block\ImageManager\BlockImageManager;
use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Pattern\VisualManagerTrait;

class ImageManager {

    use VisualManagerTrait;
    /**
     * @var ImageStorage
     */
    private static $model;

    public static $loaded = array();

    public function display() {

        $imageManagerBlock = new BlockImageManager($this->MVCHelper);
        $imageManagerBlock->display();
    }

    public static function init() {
        self::$model = new ImageStorage();
    }

    public static function hasImageData($image) {
        $image = self::$model->getByImage($image);
        if (!empty($image)) {
            return true;
        }

        return false;
    }

    public static function getImageData($image, $read = false) {
        $visual = self::$model->getByImage($image);
        if (empty($visual)) {
            if ($read) {
                return false;
            } else {
                $id     = self::addImageData($image,
ImageStorage::$emptyImage);
                $visual = self::$model->getById($id);
            }
        }
        self::$loaded[] = $visual;

        return array_merge(ImageStorage::$emptyImage,
json_decode(Base64::decode($visual['value']), true));
    }

    public static function addImageData($image, $value) {
        return self::$model->add($image, $value);
    }

    public static function setImageData($image, $value) {
        self::$model->setByImage($image, $value);
    }
}

ImageManager::init();Image/ImageStorage.php000064400000006400151161172500010645
0ustar00<?php

namespace Nextend\Framework\Image;

use Nextend\Framework\Database\Database;
use Nextend\Framework\Misc\Base64;

class ImageStorage {

    /**
     * @var \Nextend\Framework\Database\AbstractPlatformConnectorTable
     */
    private $tableImageStorage;

    public static $emptyImage = array(
        'desktop-retina' => array(
            'image' => ''
        ),
        'tablet'         => array(
            'image' => ''
        ),
        'mobile'         => array(
            'image' => ''
        )
    );

    public function __construct() {
        $this->tableImageStorage =
Database::getTable("nextend2_image_storage");
    }

    public function getById($id) {
        return $this->tableImageStorage->findByAttributes(array(
            "id" => $id
        ));
    }

    public function getByImage($image) {
        static $cache = array();

        if (!isset($cache[$image])) {
            $cache[$image] =
$this->tableImageStorage->findByAttributes(array(
                "hash" => md5($image)
            ));
        }

        return $cache[$image];
    }

    public function setById($id, $value) {

        if (is_array($value)) {
            $value = Base64::encode(json_encode($value));
        }

        $result = $this->getById($id);

        if ($result !== null) {
            $this->tableImageStorage->update(array('value'
=> $value), array(
                "id" => $id
            ));

            return true;
        }

        return false;
    }

    public function setByImage($image, $value) {

        if (is_array($value)) {
            $value = Base64::encode(json_encode($value));
        }

        $result = $this->getByImage($image);

        if ($result !== null) {
            $this->tableImageStorage->update(array('value'
=> $value), array(
                "id" => $result['id']
            ));

            return true;
        }

        return false;
    }

    public function getAll() {
        return $this->tableImageStorage->findAllByAttributes(array(),
array(
            "id",
            "hash",
            "image",
            "value"
        ));
    }

    public function set($image, $value) {

        if (is_array($value)) {
            $value = Base64::encode(json_encode($value));
        }

        $result = $this->getByImage($image);

        if (empty($result)) {
            return $this->add($image, $value);
        } else {
            $attributes = array(
                "id" => $result['id']
            );
            $this->tableImageStorage->update(array('value'
=> $value), $attributes);

            return true;
        }
    }

    public function add($image, $value) {

        if (is_array($value)) {
            $value = Base64::encode(json_encode($value));
        }

        $this->tableImageStorage->insert(array(
            "hash"  => md5($image),
            "image" => $image,
            "value" => $value
        ));

        return $this->tableImageStorage->insertId();
    }

    public function deleteById($id) {

        $this->tableImageStorage->deleteByAttributes(array(
            "id" => $id
        ));

        return true;
    }

    public function deleteByImage($image) {

        $this->tableImageStorage->deleteByAttributes(array(
            "hash" => md5($image)
        ));

        return true;
    }
}Image/Joomla/JoomlaImage.php000064400000000465151161172500011710
0ustar00<?php

namespace Nextend\Framework\Image\Joomla;

use JHtml;
use Nextend\Framework\Image\AbstractPlatformImage;

class JoomlaImage extends AbstractPlatformImage {

    public function initLightbox() {
        if (version_compare(JVERSION, '4', '<')) {
            JHtml::_('behavior.modal');
        }
    }
}Image/ModelImage.php000064400000004535151161172500010310 0ustar00<?php


namespace Nextend\Framework\Image;


use Nextend\Framework\Form\Container\ContainerTable;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Form\Element\EmptyArea;
use Nextend\Framework\Form\Element\Text\FieldImage;
use Nextend\Framework\Form\Form;
use Nextend\Framework\Visual\ModelVisual;

class ModelImage extends ModelVisual {

    protected $type = 'image';

    /** @var ImageStorage */
    protected $storage;

    protected function init() {

        $this->storage = new ImageStorage();
    }


    public function renderForm() {
        $form      = new Form($this, 'n2-image-editor');
        $container = $form->getContainer();

        $desktopTable = new ContainerTable($container, 'desktop',
n2_('Desktop'));

        $previewRow =
$desktopTable->createRow('desktop-preview');

        new EmptyArea($previewRow, 'desktop-preview',
n2_('Preview'));

        $this->renderDeviceTab($container, 'desktop-retina',
n2_('Desktop retina'));
        $this->renderDeviceTab($container, 'tablet',
n2_('Tablet'));
        $this->renderDeviceTab($container, 'mobile',
n2_('Mobile'));

        $form->render();
    }

    /**
     * @param ContainerInterface $container
     */
    private function renderDeviceTab($container, $name, $label) {

        $table = new ContainerTable($container, $name, $label);

        $row1 = $table->createRow('desktop-row-1');

        new FieldImage($row1, $name . '-image',
n2_('Image'));

        $previewRow = $table->createRow($name . '-preview');
        new EmptyArea($previewRow, $name . '-preview',
n2_('Preview'));

    }

    public function addVisual($image, $visual) {

        $visualId = $this->storage->add($image, $visual);

        $visual = $this->storage->getById($visualId);
        if (!empty($visual)) {
            return $visual;
        }

        return false;
    }

    public function getVisual($image) {
        return $this->storage->getByImage($image);
    }

    public function deleteVisual($id) {
        $visual = $this->storage->getById($id);
        $this->storage->deleteById($id);

        return $visual;
    }

    public function changeVisual($id, $value) {
        if ($this->storage->setById($id, $value)) {
            return $this->storage->getById($id);
        }

        return false;
    }

    public function getVisuals($setId) {
        return $this->storage->getAll();
    }
}Localization/AbstractLocalization.php000064400000000375151161172500014025
0ustar00<?php

namespace Nextend\Framework\Localization;

abstract class AbstractLocalization {

    public function getLocale() {
        return 'en_US';
    }

    abstract public function createMo();

    abstract public function createNOOP_Translations();
}Localization/Functions.php000064400000001603151161172500011654
0ustar00<?php

use Nextend\Framework\Localization\Localization;

function n2_($text, $domain = 'nextend') {
    $translations = Localization::getTranslationsForDomain($domain);

    return $translations->translate($text);
}

function n2_e($text, $domain = 'nextend') {
    echo n2_($text, $domain);
}

function n2_n($single, $plural, $number, $domain = 'nextend') {
    $translations = Localization::getTranslationsForDomain($domain);

    return $translations->translate_plural($single, $plural, $number);
}

function n2_en($single, $plural, $number, $domain = 'nextend') {
    echo n2_n($single, $plural, $number, $domain);
}

function n2_x($text, $context, $domain = 'nextend') {
    $translations = Localization::getTranslationsForDomain($domain);

    return $translations->translate($text, $context);
}

function n2_ex($text, $context, $domain = 'nextend') {
    echo n2_x($text, $context, $domain);
}Localization/Joomla/JoomlaLocalization.php000064400000001134151161172500014716
0ustar00<?php

namespace Nextend\Framework\Localization\Joomla;

use JFactory;
use Nextend\Framework\Localization\AbstractLocalization;
use Nextend\Framework\Localization\Joomla\Pomo\MO;
use Nextend\Framework\Localization\Joomla\Pomo\NOOP_Translations;

class JoomlaLocalization extends AbstractLocalization {

    public function getLocale() {

        $lang = JFactory::getLanguage();

        return str_replace('-', '_',
$lang->getTag());
    }

    public function createMo() {

        return new MO();
    }

    public function createNOOP_Translations() {

        return new NOOP_Translations();
    }
}Localization/Joomla/Pomo/Gettext_Translations.php000064400000010073151161172500016225
0ustar00<?php


namespace Nextend\Framework\Localization\Joomla\Pomo;


class Gettext_Translations extends Translations {

    /**
     * The gettext implementation of select_plural_form.
     *
     * It lives in this class, because there are more than one descendand,
which will use it and
     * they can't share it effectively.
     *
     * @param int $count
     */
    function gettext_select_plural_form($count) {
        if (!isset($this->_gettext_select_plural_form) ||
is_null($this->_gettext_select_plural_form)) {
            list($nplurals, $expression) =
$this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
            $this->_nplurals                   = $nplurals;
            $this->_gettext_select_plural_form =
$this->make_plural_form_function($nplurals, $expression);
        }

        return call_user_func($this->_gettext_select_plural_form,
$count);
    }

    /**
     * @param string $header
     *
     * @return array
     */
    function nplurals_and_expression_from_header($header) {
        if
(preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/',
$header, $matches)) {
            $nplurals   = (int)$matches[1];
            $expression = trim($matches[2]);

            return array(
                $nplurals,
                $expression
            );
        } else {
            return array(
                2,
                'n != 1'
            );
        }
    }

    /**
     * Makes a function, which will return the right translation index,
according to the
     * plural forms header
     *
     * @param int    $nplurals
     * @param string $expression
     */
    function make_plural_form_function($nplurals, $expression) {
        try {
            $handler = new Plural_Forms(rtrim($expression, ';'));

            return array(
                $handler,
                'get'
            );
        } catch (Exception $e) {
            // Fall back to default plural-form function.
            return $this->make_plural_form_function(2, 'n !=
1');
        }
    }

    /**
     * Adds parentheses to the inner parts of ternary operators in
     * plural expressions, because PHP evaluates ternary oerators from left
to right
     *
     * @param string $expression the expression without parentheses
     *
     * @return string the expression with parentheses added
     */
    function parenthesize_plural_exression($expression) {
        $expression .= ';';
        $res        = '';
        $depth      = 0;
        for ($i = 0; $i < strlen($expression); ++$i) {
            $char = $expression[$i];
            switch ($char) {
                case '?':
                    $res .= ' ? (';
                    $depth++;
                    break;
                case ':':
                    $res .= ') : (';
                    break;
                case ';':
                    $res   .= str_repeat(')', $depth) .
';';
                    $depth = 0;
                    break;
                default:
                    $res .= $char;
            }
        }

        return rtrim($res, ';');
    }

    /**
     * @param string $translation
     *
     * @return array
     */
    function make_headers($translation) {
        $headers = array();
        // sometimes \ns are used instead of real new lines
        $translation = str_replace('\n', "\n",
$translation);
        $lines       = explode("\n", $translation);
        foreach ($lines as $line) {
            $parts = explode(':', $line, 2);
            if (!isset($parts[1])) continue;
            $headers[trim($parts[0])] = trim($parts[1]);
        }

        return $headers;
    }

    /**
     * @param string $header
     * @param string $value
     */
    function set_header($header, $value) {
        parent::set_header($header, $value);
        if ('Plural-Forms' == $header) {
            list($nplurals, $expression) =
$this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
            $this->_nplurals                   = $nplurals;
            $this->_gettext_select_plural_form =
$this->make_plural_form_function($nplurals, $expression);
        }
    }
}Localization/Joomla/Pomo/MO.php000064400000023453151161172500012361
0ustar00<?php

namespace Nextend\Framework\Localization\Joomla\Pomo;

/**
 * Class for working with MO files
 *
 * @version    $Id: mo.php 1157 2015-11-20 04:30:11Z dd32 $
 * @package    pomo
 * @subpackage mo
 */
class MO extends Gettext_Translations {

    protected $_nplurals = 2;

    /**
     * Loaded MO file.
     *
     * @var string
     */
    private $filename = '';

    /**
     * Returns the loaded MO file.
     *
     * @return string The loaded MO file.
     */
    public function get_filename() {
        return $this->filename;
    }

    /**
     * Fills up with the entries from MO file $filename
     *
     * @param string $filename MO file to load
     */
    function import_from_file($filename) {
        $reader = new POMO_FileReader($filename);

        if (!$reader->is_resource()) {
            return false;
        }

        $this->filename = (string)$filename;

        return $this->import_from_reader($reader);
    }

    /**
     * @param string $filename
     *
     * @return bool
     */
    function export_to_file($filename) {
        $fh = fopen($filename, 'wb');
        if (!$fh) return false;
        $res = $this->export_to_file_handle($fh);
        fclose($fh);

        return $res;
    }

    /**
     * @return string|false
     */
    function export() {
        $tmp_fh = fopen("php://temp", 'r+');
        if (!$tmp_fh) return false;
        $this->export_to_file_handle($tmp_fh);
        rewind($tmp_fh);

        return stream_get_contents($tmp_fh);
    }

    /**
     * @param Translation_Entry $entry
     *
     * @return bool
     */
    function is_entry_good_for_export($entry) {
        if (empty($entry->translations)) {
            return false;
        }

        if (!array_filter($entry->translations)) {
            return false;
        }

        return true;
    }

    /**
     * @param resource $fh
     *
     * @return true
     */
    function export_to_file_handle($fh) {
        $entries = array_filter($this->entries, array(
            $this,
            'is_entry_good_for_export'
        ));
        ksort($entries);
        $magic                     = 0x950412de;
        $revision                  = 0;
        $total                     = count($entries) + 1; // all the
headers are one entry
        $originals_lenghts_addr    = 28;
        $translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
        $size_of_hash              = 0;
        $hash_addr                 = $translations_lenghts_addr + 8 *
$total;
        $current_addr              = $hash_addr;
        fwrite($fh, pack('V*', $magic, $revision, $total,
$originals_lenghts_addr, $translations_lenghts_addr, $size_of_hash,
$hash_addr));
        fseek($fh, $originals_lenghts_addr);

        // headers' msgid is an empty string
        fwrite($fh, pack('VV', 0, $current_addr));
        $current_addr++;
        $originals_table = chr(0);

        $reader = new POMO_Reader();

        foreach ($entries as $entry) {
            $originals_table .= $this->export_original($entry) . chr(0);
            $length          =
$reader->strlen($this->export_original($entry));
            fwrite($fh, pack('VV', $length, $current_addr));
            $current_addr += $length + 1; // account for the NULL byte
after
        }

        $exported_headers = $this->export_headers();
        fwrite($fh, pack('VV',
$reader->strlen($exported_headers), $current_addr));
        $current_addr       += strlen($exported_headers) + 1;
        $translations_table = $exported_headers . chr(0);

        foreach ($entries as $entry) {
            $translations_table .= $this->export_translations($entry) .
chr(0);
            $length             =
$reader->strlen($this->export_translations($entry));
            fwrite($fh, pack('VV', $length, $current_addr));
            $current_addr += $length + 1;
        }

        fwrite($fh, $originals_table);
        fwrite($fh, $translations_table);

        return true;
    }

    /**
     * @param Translation_Entry $entry
     *
     * @return string
     */
    function export_original($entry) {
        //TODO: warnings for control characters
        $exported = $entry->singular;
        if ($entry->is_plural) $exported .= chr(0) . $entry->plural;
        if ($entry->context) $exported = $entry->context . chr(4) .
$exported;

        return $exported;
    }

    /**
     * @param Translation_Entry $entry
     *
     * @return string
     */
    function export_translations($entry) {
        //TODO: warnings for control characters
        return $entry->is_plural ? implode(chr(0),
$entry->translations) : $entry->translations[0];
    }

    /**
     * @return string
     */
    function export_headers() {
        $exported = '';
        foreach ($this->headers as $header => $value) {
            $exported .= "$header: $value\n";
        }

        return $exported;
    }

    /**
     * @param int $magic
     *
     * @return string|false
     */
    function get_byteorder($magic) {
        // The magic is 0x950412de

        // bug in PHP 5.0.2, see
https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
        $magic_little    = (int)-1794895138;
        $magic_little_64 = (int)2500072158;
        // 0xde120495
        $magic_big = ((int)-569244523) & 0xFFFFFFFF;
        if ($magic_little == $magic || $magic_little_64 == $magic) {
            return 'little';
        } else if ($magic_big == $magic) {
            return 'big';
        } else {
            return false;
        }
    }

    /**
     * @param POMO_FileReader $reader
     */
    function import_from_reader($reader) {
        $endian_string = MO::get_byteorder($reader->readint32());
        if (false === $endian_string) {
            return false;
        }
        $reader->setEndian($endian_string);

        $endian = ('big' == $endian_string) ? 'N' :
'V';

        $header = $reader->read(24);
        if ($reader->strlen($header) != 24) return false;

        // parse header
        $header =
unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr",
$header);
        if (!is_array($header)) return false;

        // support revision 0 of MO format specs, only
        if ($header['revision'] != 0) {
            return false;
        }

        // seek to data blocks
        $reader->seekto($header['originals_lenghts_addr']);

        // read originals' indices
        $originals_lengths_length =
$header['translations_lenghts_addr'] -
$header['originals_lenghts_addr'];
        if ($originals_lengths_length != $header['total'] * 8) {
            return false;
        }

        $originals = $reader->read($originals_lengths_length);
        if ($reader->strlen($originals) != $originals_lengths_length) {
            return false;
        }

        // read translations' indices
        $translations_lenghts_length = $header['hash_addr'] -
$header['translations_lenghts_addr'];
        if ($translations_lenghts_length != $header['total'] * 8)
{
            return false;
        }

        $translations = $reader->read($translations_lenghts_length);
        if ($reader->strlen($translations) !=
$translations_lenghts_length) {
            return false;
        }

        // transform raw data into set of indices
        $originals    = $reader->str_split($originals, 8);
        $translations = $reader->str_split($translations, 8);

        // skip hash table
        $strings_addr = $header['hash_addr'] +
$header['hash_length'] * 4;

        $reader->seekto($strings_addr);

        $strings = $reader->read_all();
        $reader->close();

        for ($i = 0; $i < $header['total']; $i++) {
            $o = unpack("{$endian}length/{$endian}pos",
$originals[$i]);
            $t = unpack("{$endian}length/{$endian}pos",
$translations[$i]);
            if (!$o || !$t) return false;

            // adjust offset due to reading strings to separate space
before
            $o['pos'] -= $strings_addr;
            $t['pos'] -= $strings_addr;

            $original    = $reader->substr($strings,
$o['pos'], $o['length']);
            $translation = $reader->substr($strings,
$t['pos'], $t['length']);

            if ('' === $original) {
               
$this->set_headers($this->make_headers($translation));
            } else {
                $entry                        =
&$this->make_entry($original, $translation);
                $this->entries[$entry->key()] = &$entry;
            }
        }

        return true;
    }

    /**
     * Build a Translation_Entry from original string and translation
strings,
     * found in a MO file
     *
     * @static
     *
     * @param string $original    original string to translate from MO
file. Might contain
     *                            0x04 as context separator or 0x00 as
singular/plural separator
     * @param string $translation translation string from MO file. Might
contain
     *                            0x00 as a plural translations separator
     */
    function &make_entry($original, $translation) {
        $entry = new Translation_Entry();
        // look for context
        $parts = explode(chr(4), $original);
        if (isset($parts[1])) {
            $original       = $parts[1];
            $entry->context = $parts[0];
        }
        // look for plural original
        $parts           = explode(chr(0), $original);
        $entry->singular = $parts[0];
        if (isset($parts[1])) {
            $entry->is_plural = true;
            $entry->plural    = $parts[1];
        }
        // plural translations are also separated by \0
        $entry->translations = explode(chr(0), $translation);

        return $entry;
    }

    /**
     * @param int $count
     *
     * @return string
     */
    function select_plural_form($count) {
        return $this->gettext_select_plural_form($count);
    }

    /**
     * @return int
     */
    function get_plural_forms_count() {
        return $this->_nplurals;
    }
}Localization/Joomla/Pomo/NOOP_Translations.php000064400000003070151161172500015353
0ustar00<?php


namespace Nextend\Framework\Localization\Joomla\Pomo;

/**
 * Provides the same interface as Translations, but doesn't do
anything
 */
class NOOP_Translations {

    protected $entries = array();
    protected $headers = array();

    function add_entry($entry) {
        return true;
    }

    /**
     *
     * @param string $header
     * @param string $value
     */
    function set_header($header, $value) {
    }

    /**
     *
     * @param array $headers
     */
    function set_headers($headers) {
    }

    /**
     * @param string $header
     *
     * @return false
     */
    function get_header($header) {
        return false;
    }

    /**
     * @param Translation_Entry $entry
     *
     * @return false
     */
    function translate_entry(&$entry) {
        return false;
    }

    /**
     * @param string $singular
     * @param string $context
     */
    function translate($singular, $context = null) {
        return $singular;
    }

    /**
     *
     * @param int $count
     *
     * @return bool
     */
    function select_plural_form($count) {
        return 1 == $count ? 0 : 1;
    }

    /**
     * @return int
     */
    function get_plural_forms_count() {
        return 2;
    }

    /**
     * @param string $singular
     * @param string $plural
     * @param int    $count
     * @param string $context
     */
    function translate_plural($singular, $plural, $count, $context = null)
{
        return 1 == $count ? $singular : $plural;
    }

    /**
     * @param object $other
     */
    function merge_with(&$other) {
    }
}Localization/Joomla/Pomo/Plural_Forms.php000064400000024025151161172500014447
0ustar00<?php

namespace Nextend\Framework\Localization\Joomla\Pomo;

use Exception;

/**
 * A gettext Plural-Forms parser.
 *
 * @since 4.9.0
 */
class Plural_Forms {

    /**
     * Operator characters.
     *
     * @since 4.9.0
     * @var string OP_CHARS Operator characters.
     */
    const OP_CHARS = '|&><!=%?:';

    /**
     * Valid number characters.
     *
     * @since 4.9.0
     * @var string NUM_CHARS Valid number characters.
     */
    const NUM_CHARS = '0123456789';

    /**
     * Operator precedence.
     *
     * Operator precedence from highest to lowest. Higher numbers indicate
     * higher precedence, and are executed first.
     *
     * @see  
https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
     *
     * @since 4.9.0
     * @var array $op_precedence Operator precedence from highest to
lowest.
     */
    protected static $op_precedence = array(
        '%' => 6,

        '<'  => 5,
        '<=' => 5,
        '>'  => 5,
        '>=' => 5,

        '==' => 4,
        '!=' => 4,

        '&&' => 3,

        '||' => 2,

        '?:' => 1,
        '?'  => 1,

        '(' => 0,
        ')' => 0,
    );

    /**
     * Tokens generated from the string.
     *
     * @since 4.9.0
     * @var array $tokens List of tokens.
     */
    protected $tokens = array();

    /**
     * Cache for repeated calls to the function.
     *
     * @since 4.9.0
     * @var array $cache Map of $n => $result
     */
    protected $cache = array();

    /**
     * Constructor.
     *
     * @param string $str Plural function (just the bit after `plural=`
from Plural-Forms)
     *
     * @since 4.9.0
     *
     */
    public function __construct($str) {
        $this->parse($str);
    }

    /**
     * Parse a Plural-Forms string into tokens.
     *
     * Uses the shunting-yard algorithm to convert the string to Reverse
Polish
     * Notation tokens.
     *
     * @param string $str String to parse.
     *
     * @since 4.9.0
     *
     */
    protected function parse($str) {
        $pos = 0;
        $len = strlen($str);

        // Convert infix operators to postfix using the shunting-yard
algorithm.
        $output = array();
        $stack  = array();
        while ($pos < $len) {
            $next = substr($str, $pos, 1);

            switch ($next) {
                // Ignore whitespace
                case ' ':
                case "\t":
                    $pos++;
                    break;

                // Variable (n)
                case 'n':
                    $output[] = array('var');
                    $pos++;
                    break;

                // Parentheses
                case '(':
                    $stack[] = $next;
                    $pos++;
                    break;

                case ')':
                    $found = false;
                    while (!empty($stack)) {
                        $o2 = $stack[count($stack) - 1];
                        if ($o2 !== '(') {
                            $output[] = array(
                                'op',
                                array_pop($stack)
                            );
                            continue;
                        }

                        // Discard open paren.
                        array_pop($stack);
                        $found = true;
                        break;
                    }

                    if (!$found) {
                        throw new Exception('Mismatched
parentheses');
                    }

                    $pos++;
                    break;

                // Operators
                case '|':
                case '&':
                case '>':
                case '<':
                case '!':
                case '=':
                case '%':
                case '?':
                    $end_operator = strspn($str, self::OP_CHARS, $pos);
                    $operator     = substr($str, $pos, $end_operator);
                    if (!array_key_exists($operator, self::$op_precedence))
{
                        throw new Exception(sprintf('Unknown operator
"%s"', $operator));
                    }

                    while (!empty($stack)) {
                        $o2 = $stack[count($stack) - 1];

                        // Ternary is right-associative in C
                        if ($operator === '?:' || $operator ===
'?') {
                            if (self::$op_precedence[$operator] >=
self::$op_precedence[$o2]) {
                                break;
                            }
                        } elseif (self::$op_precedence[$operator] >
self::$op_precedence[$o2]) {
                            break;
                        }

                        $output[] = array(
                            'op',
                            array_pop($stack)
                        );
                    }
                    $stack[] = $operator;

                    $pos += $end_operator;
                    break;

                // Ternary "else"
                case ':':
                    $found = false;
                    $s_pos = count($stack) - 1;
                    while ($s_pos >= 0) {
                        $o2 = $stack[$s_pos];
                        if ($o2 !== '?') {
                            $output[] = array(
                                'op',
                                array_pop($stack)
                            );
                            $s_pos--;
                            continue;
                        }

                        // Replace.
                        $stack[$s_pos] = '?:';
                        $found         = true;
                        break;
                    }

                    if (!$found) {
                        throw new Exception('Missing starting
"?" ternary operator');
                    }
                    $pos++;
                    break;

                // Default - number or invalid
                default:
                    if ($next >= '0' && $next <=
'9') {
                        $span     = strspn($str, self::NUM_CHARS, $pos);
                        $output[] = array(
                            'value',
                            intval(substr($str, $pos, $span))
                        );
                        $pos      += $span;
                        break;
                    }

                    throw new Exception(sprintf('Unknown symbol
"%s"', $next));
            }
        }

        while (!empty($stack)) {
            $o2 = array_pop($stack);
            if ($o2 === '(' || $o2 === ')') {
                throw new Exception('Mismatched parentheses');
            }

            $output[] = array(
                'op',
                $o2
            );
        }

        $this->tokens = $output;
    }

    /**
     * Get the plural form for a number.
     *
     * Caches the value for repeated calls.
     *
     * @param int $num Number to get plural form for.
     *
     * @return int Plural form value.
     * @since 4.9.0
     *
     */
    public function get($num) {
        if (isset($this->cache[$num])) {
            return $this->cache[$num];
        }

        return $this->cache[$num] = $this->execute($num);
    }

    /**
     * Execute the plural form function.
     *
     * @param int $n Variable "n" to substitute.
     *
     * @return int Plural form value.
     * @since 4.9.0
     *
     */
    public function execute($n) {
        $stack = array();
        $i     = 0;
        $total = count($this->tokens);
        while ($i < $total) {
            $next = $this->tokens[$i];
            $i++;
            if ($next[0] === 'var') {
                $stack[] = $n;
                continue;
            } elseif ($next[0] === 'value') {
                $stack[] = $next[1];
                continue;
            }

            // Only operators left.
            switch ($next[1]) {
                case '%':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 % $v2;
                    break;

                case '||':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 || $v2;
                    break;

                case '&&':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 && $v2;
                    break;

                case '<':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 < $v2;
                    break;

                case '<=':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 <= $v2;
                    break;

                case '>':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 > $v2;
                    break;

                case '>=':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 >= $v2;
                    break;

                case '!=':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 != $v2;
                    break;

                case '==':
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 == $v2;
                    break;

                case '?:':
                    $v3      = array_pop($stack);
                    $v2      = array_pop($stack);
                    $v1      = array_pop($stack);
                    $stack[] = $v1 ? $v2 : $v3;
                    break;

                default:
                    throw new Exception(sprintf('Unknown operator
"%s"', $next[1]));
            }
        }

        if (count($stack) !== 1) {
            throw new Exception('Too many values remaining on the
stack');
        }

        return (int)$stack[0];
    }
}Localization/Joomla/Pomo/POMO_CachedFileReader.php000064400000000600151161172500015757
0ustar00<?php


namespace Nextend\Framework\Localization\Joomla\Pomo;

/**
 * Reads the contents of the file in the beginning.
 */
class POMO_CachedFileReader extends POMO_StringReader {

    function __construct($filename) {
        parent::__construct();
        $this->_str = file_get_contents($filename);
        if (false !== $this->_str) {
            $this->_pos = 0;
        }
    }
}Localization/Joomla/Pomo/POMO_CachedIntFileReader.php000064400000000274151161172500016441
0ustar00<?php


namespace Nextend\Framework\Localization\Joomla\Pomo;

/**
 * Reads the contents of the file in the beginning.
 */
class POMO_CachedIntFileReader extends POMO_CachedFileReader {

}Localization/Joomla/Pomo/POMO_FileReader.php000064400000002160151161172500014672
0ustar00<?php


namespace Nextend\Framework\Localization\Joomla\Pomo;


class POMO_FileReader extends POMO_Reader {

    protected $_f;

    /**
     * @param string $filename
     */
    function __construct($filename) {
        parent::__construct();
        $this->_f = fopen($filename, 'rb');
    }

    /**
     * @param int $bytes
     */
    function read($bytes) {
        return fread($this->_f, $bytes);
    }

    /**
     * @param int $pos
     *
     * @return boolean
     */
    function seekto($pos) {
        if (-1 == fseek($this->_f, $pos, SEEK_SET)) {
            return false;
        }
        $this->_pos = $pos;

        return true;
    }

    /**
     * @return bool
     */
    function is_resource() {
        return is_resource($this->_f);
    }

    /**
     * @return bool
     */
    function feof() {
        return feof($this->_f);
    }

    /**
     * @return bool
     */
    function close() {
        return fclose($this->_f);
    }

    /**
     * @return string
     */
    function read_all() {
        $all = '';
        while (!$this->feof()) $all .= $this->read(4096);

        return $all;
    }
}
Localization/Joomla/Pomo/POMO_Reader.php000064400000005661151161172500014103
0ustar00<?php


namespace Nextend\Framework\Localization\Joomla\Pomo;


class POMO_Reader {

    protected $endian = 'little';
    protected $_post = '';

    protected $is_overloaded;
    protected $_pos;

    /**
     * PHP5 constructor.
     */
    function __construct() {
        $this->is_overloaded =
((ini_get("mbstring.func_overload") & 2) != 0) &&
function_exists('mb_substr');
        $this->_pos          = 0;
    }

    /**
     * Sets the endianness of the file.
     *
     * @param $endian string 'big' or 'little'
     */
    function setEndian($endian) {
        $this->endian = $endian;
    }

    /**
     * Reads a 32bit Integer from the Stream
     *
     * @return mixed The integer, corresponding to the next 32 bits from
     *    the stream of false if there are not enough bytes or on error
     */
    function readint32() {
        $bytes = $this->read(4);
        if (4 != $this->strlen($bytes)) return false;
        $endian_letter = ('big' == $this->endian) ?
'N' : 'V';
        $int           = unpack($endian_letter, $bytes);

        return reset($int);
    }

    /**
     * Reads an array of 32-bit Integers from the Stream
     *
     * @param integer count How many elements should be read
     *
     * @return mixed Array of integers or false if there isn't
     *    enough data or on error
     */
    function readint32array($count) {
        $bytes = $this->read(4 * $count);
        if (4 * $count != $this->strlen($bytes)) return false;
        $endian_letter = ('big' == $this->endian) ?
'N' : 'V';

        return unpack($endian_letter . $count, $bytes);
    }

    /**
     * @param string $string
     * @param int    $start
     * @param int    $length
     *
     * @return string
     */
    function substr($string, $start, $length) {
        if ($this->is_overloaded) {
            return mb_substr($string, $start, $length, 'ascii');
        } else {
            return substr($string, $start, $length);
        }
    }

    /**
     * @param string $string
     *
     * @return int
     */
    function strlen($string) {
        if ($this->is_overloaded) {
            return mb_strlen($string, 'ascii');
        } else {
            return strlen($string);
        }
    }

    /**
     * @param string $string
     * @param int    $chunk_size
     *
     * @return array
     */
    function str_split($string, $chunk_size) {
        if (!function_exists('str_split')) {
            $length = $this->strlen($string);
            $out    = array();
            for ($i = 0; $i < $length; $i += $chunk_size) $out[] =
$this->substr($string, $i, $chunk_size);

            return $out;
        } else {
            return str_split($string, $chunk_size);
        }
    }

    /**
     * @return int
     */
    function pos() {
        return $this->_pos;
    }

    /**
     * @return true
     */
    function is_resource() {
        return true;
    }

    /**
     * @return true
     */
    function close() {
        return true;
    }
}
Localization/Joomla/Pomo/POMO_StringReader.php000064400000002341151161172500015262
0ustar00<?php


namespace Nextend\Framework\Localization\Joomla\Pomo;

/**
 * Provides file-like methods for manipulating a string instead
 * of a physical file.
 */
class POMO_StringReader extends POMO_Reader {

    protected $_str = '';

    /**
     * PHP5 constructor.
     */
    function __construct($str = '') {
        parent::__construct();
        $this->_str = $str;
        $this->_pos = 0;
    }

    /**
     * @param string $bytes
     *
     * @return string
     */
    function read($bytes) {
        $data       = $this->substr($this->_str, $this->_pos,
$bytes);
        $this->_pos += $bytes;
        if ($this->strlen($this->_str) < $this->_pos)
$this->_pos = $this->strlen($this->_str);

        return $data;
    }

    /**
     * @param int $pos
     *
     * @return int
     */
    function seekto($pos) {
        $this->_pos = $pos;
        if ($this->strlen($this->_str) < $this->_pos)
$this->_pos = $this->strlen($this->_str);

        return $this->_pos;
    }

    /**
     * @return int
     */
    function length() {
        return $this->strlen($this->_str);
    }

    /**
     * @return string
     */
    function read_all() {
        return $this->substr($this->_str, $this->_pos,
$this->strlen($this->_str));
    }

}Localization/Joomla/Pomo/Translations.php000064400000011454151161172500014525
0ustar00<?php

namespace Nextend\Framework\Localization\Joomla\Pomo;
/**
 * Class for a set of entries for translation and their associated headers
 *
 * @version    $Id: translations.php 1157 2015-11-20 04:30:11Z dd32 $
 * @package    pomo
 * @subpackage translations
 */
class Translations {

    protected $entries = array();
    protected $headers = array();

    /**
     * Add entry to the PO structure
     *
     * @param array|Translation_Entry $entry
     *
     * @return bool true on success, false if the entry doesn't have a
key
     */
    function add_entry($entry) {
        if (is_array($entry)) {
            $entry = new Translation_Entry($entry);
        }
        $key = $entry->key();
        if (false === $key) return false;
        $this->entries[$key] = &$entry;

        return true;
    }

    /**
     * @param array|Translation_Entry $entry
     *
     * @return bool
     */
    function add_entry_or_merge($entry) {
        if (is_array($entry)) {
            $entry = new Translation_Entry($entry);
        }
        $key = $entry->key();
        if (false === $key) return false;
        if (isset($this->entries[$key]))
$this->entries[$key]->merge_with($entry); else
            $this->entries[$key] = &$entry;

        return true;
    }

    /**
     * Sets $header PO header to $value
     *
     * If the header already exists, it will be overwritten
     *
     * TODO: this should be out of this class, it is gettext specific
     *
     * @param string $header header name, without trailing :
     * @param string $value  header value, without trailing \n
     */
    function set_header($header, $value) {
        $this->headers[$header] = $value;
    }

    /**
     * @param array $headers
     */
    function set_headers($headers) {
        foreach ($headers as $header => $value) {
            $this->set_header($header, $value);
        }
    }

    /**
     * @param string $header
     */
    function get_header($header) {
        return isset($this->headers[$header]) ?
$this->headers[$header] : false;
    }

    /**
     * @param Translation_Entry $entry
     */
    function translate_entry(&$entry) {
        $key = $entry->key();

        return isset($this->entries[$key]) ? $this->entries[$key] :
false;
    }

    /**
     * @param string $singular
     * @param string $context
     *
     * @return string
     */
    function translate($singular, $context = null) {
        $entry      = new Translation_Entry(array(
            'singular' => $singular,
            'context'  => $context
        ));
        $translated = $this->translate_entry($entry);

        return ($translated &&
!empty($translated->translations)) ? $translated->translations[0] :
$singular;
    }

    /**
     * Given the number of items, returns the 0-based index of the plural
form to use
     *
     * Here, in the base Translations class, the common logic for English
is implemented:
     *    0 if there is one element, 1 otherwise
     *
     * This function should be overridden by the sub-classes. For example
MO/PO can derive the logic
     * from their headers.
     *
     * @param integer $count number of items
     */
    function select_plural_form($count) {
        return 1 == $count ? 0 : 1;
    }

    /**
     * @return int
     */
    function get_plural_forms_count() {
        return 2;
    }

    /**
     * @param string $singular
     * @param string $plural
     * @param int    $count
     * @param string $context
     */
    function translate_plural($singular, $plural, $count, $context = null)
{
        $entry              = new Translation_Entry(array(
            'singular' => $singular,
            'plural'   => $plural,
            'context'  => $context
        ));
        $translated         = $this->translate_entry($entry);
        $index              = $this->select_plural_form($count);
        $total_plural_forms = $this->get_plural_forms_count();
        if ($translated && 0 <= $index && $index <
$total_plural_forms && is_array($translated->translations)
&& isset($translated->translations[$index])) return
$translated->translations[$index]; else
            return 1 == $count ? $singular : $plural;
    }

    /**
     * Merge $other in the current object.
     *
     * @param Object $other Another Translation object, whose translations
will be merged in this one (passed by
     *                      reference).
     *
     * @return void
     **/
    function merge_with(&$other) {
        foreach ($other->entries as $entry) {
            $this->entries[$entry->key()] = $entry;
        }
    }

    /**
     * @param object $other
     */
    function merge_originals_with(&$other) {
        foreach ($other->entries as $entry) {
            if (!isset($this->entries[$entry->key()]))
$this->entries[$entry->key()] = $entry; else
                $this->entries[$entry->key()]->merge_with($entry);
        }
    }
}Localization/Joomla/Pomo/Translation_Entry.php000064400000006333151161172500015523
0ustar00<?php

namespace Nextend\Framework\Localization\Joomla\Pomo;
/**
 * Contains Translation_Entry class
 *
 * @version    $Id: entry.php 1157 2015-11-20 04:30:11Z dd32 $
 * @package    pomo
 * @subpackage entry
 */

/**
 * Translation_Entry class encapsulates a translatable string
 */
class Translation_Entry {

    /**
     * Whether the entry contains a string and its plural form, default is
false
     *
     * @var boolean
     */
    public $is_plural = false;

    public $context = null;
    public $singular = null;
    public $plural = null;
    public $translations = array();
    protected $translator_comments = '';
    protected $extracted_comments = '';
    protected $references = array();
    protected $flags = array();

    /**
     * @param array $args associative array, support following keys:
     *                    - singular (string) -- the string to translate,
if omitted and empty entry will be created
     *                    - plural (string) -- the plural form of the
string, setting this will set {@link $is_plural}
     *                    to true
     *                    - translations (array) -- translations of the
string and possibly -- its plural forms
     *                    - context (string) -- a string differentiating
two equal strings used in different contexts
     *                    - translator_comments (string) -- comments left
by translators
     *                    - extracted_comments (string) -- comments left by
developers
     *                    - references (array) -- places in the code this
strings is used, in
     *                    relative_to_root_path/file.php:linenum form
     *                    - flags (array) -- flags like php-format
     */
    function __construct($args = array()) {
        // if no singular -- empty object
        if (!isset($args['singular'])) {
            return;
        }
        // get member variable values from args hash
        foreach ($args as $varname => $value) {
            $this->$varname = $value;
        }
        if (isset($args['plural']) &&
$args['plural']) $this->is_plural = true;
        if (!is_array($this->translations)) $this->translations =
array();
        if (!is_array($this->references)) $this->references =
array();
        if (!is_array($this->flags)) $this->flags = array();
    }

    /**
     * Generates a unique key for this entry
     *
     * @return string|bool the key or false if the entry is empty
     */
    function key() {
        if (null === $this->singular || '' ===
$this->singular) return false;

        // Prepend context and EOT, like in MO files
        $key = !$this->context ? $this->singular : $this->context
. chr(4) . $this->singular;
        // Standardize on \n line endings
        $key = str_replace(array(
            "\r\n",
            "\r"
        ), "\n", $key);

        return $key;
    }

    /**
     * @param object $other
     */
    function merge_with(&$other) {
        $this->flags      = array_unique(array_merge($this->flags,
$other->flags));
        $this->references =
array_unique(array_merge($this->references, $other->references));
        if ($this->extracted_comments != $other->extracted_comments)
{
            $this->extracted_comments .= $other->extracted_comments;
        }

    }
}Localization/Localization.php000064400000004146151161172500012341
0ustar00<?php

namespace Nextend\Framework\Localization;

use Nextend\Framework\Localization\Joomla\JoomlaLocalization;
use Nextend\Framework\Localization\WordPress\WordPressLocalization;
use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Settings;

class Localization {

    use SingletonTrait;

    /**
     * @var AbstractLocalization
     */
    private static $platformLocalization;

    private static $l10n = array();

    private static $js = array();

    protected function init() {

        require_once 'Functions.php';
        self::$platformLocalization = new JoomlaLocalization();
    
    }

    public static function getLocale() {
        return self::$platformLocalization->getLocale();
    }

    private static function loadTextDomain($domain, $mofile) {
        if (!is_readable($mofile)) return false;

        $mo = self::$platformLocalization->createMo();
        if (!$mo->import_from_file($mofile)) return false;

        if (isset(self::$l10n[$domain]))
$mo->merge_with(self::$l10n[$domain]);
        self::$l10n[$domain] = &$mo;

        return true;
    }

    public static function loadPluginTextDomain($path, $domain =
'nextend') {
        if (Platform::isAdmin() &&
Settings::get('force-english-backend')) {
            $locale = 'en_EN';
        } else {
            $locale = self::getLocale();
        }
        $mofile = $locale . '.mo';
        if ($loaded = self::loadTextDomain($domain, $path . '/' .
$mofile)) {
            return $loaded;
        }

        return false;
    }

    public static function getTranslationsForDomain($domain) {
        if (!isset(self::$l10n[$domain])) {
            self::$l10n[$domain] =
self::$platformLocalization->createNOOP_Translations();
        }

        return self::$l10n[$domain];
    }

    public static function addJS($texts) {
        foreach ((array)$texts as $text) {
            self::$js[$text] = n2_($text);
        }
    }

    public static function toJS() {
        if (count(self::$js)) {
            return '_N2._localization = ' .
json_encode(self::$js) . ';';
        }

        return '';
    }
}Misc/Base64/Decoder.php000064400000002622151161172500010542
0ustar00<?php

namespace Nextend\Framework\Misc\Base64;

class Decoder {

    public static function decode($data) {

        if (function_exists('base64_decode')) {
            return base64_decode($data);
        }

        return self::decodeShim($data);
    }

    private static function decodeShim($input) {
        $keyStr =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        $i      = 0;
        $output = "";

        // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
        $filter = $input;
        $input  = preg_replace("[^A-Za-z0-9\+\/\=]",
"", $input);
        if ($filter != $input) {
            return false;
        }

        do {
            $enc1   = strpos($keyStr, substr($input, $i++, 1));
            $enc2   = strpos($keyStr, substr($input, $i++, 1));
            $enc3   = strpos($keyStr, substr($input, $i++, 1));
            $enc4   = strpos($keyStr, substr($input, $i++, 1));
            $chr1   = ($enc1 << 2) | ($enc2 >> 4);
            $chr2   = (($enc2 & 15) << 4) | ($enc3 >> 2);
            $chr3   = (($enc3 & 3) << 6) | $enc4;
            $output = $output . chr((int)$chr1);
            if ($enc3 != 64) {
                $output = $output . chr((int)$chr2);
            }
            if ($enc4 != 64) {
                $output = $output . chr((int)$chr3);
            }
        } while ($i < strlen($input));

        return urldecode($output);
    }
}Misc/Base64/Encoder.php000064400000003134151161172500010553
0ustar00<?php


namespace Nextend\Framework\Misc\Base64;

class Encoder {

    public static function encode($data) {

        if (function_exists('base64_encode')) {
            return base64_encode($data);
        }

        return self::encodeShim($data);
    }

    private static function encodeShim($data) {
        $b64     =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        $o1      = $o2 = $o3 = $h1 = $h2 = $h3 = $h4 = $bits = $i = 0;
        $ac      = 0;
        $enc     = '';
        $tmp_arr = array();
        if (!$data) {
            return $data;
        }
        do {
            // pack three octets into four hexets
            $o1   = self::charCodeAt($data, $i++);
            $o2   = self::charCodeAt($data, $i++);
            $o3   = self::charCodeAt($data, $i++);
            $bits = $o1 << 16 | $o2 << 8 | $o3;
            $h1   = $bits >> 18 & 0x3f;
            $h2   = $bits >> 12 & 0x3f;
            $h3   = $bits >> 6 & 0x3f;
            $h4   = $bits & 0x3f;
            // use hexets to index into b64, and append result to encoded
string
            $tmp_arr[$ac++] = self::charAt($b64, $h1) . self::charAt($b64,
$h2) . self::charAt($b64, $h3) . self::charAt($b64, $h4);
        } while ($i < strlen($data));
        $enc = implode('', $tmp_arr);
        $r   = (strlen($data) % 3);

        return ($r ? substr($enc, 0, ($r - 3)) . substr('===',
$r) : $enc);
    }

    private static function charCodeAt($data, $char) {
        return ord(substr($data, $char, 1));
    }

    private static function charAt($data, $char) {
        return substr($data, $char, 1);
    }
}Misc/Base64.php000064400000000604151161172500007173 0ustar00<?php

namespace Nextend\Framework\Misc;

use Nextend\Framework\Misc\Base64\Decoder;
use Nextend\Framework\Misc\Base64\Encoder;

class Base64 {

    /**
     * @param $data
     *
     * @return string
     */
    public static function decode($data) {
        return Decoder::decode($data);
    }

    public static function encode($data) {
        return Encoder::encode($data);
    }
}Misc/cacert.pem000064400000770603151161172500007417 0ustar00##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Wed Apr 22 03:12:04 2015
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root
certificates
## file (certdata.txt).  This file can be found in the mozilla source tree:
##
http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
## an Apache+mod_ssl webserver for SSL client authentication.
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.25.
## SHA1: ed3c0bbfb7912bcc00cd2033b0cb85c98d10559c
##


Equifax Secure CA
=================
-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
70+sB3c4
-----END CERTIFICATE-----

GlobalSign Root CA
==================
-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----

GlobalSign Root CA - R2
=======================
-----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
-----END CERTIFICATE-----

Verisign Class 3 Public Primary Certification Authority - G3
============================================================
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1
EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc
cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw
EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj
055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0
xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
-----END CERTIFICATE-----

Verisign Class 4 Public Primary Certification Authority - G3
============================================================
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS
tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM
8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW
Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX
Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd
RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG
UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
-----END CERTIFICATE-----

Entrust.net Premium 2048 Secure Server CA
=========================================
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
-----END CERTIFICATE-----

Baltimore CyberTrust Root
=========================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----

AddTrust Low-Value Services Root
================================
-----BEGIN CERTIFICATE-----
MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU
cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw
CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO
ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6
54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr
oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1
Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui
GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w
HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD
AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT
RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw
HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt
ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr
mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj
ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
-----END CERTIFICATE-----

AddTrust External Root
======================
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----

AddTrust Public Services Root
=============================
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU
cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ
BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l
dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu
nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i
d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG
Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw
HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G
A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux
FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G
A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4
JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9
Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H
EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
-----END CERTIFICATE-----

AddTrust Qualified Certificates Root
====================================
-----BEGIN CERTIFICATE-----
MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU
cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx
CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx
64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3
KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o
L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR
wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU
MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE
BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y
azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD
ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze
RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB
iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
-----END CERTIFICATE-----

Entrust Root Certification Authority
====================================
-----BEGIN CERTIFICATE-----
MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----

RSA Security 2048 v3
====================
-----BEGIN CERTIFICATE-----
MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK
ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy
MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb
BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7
Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb
WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH
KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP
+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/
MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E
FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY
v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj
0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj
VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395
nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
pKnXwiJPZ9d37CAFYd4=
-----END CERTIFICATE-----

GeoTrust Global CA
==================
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
Mw==
-----END CERTIFICATE-----

GeoTrust Global CA 2
====================
-----BEGIN CERTIFICATE-----
MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw
MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/
NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k
LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA
Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b
HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH
K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7
srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh
ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL
OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC
x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF
H4z1Ir+rzoPz4iIprn2DQKi6bA==
-----END CERTIFICATE-----

GeoTrust Universal CA
=====================
-----BEGIN CERTIFICATE-----
MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
P/rmMuGNG2+k5o7Y+SlIis5z/iw=
-----END CERTIFICATE-----

GeoTrust Universal CA 2
=======================
-----BEGIN CERTIFICATE-----
MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
+/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
-----END CERTIFICATE-----

Visa eCommerce Root
===================
-----BEGIN CERTIFICATE-----
MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG
EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug
QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2
WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm
VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL
F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b
RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0
TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI
/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs
GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc
CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW
YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz
zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
398znM/jra6O1I7mT1GvFpLgXPYHDw==
-----END CERTIFICATE-----

Certum Root CA
==============
-----BEGIN CERTIFICATE-----
MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK
ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla
Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u
by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x
wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL
kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ
89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K
Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P
NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+
GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg
GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/
0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS
qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==
-----END CERTIFICATE-----

Comodo AAA Services root
========================
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----

Comodo Secure Services root
===========================
-----BEGIN CERTIFICATE-----
MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw
MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu
Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi
BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP
9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc
rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC
oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V
p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E
FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj
YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm
aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm
4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL
DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw
pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H
RR3B7Hzs/Sk=
-----END CERTIFICATE-----

Comodo Trusted Services root
============================
-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw
MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h
bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw
IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7
3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y
/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6
juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS
ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud
DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp
ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl
cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw
uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA
BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l
R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O
9y5Xt5hwXsjEeLBi
-----END CERTIFICATE-----

QuoVadis Root CA
================
-----BEGIN CERTIFICATE-----
MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
5nrQNiOKSnQ2+Q==
-----END CERTIFICATE-----

QuoVadis Root CA 2
==================
-----BEGIN CERTIFICATE-----
MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
-----END CERTIFICATE-----

QuoVadis Root CA 3
==================
-----BEGIN CERTIFICATE-----
MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
-----END CERTIFICATE-----

Security Communication Root CA
==============================
-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
FL39vmwLAw==
-----END CERTIFICATE-----

Sonera Class 2 Root CA
======================
-----BEGIN CERTIFICATE-----
MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
llpwrN9M
-----END CERTIFICATE-----

Staat der Nederlanden Root CA
=============================
-----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE
ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g
Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w
HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh
bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt
vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P
jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca
C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth
vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6
22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV
HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v
dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN
BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR
EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw
MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y
nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
-----END CERTIFICATE-----

UTN DATACorp SGC Root CA
========================
-----BEGIN CERTIFICATE-----
MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE
BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ
BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa
MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w
HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy
dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys
raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo
wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA
9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv
33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud
DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9
BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD
LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3
DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0
I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx
EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP
DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
-----END CERTIFICATE-----

UTN USERFirst Hardware Root CA
==============================
-----BEGIN CERTIFICATE-----
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE
BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd
BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx
OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0
eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz
ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI
wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd
tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8
i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf
Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw
gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF
lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF
UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW
XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2
lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn
iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67
nfhmqA==
-----END CERTIFICATE-----

Camerfirma Chambers of Commerce Root
====================================
-----BEGIN CERTIFICATE-----
MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx
NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp
cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn
MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC
AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU
xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH
NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW
DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV
d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud
EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v
cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P
AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh
bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi
fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD
L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN
UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n
ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1
erfutGWaIZDgqtCYvDi1czyL+Nw=
-----END CERTIFICATE-----

Camerfirma Global Chambersign Root
==================================
-----BEGIN CERTIFICATE-----
MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx
NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt
YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg
MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw
ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J
1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O
by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl
6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c
8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/
BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j
aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B
Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj
aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA
PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y
gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ
PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4
IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
-----END CERTIFICATE-----

NetLock Notary (Class A) Root
=============================
-----BEGIN CERTIFICATE-----
MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI
EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j
ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX
DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH
EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD
VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz
cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM
D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ
z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC
/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7
tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6
4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG
A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC
Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv
bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn
LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0
ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz
IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh
IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu
b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh
bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg
Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp
bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5
ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP
ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB
CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr
KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM
8CgHrTwXZoi1/baI
-----END CERTIFICATE-----

XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
-----END CERTIFICATE-----

Go Daddy Class 2 CA
===================
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
vZ8=
-----END CERTIFICATE-----

Starfield Class 2 CA
====================
-----BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
QBFGmh95DmK/D5fs4C8fF5Q=
-----END CERTIFICATE-----

StartCom Certification Authority
================================
-----BEGIN CERTIFICATE-----
MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0
Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj
YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH
AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw
Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg
U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5
LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl
cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh
cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT
dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC
AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh
3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm
vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk
fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3
fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ
EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl
1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/
lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro
g14=
-----END CERTIFICATE-----

Taiwan GRCA
===========
-----BEGIN CERTIFICATE-----
MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG
EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X
DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv
dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN
w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5
BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O
1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO
htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov
J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7
Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t
B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB
O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8
lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV
HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2
09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj
Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2
Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU
D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz
DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk
Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk
7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ
CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy
+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS
-----END CERTIFICATE-----

Swisscom Root CA 1
==================
-----BEGIN CERTIFICATE-----
MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG
EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4
MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC
IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM
MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF
NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe
AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC
b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn
7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN
cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp
WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5
haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY
MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9
MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn
jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ
MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H
VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl
vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl
OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3
1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq
nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy
x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW
NY6E0F/6MBr1mmz0DlP5OlvRHA==
-----END CERTIFICATE-----

DigiCert Assured ID Root CA
===========================
-----BEGIN CERTIFICATE-----
MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
-----END CERTIFICATE-----

DigiCert Global Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

DigiCert High Assurance EV Root CA
==================================
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
-----END CERTIFICATE-----

Certplus Class 2 Primary CA
===========================
-----BEGIN CERTIFICATE-----
MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE
BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN
OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy
dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR
5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ
Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO
YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e
e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME
CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ
YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t
L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD
P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R
TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+
7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
l7+ijrRU
-----END CERTIFICATE-----

DST Root CA X3
==============
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----

DST ACES CA X6
==============
-----BEGIN CERTIFICATE-----
MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG
EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT
MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha
MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE
CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI
DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa
pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow
GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy
MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud
EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu
Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy
dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU
CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2
5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs
vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
oKfN5XozNmr6mis=
-----END CERTIFICATE-----

TURKTRUST Certificate Services Provider Root 1
==============================================
-----BEGIN CERTIFICATE-----
MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP
MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0
acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx
MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg
U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB
TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC
aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX
yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i
Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ
8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4
W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME
BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46
sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE
q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy
B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY
nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H
-----END CERTIFICATE-----

TURKTRUST Certificate Services Provider Root 2
==============================================
-----BEGIN CERTIFICATE-----
MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF
bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN
MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr
dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G
A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe
LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI
x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g
QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr
5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB
AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt
Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+
hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P
9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5
UrbnBEI=
-----END CERTIFICATE-----

SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
-----END CERTIFICATE-----

SwissSign Silver CA - G2
========================
-----BEGIN CERTIFICATE-----
MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
-----END CERTIFICATE-----

GeoTrust Primary Certification Authority
========================================
-----BEGIN CERTIFICATE-----
MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
-----END CERTIFICATE-----

thawte Primary Root CA
======================
-----BEGIN CERTIFICATE-----
MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
-----END CERTIFICATE-----

VeriSign Class 3 Public Primary Certification Authority - G5
============================================================
-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
-----END CERTIFICATE-----

SecureTrust CA
==============
-----BEGIN CERTIFICATE-----
MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
-----END CERTIFICATE-----

Secure Global CA
================
-----BEGIN CERTIFICATE-----
MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
-----END CERTIFICATE-----

COMODO Certification Authority
==============================
-----BEGIN CERTIFICATE-----
MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
-----END CERTIFICATE-----

Network Solutions Certificate Authority
=======================================
-----BEGIN CERTIFICATE-----
MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
-----END CERTIFICATE-----

WellsSecure Public Root Certificate Authority
=============================================
-----BEGIN CERTIFICATE-----
MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM
F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw
NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl
bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD
VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1
iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13
i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8
bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB
K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB
AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu
cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm
lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB
i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww
GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI
K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0
bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj
qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es
E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ
tylv2G0xffX8oRAHh84vWdw+WNs=
-----END CERTIFICATE-----

COMODO ECC Certification Authority
==================================
-----BEGIN CERTIFICATE-----
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----

IGC/A
=====
-----BEGIN CERTIFICATE-----
MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD
VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE
Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy
MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI
EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT
STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2
TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW
So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy
HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd
frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ
tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB
egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC
iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK
q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q
MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI
lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF
0mBWWg==
-----END CERTIFICATE-----

Security Communication EV RootCA1
=================================
-----BEGIN CERTIFICATE-----
MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh
dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE
BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl
Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO
/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX
WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z
ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4
bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK
9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm
iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG
Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW
mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW
T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
-----END CERTIFICATE-----

OISTE WISeKey Global Root GA CA
===============================
-----BEGIN CERTIFICATE-----
MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE
BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG
A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH
bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD
VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw
IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5
IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9
Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg
Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD
d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ
/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R
LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm
MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4
+vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
-----END CERTIFICATE-----

Microsec e-Szigno Root CA
=========================
-----BEGIN CERTIFICATE-----
MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE
BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL
EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0
MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz
dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT
GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG
d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N
oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc
QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ
PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb
MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG
IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD
VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3
LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A
dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA
4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg
AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA
egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6
Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO
PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv
c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h
cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw
IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT
WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV
MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER
MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp
Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal
HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT
nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE
aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK
yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB
S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
-----END CERTIFICATE-----

Certigna
========
-----BEGIN CERTIFICATE-----
MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
-----END CERTIFICATE-----

TC TrustCenter Class 2 CA II
============================
-----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw
MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE
AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw
IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2
xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ
Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u
SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB
/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB
7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G
dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ
KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj
TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP
JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk
vQ==
-----END CERTIFICATE-----

TC TrustCenter Universal CA I
=============================
-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC
REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy
IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN
MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg
VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw
JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC
qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv
xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw
ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O
gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j
BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG
1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy
vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3
ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a
7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
-----END CERTIFICATE-----

Deutsche Telekom Root CA 2
==========================
-----BEGIN CERTIFICATE-----
MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG
A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5
MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G
A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS
b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5
bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI
KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY
AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK
Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV
jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV
HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr
E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy
zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8
rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G
dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
Cm26OWMohpLzGITY+9HPBVZkVw==
-----END CERTIFICATE-----

ComSign Secured CA
==================
-----BEGIN CERTIFICATE-----
MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE
AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w
NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD
QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs
49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH
7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB
kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1
9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw
AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t
U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA
j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC
AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a
BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp
FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP
51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
-----END CERTIFICATE-----

Cybertrust Global Root
======================
-----BEGIN CERTIFICATE-----
MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
WL1WMRJOEcgh4LMRkWXbtKaIOM5V
-----END CERTIFICATE-----

ePKI Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
-----END CERTIFICATE-----

T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet
Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3
=============================================================================================================================
-----BEGIN CERTIFICATE-----
MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH
DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q
aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry
b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV
BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg
S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4
MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl
IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF
n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl
IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft
dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl
cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO
Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1
xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR
6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd
BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4
N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT
y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh
LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M
dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=
-----END CERTIFICATE-----

Buypass Class 2 CA 1
====================
-----BEGIN CERTIFICATE-----
MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2
MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M
cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83
0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4
0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R
uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P
AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV
1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt
7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2
fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w
wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
-----END CERTIFICATE-----

Buypass Class 3 CA 1
====================
-----BEGIN CERTIFICATE-----
MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1
MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx
ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0
n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia
AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c
1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P
AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7
pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA
EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5
htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj
el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
-----END CERTIFICATE-----

EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1
==========================================================================
-----BEGIN CERTIFICATE-----
MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF
bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg
QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe
Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p
ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt
IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by
X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b
gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr
eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ
TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy
Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn
uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI
qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm
ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0
Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW
Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t
FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm
zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k
XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT
bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU
RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK
1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt
2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ
Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9
AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
-----END CERTIFICATE-----

certSIGN ROOT CA
================
-----BEGIN CERTIFICATE-----
MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
-----END CERTIFICATE-----

CNNIC ROOT
==========
-----BEGIN CERTIFICATE-----
MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE
ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw
OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD
o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz
VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT
VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or
czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK
y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC
wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S
lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5
Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM
O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8
BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2
G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m
mxE=
-----END CERTIFICATE-----

ApplicationCA - Japanese Government
===================================
-----BEGIN CERTIFICATE-----
MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT
SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw
MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl
cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4
fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN
wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE
jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu
nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU
WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV
BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD
vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs
o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g
/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD
io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW
dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
rosot4LKGAfmt1t06SAZf7IbiVQ=
-----END CERTIFICATE-----

GeoTrust Primary Certification Authority - G3
=============================================
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
-----END CERTIFICATE-----

thawte Primary Root CA - G2
===========================
-----BEGIN CERTIFICATE-----
MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
-----END CERTIFICATE-----

thawte Primary Root CA - G3
===========================
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
+BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
-----END CERTIFICATE-----

GeoTrust Primary Certification Authority - G2
=============================================
-----BEGIN CERTIFICATE-----
MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
npaqBA+K
-----END CERTIFICATE-----

VeriSign Universal Root Certification Authority
===============================================
-----BEGIN CERTIFICATE-----
MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
mJO37M2CYfE45k+XmCpajQ==
-----END CERTIFICATE-----

VeriSign Class 3 Public Primary Certification Authority - G4
============================================================
-----BEGIN CERTIFICATE-----
MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
-----END CERTIFICATE-----

NetLock Arany (Class Gold) Főtanúsítvány
============================================
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
-----END CERTIFICATE-----

Staat der Nederlanden Root CA - G2
==================================
-----BEGIN CERTIFICATE-----
MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC
TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ
5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn
vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj
CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil
e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR
OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI
CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65
48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi
trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737
qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB
AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC
ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA
A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz
+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj
f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN
kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk
CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF
URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb
CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h
oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV
IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm
66+KAQ==
-----END CERTIFICATE-----

CA Disig
========
-----BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK
QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw
MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz
bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm
GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD
Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo
hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt
ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w
gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P
AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz
aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff
ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa
BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t
WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3
mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K
ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA
4Z7CRneC9VkGjCFMhwnN5ag=
-----END CERTIFICATE-----

Juur-SK
=======
-----BEGIN CERTIFICATE-----
MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG
SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy
aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf
TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC
+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw
UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa
Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF
MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD
HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh
AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA
cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr
AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw
cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G
A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo
ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL
abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678
IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh
Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2
yyqcjg==
-----END CERTIFICATE-----

Hongkong Post Root CA 1
=======================
-----BEGIN CERTIFICATE-----
MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
-----END CERTIFICATE-----

SecureSign RootCA11
===================
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
-----END CERTIFICATE-----

ACEDICOM Root
=============
-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD
T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4
MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG
A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk
WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD
YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew
MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb
m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk
HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT
xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2
3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9
2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq
TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz
4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU
9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv
bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg
aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP
eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk
zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1
ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI
KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq
nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE
I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp
MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o
tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==
-----END CERTIFICATE-----

Microsec e-Szigno Root CA 2009
==============================
-----BEGIN CERTIFICATE-----
MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
LXpUq3DDfSJlgnCW
-----END CERTIFICATE-----

GlobalSign Root CA - R3
=======================
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
kpeDMdmztcpHWD9f
-----END CERTIFICATE-----

Autoridad de Certificacion Firmaprofesional CIF A62634068
=========================================================
-----BEGIN CERTIFICATE-----
MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
-----END CERTIFICATE-----

Izenpe.com
==========
-----BEGIN CERTIFICATE-----
MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
-----END CERTIFICATE-----

Chambers of Commerce Root - 2008
================================
-----BEGIN CERTIFICATE-----
MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
-----END CERTIFICATE-----

Global Chambersign Root - 2008
==============================
-----BEGIN CERTIFICATE-----
MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
-----END CERTIFICATE-----

Go Daddy Root Certificate Authority - G2
========================================
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
-----END CERTIFICATE-----

Starfield Root Certificate Authority - G2
=========================================
-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
-----END CERTIFICATE-----

Starfield Services Root Certificate Authority - G2
==================================================
-----BEGIN CERTIFICATE-----
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
-----END CERTIFICATE-----

AffirmTrust Commercial
======================
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
-----END CERTIFICATE-----

AffirmTrust Networking
======================
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
-----END CERTIFICATE-----

AffirmTrust Premium
===================
-----BEGIN CERTIFICATE-----
MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
-----END CERTIFICATE-----

AffirmTrust Premium ECC
=======================
-----BEGIN CERTIFICATE-----
MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
eQ==
-----END CERTIFICATE-----

Certum Trusted Network CA
=========================
-----BEGIN CERTIFICATE-----
MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
-----END CERTIFICATE-----

Certinomis - Autorité Racine
=============================
-----BEGIN CERTIFICATE-----
MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg
LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG
A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw
JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa
wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly
Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw
2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N
jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q
c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC
lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb
xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g
530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna
4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x
WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva
R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40
nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B
CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv
JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE
qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b
WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE
wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/
vgt2Fl43N+bYdJeimUV5
-----END CERTIFICATE-----

Root CA Generalitat Valenciana
==============================
-----BEGIN CERTIFICATE-----
MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE
ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290
IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3
WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE
CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2
F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B
ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ
D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte
JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB
AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n
dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB
ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl
AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA
YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy
AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt
AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA
YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu
AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA
OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0
dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV
BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G
A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S
b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh
TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz
Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63
NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH
iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
-----END CERTIFICATE-----

A-Trust-nQual-03
================
-----BEGIN CERTIFICATE-----
MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE
Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy
a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R
dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw
RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0
ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1
c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA
zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n
yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE
SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4
iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V
cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV
eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40
ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr
sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd
JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6
ahq97BvIxYSazQ==
-----END CERTIFICATE-----

TWCA Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
-----END CERTIFICATE-----

Security Communication RootCA2
==============================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
-----END CERTIFICATE-----

EC-ACC
======
-----BEGIN CERTIFICATE-----
MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
5EI=
-----END CERTIFICATE-----

Hellenic Academic and Research Institutions RootCA 2011
=======================================================
-----BEGIN CERTIFICATE-----
MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
-----END CERTIFICATE-----

Actalis Authentication Root CA
==============================
-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
-----END CERTIFICATE-----

Trustis FPS Root CA
===================
-----BEGIN CERTIFICATE-----
MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
iB6XzCGcKQENZetX2fNXlrtIzYE=
-----END CERTIFICATE-----

StartCom Certification Authority
================================
-----BEGIN CERTIFICATE-----
MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ
Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0
dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu
c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv
bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0
aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0
aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t
L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG
cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5
fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm
N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN
Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T
tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX
e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA
2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs
HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib
D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=
-----END CERTIFICATE-----

StartCom Certification Authority G2
===================================
-----BEGIN CERTIFICATE-----
MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE
ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O
o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG
4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi
Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul
Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs
O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H
vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L
nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS
FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa
z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E
BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ
KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk
J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+
JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG
/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc
nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld
blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc
l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm
7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm
obp573PYtlNXLfbQ4ddI
-----END CERTIFICATE-----

Buypass Class 2 Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
rJgWVqA=
-----END CERTIFICATE-----

Buypass Class 3 Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
Cp/HuZc=
-----END CERTIFICATE-----

T-TeleSec GlobalRoot Class 3
============================
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
-----END CERTIFICATE-----

EE Certification Centre Root CA
===============================
-----BEGIN CERTIFICATE-----
MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy
dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw
MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB
UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy
ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM
TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2
rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw
93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN
P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T
AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ
MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF
BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj
xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM
lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
dcGWxZ0=
-----END CERTIFICATE-----

TURKTRUST Certificate Services Provider Root 2007
=================================================
-----BEGIN CERTIFICATE-----
MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X
DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl
a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN
BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N
YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv
KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya
KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT
rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC
AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s
Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO
Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb
BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK
poRq0Tl9
-----END CERTIFICATE-----

D-TRUST Root Class 3 CA 2 2009
==============================
-----BEGIN CERTIFICATE-----
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
-----END CERTIFICATE-----

D-TRUST Root Class 3 CA 2 EV 2009
=================================
-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
w9y4AyHqnxbxLFS1
-----END CERTIFICATE-----

PSCProcert
==========
-----BEGIN CERTIFICATE-----
MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk
ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ
MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz
dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl
cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw
IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw
MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w
DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD
ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp
Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC
wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA
3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh
RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO
EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2
0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH
0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU
td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw
Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp
r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/
AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz
Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId
xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp
ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH
EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h
Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k
ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG
9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG
MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG
LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52
ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy
YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v
Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o
dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq
T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN
g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q
uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1
n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn
FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo
5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq
3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5
poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y
eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km
-----END CERTIFICATE-----

China Internet Network Information Center EV Certificates Root
==============================================================
-----BEGIN CERTIFICATE-----
MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV
BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D
aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg
Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG
A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM
PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl
cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y
jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV
98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H
klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23
KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC
7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV
HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD
glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5
0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM
7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws
ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0
5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=
-----END CERTIFICATE-----

Swisscom Root CA 2
==================
-----BEGIN CERTIFICATE-----
MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG
EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2
MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC
IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM
LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo
ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ
wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH
Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a
SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS
NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab
mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY
Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3
qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O
BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu
MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO
v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ
82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz
o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs
a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx
OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW
mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o
+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC
rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX
5OfNeOI5wSsSnqaeG8XmDtkx2Q==
-----END CERTIFICATE-----

Swisscom Root EV CA 2
=====================
-----BEGIN CERTIFICATE-----
MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE
BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl
cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN
MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT
HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg
Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz
o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy
Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti
GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li
qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH
Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG
alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa
m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox
bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi
xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/
BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED
MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB
bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL
j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU
wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7
XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH
59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/
23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq
J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA
HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi
uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW
l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=
-----END CERTIFICATE-----

CA Disig Root R1
================
-----BEGIN CERTIFICATE-----
MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw
EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx
EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy
3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8
u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2
m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk
CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa
YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6
vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL
LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX
ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is
XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV
HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ
04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B
LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM
CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb
VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85
YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS
ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix
lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N
UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ
a7+h89n07eLw4+1knj0vllJPgFOL
-----END CERTIFICATE-----

CA Disig Root R2
================
-----BEGIN CERTIFICATE-----
MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
7+ZtsH8tZ/3zbBt1RqPlShfppNcL
-----END CERTIFICATE-----

ACCVRAIZ1
=========
-----BEGIN CERTIFICATE-----
MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
EfbRD0tVNEYqi4Y7
-----END CERTIFICATE-----

TWCA Global Root CA
===================
-----BEGIN CERTIFICATE-----
MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
-----END CERTIFICATE-----

TeliaSonera Root CA v1
======================
-----BEGIN CERTIFICATE-----
MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
-----END CERTIFICATE-----

E-Tugra Certification Authority
===============================
-----BEGIN CERTIFICATE-----
MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
C7TbO6Orb1wdtn7os4I07QZcJA==
-----END CERTIFICATE-----

T-TeleSec GlobalRoot Class 2
============================
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
-----END CERTIFICATE-----

Atos TrustedRoot 2011
=====================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----

QuoVadis Root CA 1 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
hMJKzRwuJIczYOXD
-----END CERTIFICATE-----

QuoVadis Root CA 2 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
O3jtZsSOeWmD3n+M
-----END CERTIFICATE-----

QuoVadis Root CA 3 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
PpxxVJkES/1Y+Zj0
-----END CERTIFICATE-----

DigiCert Assured ID Root G2
===========================
-----BEGIN CERTIFICATE-----
MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
IhNzbM8m9Yop5w==
-----END CERTIFICATE-----

DigiCert Assured ID Root G3
===========================
-----BEGIN CERTIFICATE-----
MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
1vUhZscv6pZjamVFkpUBtA==
-----END CERTIFICATE-----

DigiCert Global Root G2
=======================
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----

DigiCert Global Root G3
=======================
-----BEGIN CERTIFICATE-----
MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
VOKa5Vt8sycX
-----END CERTIFICATE-----

DigiCert Trusted Root G4
========================
-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
82Z+
-----END CERTIFICATE-----

WoSign
======
-----BEGIN CERTIFICATE-----
MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG
EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g
QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ
BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO
CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX
2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5
KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR
+ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez
EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk
lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2
8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY
yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C
AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R
8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1
LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq
T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj
y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC
2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes
5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/
EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh
mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx
kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi
kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w==
-----END CERTIFICATE-----

WoSign China
============
-----BEGIN CERTIFICATE-----
MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG
EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv
geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD
VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k
8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5
uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85
dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5
Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy
b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc
76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m
+Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6
yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX
GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA
A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6
yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY
r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115
j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A
kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97
qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y
jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB
ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv
T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO
kI26oQ==
-----END CERTIFICATE-----

COMODO RSA Certification Authority
==================================
-----BEGIN CERTIFICATE-----
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
LaZRfyHBNVOFBkpdn627G190
-----END CERTIFICATE-----

USERTrust RSA Certification Authority
=====================================
-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----

USERTrust ECC Certification Authority
=====================================
-----BEGIN CERTIFICATE-----
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
-----END CERTIFICATE-----

GlobalSign ECC Root CA - R4
===========================
-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
-----END CERTIFICATE-----

GlobalSign ECC Root CA - R5
===========================
-----BEGIN CERTIFICATE-----
MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
-----END CERTIFICATE-----

Staat der Nederlanden Root CA - G3
==================================
-----BEGIN CERTIFICATE-----
MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC
TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y
olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t
x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy
EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K
Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur
mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5
1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp
07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo
FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE
41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB
AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu
yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq
KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1
v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA
8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b
8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r
mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq
1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI
JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV
tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=
-----END CERTIFICATE-----

Staat der Nederlanden EV Root CA
================================
-----BEGIN CERTIFICATE-----
MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE
CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M
MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl
cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk
SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW
O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r
0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8
Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV
XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr
08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV
0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd
74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx
fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa
ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu
c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq
5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN
b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN
f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi
5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4
WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK
DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy
eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
-----END CERTIFICATE-----

IdenTrust Commercial Root CA 1
==============================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
cGzM7vRX+Bi6hG6H
-----END CERTIFICATE-----

IdenTrust Public Sector Root CA 1
=================================
-----BEGIN CERTIFICATE-----
MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
3Wl9af0AVqW3rLatt8o+Ae+c
-----END CERTIFICATE-----

Entrust Root Certification Authority - G2
=========================================
-----BEGIN CERTIFICATE-----
MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
e4pIb4tF9g==
-----END CERTIFICATE-----

Entrust Root Certification Authority - EC1
==========================================
-----BEGIN CERTIFICATE-----
MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
-----END CERTIFICATE-----

CFCA EV ROOT
============
-----BEGIN CERTIFICATE-----
MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
-----END CERTIFICATE-----
Misc/HttpClient.php000064400000010071151161172500010224 0ustar00<?php

namespace Nextend\Framework\Misc;

use Nextend\Framework\Notification\Notification;
use Nextend\Framework\Settings;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;

class HttpClient {

    public static function getCacertPath() {
        return dirname(__FILE__) . '/cacert.pem';
    }

    public static function get($url, $options = array()) {

        $options = array_merge(array(
            'referer' => $_SERVER['REQUEST_URI']
        ), $options);

        if (function_exists('curl_init') &&
function_exists('curl_exec') &&
Settings::get('curl', 1)) {

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows
NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/73.0.3683.103 Safari/537.36');

            if (!empty($options['referer'])) {
                curl_setopt($ch, CURLOPT_REFERER,
$options['referer']);
            }


            if (Settings::get('curl-clean-proxy', 0)) {
                curl_setopt($ch, CURLOPT_PROXY, '');
            }

            $data = curl_exec($ch);
            if (curl_errno($ch) == 60) {
                curl_setopt($ch, CURLOPT_CAINFO, self::getCacertPath());
                $data = curl_exec($ch);
            }
            $error           = curl_error($ch);
            $curlErrorNumber = curl_errno($ch);
            curl_close($ch);

            if ($curlErrorNumber) {


                $href = ApplicationSmartSlider3::getInstance()
                                              
->getApplicationTypeAdmin()
                                               ->getUrlHelpCurl();

                if (!isset($options['error']) ||
$options['error'] !== false) {
                    Notification::error(Html::tag('a', array(
                        'href' => $href .
'#support-form'
                    ), n2_('Debug error')));

                    Notification::error($curlErrorNumber . $error);
                }

                return false;
            }

            return $data;
        } else {

            if (!ini_get('allow_url_fopen')) {
                Notification::error(sprintf(n2_('The %1$s is not
turned on in your server, which is necessary to read rss feeds. You should
contact your server host, and ask them to enable it!'), '<a
href="http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen"
target="_blank">allow_url_fopen</a>'));

                return false;
            }

            $opts    = array(
                'http' => array(
                    'method' => 'GET'
                )
            );
            $context = stream_context_create($opts);
            $data    = file_get_contents($url, false, $context);
            if ($data === false) {
                Notification::error(n2_('CURL disabled in your php.ini
configuration. Please enable it!'));

                return false;
            }
            $headers = self::parseHeaders($http_response_header);
            if ($headers['status'] != '200') {
                Notification::error(n2_('Unable to contact with the
licensing server, please try again later!'));

                return false;
            }

            return $data;
        }
    }

    private static function parseHeaders(array $headers, $header = null) {
        $output = array();
        if ('HTTP' === substr($headers[0], 0, 4)) {
            list(, $output['status'],
$output['status_text']) = explode(' ', $headers[0]);
            unset($headers[0]);
        }
        foreach ($headers as $v) {
            $h = preg_split('/:\s*/', $v);
            if (count($h) >= 2) {
                $output[strtolower($h[0])] = $h[1];
            }
        }
        if (null !== $header) {
            if (isset($output[strtolower($header)])) {
                return $output[strtolower($header)];
            }

            return null;
        }

        return $output;
    }
}Misc/OAuth/HTTP.php000064400000260224151161172500007754 0ustar00<?php

namespace Nextend\Framework\Misc\OAuth;


use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Misc\HttpClient;

defined('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR') ||
define('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR', -1);
defined('HTTP_CLIENT_ERROR_NO_ERROR') ||
define('HTTP_CLIENT_ERROR_NO_ERROR', 0);
defined('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS') ||
define('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS', 1);
defined('HTTP_CLIENT_ERROR_CANNOT_CONNECT') ||
define('HTTP_CLIENT_ERROR_CANNOT_CONNECT', 2);
defined('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE') ||
define('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE', 3);
defined('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE') ||
define('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE', 4);
defined('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE') ||
define('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE', 5);
defined('HTTP_CLIENT_ERROR_INVALID_PARAMETERS') ||
define('HTTP_CLIENT_ERROR_INVALID_PARAMETERS', 6);

class HTTP {

    var $host_name = "";
    var $host_port = 0;
    var $proxy_host_name = "";
    var $proxy_host_port = 80;
    var $socks_host_name = '';
    var $socks_host_port = 1080;
    var $socks_version = '5';

    var $protocol = "http";
    var $request_method = "GET";
    var $user_agent = 'httpclient
(http://www.phpclasses.org/httpclient $Revision: 1.92 $)';
    var $accept = '';
    var $authentication_mechanism = "";
    var $user;
    var $password;
    var $realm;
    var $workstation;
    var $proxy_authentication_mechanism = "";
    var $proxy_user;
    var $proxy_password;
    var $proxy_realm;
    var $proxy_workstation;
    var $request_uri = "";
    var $request = "";
    var $request_headers = array();
    var $request_user;
    var $request_password;
    var $request_realm;
    var $request_workstation;
    var $proxy_request_user;
    var $proxy_request_password;
    var $proxy_request_realm;
    var $proxy_request_workstation;
    var $request_body = "";
    var $request_arguments = array();
    var $protocol_version = "1.1";
    var $timeout = 0;
    var $data_timeout = 0;
    var $debug = 0;
    var $log_debug = 0;
    var $debug_response_body = 1;
    var $html_debug = 0;
    var $support_cookies = 1;
    var $cookies = array();
    var $error = "";
    var $error_code = HTTP_CLIENT_ERROR_NO_ERROR;
    var $exclude_address = "";
    var $follow_redirect = 0;
    var $redirection_limit = 5;
    var $response_status = "";
    var $response_message = "";
    var $file_buffer_length = 8000;
    var $force_multipart_form_post = 0;
    var $prefer_curl = 1;
    var $keep_alive = 1;
    var $sasl_authenticate = 1;

    /* private variables - DO NOT ACCESS */

    var $state = "Disconnected";
    var $use_curl = 0;
    var $connection = 0;
    var $content_length = 0;
    var $response = "";
    var $read_response = 0;
    var $read_length = 0;
    var $request_host = "";
    var $next_token = "";
    var $redirection_level = 0;
    var $chunked = 0;
    var $remaining_chunk = 0;
    var $last_chunk_read = 0;
    var $months = array(
        "Jan" => "01",
        "Feb" => "02",
        "Mar" => "03",
        "Apr" => "04",
        "May" => "05",
        "Jun" => "06",
        "Jul" => "07",
        "Aug" => "08",
        "Sep" => "09",
        "Oct" => "10",
        "Nov" => "11",
        "Dec" => "12"
    );
    var $session = '';
    var $connection_close = 0;
    var $force_close = 0;
    var $connected_host = '';
    var $connected_port = -1;
    var $connected_ssl = 0;

    public static function PHPErrorMessage() {
        $lastError = error_get_last();
        if ($lastError === null) {
            return '';
        }

        return $lastError['message'];
    }

    /* Private methods - DO NOT CALL */

    Function Tokenize($string, $separator = "") {
        if (!strcmp($separator, "")) {
            $separator = $string;
            $string    = $this->next_token;
        }
        for ($character = 0; $character < strlen($separator);
$character++) {
            $position = strpos($string, $separator[$character]);
            if (GetType($position) == "integer") $found =
(IsSet($found) ? min($found, $position) : $position);
        }
        if (IsSet($found)) {
            $this->next_token = substr($string, $found + 1);

            return (substr($string, 0, $found));
        } else {
            $this->next_token = "";

            return ($string);
        }
    }

    Function CookieEncode($value, $name) {
        return ($name ? str_replace("=", "%25", $value)
: str_replace(";", "%3B", $value));
    }

    Function SetError($error, $error_code =
HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR) {
        $this->error_code = $error_code;

        return ($this->error = $error);
    }

    Function SetPHPError($error, $php_error_message, $error_code =
HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR) {
        if (IsSet($php_error_message) &&
strlen($php_error_message)) $error .= ": " . $php_error_message;

        return ($this->SetError($error, $error_code));
    }

    Function SetDataAccessError($error, $check_connection = 0) {
        $this->error      = $error;
        $this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
        if (!$this->use_curl &&
function_exists("socket_get_status")) {
            $status = socket_get_status($this->connection);
            if ($status["timed_out"]) $this->error .= ":
data access time out"; elseif ($status["eof"]) {
                if ($check_connection) $this->error = ""; else
                    $this->error .= ": the server
disconnected";
            }
        }
    }

    Function OutputDebug($message) {
        if ($this->log_debug) error_log($message); else {
            $message .= "\n";
            if ($this->html_debug) $message =
str_replace("\n", "<br>\n",
HtmlEntities($message));
            echo $message;
            flush();
        }
    }

    Function GetLine() {
        for ($line = ""; ;) {
            if ($this->use_curl) {
                $eol                 = strpos($this->response,
"\n", $this->read_response);
                $data                = ($eol ? substr($this->response,
$this->read_response, $eol + 1 - $this->read_response) :
"");
                $this->read_response += strlen($data);
            } else {
                if (feof($this->connection)) {
                    $this->SetDataAccessError("reached the end of
data while reading from the HTTP server connection");

                    return (0);
                }
                $data = fgets($this->connection, 100);
            }
            if (GetType($data) != "string" || strlen($data) == 0)
{
                $this->SetDataAccessError("it was not possible to
read line from the HTTP server");

                return (0);
            }
            $line   .= $data;
            $length = strlen($line);
            if ($length && !strcmp(substr($line, $length - 1, 1),
"\n")) {
                $length -= (($length >= 2 &&
!strcmp(substr($line, $length - 2, 1), "\r")) ? 2 : 1);
                $line   = substr($line, 0, $length);
                if ($this->debug) $this->OutputDebug("S
$line");

                return ($line);
            }
        }
    }

    Function PutLine($line) {
        if ($this->debug) $this->OutputDebug("C $line");
        if (!fputs($this->connection, $line . "\r\n")) {
            $this->SetDataAccessError("it was not possible to send
a line to the HTTP server");

            return (0);
        }

        return (1);
    }

    Function PutData($data) {
        if (strlen($data)) {
            if ($this->debug) $this->OutputDebug('C ' .
$data);
            if (!fputs($this->connection, $data)) {
                $this->SetDataAccessError("it was not possible to
send data to the HTTP server");

                return (0);
            }
        }

        return (1);
    }

    Function FlushData() {
        if (!fflush($this->connection)) {
            $this->SetDataAccessError("it was not possible to send
data to the HTTP server");

            return (0);
        }

        return (1);
    }

    Function ReadChunkSize() {
        if ($this->remaining_chunk == 0) {
            $debug = $this->debug;
            if (!$this->debug_response_body) $this->debug = 0;
            $line        = $this->GetLine();
            $this->debug = $debug;
            if (GetType($line) != "string") return
($this->SetError("could not read chunk start: " .
$this->error, $this->error_code));
            $this->remaining_chunk = hexdec($line);
            if ($this->remaining_chunk == 0) {
                if (!$this->debug_response_body) $this->debug = 0;
                $line        = $this->GetLine();
                $this->debug = $debug;
                if (GetType($line) != "string") return
($this->SetError("could not read chunk end: " .
$this->error, $this->error_code));
            }
        }

        return ("");
    }

    Function ReadBytes($length) {
        if ($this->use_curl) {
            $bytes               = substr($this->response,
$this->read_response, min($length, strlen($this->response) -
$this->read_response));
            $this->read_response += strlen($bytes);
            if ($this->debug && $this->debug_response_body
&& strlen($bytes)) $this->OutputDebug("S " . $bytes);
        } else {
            if ($this->chunked) {
                for ($bytes = "", $remaining = $length;
$remaining;) {
                    if (strlen($this->ReadChunkSize())) return
("");
                    if ($this->remaining_chunk == 0) {
                        $this->last_chunk_read = 1;
                        break;
                    }
                    $ask   = min($this->remaining_chunk, $remaining);
                    $chunk = @fread($this->connection, $ask);
                    $read  = strlen($chunk);
                    if ($read == 0) {
                        $this->SetDataAccessError("it was not
possible to read data chunk from the HTTP server");

                        return ("");
                    }
                    if ($this->debug &&
$this->debug_response_body) $this->OutputDebug("S " .
$chunk);
                    $bytes                 .= $chunk;
                    $this->remaining_chunk -= $read;
                    $remaining             -= $read;
                    if ($this->remaining_chunk == 0) {
                        if (feof($this->connection)) return
($this->SetError("reached the end of data while reading the end of
data chunk mark from the HTTP server",
HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
                        $data = @fread($this->connection, 2);
                        if (strcmp($data, "\r\n")) {
                            $this->SetDataAccessError("it was not
possible to read end of data chunk from the HTTP server");

                            return ("");
                        }
                    }
                }
            } else {
                $bytes = @fread($this->connection, $length);
                if (strlen($bytes)) {
                    if ($this->debug &&
$this->debug_response_body) $this->OutputDebug("S " .
$bytes);
                } else
                    $this->SetDataAccessError("it was not possible
to read data from the HTTP server", $this->connection_close);
            }
        }

        return ($bytes);
    }

    Function EndOfInput() {
        if ($this->use_curl) return ($this->read_response >=
strlen($this->response));
        if ($this->chunked) return ($this->last_chunk_read);
        if ($this->content_length_set) return ($this->content_length
<= $this->read_length);

        return (feof($this->connection));
    }

    Function Resolve($domain, &$ip, $server_type) {
        if
(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',
$domain)) $ip = $domain; else {
            if ($this->debug) $this->OutputDebug('Resolving
' . $server_type . ' server domain "' . $domain .
'"...');
            if (!strcmp($ip = @gethostbyname($domain), $domain)) $ip =
"";
        }
        if (strlen($ip) == 0 || (strlen($this->exclude_address)
&& !strcmp(@gethostbyname($this->exclude_address), $ip))) return
($this->SetError("could not resolve the host domain \"" .
$domain . "\"", HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS));

        return ('');
    }

    Function Connect($host_name, $host_port, $ssl, $server_type =
'HTTP') {
        $domain = $host_name;
        $port   = $host_port;
        if (strlen($error = $this->Resolve($domain, $ip, $server_type)))
return ($error);
        if (strlen($this->socks_host_name)) {
            switch ($this->socks_version) {
                case '4':
                    $version = 4;
                    break;
                case '5':
                    $version = 5;
                    break;
                default:
                    return ('it was not specified a supported SOCKS
protocol version');
                    break;
            }
            $host_ip          = $ip;
            $port             = $this->socks_host_port;
            $host_server_type = $server_type;
            $server_type      = 'SOCKS';
            if (strlen($error =
$this->Resolve($this->socks_host_name, $ip, $server_type))) return
($error);
        }
        if ($this->debug) $this->OutputDebug('Connecting to
' . $server_type . ' server IP ' . $ip . ' port '
. $port . '...');
        if ($ssl) $ip = "ssl://" . $host_name;
        if (($this->connection = ($this->timeout ? @fsockopen($ip,
$port, $errno, $error, $this->timeout) : @fsockopen($ip, $port,
$errno))) == 0) {
            $error_code = HTTP_CLIENT_ERROR_CANNOT_CONNECT;
            switch ($errno) {
                case -3:
                    return ($this->SetError("socket could not be
created", $error_code));
                case -4:
                    return ($this->SetError("dns lookup on hostname
\"" . $host_name . "\" failed", $error_code));
                case -5:
                    return ($this->SetError("connection refused or
timed out", $error_code));
                case -6:
                    return ($this->SetError("fdopen() call
failed", $error_code));
                case -7:
                    return ($this->SetError("setvbuf() call
failed", $error_code));
                default:
                    return ($this->SetPHPError($errno . " could not
connect to the host \"" . $host_name . "\"",
self::PHPErrorMessage(), $error_code));
            }
        } else {
            if ($this->data_timeout &&
function_exists("socket_set_timeout"))
socket_set_timeout($this->connection, $this->data_timeout, 0);
            if (strlen($this->socks_host_name)) {
                if ($this->debug) $this->OutputDebug('Connected
to the SOCKS server ' . $this->socks_host_name);
                $send_error    = 'it was not possible to send data to
the SOCKS server';
                $receive_error = 'it was not possible to receive data
from the SOCKS server';
                switch ($version) {
                    case 4:
                        $command = 1;
                        $user    = '';
                        if (!fputs($this->connection, chr($version) .
chr($command) . pack('nN', $host_port, ip2long($host_ip)) . $user
. Chr(0))) $error = $this->SetDataAccessError($send_error); else {
                            $response = fgets($this->connection, 9);
                            if (strlen($response) != 8) $error =
$this->SetDataAccessError($receive_error); else {
                                $socks_errors = array(
                                    "\x5a" => '',
                                    "\x5b" => 'request
rejected',
                                    "\x5c" => 'request
failed because client is not running identd (or not reachable from the
server)',
                                    "\x5d" => 'request
failed because client\'s identd could not confirm the user ID string
in the request',
                                );
                                $error_code   = $response[1];
                                $error        =
(IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] :
'unknown');
                                if (strlen($error)) $error = 'SOCKS
error: ' . $error;
                            }
                        }
                        break;
                    case 5:
                        if ($this->debug)
$this->OutputDebug('Negotiating the authentication method
...');
                        $methods = 1;
                        $method  = 0;
                        if (!fputs($this->connection, chr($version) .
chr($methods) . chr($method))) $error =
$this->SetDataAccessError($send_error); else {
                            $response = fgets($this->connection, 3);
                            if (strlen($response) != 2) $error =
$this->SetDataAccessError($receive_error); elseif (Ord($response[1]) !=
$method) $error = 'the SOCKS server requires an authentication method
that is not yet supported';
                            else {
                                if ($this->debug)
$this->OutputDebug('Connecting to ' . $host_server_type .
' server IP ' . $host_ip . ' port ' . $host_port .
'...');
                                $command      = 1;
                                $address_type = 1;
                                if (!fputs($this->connection,
chr($version) . chr($command) . "\x00" . chr($address_type) .
pack('Nn', ip2long($host_ip), $host_port))) $error =
$this->SetDataAccessError($send_error); else {
                                    $response = fgets($this->connection,
11);
                                    if (strlen($response) != 10) $error =
$this->SetDataAccessError($receive_error); else {
                                        $socks_errors = array(
                                            "\x00" =>
'',
                                            "\x01" =>
'general SOCKS server failure',
                                            "\x02" =>
'connection not allowed by ruleset',
                                            "\x03" =>
'Network unreachable',
                                            "\x04" =>
'Host unreachable',
                                            "\x05" =>
'Connection refused',
                                            "\x06" =>
'TTL expired',
                                            "\x07" =>
'Command not supported',
                                            "\x08" =>
'Address type not supported'
                                        );
                                        $error_code   = $response[1];
                                        $error        =
(IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] :
'unknown');
                                        if (strlen($error)) $error =
'SOCKS error: ' . $error;
                                    }
                                }
                            }
                        }
                        break;
                    default:
                        $error = 'support for SOCKS protocol version
' . $this->socks_version . ' is not yet implemented';
                        break;
                }
                if (strlen($error)) {
                    fclose($this->connection);

                    return ($error);
                }
            }
            if ($this->debug) $this->OutputDebug("Connected to
$host_name");
            if (strlen($this->proxy_host_name) &&
!strcmp(strtolower($this->protocol), 'https')) {
                if
(function_exists('stream_socket_enable_crypto') &&
in_array('ssl', stream_get_transports())) $this->state =
"ConnectedToProxy"; else {
                    $this->OutputDebug("It is not possible to start
SSL after connecting to the proxy server. If the proxy refuses to forward
the SSL request, you may need to upgrade to PHP 5.1 or later with OpenSSL
support enabled.");
                    $this->state = "Connected";
                }
            } else
                $this->state = "Connected";

            return ("");
        }
    }

    Function Disconnect() {
        if ($this->debug) $this->OutputDebug("Disconnected from
" . $this->connected_host);
        if ($this->use_curl) {
            curl_close($this->connection);
            $this->response = "";
        } else
            fclose($this->connection);
        $this->state = "Disconnected";

        return ("");
    }

    /* Public methods */

    Function GetRequestArguments($url, &$arguments) {
        $this->error      = '';
        $this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
        $arguments        = array();
        $url              = str_replace(' ', '%20',
$url);
        $parameters       = @parse_url($url);
        if (!$parameters) return ($this->SetError("it was not
specified a valid URL", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        if (!IsSet($parameters["scheme"])) return
($this->SetError("it was not specified the protocol type
argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        switch (strtolower($parameters["scheme"])) {
            case "http":
            case "https":
                $arguments["Protocol"] =
$parameters["scheme"];
                break;
            default:
                return ($parameters["scheme"] . " connection
scheme is not yet supported");
        }
        if (!IsSet($parameters["host"])) return
($this->SetError("it was not specified the connection host
argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        $arguments["HostName"] = $parameters["host"];
        $arguments["Headers"]  = array("Host" =>
$parameters["host"] . (IsSet($parameters["port"]) ?
":" . $parameters["port"] : ""));
        if (IsSet($parameters["user"])) {
            $arguments["AuthUser"] =
UrlDecode($parameters["user"]);
            if (!IsSet($parameters["pass"]))
$arguments["AuthPassword"] = "";
        }
        if (IsSet($parameters["pass"])) {
            if (!IsSet($parameters["user"]))
$arguments["AuthUser"] = "";
            $arguments["AuthPassword"] =
UrlDecode($parameters["pass"]);
        }
        if (IsSet($parameters["port"])) {
            if (strcmp($parameters["port"],
strval(intval($parameters["port"])))) return
($this->SetError("it was not specified a valid connection host
argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            $arguments["HostPort"] =
intval($parameters["port"]);
        } else
            $arguments["HostPort"] = 0;
        $arguments["RequestURI"] =
(IsSet($parameters["path"]) ? $parameters["path"] :
"/") . (IsSet($parameters["query"]) ? "?" .
$parameters["query"] : "");
        if (strlen($this->user_agent))
$arguments["Headers"]["User-Agent"] =
$this->user_agent;
        if (strlen($this->accept))
$arguments["Headers"]["Accept"] = $this->accept;

        return ("");
    }

    Function Open($arguments) {
        if (strlen($this->error)) return ($this->error);
        $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR;
        if (IsSet($arguments["HostName"])) $this->host_name =
$arguments["HostName"];
        if (IsSet($arguments["HostPort"])) $this->host_port =
$arguments["HostPort"];
        if (IsSet($arguments["ProxyHostName"]))
$this->proxy_host_name = $arguments["ProxyHostName"];
        if (IsSet($arguments["ProxyHostPort"]))
$this->proxy_host_port = $arguments["ProxyHostPort"];
        if (IsSet($arguments["SOCKSHostName"]))
$this->socks_host_name = $arguments["SOCKSHostName"];
        if (IsSet($arguments["SOCKSHostPort"]))
$this->socks_host_port = $arguments["SOCKSHostPort"];
        if (IsSet($arguments["SOCKSVersion"]))
$this->socks_version = $arguments["SOCKSVersion"];
        if (IsSet($arguments["Protocol"])) $this->protocol =
$arguments["Protocol"];
        switch (strtolower($this->protocol)) {
            case "http":
                $default_port = 80;
                break;
            case "https":
                $default_port = 443;
                break;
            default:
                return ($this->SetError("it was not specified a
valid connection protocol", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        }
        if (strlen($this->proxy_host_name) == 0) {
            if (strlen($this->host_name) == 0) return
($this->SetError("it was not specified a valid hostname",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            $host_name   = $this->host_name;
            $host_port   = ($this->host_port ? $this->host_port :
$default_port);
            $server_type = 'HTTP';
        } else {
            $host_name   = $this->proxy_host_name;
            $host_port   = $this->proxy_host_port;
            $server_type = 'HTTP proxy';
        }
        $ssl = (strtolower($this->protocol) == "https"
&& strlen($this->proxy_host_name) == 0);
        if ($ssl && strlen($this->socks_host_name)) return
($this->SetError('establishing SSL connections via a SOCKS server
is not yet supported', HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        $this->use_curl = ($ssl && $this->prefer_curl
&& function_exists("curl_init"));
        switch ($this->state) {
            case 'Connected':
                if (!strcmp($host_name, $this->connected_host)
&& intval($host_port) == $this->connected_port &&
intval($ssl) == $this->connected_ssl) {
                    if ($this->debug)
$this->OutputDebug("Reusing connection to " .
$this->connected_host);

                    return ('');
                }
                if (strlen($error = $this->Disconnect())) return
($error);
                break;
            case "Disconnected":
                break;
            default:
                return ("1 already connected");
        }
        if ($this->debug) $this->OutputDebug("Connecting to
" . $this->host_name);
        if ($this->use_curl) {
            $error = (($this->connection = curl_init($this->protocol
. "://" . $this->host_name . ($host_port == $default_port ?
"" : ":" . strval($host_port)) . "/")) ?
"" : "Could not initialize a CURL session");
            if (strlen($error) == 0) {
                curl_setopt($this->connection, CURLOPT_CAINFO,
HttpClient::getCacertPath());
                if (IsSet($arguments["SSLCertificateFile"]))
curl_setopt($this->connection, CURLOPT_SSLCERT,
$arguments["SSLCertificateFile"]);
                if (IsSet($arguments["SSLCertificatePassword"]))
curl_setopt($this->connection, CURLOPT_SSLCERTPASSWD,
$arguments["SSLCertificatePassword"]);
                if (IsSet($arguments["SSLKeyFile"]))
curl_setopt($this->connection, CURLOPT_SSLKEY,
$arguments["SSLKeyFile"]);
                if (IsSet($arguments["SSLKeyPassword"]))
curl_setopt($this->connection, CURLOPT_SSLKEYPASSWD,
$arguments["SSLKeyPassword"]);
            }
            $this->state = "Connected";
        } else {
            $error = "";
            if (strlen($this->proxy_host_name) &&
(IsSet($arguments["SSLCertificateFile"]) ||
IsSet($arguments["SSLCertificateFile"]))) $error =
"establishing SSL connections using certificates or private keys via
non-SSL proxies is not supported"; else {
                if ($ssl) {
                    if (IsSet($arguments["SSLCertificateFile"]))
$error = "establishing SSL connections using certificates is only
supported when the cURL extension is enabled"; elseif
(IsSet($arguments["SSLKeyFile"])) $error = "establishing SSL
connections using a private key is only supported when the cURL extension
is enabled";
                }
                if (strlen($error) == 0) {
                    $error      = $this->Connect($host_name, $host_port,
$ssl, $server_type);
                    $error_code = $this->error_code;
                }
            }
        }
        if (strlen($error)) return ($this->SetError($error,
$error_code));
        $this->session        = md5(uniqid(""));
        $this->connected_host = $host_name;
        $this->connected_port = intval($host_port);
        $this->connected_ssl  = intval($ssl);

        return ("");
    }

    Function Close($force = 0) {
        if ($this->state == "Disconnected") return ("1
already disconnected");
        if (!$this->force_close && $this->keep_alive
&& !$force && $this->state ==
'ResponseReceived') {
            if ($this->debug) $this->OutputDebug('Keeping the
connection alive to ' . $this->connected_host);
            $this->state = 'Connected';

            return ('');
        }

        return ($this->Disconnect());
    }

    Function PickCookies(&$cookies, $secure) {
        if (IsSet($this->cookies[$secure])) {
            $now = gmdate("Y-m-d H-i-s");
            for ($domain = 0, Reset($this->cookies[$secure]); $domain
< count($this->cookies[$secure]); Next($this->cookies[$secure]),
$domain++) {
                $domain_pattern = Key($this->cookies[$secure]);
                $match          = strlen($this->request_host) -
strlen($domain_pattern);
                if ($match >= 0 && !strcmp($domain_pattern,
substr($this->request_host, $match)) && ($match == 0 ||
$domain_pattern[0] == "." || $this->request_host[$match - 1]
== ".")) {
                    for
(Reset($this->cookies[$secure][$domain_pattern]), $path_part = 0;
$path_part < count($this->cookies[$secure][$domain_pattern]);
Next($this->cookies[$secure][$domain_pattern]), $path_part++) {
                        $path =
Key($this->cookies[$secure][$domain_pattern]);
                        if (strlen($this->request_uri) >=
strlen($path) && substr($this->request_uri, 0, strlen($path)) ==
$path) {
                            for
(Reset($this->cookies[$secure][$domain_pattern][$path]), $cookie = 0;
$cookie < count($this->cookies[$secure][$domain_pattern][$path]);
Next($this->cookies[$secure][$domain_pattern][$path]), $cookie++) {
                                $cookie_name =
Key($this->cookies[$secure][$domain_pattern][$path]);
                                $expires     =
$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
                                if ($expires == "" ||
strcmp($now, $expires) < 0) $cookies[$cookie_name] =
$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
                            }
                        }
                    }
                }
            }
        }
    }

    Function GetFileDefinition($file, &$definition) {
        $name = "";
        if (IsSet($file["FileName"])) $name =
basename($file["FileName"]);
        if (IsSet($file["Name"])) $name =
$file["Name"];
        if (strlen($name) == 0) return ("it was not specified the file
part name");
        if (IsSet($file["Content-Type"])) {
            $content_type = $file["Content-Type"];
            $type         = $this->Tokenize(strtolower($content_type),
"/");
            $sub_type     = $this->Tokenize("");
            switch ($type) {
                case "text":
                case "image":
                case "audio":
                case "video":
                case "application":
                case "message":
                    break;
                case "automatic":
                    switch ($sub_type) {
                        case "name":
                            switch (GetType($dot = strrpos($name,
".")) == "integer" ? strtolower(substr($name, $dot)) :
"") {
                                case ".xls":
                                    $content_type =
"application/excel";
                                    break;
                                case ".hqx":
                                    $content_type =
"application/macbinhex40";
                                    break;
                                case ".doc":
                                case ".dot":
                                case ".wrd":
                                    $content_type =
"application/msword";
                                    break;
                                case ".pdf":
                                    $content_type =
"application/pdf";
                                    break;
                                case ".pgp":
                                    $content_type =
"application/pgp";
                                    break;
                                case ".ps":
                                case ".eps":
                                case ".ai":
                                    $content_type =
"application/postscript";
                                    break;
                                case ".ppt":
                                    $content_type =
"application/powerpoint";
                                    break;
                                case ".rtf":
                                    $content_type =
"application/rtf";
                                    break;
                                case ".tgz":
                                case ".gtar":
                                    $content_type =
"application/x-gtar";
                                    break;
                                case ".gz":
                                    $content_type =
"application/x-gzip";
                                    break;
                                case ".php":
                                case ".php3":
                                    $content_type =
"application/x-httpd-php";
                                    break;
                                case ".js":
                                    $content_type =
"application/x-javascript";
                                    break;
                                case ".ppd":
                                case ".psd":
                                    $content_type =
"application/x-photoshop";
                                    break;
                                case ".svg":
                                    $content_type =
"image/svg+xml";
                                    break;
                                case ".swf":
                                case ".swc":
                                case ".rf":
                                    $content_type =
"application/x-shockwave-flash";
                                    break;
                                case ".tar":
                                    $content_type =
"application/x-tar";
                                    break;
                                case ".zip":
                                    $content_type =
"application/zip";
                                    break;
                                case ".mid":
                                case ".midi":
                                case ".kar":
                                    $content_type = "audio/midi";
                                    break;
                                case ".mp2":
                                case ".mp3":
                                case ".mpga":
                                    $content_type = "audio/mpeg";
                                    break;
                                case ".ra":
                                    $content_type =
"audio/x-realaudio";
                                    break;
                                case ".wav":
                                    $content_type = "audio/wav";
                                    break;
                                case ".bmp":
                                    $content_type =
"image/bitmap";
                                    break;
                                case ".gif":
                                    $content_type = "image/gif";
                                    break;
                                case ".iff":
                                    $content_type = "image/iff";
                                    break;
                                case ".jb2":
                                    $content_type = "image/jb2";
                                    break;
                                case ".jpg":
                                case ".jpe":
                                case ".jpeg":
                                    $content_type = "image/jpeg";
                                    break;
                                case ".jpx":
                                    $content_type = "image/jpx";
                                    break;
                                case ".png":
                                    $content_type = "image/png";
                                    break;
                                case ".tif":
                                case ".tiff":
                                    $content_type = "image/tiff";
                                    break;
                                case ".wbmp":
                                    $content_type =
"image/vnd.wap.wbmp";
                                    break;
                                case ".webp":
                                    $content_type = "image/webp";
                                    break;
                                case ".xbm":
                                    $content_type = "image/xbm";
                                    break;
                                case ".css":
                                    $content_type = "text/css";
                                    break;
                                case ".txt":
                                    $content_type = "text/plain";
                                    break;
                                case ".htm":
                                case ".html":
                                    $content_type = "text/html";
                                    break;
                                case ".xml":
                                    $content_type = "text/xml";
                                    break;
                                case ".mpg":
                                case ".mpe":
                                case ".mpeg":
                                    $content_type = "video/mpeg";
                                    break;
                                case ".qt":
                                case ".mov":
                                    $content_type =
"video/quicktime";
                                    break;
                                case ".avi":
                                    $content_type =
"video/x-ms-video";
                                    break;
                                case ".eml":
                                    $content_type =
"message/rfc822";
                                    break;
                                default:
                                    $content_type =
"application/octet-stream";
                                    break;
                            }
                            break;
                        default:
                            return ($content_type . " is not a
supported automatic content type detection method");
                    }
                    break;
                default:
                    return ($content_type . " is not a supported file
content type");
            }
        } else
            $content_type = "application/octet-stream";
        $definition = array(
            "Content-Type" => $content_type,
            "NAME"         => $name
        );
        if (IsSet($file["FileName"])) {
            if (GetType($length = @filesize($file["FileName"]))
!= "integer") {
                $error        = "it was not possible to determine the
length of the file " . $file["FileName"];
                $errorMessage = self::PHPErrorMessage();
                if (strlen($errorMessage)) $error .= ": " .
$errorMessage;
                if (!file_exists($file["FileName"])) $error =
"it was not possible to access the file " .
$file["FileName"];

                return ($error);
            }
            $definition["FILENAME"]       =
$file["FileName"];
            $definition["Content-Length"] = $length;
        } elseif (IsSet($file["Data"]))
$definition["Content-Length"] =
strlen($definition["DATA"] = $file["Data"]);
        else
            return ("it was not specified a valid file name");

        return ("");
    }

    Function ConnectFromProxy($arguments, &$headers) {
        if (!$this->PutLine('CONNECT ' . $this->host_name .
':' . ($this->host_port ? $this->host_port : 443) . '
HTTP/1.0') || (strlen($this->user_agent) &&
!$this->PutLine('User-Agent: ' . $this->user_agent)) ||
(strlen($this->accept) && !$this->PutLine('Accept:
' . $this->accept)) ||
(IsSet($arguments['Headers']['Proxy-Authorization'])
&& !$this->PutLine('Proxy-Authorization: ' .
$arguments['Headers']['Proxy-Authorization'])) ||
!$this->PutLine('')) {
            $this->Disconnect();

            return ($this->error);
        }
        $this->state = "ConnectSent";
        if (strlen($error = $this->ReadReplyHeadersResponse($headers)))
return ($error);
        $proxy_authorization = "";
        while (!strcmp($this->response_status, "100")) {
            $this->state = "ConnectSent";
            if (strlen($error =
$this->ReadReplyHeadersResponse($headers))) return ($error);
        }
        switch ($this->response_status) {
            case "200":
                if (!@stream_socket_enable_crypto($this->connection, 1,
STREAM_CRYPTO_METHOD_SSLv23_CLIENT)) {
                    $this->SetPHPError('it was not possible to
start a SSL encrypted connection via this proxy',
self::PHPErrorMessage(), HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE);
                    $this->Disconnect();

                    return ($this->error);
                }
                $this->state = "Connected";
                break;
            case "407":
                if (strlen($error = $this->Authenticate($headers, -1,
$proxy_authorization, $this->proxy_request_user,
$this->proxy_request_password, $this->proxy_request_realm,
$this->proxy_request_workstation))) return ($error);
                break;
            default:
                return ($this->SetError("unable to send request via
proxy", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
        }

        return ("");
    }

    Function SendRequest($arguments) {
        if (strlen($this->error)) return ($this->error);
        if (IsSet($arguments["ProxyUser"]))
$this->proxy_request_user = $arguments["ProxyUser"]; elseif
(IsSet($this->proxy_user)) $this->proxy_request_user =
$this->proxy_user;
        if (IsSet($arguments["ProxyPassword"]))
$this->proxy_request_password = $arguments["ProxyPassword"];
elseif (IsSet($this->proxy_password)) $this->proxy_request_password =
$this->proxy_password;
        if (IsSet($arguments["ProxyRealm"]))
$this->proxy_request_realm = $arguments["ProxyRealm"]; elseif
(IsSet($this->proxy_realm)) $this->proxy_request_realm =
$this->proxy_realm;
        if (IsSet($arguments["ProxyWorkstation"]))
$this->proxy_request_workstation =
$arguments["ProxyWorkstation"]; elseif
(IsSet($this->proxy_workstation)) $this->proxy_request_workstation =
$this->proxy_workstation;
        switch ($this->state) {
            case "Disconnected":
                return ($this->SetError("connection was not yet
established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "Connected":
                $connect = 0;
                break;
            case "ConnectedToProxy":
                if (strlen($error = $this->ConnectFromProxy($arguments,
$headers))) return ($error);
                $connect = 1;
                break;
            default:
                return ($this->SetError("can not send request in
the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        }
        if (IsSet($arguments["RequestMethod"]))
$this->request_method = $arguments["RequestMethod"];
        if (IsSet($arguments["User-Agent"])) $this->user_agent
= $arguments["User-Agent"];
        if (!IsSet($arguments["Headers"]["User-Agent"])
&& strlen($this->user_agent))
$arguments["Headers"]["User-Agent"] =
$this->user_agent;
        if (IsSet($arguments["KeepAlive"])) $this->keep_alive
= intval($arguments["KeepAlive"]);
        if (!IsSet($arguments["Headers"]["Connection"])
&& $this->keep_alive)
$arguments["Headers"]["Connection"] =
'Keep-Alive';
        if (IsSet($arguments["Accept"])) $this->user_agent =
$arguments["Accept"];
        if (!IsSet($arguments["Headers"]["Accept"])
&& strlen($this->accept))
$arguments["Headers"]["Accept"] = $this->accept;
        if (strlen($this->request_method) == 0) return
($this->SetError("it was not specified a valid request
method", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        if (IsSet($arguments["RequestURI"]))
$this->request_uri = $arguments["RequestURI"];
        if (strlen($this->request_uri) == 0 ||
substr($this->request_uri, 0, 1) != "/") return
($this->SetError("it was not specified a valid request URI",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        $this->request_arguments = $arguments;
        $this->request_headers   =
(IsSet($arguments["Headers"]) ? $arguments["Headers"] :
array());
        $body_length             = 0;
        $this->request_body      = "";
        $get_body                = 1;
        if ($this->request_method == "POST" ||
$this->request_method == "PUT") {
            if (IsSet($arguments['StreamRequest'])) {
                $get_body                                   = 0;
                $this->request_headers["Transfer-Encoding"] =
"chunked";
            } elseif (IsSet($arguments["PostFiles"]) ||
($this->force_multipart_form_post &&
IsSet($arguments["PostValues"]))) {
                $boundary                              = "--" .
md5(uniqid(time()));
                $this->request_headers["Content-Type"] =
"multipart/form-data; boundary=" . $boundary .
(IsSet($arguments["CharSet"]) ? "; charset=" .
$arguments["CharSet"] : "");
                $post_parts                            = array();
                if (IsSet($arguments["PostValues"])) {
                    $values = $arguments["PostValues"];
                    if (GetType($values) != "array") return
($this->SetError("it was not specified a valid POST method values
array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
                    for (Reset($values), $value = 0; $value <
count($values); Next($values), $value++) {
                        $input        = Key($values);
                        $headers      = "--" . $boundary .
"\r\nContent-Disposition: form-data; name=\"" . $input .
"\"\r\n\r\n";
                        $data         = $values[$input];
                        $post_parts[] = array(
                            "HEADERS" => $headers,
                            "DATA"    => $data
                        );
                        $body_length  += strlen($headers) + strlen($data) +
strlen("\r\n");
                    }
                }
                $body_length += strlen("--" . $boundary .
"--\r\n");
                $files       = (IsSet($arguments["PostFiles"]) ?
$arguments["PostFiles"] : array());
                Reset($files);
                $end = (GetType($input = Key($files)) !=
"string");
                for (; !$end;) {
                    if (strlen($error =
$this->GetFileDefinition($files[$input], $definition))) return ("3
" . $error);
                    $headers           = "--" . $boundary .
"\r\nContent-Disposition: form-data; name=\"" . $input .
"\"; filename=\"" . $definition["NAME"] .
"\"\r\nContent-Type: " .
$definition["Content-Type"] . "\r\n\r\n";
                    $part              = count($post_parts);
                    $post_parts[$part] = array("HEADERS" =>
$headers);
                    if (IsSet($definition["FILENAME"])) {
                        $post_parts[$part]["FILENAME"] =
$definition["FILENAME"];
                        $data                          = "";
                    } else
                        $data = $definition["DATA"];
                    $post_parts[$part]["DATA"] = $data;
                    $body_length               += strlen($headers) +
$definition["Content-Length"] + strlen("\r\n");
                    Next($files);
                    $end = (GetType($input = Key($files)) !=
"string");
                }
                $get_body = 0;
            } elseif (IsSet($arguments["PostValues"])) {
                $values = $arguments["PostValues"];
                if (GetType($values) != "array") return
($this->SetError("it was not specified a valid POST method values
array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
                for (Reset($values), $value = 0; $value <
count($values); Next($values), $value++) {
                    $k = Key($values);
                    if (GetType($values[$k]) == "array") {
                        for ($v = 0; $v < count($values[$k]); $v++) {
                            if ($value + $v > 0) $this->request_body
.= "&";
                            $this->request_body .= UrlEncode($k) .
"=" . UrlEncode($values[$k][$v]);
                        }
                    } else {
                        if ($value > 0) $this->request_body .=
"&";
                        $this->request_body .= UrlEncode($k) .
"=" . UrlEncode($values[$k]);
                    }
                }
                $this->request_headers["Content-Type"] =
"application/x-www-form-urlencoded" .
(IsSet($arguments["CharSet"]) ? "; charset=" .
$arguments["CharSet"] : "");
                $get_body                              = 0;
            }
        }
        if ($get_body && (IsSet($arguments["Body"]) ||
IsSet($arguments["BodyStream"]))) {
            if (IsSet($arguments["Body"])) $this->request_body
= $arguments["Body"]; else {
                $stream             = $arguments["BodyStream"];
                $this->request_body = "";
                for ($part = 0; $part < count($stream); $part++) {
                    if (IsSet($stream[$part]["Data"]))
$this->request_body .= $stream[$part]["Data"]; elseif
(IsSet($stream[$part]["File"])) {
                        if (!($file =
@fopen($stream[$part]["File"], "rb"))) return
($this->SetPHPError("could not open upload file " .
$stream[$part]["File"], self::PHPErrorMessage(),
HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE));
                        while (!feof($file)) {
                            if (GetType($block = @fread($file,
$this->file_buffer_length)) != "string") {
                                $error = $this->SetPHPError("could
not read body stream file " . $stream[$part]["File"],
self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
                                fclose($file);

                                return ($error);
                            }
                            $this->request_body .= $block;
                        }
                        fclose($file);
                    } else
                        return ("5 it was not specified a valid file
or data body stream element at position " . $part);
                }
            }
            if
(!IsSet($this->request_headers["Content-Type"]))
$this->request_headers["Content-Type"] =
"application/octet-stream" .
(IsSet($arguments["CharSet"]) ? "; charset=" .
$arguments["CharSet"] : "");
        }
        if (IsSet($arguments["AuthUser"])) $this->request_user
= $arguments["AuthUser"]; elseif (IsSet($this->user))
$this->request_user = $this->user;
        if (IsSet($arguments["AuthPassword"]))
$this->request_password = $arguments["AuthPassword"]; elseif
(IsSet($this->password)) $this->request_password =
$this->password;
        if (IsSet($arguments["AuthRealm"]))
$this->request_realm = $arguments["AuthRealm"]; elseif
(IsSet($this->realm)) $this->request_realm = $this->realm;
        if (IsSet($arguments["AuthWorkstation"]))
$this->request_workstation = $arguments["AuthWorkstation"];
elseif (IsSet($this->workstation)) $this->request_workstation =
$this->workstation;
        if (strlen($this->proxy_host_name) == 0 || $connect)
$request_uri = $this->request_uri; else {
            switch (strtolower($this->protocol)) {
                case "http":
                    $default_port = 80;
                    break;
                case "https":
                    $default_port = 443;
                    break;
            }
            $request_uri = strtolower($this->protocol) . "://"
. $this->host_name . (($this->host_port == 0 || $this->host_port
== $default_port) ? "" : ":" . $this->host_port) .
$this->request_uri;
        }
        if ($this->use_curl) {
            $version          = (GetType($v = curl_version()) ==
"array" ? (IsSet($v["version"]) ?
$v["version"] : "0.0.0") :
(preg_match("/^libcurl\\/([0-9]+\\.[0-9]+\\.[0-9]+)/", $v, $m) ?
$m[1] : "0.0.0"));
            $curl_version     = 100000 *
intval($this->Tokenize($version, ".")) + 1000 *
intval($this->Tokenize(".")) +
intval($this->Tokenize(""));
            $protocol_version = ($curl_version < 713002 ?
"1.0" : $this->protocol_version);
        } else
            $protocol_version = $this->protocol_version;
        $this->request = $this->request_method . " " .
$request_uri . " HTTP/" . $protocol_version;
        if ($body_length || ($body_length = strlen($this->request_body))
|| !strcmp($this->request_method, 'POST'))
$this->request_headers["Content-Length"] = $body_length;
        for ($headers = array(), $host_set = 0,
Reset($this->request_headers), $header = 0; $header <
count($this->request_headers); Next($this->request_headers),
$header++) {
            $header_name  = Key($this->request_headers);
            $header_value = $this->request_headers[$header_name];
            if (GetType($header_value) == "array") {
                for (Reset($header_value), $value = 0; $value <
count($header_value); Next($header_value), $value++) $headers[] =
$header_name . ": " . $header_value[Key($header_value)];
            } else
                $headers[] = $header_name . ": " . $header_value;
            if (strtolower(Key($this->request_headers)) ==
"host") {
                $this->request_host = strtolower($header_value);
                $host_set           = 1;
            }
        }
        if (!$host_set) {
            $headers[]          = "Host: " . $this->host_name;
            $this->request_host = strtolower($this->host_name);
        }
        if (count($this->cookies)) {
            $cookies = array();
            $this->PickCookies($cookies, 0);
            if (strtolower($this->protocol) == "https")
$this->PickCookies($cookies, 1);
            if (count($cookies)) {
                $h           = count($headers);
                $headers[$h] = "Cookie:";
                for (Reset($cookies), $cookie = 0; $cookie <
count($cookies); Next($cookies), $cookie++) {
                    $cookie_name = Key($cookies);
                    $headers[$h] .= " " . $cookie_name .
"=" . $cookies[$cookie_name]["value"] . ";";
                }
            }
        }
        $next_state = "RequestSent";
        if ($this->use_curl) {
            if (IsSet($arguments['StreamRequest'])) return
($this->SetError("Streaming request data is not supported when
using Curl", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            if ($body_length && strlen($this->request_body) ==
0) {
                for ($request_body = "", $success = 1, $part = 0;
$part < count($post_parts); $part++) {
                    $request_body .=
$post_parts[$part]["HEADERS"] .
$post_parts[$part]["DATA"];
                    if (IsSet($post_parts[$part]["FILENAME"])) {
                        if (!($file =
@fopen($post_parts[$part]["FILENAME"], "rb"))) {
                            $this->SetPHPError("could not open
upload file " . $post_parts[$part]["FILENAME"],
self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
                            $success = 0;
                            break;
                        }
                        while (!feof($file)) {
                            if (GetType($block = @fread($file,
$this->file_buffer_length)) != "string") {
                                $this->SetPHPError("could not read
upload file", self::PHPErrorMessage(),
HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
                                $success = 0;
                                break;
                            }
                            $request_body .= $block;
                        }
                        fclose($file);
                        if (!$success) break;
                    }
                    $request_body .= "\r\n";
                }
                $request_body .= "--" . $boundary .
"--\r\n";
            } else
                $request_body = $this->request_body;
            curl_setopt($this->connection, CURLOPT_HEADER, 1);
            curl_setopt($this->connection, CURLOPT_RETURNTRANSFER, 1);
            if ($this->timeout) curl_setopt($this->connection,
CURLOPT_TIMEOUT, $this->timeout);
            curl_setopt($this->connection, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($this->connection, CURLOPT_SSL_VERIFYHOST, 0);
            $request = $this->request . "\r\n" .
implode("\r\n", $headers) . "\r\n\r\n" . $request_body;
            curl_setopt($this->connection, CURLOPT_CUSTOMREQUEST,
$request);
            if ($this->debug) $this->OutputDebug("C " .
$request);
            if (!($success = (strlen($this->response =
curl_exec($this->connection)) != 0))) {
                $error = curl_error($this->connection);
                $this->SetError("Could not execute the
request" . (strlen($error) ? ": " . $error : ""),
HTTP_CLIENT_ERROR_PROTOCOL_FAILURE);
            }
        } else {
            if (($success = $this->PutLine($this->request))) {
                for ($header = 0; $header < count($headers); $header++)
{
                    if (!$success = $this->PutLine($headers[$header]))
break;
                }
                if ($success && ($success =
$this->PutLine(""))) {
                    if (IsSet($arguments['StreamRequest']))
$next_state = "SendingRequestBody"; elseif ($body_length) {
                        if (strlen($this->request_body)) $success =
$this->PutData($this->request_body); else {
                            for ($part = 0; $part < count($post_parts);
$part++) {
                                if (!($success =
$this->PutData($post_parts[$part]["HEADERS"])) || !($success =
$this->PutData($post_parts[$part]["DATA"]))) break;
                                if
(IsSet($post_parts[$part]["FILENAME"])) {
                                    if (!($file =
@fopen($post_parts[$part]["FILENAME"], "rb"))) {
                                        $this->SetPHPError("could
not open upload file " . $post_parts[$part]["FILENAME"],
self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
                                        $success = 0;
                                        break;
                                    }
                                    while (!feof($file)) {
                                        if (GetType($block = @fread($file,
$this->file_buffer_length)) != "string") {
                                           
$this->SetPHPError("could not read upload file",
self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
                                            $success = 0;
                                            break;
                                        }
                                        if (!($success =
$this->PutData($block))) break;
                                    }
                                    fclose($file);
                                    if (!$success) break;
                                }
                                if (!($success =
$this->PutLine(""))) break;
                            }
                            if ($success) $success =
$this->PutLine("--" . $boundary . "--");
                        }
                        if ($success) $sucess = $this->FlushData();
                    }
                }
            }
        }
        if (!$success) return ($this->SetError("could not send the
HTTP request: " . $this->error, $this->error_code));
        $this->state = $next_state;

        return ("");
    }

    Function SetCookie($name, $value, $expires = "", $path =
"/", $domain = "", $secure = 0, $verbatim = 0) {
        if (strlen($this->error)) return ($this->error);
        if (strlen($name) == 0) return ($this->SetError("it was not
specified a valid cookie name",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        if (strlen($path) == 0 || strcmp($path[0], "/")) return
($this->SetError($path . " is not a valid path for setting cookie
" . $name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        if ($domain == "" || strpos($domain, ".",
$domain[0] == "." ? 1 : 0) === false) return
($this->SetError($domain . " is not a valid domain for setting
cookie " . $name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        $domain = strtolower($domain);
        if (!strcmp($domain[0], ".")) $domain = substr($domain,
1);
        if (!$verbatim) {
            $name  = $this->CookieEncode($name, 1);
            $value = $this->CookieEncode($value, 0);
        }
        $secure                                        = intval($secure);
        $this->cookies[$secure][$domain][$path][$name] = array(
            "name"    => $name,
            "value"   => $value,
            "domain"  => $domain,
            "path"    => $path,
            "expires" => $expires,
            "secure"  => $secure
        );

        return ("");
    }

    Function SendRequestBody($data, $end_of_data) {
        if (strlen($this->error)) return ($this->error);
        switch ($this->state) {
            case "Disconnected":
                return ($this->SetError("connection was not yet
established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "Connected":
            case "ConnectedToProxy":
                return ($this->SetError("request was not
sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "SendingRequestBody":
                break;
            case "RequestSent":
                return ($this->SetError("request body was already
sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            default:
                return ($this->SetError("can not send the request
body in the current connection state",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        }
        $length = strlen($data);
        if ($length) {
            $size = dechex($length) . "\r\n";
            if (!$this->PutData($size) || !$this->PutData($data))
return ($this->error);
        }
        if ($end_of_data) {
            $size = "0\r\n";
            if (!$this->PutData($size)) return ($this->error);
            $this->state = "RequestSent";
        }

        return ("");
    }

    Function ReadReplyHeadersResponse(&$headers) {
        $headers = array();
        if (strlen($this->error)) return ($this->error);
        switch ($this->state) {
            case "Disconnected":
                return ($this->SetError("connection was not yet
established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "Connected":
                return ($this->SetError("request was not
sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "ConnectedToProxy":
                return ($this->SetError("connection from the remote
server from the proxy was not yet established",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "SendingRequestBody":
                return ($this->SetError("request body data was not
completely sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "ConnectSent":
                $connect = 1;
                break;
            case "RequestSent":
                $connect = 0;
                break;
            default:
                return ($this->SetError("can not get request
headers in the current connection state",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        }
        $this->content_length     = $this->read_length =
$this->read_response = $this->remaining_chunk = 0;
        $this->content_length_set = $this->chunked =
$this->last_chunk_read = $chunked = 0;
        $this->force_close        = $this->connection_close = 0;
        for ($this->response_status = ""; ;) {
            $line = $this->GetLine();
            if (GetType($line) != "string") return
($this->SetError("could not read request reply: " .
$this->error, $this->error_code));
            if (strlen($this->response_status) == 0) {
                if (!preg_match($match = "/^http\\/[0-9]+\\.[0-9]+[
\t]+([0-9]+)[ \t]*(.*)\$/i", $line, $matches)) return
($this->SetError("it was received an unexpected HTTP response
status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
                $this->response_status  = $matches[1];
                $this->response_message = $matches[2];
                if ($this->response_status == 204) {
                    $this->content_length     = 0;
                    $this->content_length_set = 1;
                }
            }
            if ($line == "") {
                if (strlen($this->response_status) == 0) return
($this->SetError("it was not received HTTP response status",
HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
                $this->state = ($connect ? "GotConnectHeaders"
: "GotReplyHeaders");
                break;
            }
            $header_name  = strtolower($this->Tokenize($line,
":"));
            $header_value =
Trim(Chop($this->Tokenize("\r\n")));
            if (IsSet($headers[$header_name])) {
                if (GetType($headers[$header_name]) == "string")
$headers[$header_name] = array($headers[$header_name]);
                $headers[$header_name][] = $header_value;
            } else
                $headers[$header_name] = $header_value;
            if (!$connect) {
                switch ($header_name) {
                    case "content-length":
                        $this->content_length     =
intval($headers[$header_name]);
                        $this->content_length_set = 1;
                        break;
                    case "transfer-encoding":
                        $encoding = $this->Tokenize($header_value,
"; \t");
                        if (!$this->use_curl &&
!strcmp($encoding, "chunked")) $chunked = 1;
                        break;
                    case "set-cookie":
                        if ($this->support_cookies) {
                            if (GetType($headers[$header_name]) ==
"array") $cookie_headers = $headers[$header_name]; else
                                $cookie_headers =
array($headers[$header_name]);
                            for ($cookie = 0; $cookie <
count($cookie_headers); $cookie++) {
                                $cookie_name  =
trim($this->Tokenize($cookie_headers[$cookie], "="));
                                $cookie_value =
$this->Tokenize(";");
                                $domain       = $this->request_host;
                                $path         = "/";
                                $expires      = "";
                                $secure       = 0;
                                while (($name =
strtolower(trim(UrlDecode($this->Tokenize("="))))) !=
"") {
                                    $value =
UrlDecode($this->Tokenize(";"));
                                    switch ($name) {
                                        case "domain":
                                            $domain = $value;
                                            break;
                                        case "path":
                                            $path = $value;
                                            break;
                                        case "expires":
                                            if
(preg_match("/^((Mon|Monday|Tue|Tuesday|Wed|Wednesday|Thu|Thursday|Fri|Friday|Sat|Saturday|Sun|Sunday),
)?([0-9]{2})\\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\-([0-9]{2,4})
([0-9]{2})\\:([0-9]{2})\\:([0-9]{2}) GMT\$/", $value, $matches)) {
                                                $year =
intval($matches[5]);
                                                if ($year < 1900) $year
+= ($year < 70 ? 2000 : 1900);
                                                $expires =
"$year-" . $this->months[$matches[4]] . "-" .
$matches[3] . " " . $matches[6] . ":" . $matches[7] .
":" . $matches[8];
                                            }
                                            break;
                                        case "secure":
                                            $secure = 1;
                                            break;
                                    }
                                }
                                if
(strlen($this->SetCookie($cookie_name, $cookie_value, $expires, $path,
$domain, $secure, 1))) $this->error = "";
                            }
                        }
                        break;
                    case "connection":
                        $this->force_close = $this->connection_close
= !strcmp(strtolower($header_value), "close");
                        break;
                }
            }
        }
        $this->chunked = $chunked;
        if ($this->content_length_set) $this->connection_close = 0;

        return ("");
    }

    Function Redirect(&$headers) {
        if ($this->follow_redirect) {
            if (!IsSet($headers["location"]) ||
(GetType($headers["location"]) != "array" &&
strlen($location = $headers["location"]) == 0) ||
(GetType($headers["location"]) == "array" &&
strlen($location = $headers["location"][0]) == 0)) return
($this->SetError("it was received a redirect without location
URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
            if (strcmp($location[0], "/")) {
                if (!($location_arguments = @parse_url($location))) return
($this->SetError("the server did not return a valid redirection
location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
                if (!IsSet($location_arguments["scheme"]))
$location = ((GetType($end = strrpos($this->request_uri, "/"))
== "integer" && $end > 1) ?
substr($this->request_uri, 0, $end) : "") . "/" .
$location;
            }
            if (!strcmp($location[0], "/")) $location =
$this->protocol . "://" . $this->host_name .
($this->host_port ? ":" . $this->host_port : "")
. $location;
            $error = $this->GetRequestArguments($location, $arguments);
            if (strlen($error)) return ($this->SetError("could not
process redirect url: " . $error,
HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
            $arguments["RequestMethod"] = "GET";
            if (strlen($error = $this->Close()) == 0 &&
strlen($error = $this->Open($arguments)) == 0 && strlen($error =
$this->SendRequest($arguments)) == 0) {
                $this->redirection_level++;
                if ($this->redirection_level >
$this->redirection_limit) {
                    $error            = "it was exceeded the limit of
request redirections";
                    $this->error_code =
HTTP_CLIENT_ERROR_PROTOCOL_FAILURE;
                } else
                    $error = $this->ReadReplyHeaders($headers);
                $this->redirection_level--;
            }
            if (strlen($error)) return ($this->SetError($error,
$this->error_code));
        }

        return ("");
    }

    Function Authenticate(&$headers, $proxy, &$proxy_authorization,
&$user, &$password, &$realm, &$workstation) {
        if ($proxy) {
            $authenticate_header      = "proxy-authenticate";
            $authorization_header     = "Proxy-Authorization";
            $authenticate_status      = "407";
            $authentication_mechanism =
$this->proxy_authentication_mechanism;
        } else {
            $authenticate_header      = "www-authenticate";
            $authorization_header     = "Authorization";
            $authenticate_status      = "401";
            $authentication_mechanism = $this->authentication_mechanism;
        }
        if (IsSet($headers[$authenticate_header]) &&
$this->sasl_authenticate) {
            if (function_exists("class_exists") &&
!class_exists("sasl_client_class")) return
($this->SetError("the SASL client class needs to be loaded to be
able to authenticate" . ($proxy ? " with the proxy server" :
"") . " and access this site",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            if (GetType($headers[$authenticate_header]) ==
"array") $authenticate = $headers[$authenticate_header]; else
                $authenticate = array($headers[$authenticate_header]);
            for ($response = "", $mechanisms = array(), $m = 0;
$m < count($authenticate); $m++) {
                $mechanism = $this->Tokenize($authenticate[$m], "
");
                $response  = $this->Tokenize("");
                if (strlen($authentication_mechanism)) {
                    if (!strcmp($authentication_mechanism, $mechanism)) {
                        $mechanisms[] = $mechanism;
                        break;
                    }
                } else
                    $mechanisms[] = $mechanism;
            }
            $sasl = new sasl_client_class;
            if (IsSet($user)) $sasl->SetCredential("user",
$user);
            if (IsSet($password))
$sasl->SetCredential("password", $password);
            if (IsSet($realm)) $sasl->SetCredential("realm",
$realm);
            if (IsSet($workstation))
$sasl->SetCredential("workstation", $workstation);
            $sasl->SetCredential("uri",
$this->request_uri);
            $sasl->SetCredential("method",
$this->request_method);
            $sasl->SetCredential("session",
$this->session);
            do {
                $status = $sasl->Start($mechanisms, $message,
$interactions);
            } while ($status == SASL_INTERACT);
            switch ($status) {
                case SASL_CONTINUE:
                    break;
                case SASL_NOMECH:
                    return ($this->SetError(($proxy ? "proxy "
: "") . "authentication error: " .
(strlen($authentication_mechanism) ? "authentication mechanism "
. $authentication_mechanism . " may not be used: " :
"") . $sasl->error, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
                default:
                    return ($this->SetError("Could not start the
SASL " . ($proxy ? "proxy " : "") .
"authentication client: " . $sasl->error,
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            }
            if ($proxy >= 0) {
                for (; ;) {
                    if (strlen($error = $this->ReadReplyBody($body,
$this->file_buffer_length))) return ($error);
                    if (strlen($body) == 0) break;
                }
            }
            $authorization_value                         =
$sasl->mechanism . (IsSet($message) ? " " .
($sasl->encode_response ? Base64::encode($message) : $message) :
"");
            $request_arguments                           =
$this->request_arguments;
            $arguments                                   =
$request_arguments;
            $arguments["Headers"][$authorization_header] =
$authorization_value;
            if (!$proxy && strlen($proxy_authorization))
$arguments["Headers"]["Proxy-Authorization"] =
$proxy_authorization;
            if (strlen($error = $this->Close()) || strlen($error =
$this->Open($arguments))) return ($this->SetError($error,
$this->error_code));
            $authenticated = 0;
            if (IsSet($message)) {
                if ($proxy < 0) {
                    if (strlen($error =
$this->ConnectFromProxy($arguments, $headers))) return
($this->SetError($error, $this->error_code));
                } else {
                    if (strlen($error = $this->SendRequest($arguments))
|| strlen($error = $this->ReadReplyHeadersResponse($headers))) return
($this->SetError($error, $this->error_code));
                }
                if (!IsSet($headers[$authenticate_header])) $authenticate =
array(); elseif (GetType($headers[$authenticate_header]) ==
"array") $authenticate = $headers[$authenticate_header];
                else
                    $authenticate = array($headers[$authenticate_header]);
                for ($mechanism = 0; $mechanism < count($authenticate);
$mechanism++) {
                    if
(!strcmp($this->Tokenize($authenticate[$mechanism], " "),
$sasl->mechanism)) {
                        $response = $this->Tokenize("");
                        break;
                    }
                }
                switch ($this->response_status) {
                    case $authenticate_status:
                        break;
                    case "301":
                    case "302":
                    case "303":
                    case "307":
                        if ($proxy >= 0) return
($this->Redirect($headers));
                    default:
                        if (intval($this->response_status / 100) == 2) {
                            if ($proxy) $proxy_authorization =
$authorization_value;
                            $authenticated = 1;
                            break;
                        }
                        if ($proxy &&
!strcmp($this->response_status, "401")) {
                            $proxy_authorization = $authorization_value;
                            $authenticated       = 1;
                            break;
                        }

                        return ($this->SetError(($proxy ? "proxy
" : "") . "authentication error: " .
$this->response_status . " " . $this->response_message,
HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
                }
            }
            for (; !$authenticated;) {
                do {
                    $status = $sasl->Step($response, $message,
$interactions);
                } while ($status == SASL_INTERACT);
                switch ($status) {
                    case SASL_CONTINUE:
                        $authorization_value                         =
$sasl->mechanism . (IsSet($message) ? " " .
($sasl->encode_response ? Base64::encode($message) : $message) :
"");
                        $arguments                                   =
$request_arguments;
                       
$arguments["Headers"][$authorization_header] =
$authorization_value;
                        if (!$proxy &&
strlen($proxy_authorization))
$arguments["Headers"]["Proxy-Authorization"] =
$proxy_authorization;
                        if ($proxy < 0) {
                            if (strlen($error =
$this->ConnectFromProxy($arguments, $headers))) return
($this->SetError($error, $this->error_code));
                        } else {
                            if (strlen($error =
$this->SendRequest($arguments)) || strlen($error =
$this->ReadReplyHeadersResponse($headers))) return
($this->SetError($error, $this->error_code));
                        }
                        switch ($this->response_status) {
                            case $authenticate_status:
                                if (GetType($headers[$authenticate_header])
== "array") $authenticate = $headers[$authenticate_header]; else
                                    $authenticate =
array($headers[$authenticate_header]);
                                for ($response = "", $mechanism =
0; $mechanism < count($authenticate); $mechanism++) {
                                    if
(!strcmp($this->Tokenize($authenticate[$mechanism], " "),
$sasl->mechanism)) {
                                        $response =
$this->Tokenize("");
                                        break;
                                    }
                                }
                                if ($proxy >= 0) {
                                    for (; ;) {
                                        if (strlen($error =
$this->ReadReplyBody($body, $this->file_buffer_length))) return
($error);
                                        if (strlen($body) == 0) break;
                                    }
                                }
                                $this->state = "Connected";
                                break;
                            case "301":
                            case "302":
                            case "303":
                            case "307":
                                if ($proxy >= 0) return
($this->Redirect($headers));
                            default:
                                if (intval($this->response_status / 100)
== 2) {
                                    if ($proxy) $proxy_authorization =
$authorization_value;
                                    $authenticated = 1;
                                    break;
                                }
                                if ($proxy &&
!strcmp($this->response_status, "401")) {
                                    $proxy_authorization =
$authorization_value;
                                    $authenticated       = 1;
                                    break;
                                }

                                return ($this->SetError(($proxy ?
"proxy " : "") . "authentication error: " .
$this->response_status . " " . $this->response_message));
                        }
                        break;
                    default:
                        return ($this->SetError("Could not process
the SASL " . ($proxy ? "proxy " : "") .
"authentication step: " . $sasl->error,
HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
                }
            }
        }

        return ("");
    }

    Function ReadReplyHeaders(&$headers) {
        if (strlen($error = $this->ReadReplyHeadersResponse($headers)))
return ($error);
        $proxy_authorization = "";
        while (!strcmp($this->response_status, "100")) {
            $this->state = "RequestSent";
            if (strlen($error =
$this->ReadReplyHeadersResponse($headers))) return ($error);
        }
        switch ($this->response_status) {
            case "301":
            case "302":
            case "303":
            case "307":
                if (strlen($error = $this->Redirect($headers))) return
($error);
                break;
            case "407":
                if (strlen($error = $this->Authenticate($headers, 1,
$proxy_authorization, $this->proxy_request_user,
$this->proxy_request_password, $this->proxy_request_realm,
$this->proxy_request_workstation))) return ($error);
                if (strcmp($this->response_status, "401"))
return ("");
            case "401":
                return ($this->Authenticate($headers, 0,
$proxy_authorization, $this->request_user, $this->request_password,
$this->request_realm, $this->request_workstation));
        }

        return ("");
    }

    Function ReadReplyBody(&$body, $length) {
        $body = "";
        if (strlen($this->error)) return ($this->error);
        switch ($this->state) {
            case "Disconnected":
                return ($this->SetError("connection was not yet
established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "Connected":
            case "ConnectedToProxy":
                return ($this->SetError("request was not
sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            case "RequestSent":
                if (($error = $this->ReadReplyHeaders($headers)) !=
"") return ($error);
                break;
            case "GotReplyHeaders":
                break;
            case 'ResponseReceived':
                $body = '';

                return ('');
            default:
                return ($this->SetError("can not get request
headers in the current connection state",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
        }
        if ($this->content_length_set) $length =
min($this->content_length - $this->read_length, $length);
        $body = '';
        if ($length > 0) {
            if (!$this->EndOfInput() && ($body =
$this->ReadBytes($length)) == "") {
                if (strlen($this->error)) return
($this->SetError("could not get the request reply body: " .
$this->error, $this->error_code));
            }
            $this->read_length += strlen($body);
            if ($this->EndOfInput()) $this->state =
'ResponseReceived';
        }

        return ("");
    }

    Function ReadWholeReplyBody(&$body) {
        $body = '';
        for (; ;) {
            if (strlen($error = $this->ReadReplyBody($block,
$this->file_buffer_length))) return ($error);
            if (strlen($block) == 0) return ('');
            $body .= $block;
        }
    }

    Function ReadWholeReplyIntoTemporaryFile(&$file) {
        if (!($file = tmpfile())) return $this->SetPHPError('could
not create the temporary file to save the response',
self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
        for (; ;) {
            if (strlen($error = $this->ReadReplyBody($block,
$this->file_buffer_length))) {
                fclose($file);

                return ($error);
            }
            if (strlen($block) == 0) {
                if (@fseek($file, 0) != 0) {
                    $error = $this->SetPHPError('could not seek to
the beginning of temporary file with the response',
self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
                    fclose($file);

                    return $error;
                }

                return ('');
            }
            if (!@fwrite($file, $block)) {
                $error = $this->SetPHPError('could not write to the
temporary file to save the response', self::PHPErrorMessage(),
HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
                fclose($file);

                return $error;
            }
        }
    }

    Function SaveCookies(&$cookies, $domain = '',
$secure_only = 0, $persistent_only = 0) {
        $now     = gmdate("Y-m-d H-i-s");
        $cookies = array();
        for ($secure_cookies = 0, Reset($this->cookies); $secure_cookies
< count($this->cookies); Next($this->cookies), $secure_cookies++)
{
            $secure = Key($this->cookies);
            if (!$secure_only || $secure) {
                for ($cookie_domain = 0, Reset($this->cookies[$secure]);
$cookie_domain < count($this->cookies[$secure]);
Next($this->cookies[$secure]), $cookie_domain++) {
                    $domain_pattern = Key($this->cookies[$secure]);
                    $match          = strlen($domain) -
strlen($domain_pattern);
                    if (strlen($domain) == 0 || ($match >= 0 &&
!strcmp($domain_pattern, substr($domain, $match)) && ($match == 0
|| $domain_pattern[0] == "." || $domain[$match - 1] ==
"."))) {
                        for
(Reset($this->cookies[$secure][$domain_pattern]), $path_part = 0;
$path_part < count($this->cookies[$secure][$domain_pattern]);
Next($this->cookies[$secure][$domain_pattern]), $path_part++) {
                            $path =
Key($this->cookies[$secure][$domain_pattern]);
                            for
(Reset($this->cookies[$secure][$domain_pattern][$path]), $cookie = 0;
$cookie < count($this->cookies[$secure][$domain_pattern][$path]);
Next($this->cookies[$secure][$domain_pattern][$path]), $cookie++) {
                                $cookie_name =
Key($this->cookies[$secure][$domain_pattern][$path]);
                                $expires     =
$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
                                if ((!$persistent_only &&
strlen($expires) == 0) || (strlen($expires) && strcmp($now,
$expires) < 0)) $cookies[$secure][$domain_pattern][$path][$cookie_name]
= $this->cookies[$secure][$domain_pattern][$path][$cookie_name];
                            }
                        }
                    }
                }
            }
        }
    }

    Function SavePersistentCookies(&$cookies, $domain = '',
$secure_only = 0) {
        $this->SaveCookies($cookies, $domain, $secure_only, 1);
    }

    Function GetPersistentCookies(&$cookies, $domain = '',
$secure_only = 0) {
        $this->SavePersistentCookies($cookies, $domain, $secure_only);
    }

    Function RestoreCookies($cookies, $clear = 1) {
        $new_cookies = ($clear ? array() : $this->cookies);
        for ($secure_cookies = 0, Reset($cookies); $secure_cookies <
count($cookies); Next($cookies), $secure_cookies++) {
            $secure = Key($cookies);
            if (GetType($secure) != "integer") return
($this->SetError("invalid cookie secure value type (" .
serialize($secure) . ")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
            for ($cookie_domain = 0, Reset($cookies[$secure]);
$cookie_domain < count($cookies[$secure]); Next($cookies[$secure]),
$cookie_domain++) {
                $domain_pattern = Key($cookies[$secure]);
                if (GetType($domain_pattern) != "string") return
($this->SetError("invalid cookie domain value type (" .
serialize($domain_pattern) . ")",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
                for (Reset($cookies[$secure][$domain_pattern]), $path_part
= 0; $path_part < count($cookies[$secure][$domain_pattern]);
Next($cookies[$secure][$domain_pattern]), $path_part++) {
                    $path = Key($cookies[$secure][$domain_pattern]);
                    if (GetType($path) != "string" ||
strcmp(substr($path, 0, 1), "/")) return
($this->SetError("invalid cookie path value type (" .
serialize($path) . ")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
                    for (Reset($cookies[$secure][$domain_pattern][$path]),
$cookie = 0; $cookie < count($cookies[$secure][$domain_pattern][$path]);
Next($cookies[$secure][$domain_pattern][$path]), $cookie++) {
                        $cookie_name =
Key($cookies[$secure][$domain_pattern][$path]);
                        $expires     =
$cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
                        $value       =
$cookies[$secure][$domain_pattern][$path][$cookie_name]["value"];
                        if (GetType($expires) != "string" ||
(strlen($expires) && !preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2}
[0-9]{2}:[0-9]{2}:[0-9]{2}\$/", $expires))) return
($this->SetError("invalid cookie expiry value type (" .
serialize($expires) . ")",
HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
                       
$new_cookies[$secure][$domain_pattern][$path][$cookie_name] = array(
                            "name"    => $cookie_name,
                            "value"   => $value,
                            "domain"  => $domain_pattern,
                            "path"    => $path,
                            "expires" => $expires,
                            "secure"  => $secure
                        );
                    }
                }
            }
        }
        $this->cookies = $new_cookies;

        return ("");
    }
}

Misc/OAuth/OAuth.php000064400000356461151161172500010226 0ustar00<?php

namespace Nextend\Framework\Misc\OAuth;

/*
{metadocument}<?xml version="1.0"
encoding="ISO-8859-1" ?>
<class>

	<package>net.manuellemos.oauth</package>

	<version>@(#) $Id: oauth_client.php,v 1.139 2015/07/23 20:41:37
mlemos Exp $</version>
	<copyright>Copyright � (C) Manuel Lemos 2012</copyright>
	<title>OAuth client</title>
	<author>Manuel Lemos</author>
	<authoraddress>mlemos-at-acm.org</authoraddress>

	<documentation>
		<idiom>en</idiom>
		<purpose>This class serves two main purposes:<paragraphbreak
/>
			1) Implement the OAuth protocol to retrieve a token from a server to
			authorize the access to an API on behalf of the current
			user.<paragraphbreak />
			2) Perform calls to a Web services API using a token previously
			obtained using this class or a token provided some other way by the
			Web services provider.</purpose>
		<usage>Regardless of your purposes, you always need to start
calling
			the class <functionlink>Initialize</functionlink> function
after
			initializing setup variables. After you are done with the class,
			always call the <functionlink>Finalize</functionlink>
function at
			the end.<paragraphbreak />
			This class supports either OAuth protocol versions 1.0, 1.0a and
			2.0. It abstracts the differences between these protocol versions,
			so the class usage is the same independently of the OAuth
			version of the server.<paragraphbreak />
			The class also provides built-in support to several popular OAuth
			servers, so you do not have to manually configure all the details to
			access those servers. Just set the
			<variablelink>server</variablelink> variable to configure
the class
			to access one of the built-in supported servers.<paragraphbreak />
			If you need to access one type of server that is not yet directly
			supported by the class, you need to configure it explicitly setting
			the variables: <variablelink>oauth_version</variablelink>,
			<variablelink>url_parameters</variablelink>,
			<variablelink>authorization_header</variablelink>,
			<variablelink>request_token_url</variablelink>,
			<variablelink>dialog_url</variablelink>,
			<variablelink>pin_dialog_url</variablelink>,
			<variablelink>offline_dialog_url</variablelink>,
			<variablelink>append_state_to_redirect_uri</variablelink>
and
			<variablelink>access_token_url</variablelink>.<paragraphbreak
/>
			Before proceeding to the actual OAuth authorization process, you
			need to have registered your application with the OAuth server. The
			registration provides you values to set the variables
			<variablelink>client_id</variablelink> and 
			<variablelink>client_secret</variablelink>. Some servers
also
			provide an additional value to set the
			<variablelink>api_key</variablelink>
variable.<paragraphbreak />
			You also need to set the variables
			<variablelink>redirect_uri</variablelink> and
			<variablelink>scope</variablelink> before calling the
			<functionlink>Process</functionlink> function to make the
class
			perform the necessary interactions with the OAuth
			server.<paragraphbreak />
			The OAuth protocol involves multiple steps that include redirection
			to the OAuth server. There it asks permission to the current user to
			grant your application access to APIs on his/her behalf. When there
			is a redirection, the class will set the
			<variablelink>exit</variablelink> variable to
			<booleanvalue>1</booleanvalue>. Then your script should exit
			immediately without outputting anything.<paragraphbreak />
			When the OAuth access token is successfully obtained, the following
			variables are set by the class with the obtained values:
			<variablelink>access_token</variablelink>,
			<variablelink>access_token_secret</variablelink>,
			<variablelink>access_token_expiry</variablelink>,
			<variablelink>access_token_type</variablelink>. You may want
to
			store these values to use them later when calling the server
			APIs.<paragraphbreak />
			If there was a problem during OAuth authorization process, check the
			variable <variablelink>authorization_error</variablelink> to
			determine the reason.<paragraphbreak />
			Once you get the access token, you can call the server APIs using
			the <functionlink>CallAPI</functionlink> function. Check the
			<variablelink>access_token_error</variablelink> variable to
			determine if there was an error when trying to to call the
			API.<paragraphbreak />
			If for some reason the user has revoked the access to your
			application, you need to ask the user to authorize your application
			again. First you may need to call the function
			<functionlink>ResetAccessToken</functionlink> to reset the
value of
			the access token that may be cached in session variables.</usage>
	</documentation>

{/metadocument}
*/

use Nextend\Framework\Misc\Base64;

class OAuth {

    /*
    {metadocument}
        <variable>
            <name>error</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Store the message that is returned when an
error
                    occurs.</purpose>
                <usage>Check this variable to understand what
happened when a call to
                    any of the class functions has
failed.<paragraphbreak />
                    This class uses cumulative error handling. This means
that if one
                    class functions that may fail is called and this
variable was
                    already set to an error message due to a failure in a
previous call
                    to the same or other function, the function will also
fail and does
                    not do anything.<paragraphbreak />
                    This allows programs using this class to safely call
several
                    functions that may fail and only check the failure
condition after
                    the last function call.<paragraphbreak />
                    Just set this variable to an empty string to clear the
error
                    condition.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $error = '';

    /*
    {metadocument}
        <variable>
            <name>debug</name>
            <type>BOOLEAN</type>
            <value>0</value>
            <documentation>
                <purpose>Control whether debug output is
enabled</purpose>
                <usage>Set this variable to
<booleanvalue>1</booleanvalue> if you
                    need to check what is going on during calls to the
class. When
                    enabled, the debug output goes either to the variable
                    <variablelink>debug_output</variablelink>
and the PHP error log.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $debug = false;

    /*
    {metadocument}
        <variable>
            <name>debug_http</name>
            <type>BOOLEAN</type>
            <value>0</value>
            <documentation>
                <purpose>Control whether the dialog with the remote
Web server
                    should also be logged.</purpose>
                <usage>Set this variable to
<booleanvalue>1</booleanvalue> if you
                    want to inspect the data exchange with the OAuth
server.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $debug_http = false;

    /*
    {metadocument}
        <variable>
            <name>exit</name>
            <type>BOOLEAN</type>
            <value>0</value>
            <documentation>
                <purpose>Determine if the current script should be
exited.</purpose>
                <usage>Check this variable after calling the
                    <functionlink>Process</functionlink>
function and exit your script
                    immediately if the variable is set to
                   
<booleanvalue>1</booleanvalue>.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $exit = false;

    /*
    {metadocument}
        <variable>
            <name>debug_output</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Capture the debug output generated by the
class</purpose>
                <usage>Inspect this variable if you need to see what
happened during
                    the class function calls.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $debug_output = '';

    /*
    {metadocument}
        <variable>
            <name>debug_prefix</name>
            <type>STRING</type>
            <value>OAuth client: </value>
            <documentation>
                <purpose>Mark the lines of the debug output to
identify actions
                    performed by this class.</purpose>
                <usage>Change this variable if you prefer the debug
output lines to
                    be prefixed with a different text.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $debug_prefix = 'OAuth client: ';

    /*
    {metadocument}
        <variable>
            <name>server</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Identify the type of OAuth server to
access.</purpose>
                <usage>The class provides built-in support to several
types of OAuth
                    servers. This means that the class can automatically
initialize
                    several configuration variables just by setting this
server
                    variable.<paragraphbreak />
                    Currently it supports the following servers:
                    <stringvalue>37Signals</stringvalue>,
                    <stringvalue>Amazon</stringvalue>,
                    <stringvalue>AOL</stringvalue>,
                    <stringvalue>Bitbucket</stringvalue>,
                    <stringvalue>Bitly</stringvalue>,
                    <stringvalue>Box</stringvalue>,
                    <stringvalue>Buffer</stringvalue>,
                    <stringvalue>Copy</stringvalue>,
                    <stringvalue>Dailymotion</stringvalue>,
                    <stringvalue>Discogs</stringvalue>,
                    <stringvalue>Disqus</stringvalue>,
                    <stringvalue>Dropbox</stringvalue> (Dropbox
with OAuth 1.0),
                    <stringvalue>Dropbox2</stringvalue>
(Dropbox with OAuth 2.0),
                    <stringvalue>Etsy</stringvalue>,
                    <stringvalue>Eventful</stringvalue>,
                    <stringvalue>Facebook</stringvalue>,
                    <stringvalue>Fitbit</stringvalue>,
                    <stringvalue>Flickr</stringvalue>,
                    <stringvalue>Foursquare</stringvalue>,
                    <stringvalue>github</stringvalue>,
                    <stringvalue>Google</stringvalue>,
                    <stringvalue>Google1</stringvalue> (Google
with OAuth 1.0),
                    <stringvalue>imgur</stringvalue>,
                    <stringvalue>Intuit</stringvalue>,
                    <stringvalue>Instagram</stringvalue>,
                    <stringvalue>Jawbone</stringvalue>,
                    <stringvalue>LinkedIn</stringvalue>,
                    <stringvalue>LinkedIn2</stringvalue>
(LinkedIn with OAuth 2.0),
                    <stringvalue>mail.ru</stringvalue>,
                    <stringvalue>MailChimp</stringvalue>,
                    <stringvalue>Mavenlink</stringvalue>,
                    <stringvalue>Meetup</stringvalue>,
                    <stringvalue>Microsoft</stringvalue>,
                    <stringvalue>Misfit</stringvalue>,
                    <stringvalue>oDesk</stringvalue>,
                    <stringvalue>Paypal</stringvalue>,
                   
<stringvalue>PaypalApplication</stringvalue>,
                    <stringvalue>Rdio</stringvalue>,
                    <stringvalue>Reddit</stringvalue>,
                    <stringvalue>RunKeeper</stringvalue>,
                    <stringvalue>Salesforce</stringvalue>,
                    <stringvalue>Scoop.it</stringvalue>,
                    <stringvalue>StockTwits</stringvalue>,
                    <stringvalue>SurveyMonkey</stringvalue>,
                    <stringvalue>TeamViewer</stringvalue>,
                    <stringvalue>Tumblr</stringvalue>,
                    <stringvalue>Twitter</stringvalue>,
                    <stringvalue>Vimeo</stringvalue>,
                    <stringvalue>VK</stringvalue>,
                    <stringvalue>Withings</stringvalue>,
                    <stringvalue>Wordpress</stringvalue>,
                    <stringvalue>Xero</stringvalue>,
                    <stringvalue>XING</stringvalue>,
                    <stringvalue>Yahoo</stringvalue> and
                    <stringvalue>Yandex</stringvalue>. Please
contact the author if you
                    would like to ask to add built-in support for other
types of OAuth
                    servers.<paragraphbreak />
                    If you want to access other types of OAuth servers that
are not
                    yet supported, set this variable to an empty string and
configure
                    other variables with values specific to those
servers.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $server = '';

    /*
    {metadocument}
        <variable>
            <name>configuration_file</name>
            <type>STRING</type>
            <value>oauth_configuration.json</value>
            <documentation>
                <purpose>Specify the path of the configuration file
that defines the
                    properties of additional OAuth server
types.</purpose>
                <usage>Change the path in this variable if you are
accessing a type
                    of server without support built-in the class and you
need to put
                    the configuration file path in a different
directory.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $configuration_file = 'oauth_configuration.json';

    /*
    {metadocument}
        <variable>
            <name>request_token_url</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>URL of the OAuth server to request the
initial token for
                    OAuth 1.0 and 1.0a servers.</purpose>
                <usage>Set this variable to the OAuth request token
URL when you are
                    not accessing one of the built-in supported OAuth
                    servers.<paragraphbreak />
                    For OAuth 1.0 and 1.0a servers, the request token URL
can have
                    certain marks that will act as template placeholders
which will be
                    replaced with given values before requesting the
authorization
                    token. Currently it supports the following placeholder
                    marks:<paragraphbreak />
                    {SCOPE} - scope of the requested permissions to the
granted by the
                    OAuth server with the user permissions</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $request_token_url = '';

    /*
    {metadocument}
        <variable>
            <name>dialog_url</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>URL of the OAuth server to redirect the
browser so the user
                    can grant access to your application.</purpose>
                <usage>Set this variable to the OAuth request token
URL when you are
                    not accessing one of the built-in supported OAuth
servers.<paragraphbreak />
                    For OAuth 1.0a servers that return the login dialog URL
                    automatically, set this variable to
                   
<stringvalue>automatic</stringvalue><paragraphbreak />
                    For certain servers, the dialog URL can have certain
marks that
                    will act as template placeholders which will be
replaced with
                    values defined before redirecting the users browser.
Currently it
                    supports the following placeholder
marks:<paragraphbreak />
                    {REDIRECT_URI} - URL to redirect when returning from
the OAuth
                    server authorization page<paragraphbreak />
                    {CLIENT_ID} - client application identifier registered
at the
                    server<paragraphbreak />
                    {SCOPE} - scope of the requested permissions to the
granted by the
                    OAuth server with the user
permissions<paragraphbreak />
                    {STATE} - identifier of the OAuth session
state<paragraphbreak />
                    {API_KEY} - API key to access the
server<paragraphbreak />
                    {REALM} - realm name for OpenID Connect</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $dialog_url = '';

    /*
    {metadocument}
        <variable>
            <name>pin_dialog_url</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>URL of the OAuth server to redirect the
browser so the user
                    can grant access to your application.</purpose>
                <usage>Set this variable when using the pin based
authorization and
                    the format of the of the authorization dialog page URL
is
                    different than the one set to the
                    <variablelink>dialog_url</variablelink>
variable.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $pin_dialog_url = '';

    /*
    {metadocument}
        <variable>
            <name>offline_dialog_url</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>URL of the OAuth server to redirect the
browser so the user
                    can grant access to your application when offline
access is
                    requested.</purpose>
                <usage>Set this variable to the OAuth request token
URL when you are
                    not accessing one of the built-in supported OAuth
servers and the
                    OAuth server supports offline access.<paragraphbreak
/>
                    It should have the same format as the
                    <variablelink>dialog_url</variablelink>
variable.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $offline_dialog_url = '';

    /*
    {metadocument}
        <variable>
            <name>pin</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Value of the pin code for pin based
authorization.</purpose>
                <usage>Set this value to the pin informed by the user
when
                    implementing the pin based
authorization.<paragraphbreak />
                    Make sure the
<variablelink>redirect_uri</variablelink> variable
                    is set to
<stringvalue>oob</stringvalue>.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $pin = '';

    /*
    {metadocument}
        <variable>
            <name>append_state_to_redirect_uri</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Pass the OAuth session state in a variable
with a different
                    name to work around implementation bugs of certain
OAuth
                    servers</purpose>
                <usage>Set this variable  when you are not accessing
one of the
                    built-in supported OAuth servers if the OAuth server
has a bug
                    that makes it not pass back the OAuth state identifier
in a
                    request variable named state.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $append_state_to_redirect_uri = '';

    /*
    {metadocument}
        <variable>
            <name>access_token_url</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>OAuth server URL that will return the access
token
                    URL.</purpose>
                <usage>Set this variable to the OAuth access token
URL when you are
                    not accessing one of the built-in supported OAuth
servers.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_url = '';


    /*
    {metadocument}
        <variable>
            <name>oauth_version</name>
            <type>STRING</type>
            <value>2.0</value>
            <documentation>
                <purpose>Version of the protocol version supported by
the OAuth
                    server.</purpose>
                <usage>Set this variable to the OAuth server protocol
version when
                    you are not accessing one of the built-in supported
OAuth
                    servers.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $oauth_version = '2.0';

    /*
    {metadocument}
        <variable>
            <name>url_parameters</name>
            <type>BOOLEAN</type>
            <value>0</value>
            <documentation>
                <purpose>Determine if the API call parameters should
be moved to the
                    call URL.</purpose>
                <usage>Set this variable to
<booleanvalue>1</booleanvalue> if the
                    API you need to call requires that the call parameters
always be
                    passed via the API URL.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $url_parameters = false;

    /*
    {metadocument}
        <variable>
            <name>authorization_header</name>
            <type>BOOLEAN</type>
            <value>1</value>
            <documentation>
                <purpose>Determine if the OAuth parameters should be
passed via HTTP
                    Authorization request header.</purpose>
                <usage>Set this variable to
<booleanvalue>1</booleanvalue> if the
                    OAuth server requires that the OAuth parameters be
passed using
                    the HTTP Authorization instead of the request URI
parameters.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $authorization_header = true;

    /*
    {metadocument}
        <variable>
            <name>token_request_method</name>
            <type>STRING</type>
            <value>GET</value>
            <documentation>
                <purpose>Define the HTTP method that should be used
to request
                    tokens from the server.</purpose>
                <usage>Set this variable to
<stringvalue>POST</stringvalue> if the
                    OAuth server does not support requesting tokens using
the HTTP GET
                    method.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $token_request_method = 'GET';

    /*
    {metadocument}
        <variable>
            <name>signature_method</name>
            <type>STRING</type>
            <value>HMAC-SHA1</value>
            <documentation>
                <purpose>Define the method to generate the signature
for API request
                    parameters values.</purpose>
                <usage>Currently it supports
<stringvalue>PLAINTEXT</stringvalue>
                    and
<stringvalue>HMAC-SHA1</stringvalue>.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $signature_method = 'HMAC-SHA1';

    /*
    {metadocument}
        <variable>
            <name>redirect_uri</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>URL of the current script page that is
calling this
                    class</purpose>
                <usage>Set this variable to the current script page
URL before
                    proceeding the the OAuth authorization
process.<paragraphbreak />
                    For pin based authorization, set this variable to
                   
<stringvalue>oob</stringvalue>.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $redirect_uri = '';

    /*
    {metadocument}
        <variable>
            <name>client_id</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Identifier of your application registered
with the OAuth
                    server</purpose>
                <usage>Set this variable to the application
identifier that is
                    provided by the OAuth server when you register the
                    application.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $client_id = '';

    /*
    {metadocument}
        <variable>
            <name>client_secret</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Secret value assigned to your application
when it is
                    registered with the OAuth server.</purpose>
                <usage>Set this variable to the application secret
that is provided
                    by the OAuth server when you register the
application.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $client_secret = '';

    /*
    {metadocument}
        <variable>
            <name>api_key</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Identifier of your API key provided by the
OAuth
                    server</purpose>
                <usage>Set this variable to the API key if the OAuth
server requires
                    one.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $api_key = '';

    /*
    {metadocument}
        <variable>
            <name>get_token_with_api_key</name>
            <type>BOOLEAN</type>
            <value>0</value>
            <documentation>
                <purpose>Option to determine if the access token
should be retrieved
                    using the API key value instead of the client
secret.</purpose>
                <usage>Set this variable to
<booleanvalue>1</booleanvalue> if the
                    OAuth server requires that the client secret be set to
the API key
                    when retrieving the OAuth token.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $get_token_with_api_key = false;

    /*
    {metadocument}
        <variable>
            <name>scope</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Permissions that your application needs to
call the OAuth
                    server APIs</purpose>
                <usage>Check the documentation of the APIs that your
application
                    needs to call to set this variable with the identifiers
of the
                    permissions that the user needs to grant to your
application.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $scope = '';

    /*
    {metadocument}
        <variable>
            <name>realm</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Realm of authorization for OpenID
Connect</purpose>
                <usage>Set this variable to the realm value when
using OpenID
                    Connect.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $realm = '';

    /*
    {metadocument}
        <variable>
            <name>offline</name>
            <type>BOOLEAN</type>
            <value>0</value>
            <documentation>
                <purpose>Specify whether it will be necessary to call
the API when
                    the user is not present and the server supports
renewing expired
                    access tokens using refresh tokens.</purpose>
                <usage>Set this variable to
<booleanvalue>1</booleanvalue> if the
                    server supports renewing expired tokens automatically
when the
                    user is not present.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $offline = false;

    /*
    {metadocument}
        <variable>
            <name>access_token</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Access token obtained from the OAuth
server</purpose>
                <usage>Check this variable to get the obtained access
token upon
                    successful OAuth authorization.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token = '';

    /*
    {metadocument}
        <variable>
            <name>access_token_secret</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Access token secret obtained from the OAuth
server</purpose>
                <usage>If the OAuth protocol version is 1.0 or 1.0a,
check this
                    variable to get the obtained access token secret upon
successful
                    OAuth authorization.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_secret = '';

    /*
    {metadocument}
        <variable>
            <name>access_token_expiry</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Timestamp of the expiry of the access token
obtained from
                    the OAuth server.</purpose>
                <usage>Check this variable to get the obtained access
token expiry
                    time upon successful OAuth authorization. If this
variable is
                    empty, that means no expiry time was set.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_expiry = '';

    /*
    {metadocument}
        <variable>
            <name>access_token_type</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Type of access token obtained from the OAuth
server.</purpose>
                <usage>Check this variable to get the obtained access
token type
                    upon successful OAuth authorization.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_type = '';

    /*
    {metadocument}
        <variable>
            <name>default_access_token_type</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Type of access token to be assumed when the
OAuth server
                    does not specify an access token type.</purpose>
                <usage>Set this variable if the server requires a
certain type of
                    access token to be used but it does not specify a token
type
                    when the access token is returned.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $default_access_token_type = '';


    /*
    {metadocument}
        <variable>
            <name>access_token_parameter</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Name of the access token parameter to be
passed in API call
                    requests.</purpose>
                <usage>Set this variable to a non-empty string to
override the
                    default name for the access token parameter which is
                    <stringvalue>oauth_token</stringvalue> of
OAuth 1 and
                    <stringvalue>access_token</stringvalue> for
OAuth 2.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_parameter = '';


    /*
    {metadocument}
        <variable>
            <name>access_token_response</name>
            <type>ARRAY</type>
            <documentation>
                <purpose>The original response for the access token
request</purpose>
                <usage>Check this variable if the OAuth server
returns custom
                    parameters in the request to obtain the access
token.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_response;

    /*
    {metadocument}
        <variable>
            <name>store_access_token_response</name>
            <type>BOOLEAN</type>
            <value>0</value>
            <documentation>
                <purpose>Option to determine if the original response
for the access
                    token request should be stored in the
                   
<variablelink>access_token_response</variablelink>
                    variable.</purpose>
                <usage>Set this variable to
<booleanvalue>1</booleanvalue> if the
                    OAuth server returns custom parameters in the request
to obtain
                    the access token that may be needed in subsequent API
calls.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $store_access_token_response = false;

    /*
    {metadocument}
        <variable>
            <name>access_token_authentication</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Option to determine if the requests to
obtain a new access
                    token should use authentication to pass the application
client ID
                    and secret.</purpose>
                <usage>Set this variable to
<stringvalue>basic</stringvalue> if the
                    OAuth server requires that the the client ID and secret
be passed
                    using HTTP basic authentication headers when retrieving
a new
                    token.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_authentication = '';

    /*
    {metadocument}
        <variable>
            <name>refresh_token</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Refresh token obtained from the OAuth
server</purpose>
                <usage>Check this variable to get the obtained
refresh token upon
                    successful OAuth authorization.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $refresh_token = '';

    /*
    {metadocument}
        <variable>
            <name>access_token_error</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Error message returned when a call to the
API fails.</purpose>
                <usage>Check this variable to determine if there was
an error while
                    calling the Web services API when using the
                    <functionlink>CallAPI</functionlink>
function.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $access_token_error = '';

    /*
    {metadocument}
        <variable>
            <name>authorization_error</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Error message returned when it was not
possible to obtain
                    an OAuth access token</purpose>
                <usage>Check this variable to determine if there was
an error while
                    trying to obtain the OAuth access token.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $authorization_error = '';

    /*
    {metadocument}
        <variable>
            <name>response_status</name>
            <type>INTEGER</type>
            <value>0</value>
            <documentation>
                <purpose>HTTP response status returned by the server
when calling an
                    API</purpose>
                <usage>Check this variable after calling the
                    <functionlink>CallAPI</functionlink>
function if the API calls and you
                    need to process the error depending the response
status.
                    <integervalue>200</integervalue> means no
error.
                    <integervalue>0</integervalue> means the
server response was not
                    retrieved.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $response_status = 0;

    /*
    {metadocument}
        <variable>
            <name>oauth_username</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Define the user name to obtain authorization
using a password.</purpose>
                <usage>Set this variable to the user name of the
account to
                    authorize instead of going through the interactive user
                    authorization process.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $oauth_username = '';

    /*
    {metadocument}
        <variable>
            <name>oauth_password</name>
            <type>STRING</type>
            <value></value>
            <documentation>
                <purpose>Define the user name to obtain authorization
using a password.</purpose>
                <usage>Set this variable to the user password of the
account to
                    authorize instead of going through the interactive user
                    authorization process.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $oauth_password = '';

    /*
    {metadocument}
        <variable>
            <name>grant_type</name>
            <type>STRING</type>
            <value>authorization_code</value>
            <documentation>
                <purpose>Define the type of grant to obtain the OAuth
2 access
                    token.</purpose>
                <usage>Change this variable to
                   
<stringvalue>client_credentials</stringvalue> to obtain
                    application only access token.<paragraphbreak />
                    Change this variable to
<stringvalue>password</stringvalue> to
                    obtain an access token on behalf of an user with a
given username
                    and password specified by the
                    <variablelink>oauth_username</variablelink>
and
                    <variablelink>oauth_password</variablelink>
variables
                    respectively.<paragraphbreak />In this case the
user does not need
                    to be present, so the class will not redirect the user
to the
                    authorization dialog page.<paragraphbreak />
                        </usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $grant_type = "authorization_code";

    /*
    {metadocument}
        <variable>
            <name>http_arguments</name>
            <type>HASH</type>
            <value></value>
            <documentation>
                <purpose>Define additional arguments to configure the
HTTP
                    requests.</purpose>
                <usage>Set this associative array with argument
values that you need
                    to set options of the HTTP requests sent to the OAuth
server and
                    API URLs.<paragraphbreak />
                    Check the documentation of the <link>
                        <data>HTTP client class</data>
                       
<url>http://www.phpclasses.org/httpclient</url>
                    </link> for more
                    information on the available arguments that can be
configured
                    using this option.</usage>
            </documentation>
        </variable>
    {/metadocument}
    */
    var $http_arguments = array();
    var $oauth_user_agent = 'PHP-OAuth-API
(http://www.phpclasses.org/oauth-api $Revision: 1.139 $)';

    var $response_time = 0;

    function __construct() {
        $this->configuration_file = dirname(__FILE__) .
'/oauth_configuration.json';
    }

    public static function PHPErrorMessage() {
        $lastError = error_get_last();
        if ($lastError === null) {
            return '';
        }

        return $lastError['message'];
    }

    Function SetError($error) {
        $this->error = $error;
        if ($this->debug) $this->OutputDebug('Error: ' .
$error);

        return (false);
    }

    Function SetPHPError($error, $php_error_message) {
        if (IsSet($php_error_message) &&
strlen($php_error_message)) $error .= ": " . $php_error_message;

        return ($this->SetError($error));
    }

    Function OutputDebug($message) {
        if ($this->debug) {
            $message            = $this->debug_prefix . $message;
            $this->debug_output .= $message . "\n";
            error_log($message);
        }

        return (true);
    }

    Function GetRequestTokenURL(&$request_token_url) {
        $request_token_url = $this->request_token_url;

        return (true);
    }

    Function GetDialogURL(&$url, $redirect_uri = '', $state =
'') {
        $url = (($this->offline &&
strlen($this->offline_dialog_url)) ? $this->offline_dialog_url :
(($redirect_uri === 'oob' &&
strlen($this->pin_dialog_url)) ? $this->pin_dialog_url :
$this->dialog_url));
        if (strlen($url) === 0) return $this->SetError('the dialog
URL ' . ($this->offline ? 'for offline access ' :
'') . 'is not defined for this server');
        $url = str_replace('{REDIRECT_URI}',
UrlEncode($redirect_uri), str_replace('{STATE}',
UrlEncode($state), str_replace('{CLIENT_ID}',
UrlEncode($this->client_id), str_replace('{API_KEY}',
UrlEncode($this->api_key), str_replace('{SCOPE}',
UrlEncode($this->scope), str_replace('{REALM}',
UrlEncode($this->realm), $url))))));

        return (true);
    }

    Function GetAccessTokenURL(&$access_token_url) {
        $access_token_url = str_replace('{API_KEY}',
$this->api_key, $this->access_token_url);

        return (true);
    }

    Function GetStoredState(&$state) {
        if (!function_exists('session_start')) return
$this->SetError('Session variables are not accessible in this PHP
environment');
        if (session_id() === '' && !session_start())
return ($this->SetPHPError('it was not possible to start the PHP
session', self::PHPErrorMessage()));
        if (IsSet($_SESSION['OAUTH_STATE'])) $state =
$_SESSION['OAUTH_STATE']; else
            $state = $_SESSION['OAUTH_STATE'] = time() .
'-' . substr(md5(rand() . time()), 0, 6);

        return (true);
    }

    Function GetRequestState(&$state) {
        $check = (strlen($this->append_state_to_redirect_uri) ?
$this->append_state_to_redirect_uri : 'state');
        $state = (IsSet($_GET[$check]) ? $_GET[$check] : null);

        return (true);
    }

    Function GetRequestCode(&$code) {
        $code = (IsSet($_GET['code']) ? $_GET['code'] :
null);

        return (true);
    }

    Function GetRequestError(&$error) {
        $error = (IsSet($_GET['error']) ?
$_GET['error'] : null);

        return (true);
    }

    Function GetRequestDenied(&$denied) {
        $denied = (IsSet($_GET['denied']) ?
$_GET['denied'] : null);

        return (true);
    }

    Function GetRequestToken(&$token, &$verifier) {
        $token    = (IsSet($_GET['oauth_token']) ?
$_GET['oauth_token'] : null);
        $verifier = (IsSet($_GET['oauth_verifier']) ?
$_GET['oauth_verifier'] : null);

        return (true);
    }

    Function GetRedirectURI(&$redirect_uri) {
        if (strlen($this->redirect_uri)) $redirect_uri =
$this->redirect_uri; else
            $redirect_uri = 'http://' .
$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

        return true;
    }

    /*
    {metadocument}
        <function>
            <name>Redirect</name>
            <type>VOID</type>
            <documentation>
                <purpose>Redirect the user browser to a given
page.</purpose>
                <usage>This function is meant to be only be called
from inside the
                    class. By default it issues HTTP 302 response status
and sets the
                    redirection location to a given URL. Sub-classes may
override this
                    function to implement a different way to redirect the
user
                    browser.</usage>
            </documentation>
            <argument>
                <name>url</name>
                <type>STRING</type>
                <documentation>
                    <purpose>String with the full URL of the page to
redirect.</purpose>
                </documentation>
            </argument>
            <do>
    {/metadocument}
    */
    Function Redirect($url) {
        Header('HTTP/1.0 302 OAuth Redirection');
        Header('Location: ' . $url);
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>StoreAccessToken</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Store the values of the access token when it
is succefully
                    retrieved from the OAuth server.</purpose>
                <usage>This function is meant to be only be called
from inside the
                    class. By default it stores access tokens in a session
variable
                    named
<stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak
/>
                    Actual implementations should create a sub-class and
override this
                    function to make the access token values be stored in
other types
                    of containers, like for instance
databases.</usage>
                <returnvalue>This function should return
                    <booleanvalue>1</booleanvalue> if the
access token was stored
                    successfully.</returnvalue>
            </documentation>
            <argument>
                <name>access_token</name>
                <type>HASH</type>
                <documentation>
                    <purpose>Associative array with properties of the
access token.
                        The array may have set the following
                        properties:<paragraphbreak />
                        <stringvalue>value</stringvalue>:
string value of the access
                            token<paragraphbreak />
                        <stringvalue>authorized</stringvalue>:
boolean value that
                            determines if the access token was obtained
                            successfully<paragraphbreak />
                        <stringvalue>expiry</stringvalue>:
(optional) timestamp in ISO
                            format relative to UTC time zone of the access
token expiry
                            time<paragraphbreak />
                        <stringvalue>type</stringvalue>:
(optional) type of OAuth token
                            that may determine how it should be used when
sending API call
                            requests.<paragraphbreak />
                        <stringvalue>refresh</stringvalue>:
(optional) token that some
                            servers may set to allowing refreshing access
tokens when they
                            expire.</purpose>
                </documentation>
            </argument>
            <do>
    {/metadocument}
    */
    Function StoreAccessToken($access_token) {
        if (!function_exists('session_start')) return
$this->SetError('Session variables are not accessible in this PHP
environment');
        if (session_id() === '' && !session_start())
return ($this->SetPHPError('it was not possible to start the PHP
session', self::PHPErrorMessage()));
        if (!$this->GetAccessTokenURL($access_token_url)) return false;
        $_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url] =
$access_token;

        return true;
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>GetAccessToken</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Retrieve the OAuth access token if it was
already
                    previously stored by the
                   
<functionlink>StoreAccessToken</functionlink>
function.</purpose>
                <usage>This function is meant to be only be called
from inside the
                    class. By default it retrieves access tokens stored in
a session
                    variable named
                   
<stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak
/>
                    Actual implementations should create a sub-class and
override this
                    function to retrieve the access token values from other
types of
                    containers, like for instance databases.</usage>
                <returnvalue>This function should return
                    <booleanvalue>1</booleanvalue> if the
access token was retrieved
                    successfully.</returnvalue>
            </documentation>
            <argument>
                <name>access_token</name>
                <type>STRING</type>
                <out />
                <documentation>
                    <purpose>Return the properties of the access
token in an
                        associative array. If the access token was not yet
stored, it
                        returns an empty array. Otherwise, the properties
it may return
                        are the same that may be passed to the
                       
<functionlink>StoreAccessToken</functionlink>.</purpose>
                </documentation>
            </argument>
            <do>
    {/metadocument}
    */
    Function GetAccessToken(&$access_token) {
        if (!function_exists('session_start')) return
$this->SetError('Session variables are not accessible in this PHP
environment');
        if (session_id() === '' && !session_start())
return ($this->SetPHPError('it was not possible to start the PHP
session', self::PHPErrorMessage()));
        if (!$this->GetAccessTokenURL($access_token_url)) return false;
        if
(IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url]))
$access_token =
$_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url]; else
            $access_token = array();

        return true;
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>ResetAccessToken</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Reset the access token to a state back when
the user has
                    not yet authorized the access to the OAuth server
API.</purpose>
                <usage>Call this function if for some reason the
token to access
                    the API was revoked and you need to ask the user to
authorize
                    the access again.<paragraphbreak />
                    By default the class stores and retrieves access tokens
in a
                    session variable named
                   
<stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak
/>
                    This function must be called when the user is accessing
your site
                    pages, so it can reset the information stored in
session variables
                    that cache the state of a previously retrieved access
                    token.<paragraphbreak />
                    Actual implementations should create a sub-class and
override this
                    function to reset the access token state when it is
stored in
                    other types of containers, like for instance
databases.</usage>
                <returnvalue>This function should return
                    <booleanvalue>1</booleanvalue> if the
access token was resetted
                    successfully.</returnvalue>
            </documentation>
            <do>
    {/metadocument}
    */
    Function ResetAccessToken() {
        if (!$this->GetAccessTokenURL($access_token_url)) return false;
        if ($this->debug) $this->OutputDebug('Resetting the
access token status for OAuth server located at ' .
$access_token_url);
        if (!function_exists('session_start')) return
$this->SetError('Session variables are not accessible in this PHP
environment');
        if (session_id() === '' && !session_start())
return ($this->SetPHPError('it was not possible to start the PHP
session', self::PHPErrorMessage()));
       
Unset($_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url]);
        UnSet($_SESSION['OAUTH_STATE']);

        return true;
    }

    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    Function Encode($value) {
        return (is_array($value) ? $this->EncodeArray($value) :
str_replace('%7E', '~', str_replace('+',
' ', RawURLEncode($value))));
    }

    Function EncodeArray($array) {
        foreach ($array as $key => $value) $array[$key] =
$this->Encode($value);

        return $array;
    }

    Function HMAC($function, $data, $key) {
        switch ($function) {
            case 'sha1':
                $pack = 'H40';
                break;
            default:
                if ($this->debug) $this->OutputDebug($function .
' is not a supported an HMAC hash type');

                return ('');
        }
        if (strlen($key) > 64) $key = pack($pack, $function($key));
        if (strlen($key) < 64) $key = str_pad($key, 64, "\0");

        return (pack($pack, $function((str_repeat("\x5c", 64) ^
$key) . pack($pack, $function((str_repeat("\x36", 64) ^ $key) .
$data)))));
    }

    Function Sign(&$url, $method, $parameters, $oauth,
$request_content_type, $has_files, $post_values_in_uri,
&$authorization, &$post_values) {
        $values = array(
            'oauth_consumer_key'     => $this->client_id,
            'oauth_nonce'            => md5(uniqid(rand(),
true)),
            'oauth_signature_method' =>
$this->signature_method,
            'oauth_timestamp'        => time(),
            'oauth_version'          => '1.0',
        );
        if ($has_files) $value_parameters = array(); else {
            if (($this->url_parameters || $method !== 'POST')
&& $request_content_type ===
'application/x-www-form-urlencoded' &&
count($parameters)) {
                $first = (strpos($url, '?') === false);
                foreach ($parameters as $parameter => $value) {
                    $url   .= ($first ? '?' : '&')
. UrlEncode($parameter) . '=' . UrlEncode($value);
                    $first = false;
                }
                $parameters = array();
            }
            $value_parameters = (($request_content_type !==
'application/x-www-form-urlencoded') ? array() : $parameters);
        }
        $header_values = ($method === 'GET' ?
array_merge($values, $oauth, $value_parameters) : array_merge($values,
$oauth));
        $values        = array_merge($values, $oauth, $value_parameters);
        $key           = $this->Encode($this->client_secret) .
'&' . $this->Encode($this->access_token_secret);
        switch ($this->signature_method) {
            case 'PLAINTEXT':
                $values['oauth_signature'] = $key;
                break;
            case 'HMAC-SHA1':
                $uri         = strtok($url, '?');
                $sign        = $method . '&' .
$this->Encode($uri) . '&';
                $first       = true;
                $sign_values = $values;
                $u           = parse_url($url);
                if (IsSet($u['query'])) {
                    parse_str($u['query'], $q);
                    foreach ($q as $parameter => $value)
$sign_values[$parameter] = $value;
                }
                KSort($sign_values);
                foreach ($sign_values as $parameter => $value) {
                    $sign  .= $this->Encode(($first ? '' :
'&') . $parameter . '=' .
$this->Encode($value));
                    $first = false;
                }
                $header_values['oauth_signature'] =
$values['oauth_signature'] =
Base64::encode($this->HMAC('sha1', $sign, $key));
                break;
            default:
                return $this->SetError($this->signature_method .
' signature method is not yet supported');
        }
        if ($this->authorization_header) {
            $authorization = 'OAuth';
            $first         = true;
            foreach ($header_values as $parameter => $value) {
                $authorization .= ($first ? ' ' : ',')
. $parameter . '="' . $this->Encode($value) .
'"';
                $first         = false;
            }
            $post_values = $parameters;
        } else {
            if ($method !== 'POST' || $post_values_in_uri) {
                $first = (strcspn($url, '?') == strlen($url));
                foreach ($values as $parameter => $value) {
                    $url   .= ($first ? '?' : '&')
. $parameter . '=' . $this->Encode($value);
                    $first = false;
                }
                $post_values = array();
            } else
                $post_values = $values;
        }

        return true;
    }

    Function SendAPIRequest($url, $method, $parameters, $oauth, $options,
&$response) {
        $this->response_status   = 0;
        $http                    = new HTTP();
        $http->debug             = ($this->debug &&
$this->debug_http);
        $http->log_debug         = true;
        $http->sasl_authenticate = 0;
        $http->user_agent        = $this->oauth_user_agent;
        $http->redirection_limit =
(IsSet($options['FollowRedirection']) ?
intval($options['FollowRedirection']) : 0);
        $http->follow_redirect   = ($http->redirection_limit != 0);
        if ($this->debug) $this->OutputDebug('Accessing the
' . $options['Resource'] . ' at ' . $url);
        $post_files           = array();
        $method               = strtoupper($method);
        $authorization        = '';
        $request_content_type =
(IsSet($options['RequestContentType']) ?
strtolower(trim(strtok($options['RequestContentType'],
';'))) : (($method === 'POST' || IsSet($oauth)) ?
'application/x-www-form-urlencoded' : ''));
        $files                = (IsSet($options['Files']) ?
$options['Files'] : array());
        if (count($files)) {
            foreach ($files as $name => $value) {
                if (!IsSet($parameters[$name])) return
($this->SetError('it was not specified a file parameter named
' . $name));
                $file       = array();
                $value_type = IsSet($value['Type']) ?
$value['Type'] : 'FileName';
                switch ($value_type) {
                    case 'FileName':
                        $file['FileName'] = $parameters[$name];
                        if (IsSet($value['FileName']))
$file['Name'] = $value['FileName'];
                        break;
                    case 'Data':
                        $file['Data'] = $parameters[$name];
                        if (!IsSet($value['FileName'])) return
($this->SetError('it was not specified the file name for data file
parameter ' . $name));
                        $file['Name'] =
$value['FileName'];
                        break;
                    default:
                        return ($this->SetError($value_type . ' is
not a valid type for file ' . $name));
                }
                $file['Content-Type'] =
(IsSet($value['ContentType']) ? $value['ContentType'] :
'automatic/name');
                $post_files[$name]    = $file;
            }
            UnSet($parameters[$name]);
            if ($method !== 'POST') {
                $this->OutputDebug('For uploading files the method
should be POST not ' . $method);
                $method = 'POST';
            }
            if ($request_content_type !== 'multipart/form-data')
{
                if (IsSet($options['RequestContentType'])) return
($this->SetError('the request content type for uploading files
should be multipart/form-data'));
                $request_content_type = 'multipart/form-data';
            }
        }
        if (IsSet($oauth)) {
            if (!$this->Sign($url, $method, $parameters, $oauth,
$request_content_type, count($files) !== 0,
IsSet($options['PostValuesInURI']) &&
$options['PostValuesInURI'], $authorization, $post_values))
return false;
        } else {
            $post_values = $parameters;
            if (count($parameters)) {
                switch ($request_content_type) {
                    case 'application/x-www-form-urlencoded':
                    case 'multipart/form-data':
                    case 'application/json':
                    case 'application/javascript':
                        break;
                    default:
                        $first = (strpos($url, '?') === false);
                        foreach ($parameters as $name => $value) {
                            if (GetType($value) === 'array') {
                                foreach ($value as $index => $data) {
                                    $url   .= ($first ? '?' :
'&') . $name . '=' . UrlEncode($data);
                                    $first = false;
                                }
                            } else {
                                $url   .= ($first ? '?' :
'&') . $name . '=' . UrlEncode($value);
                                $first = false;
                            }
                        }
                }
            }
        }
        if (strlen($authorization) === 0 &&
!strcasecmp($this->access_token_type, 'Bearer'))
$authorization = 'Bearer ' . $this->access_token;
        if (strlen($error = $http->GetRequestArguments($url,
$arguments))) return ($this->SetError('it was not possible to open
the ' . $options['Resource'] . ' URL: ' .
$error));
        $arguments = array_merge($this->http_arguments, $arguments);
        if (strlen($error = $http->Open($arguments))) return
($this->SetError('it was not possible to open the ' .
$options['Resource'] . ' URL: ' . $error));
        if (count($post_files)) $arguments['PostFiles'] =
$post_files;
        $arguments['RequestMethod'] = $method;
        switch ($request_content_type) {
            case 'application/x-www-form-urlencoded':
            case 'multipart/form-data':
                if (IsSet($options['RequestBody'])) return
($this->SetError('the request body is defined automatically from
the parameters'));
                $arguments['PostValues'] = $post_values;
                break;
            case 'application/json':
            case 'application/javascript':
                $arguments['Headers']['Content-Type'] =
$options['RequestContentType'];
                $arguments['Body']                    =
(IsSet($options['RequestBody']) ?
$options['RequestBody'] : json_encode($parameters));
                break;
            default:
                if (!IsSet($options['RequestBody'])) {
                    if (IsSet($options['RequestContentType']))
return ($this->SetError('it was not specified the body value of the
of the API call request'));
                    break;
                }
                $arguments['Headers']['Content-Type'] =
$options['RequestContentType'];
                $arguments['Body']                    =
$options['RequestBody'];
                break;
        }
        $arguments['Headers']['Accept'] =
(IsSet($options['Accept']) ? $options['Accept'] :
'*/*');
        switch ($authentication =
(IsSet($options['AccessTokenAuthentication']) ?
strtolower($options['AccessTokenAuthentication']) :
'')) {
            case 'basic':
                $arguments['Headers']['Authorization']
= 'Basic ' . Base64::encode($this->client_id . ':' .
($this->get_token_with_api_key ? $this->api_key :
$this->client_secret));
                break;
            case '':
                if (strlen($authorization))
$arguments['Headers']['Authorization'] =
$authorization;
                break;
            default:
                return ($this->SetError($authentication . ' is not
a supported authentication mechanism to retrieve an access token'));
        }
        if (IsSet($options['RequestHeaders']))
$arguments['Headers'] =
array_merge($arguments['Headers'],
$options['RequestHeaders']);
        if (strlen($error = $http->SendRequest($arguments)) ||
strlen($error = $http->ReadReplyHeaders($headers))) {
            $http->Close();

            return ($this->SetError('it was not possible to
retrieve the ' . $options['Resource'] . ': ' .
$error));
        }
        $error = $http->ReadWholeReplyBody($data);
        $http->Close();
        if (strlen($error)) {
            return ($this->SetError('it was not possible to access
the ' . $options['Resource'] . ': ' . $error));
        }
        $this->response_status = intval($http->response_status);
        $content_type          =
(IsSet($options['ResponseContentType']) ?
$options['ResponseContentType'] :
(IsSet($headers['content-type']) ?
strtolower(trim(strtok($headers['content-type'], ';')))
: 'unspecified'));
        $content_type          =
preg_replace('/^(.+\\/).+\\+(.+)$/', '\\1\\2',
$content_type);
        $this->response_time   = (IsSet($headers['date']) ?
strtotime(GetType($headers['date']) === 'array' ?
$headers['date'][0] : $headers['date']) : time());
        switch ($content_type) {
            case 'text/javascript':
            case 'application/json':
            case 'application/javascript':
                if (!function_exists('json_decode')) return
($this->SetError('the JSON extension is not available in this PHP
setup'));
                $object = json_decode($data);
                switch (GetType($object)) {
                    case 'object':
                        if (!IsSet($options['ConvertObjects']) ||
!$options['ConvertObjects']) $response = $object; else {
                            $response = array();
                            foreach ($object as $property => $value)
$response[$property] = $value;
                        }
                        break;
                    case 'array':
                        $response = $object;
                        break;
                    default:
                        if (!IsSet($object)) return
($this->SetError('it was not returned a valid JSON definition of
the ' . $options['Resource'] . ' values'));
                        $response = $object;
                        break;
                }
                break;
            case 'application/x-www-form-urlencoded':
            case 'text/plain':
            case 'text/html':
                parse_str($data, $response);
                break;
            case 'text/xml':
                if (IsSet($options['DecodeXMLResponse'])) {
                    switch
(strtolower($options['DecodeXMLResponse'])) {
                        case 'simplexml':
                            if ($this->debug)
$this->OutputDebug('Decoding XML response with simplexml');
                            try {
                                $response = @new \SimpleXMLElement($data);
                            } catch (\Exception $exception) {
                                return $this->SetError('Could not
parse XML response: ' . $exception->getMessage());
                            }
                            break 2;
                        default:
                            return
$this->SetError($options['DecodeXML'] . ' is not a
supported method to decode XML responses');
                    }
                }
            default:
                $response = $data;
                break;
        }
        if ($this->response_status >= 200 &&
$this->response_status < 300) $this->access_token_error =
''; else {
            $this->access_token_error = 'it was not possible to
access the ' . $options['Resource'] . ': it was
returned an unexpected response status ' . $http->response_status .
' Response: ' . $data;
            if ($this->debug) $this->OutputDebug('Could not
retrieve the OAuth access token. Error: ' .
$this->access_token_error);
            if (IsSet($options['FailOnAccessError']) &&
$options['FailOnAccessError']) {
                $this->error = $this->access_token_error;

                return false;
            }
        }

        return true;
    }

    Function ProcessToken1($oauth, &$access_token) {
        if (!$this->GetAccessTokenURL($url)) return false;
        $options = array('Resource' => 'OAuth access
token');
        $method  = strtoupper($this->token_request_method);
        switch ($method) {
            case 'GET':
                break;
            case 'POST':
                $options['PostValuesInURI'] = true;
                break;
            default:
                $this->error = $method . ' is not a supported
method to request tokens';

                return false;
        }
        if (!$this->SendAPIRequest($url, $method, array(), $oauth,
$options, $response)) return false;
        if (strlen($this->access_token_error)) {
            $this->authorization_error = $this->access_token_error;

            return true;
        }
        if (!IsSet($response['oauth_token']) ||
!IsSet($response['oauth_token_secret'])) {
            $this->authorization_error = 'it was not returned the
access token and secret';

            return true;
        }
        $access_token = array(
            'value'      =>
$response['oauth_token'],
            'secret'     =>
$response['oauth_token_secret'],
            'authorized' => true
        );
        if (IsSet($response['oauth_expires_in']) &&
$response['oauth_expires_in'] == 0) {
            if ($this->debug) $this->OutputDebug('Ignoring
access token expiry set to 0');
            $this->access_token_expiry = '';
        } elseif (IsSet($response['oauth_expires_in'])) {
            $expires = $response['oauth_expires_in'];
            if (strval($expires) !== strval(intval($expires)) || $expires
<= 0) return ($this->SetError('OAuth server did not return a
supported type of access token expiry time'));
            $this->access_token_expiry = gmstrftime('%Y-%m-%d
%H:%M:%S', $this->response_time + $expires);
            if ($this->debug) $this->OutputDebug('Access token
expiry: ' . $this->access_token_expiry . ' UTC');
            $access_token['expiry'] =
$this->access_token_expiry;
        } else
            $this->access_token_expiry = '';
        if (IsSet($response['oauth_session_handle'])) {
            $access_token['refresh'] =
$response['oauth_session_handle'];
            if ($this->debug) $this->OutputDebug('Refresh token:
' . $access_token['refresh']);
        }

        return $this->StoreAccessToken($access_token);
    }

    Function ProcessToken2($code, $refresh) {
        if (!$this->GetRedirectURI($redirect_uri)) return false;
        $authentication = $this->access_token_authentication;
        if (strlen($this->oauth_username)) {
            $values         = array(
                'grant_type'   => 'password',
                'username'     => $this->oauth_username,
                'password'     => $this->oauth_password,
                'redirect_uri' => $redirect_uri
            );
            $authentication = 'Basic';
        } elseif ($this->redirect_uri === 'oob' &&
strlen($this->pin)) {
            $values = array(
                'grant_type' => 'pin',
                'pin'        => $this->pin,
                'scope'      => $this->scope,
            );
        } elseif ($refresh) {
            $values = array(
                'refresh_token' => $this->refresh_token,
                'grant_type'    => 'refresh_token',
                'scope'         => $this->scope,
            );
        } else {
            switch ($this->grant_type) {
                case 'password':
                    return $this->SetError('it was not specified
the username for obtaining a password based OAuth 2 authorization');
                case 'authorization_code':
                    $values         = array(
                        'code'         => $code,
                        'redirect_uri' => $redirect_uri,
                        'grant_type'   =>
'authorization_code'
                    );
                    $authentication =
$this->access_token_authentication;
                    break;
                case 'client_credentials':
                    $values         = array(
                        'grant_type' =>
'client_credentials'
                    );
                    $authentication = 'Basic';
                    break;
                default:
                    return $this->SetError($this->grant_type . '
is not yet a supported OAuth 2 grant type');
            }
        }
        $options = array(
            'Resource'       => 'OAuth ' . ($refresh
? 'refresh' : 'access') . ' token',
            'ConvertObjects' => true
        );
        switch (strtolower($authentication)) {
            case 'basic':
                $options['AccessTokenAuthentication'] =
$authentication;
                break;
            case '':
                $values['client_id']     = $this->client_id;
                $values['client_secret'] =
($this->get_token_with_api_key ? $this->api_key :
$this->client_secret);
                break;
            default:
                return ($this->SetError($authentication . ' is not
a supported authentication mechanism to retrieve an access token'));
        }
        if (!$this->GetAccessTokenURL($access_token_url)) return false;
        if (!$this->SendAPIRequest($access_token_url, 'POST',
$values, null, $options, $response)) return false;
        if (strlen($this->access_token_error)) {
            $this->authorization_error = $this->access_token_error;

            return true;
        }
        if (!IsSet($response['access_token'])) {
            if (IsSet($response['error'])) {
                $this->authorization_error = 'it was not possible
to retrieve the access token: it was returned the error: ' .
$response['error'];

                return true;
            }

            return ($this->SetError('OAuth server did not return
the access token'));
        }
        $access_token = array(
            'value'      => ($this->access_token =
$response['access_token']),
            'authorized' => true,
        );
        if ($this->store_access_token_response)
$access_token['response'] = $this->access_token_response =
$response;
        if ($this->debug) $this->OutputDebug('Access token:
' . $this->access_token);
        if (IsSet($response['expires_in']) &&
$response['expires_in'] == 0) {
            if ($this->debug) $this->OutputDebug('Ignoring
access token expiry set to 0');
            $this->access_token_expiry = '';
        } elseif (IsSet($response['expires']) ||
IsSet($response['expires_in'])) {
            $expires = (IsSet($response['expires_in']) ?
$response['expires_in'] : $response['expires'] -
($response['expires'] > $this->response_time ?
$this->response_time : 0));
            if (strval($expires) !== strval(intval($expires)) || $expires
<= 0) return ($this->SetError('OAuth server did not return a
supported type of access token expiry time'));
            $this->access_token_expiry = gmstrftime('%Y-%m-%d
%H:%M:%S', $this->response_time + $expires);
            if ($this->debug) $this->OutputDebug('Access token
expiry: ' . $this->access_token_expiry . ' UTC');
            $access_token['expiry'] =
$this->access_token_expiry;
        } else
            $this->access_token_expiry = '';
        if (IsSet($response['token_type'])) {
            $this->access_token_type =
$response['token_type'];
            if (strlen($this->access_token_type) &&
$this->debug) $this->OutputDebug('Access token type: ' .
$this->access_token_type);
            $access_token['type'] = $this->access_token_type;
        } else {
            $this->access_token_type =
$this->default_access_token_type;
            if (strlen($this->access_token_type) &&
$this->debug) $this->OutputDebug('Assumed the default for OAuth
access token type which is ' . $this->access_token_type);
        }
        if (IsSet($response['refresh_token'])) {
            $this->refresh_token = $response['refresh_token'];
            if ($this->debug) $this->OutputDebug('Refresh token:
' . $this->refresh_token);
            $access_token['refresh'] = $this->refresh_token;
        } elseif (strlen($this->refresh_token)) {
            if ($this->debug) $this->OutputDebug('Reusing
previous refresh token: ' . $this->refresh_token);
            $access_token['refresh'] = $this->refresh_token;
        }

        return $this->StoreAccessToken($access_token);
    }

    Function RetrieveToken(&$valid) {
        $valid = false;
        if (!$this->GetAccessToken($access_token)) return false;
        if (IsSet($access_token['value'])) {
            $this->access_token_expiry = '';
            $expired                   =
(IsSet($access_token['expiry']) &&
strcmp($this->access_token_expiry = $access_token['expiry'],
gmstrftime('%Y-%m-%d %H:%M:%S')) < 0);
            if ($expired) {
                if ($this->debug) $this->OutputDebug('The OAuth
access token expired on ' . $this->access_token_expiry . '
UTC');
            }
            $this->access_token = $access_token['value'];
            if (!$expired && $this->debug)
$this->OutputDebug('The OAuth access token ' .
$this->access_token . ' is valid');
            if (IsSet($access_token['type'])) {
                $this->access_token_type =
$access_token['type'];
                if (strlen($this->access_token_type) &&
!$expired && $this->debug) $this->OutputDebug('The OAuth
access token is of type ' . $this->access_token_type);
            } else {
                $this->access_token_type =
$this->default_access_token_type;
                if (strlen($this->access_token_type) &&
!$expired && $this->debug) $this->OutputDebug('Assumed
the default for OAuth access token type which is ' .
$this->access_token_type);
            }
            if (IsSet($access_token['secret'])) {
                $this->access_token_secret =
$access_token['secret'];
                if ($this->debug && !$expired &&
strlen($this->access_token_secret)) $this->OutputDebug('The
OAuth access token secret is ' . $this->access_token_secret);
            }
            if (IsSet($access_token['refresh']))
$this->refresh_token = $access_token['refresh']; else
                $this->refresh_token = '';
            $this->access_token_response =
(($this->store_access_token_response &&
IsSet($access_token['response'])) ?
$access_token['response'] : null);
            $valid                       = true;
        }

        return true;
    }

    /*
    {metadocument}
        <function>
            <name>CallAPI</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Send a HTTP request to the Web services API
using a
                    previously obtained authorization token via
OAuth.</purpose>
                <usage>This function can be used to call an API after
having
                    previously obtained an access token through the OAuth
protocol
                    using the
<functionlink>Process</functionlink> function, or by
                    directly setting the variables
                    <variablelink>access_token</variablelink>,
as well as
                   
<variablelink>access_token_secret</variablelink> in case of
using
                    OAuth 1.0 or 1.0a services.</usage>
                <returnvalue>This function returns
<booleanvalue>1</booleanvalue> if
                    the call was done successfully.</returnvalue>
            </documentation>
            <argument>
                <name>url</name>
                <type>STRING</type>
                <documentation>
                    <purpose>URL of the API where the HTTP request
will be sent.</purpose>
                </documentation>
            </argument>
            <argument>
                <name>method</name>
                <type>STRING</type>
                <documentation>
                    <purpose>HTTP method that will be used to send
the request. It can
                    be <stringvalue>GET</stringvalue>,
                    <stringvalue>POST</stringvalue>,
                    <stringvalue>DELETE</stringvalue>,
<stringvalue>PUT</stringvalue>,
                    etc..</purpose>
                </documentation>
            </argument>
            <argument>
                <name>parameters</name>
                <type>HASH</type>
                <documentation>
                    <purpose>Associative array with the names and
values of the API
                        call request parameters.</purpose>
                </documentation>
            </argument>
            <argument>
                <name>options</name>
                <type>HASH</type>
                <documentation>
                    <purpose>Associative array with additional
options to configure
                        the request. Currently it supports the following
                        options:<paragraphbreak />
                        <stringvalue>2Legged</stringvalue>:
boolean option that
                            determines if the API request should be 2
legged. The default
                            value is
<tt><booleanvalue>0</booleanvalue></tt>.<paragraphbreak
/>
                        <stringvalue>Accept</stringvalue>:
content type value of the
                            Accept HTTP header to be sent in the API call
HTTP request.
                            Some APIs require that a certain value be sent
to specify
                            which version of the API is being called. The
default value is
                           
<stringvalue>*&#47;*</stringvalue>.<paragraphbreak />
                       
<stringvalue>ConvertObjects</stringvalue>: boolean option that
                            determines if objects should be converted into
arrays when the
                            response is returned in JSON format. The
default value is
                           
<booleanvalue>0</booleanvalue>.<paragraphbreak />
                       
<stringvalue>DecodeXMLResponse</stringvalue>: name of the
method
                            to decode XML responses. Currently only
                           
<stringvalue>simplexml</stringvalue> is supported. It makes a
                            XML response be parsed and returned as a
SimpleXMLElement
                            object.<paragraphbreak />
                       
<stringvalue>FailOnAccessError</stringvalue>: boolean option
                            that determines if this functions should fail
when the server
                            response status is not between 200 and 299. The
default value
                            is
<booleanvalue>0</booleanvalue>.<paragraphbreak />
                        <stringvalue>Files</stringvalue>:
associative array with
                            details of the parameters that must be passed
as file uploads.
                            The array indexes must have the same name of
the parameters
                            to be sent as files. The respective array entry
values must
                            also be associative arrays with the parameters
for each file.
                            Currently it supports the following
parameters:<paragraphbreak />
                            - <tt>Type</tt> - defines how the
parameter value should be
                            treated. It can be
<tt>'FileName'</tt> if the parameter value is
                            is the name of a local file to be uploaded. It
may also be
                            <tt>'Data'</tt> if the
parameter value is the actual data of
                            the file to be uploaded.<paragraphbreak
/>
                            Default:
<tt>'FileName'</tt><paragraphbreak />
                            - <tt>FileName</tt> - defines a
custom file name for the file
                            to be uploaded.<paragraphbreak />
                            Default: none<paragraphbreak />
                            - <tt>ContentType</tt> - MIME value
of the content type of the
                            file. It can be
<tt>'automatic/name'</tt> if the content type
                            should be determine from the file name
extension.<paragraphbreak />
                            Default:
<tt>'automatic/name'</tt><paragraphbreak />
                       
<stringvalue>PostValuesInURI</stringvalue>: boolean option to
                            determine that a POST request should pass the
request values
                            in the URI. The default value is
                           
<booleanvalue>0</booleanvalue>.<paragraphbreak />
                       
<stringvalue>FollowRedirection</stringvalue>: limit number of
                            times that HTTP response redirects will be
followed. If it is
                            set to
<integervalue>0</integervalue>, redirection responses
                            fail in error. The default value is
                           
<integervalue>0</integervalue>.<paragraphbreak />
                        <stringvalue>RequestBody</stringvalue>:
request body data of a
                            custom type. The
<stringvalue>RequestContentType</stringvalue>
                            option must be specified, so the
                           
<stringvalue>RequestBody</stringvalue> option is
considered.<paragraphbreak />
                       
<stringvalue>RequestContentType</stringvalue>: content type
that
                            should be used to send the request values. It
can be either
                           
<stringvalue>application/x-www-form-urlencoded</stringvalue>
                            for sending values like from Web forms, or
                           
<stringvalue>application/json</stringvalue> for sending the
                            values encoded in JSON format. Other types are
accepted if the
                           
<stringvalue>RequestBody</stringvalue> option is specified.
                            The default value is
                           
<stringvalue>application/x-www-form-urlencoded</stringvalue>.<paragraphbreak
/>
                       
<stringvalue>RequestHeaders</stringvalue>: associative array of
                            custom headers to be sent with the API call.
These headers
                            override any values set by the class when
sending the API
                            call HTTP request.<paragraphbreak />
                        <stringvalue>Resource</stringvalue>:
string with a label that
                            will be used in the error messages and debug
log entries to
                            identify what operation the request is
performing. The default
                            value is <stringvalue>API
call</stringvalue>.<paragraphbreak />
                       
<stringvalue>ResponseContentType</stringvalue>: content type
                            that should be considered when decoding the API
request
                            response. This overrides the
<tt>Content-Type</tt> header
                            returned by the server. If the content type is
                           
<stringvalue>application/x-www-form-urlencoded</stringvalue>
                            the function will parse the data returning an
array of
                            key-value pairs. If the content type is
                           
<stringvalue>application/json</stringvalue> the response will
                            be decode as a JSON-encoded data type. Other
content type
                            values will make the function return the
original response
                            value as it was returned from the server. The
default value
                            for this option is to use what the server
returned in the
                            <tt>Content-Type</tt>
header.</purpose>
                </documentation>
            </argument>
            <argument>
                <name>response</name>
                <type>STRING</type>
                <out />
                <documentation>
                    <purpose>Return the value of the API response. If
the value is
                        JSON encoded, this function will decode it and
return the value
                        converted to respective types. If the value is form
encoded,
                        this function will decode the response and return
it as an
                        array. Otherwise, the class will return the value
as a
                        string.</purpose>
                </documentation>
            </argument>
            <do>
    {/metadocument}
    */
    Function CallAPI($url, $method, $parameters, $options, &$response)
{
        if (!IsSet($options['Resource']))
$options['Resource'] = 'API call';
        if (!IsSet($options['ConvertObjects']))
$options['ConvertObjects'] = false;
        $version    = intval($this->oauth_version);
        $two_legged = ($version === 1 &&
IsSet($options['2Legged']) &&
$options['2Legged']);
        if (strlen($this->access_token) === 0 && !$two_legged) {
            if (!$this->RetrieveToken($valid)) return false;
            if (!$valid) return $this->SetError('the access token
is not set to a valid value');
        }
        switch ($version) {
            case 1:
                if (!$two_legged &&
strlen($this->access_token_expiry) &&
strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d
%H:%M:%S')) <= 0) {
                    if (strlen($this->refresh_token) === 0) return
($this->SetError('the access token expired and no refresh token is
available'));
                    if ($this->debug)
$this->OutputDebug('Refreshing the OAuth access token expired on
' . $this->access_token_expiry);
                    $oauth = array(
                        'oauth_token'          =>
$this->access_token,
                        'oauth_session_handle' =>
$this->refresh_token
                    );
                    if (!$this->ProcessToken1($oauth, $access_token))
return false;
                    if (IsSet($options['FailOnAccessError'])
&& $options['FailOnAccessError'] &&
strlen($this->authorization_error)) {
                        $this->error = $this->authorization_error;

                        return false;
                    }
                    if (!IsSet($access_token['authorized']) ||
!$access_token['authorized']) return
($this->SetError('failed to obtain a renewed the expired access
token'));
                    $this->access_token        =
$access_token['value'];
                    $this->access_token_secret =
$access_token['secret'];
                    if (IsSet($access_token['refresh']))
$this->refresh_token = $access_token['refresh'];
                }
                $oauth = array();
                if (!$two_legged)
$oauth[strlen($this->access_token_parameter) ?
$this->access_token_parameter : 'oauth_token'] =
$this->access_token;
                break;

            case 2:
                if (strlen($this->access_token_expiry) &&
strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d
%H:%M:%S')) <= 0) {
                    if (strlen($this->refresh_token) === 0) return
($this->SetError('the access token expired and no refresh token is
available'));
                    if ($this->debug)
$this->OutputDebug('Refreshing the OAuth access token expired on
' . $this->access_token_expiry);
                    if (!$this->ProcessToken2(null, true)) return false;
                    if (IsSet($options['FailOnAccessError'])
&& $options['FailOnAccessError'] &&
strlen($this->authorization_error)) {
                        $this->error = $this->authorization_error;

                        return false;
                    }
                }
                $oauth = null;
                if (strcasecmp($this->access_token_type,
'Bearer')) $url .= (strcspn($url, '?') <
strlen($url) ? '&' : '?') .
(strlen($this->access_token_parameter) ?
$this->access_token_parameter : 'access_token') .
'=' . UrlEncode($this->access_token);
                break;

            default:
                return ($this->SetError($this->oauth_version . '
is not a supported version of the OAuth protocol'));
        }

        return ($this->SendAPIRequest($url, $method, $parameters,
$oauth, $options, $response));
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>Initialize</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Initialize the class variables and internal
state. It must
                    be called before calling other class
functions.</purpose>
                <usage>Set the
<variablelink>server</variablelink> variable before
                    calling this function to let it initialize the class
variables to
                    work with the specified server type. Alternatively, you
can set
                    other class variables manually to make it work with
servers that
                    are not yet built-in supported.</usage>
                <returnvalue>This function returns
<booleanvalue>1</booleanvalue> if
                    it was able to successfully initialize the class for
the specified
                    server type.</returnvalue>
            </documentation>
            <do>
    {/metadocument}
    */
    Function Initialize() {
        if (strlen($this->server) === 0) return true;
        $this->oauth_version               = $this->dialog_url =
$this->pin_dialog_url = $this->access_token_url =
$this->request_token_url = $this->append_state_to_redirect_uri =
'';
        $this->authorization_header        = true;
        $this->url_parameters              = false;
        $this->token_request_method        = 'GET';
        $this->signature_method            = 'HMAC-SHA1';
        $this->access_token_authentication = '';
        $this->access_token_parameter      = '';
        $this->default_access_token_type   = '';
        $this->store_access_token_response = false;
        switch ($this->server) {
            case 'Facebook':
                $this->oauth_version    = '2.0';
                $this->dialog_url       =
'https://www.facebook.com/v2.3/dialog/oauth?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
                $this->access_token_url =
'https://graph.facebook.com/oauth/access_token';
                break;

            case 'github':
                $this->oauth_version    = '2.0';
                $this->dialog_url       =
'https://github.com/login/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
                $this->access_token_url =
'https://github.com/login/oauth/access_token';
                break;

            case 'Google':
                $this->oauth_version      = '2.0';
                $this->dialog_url         =
'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
                $this->offline_dialog_url =
'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}&access_type=offline&approval_prompt=force';
                $this->access_token_url   =
'https://accounts.google.com/o/oauth2/token';
                break;

            case 'LinkedIn':
                $this->oauth_version     = '1.0a';
                $this->request_token_url =
'https://api.linkedin.com/uas/oauth/requestToken?scope={SCOPE}';
                $this->dialog_url        =
'https://api.linkedin.com/uas/oauth/authenticate';
                $this->access_token_url  =
'https://api.linkedin.com/uas/oauth/accessToken';
                $this->url_parameters    = true;
                break;

            case 'Microsoft':
                $this->oauth_version    = '2.0';
                $this->dialog_url       =
'https://login.live.com/oauth20_authorize.srf?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}';
                $this->access_token_url =
'https://login.live.com/oauth20_token.srf';
                break;

            case 'Twitter':
                $this->oauth_version     = '1.0a';
                $this->request_token_url =
'https://api.twitter.com/oauth/request_token';
                $this->dialog_url        =
'https://api.twitter.com/oauth/authenticate';
                $this->access_token_url  =
'https://api.twitter.com/oauth/access_token';
                $this->url_parameters    = false;
                break;

            case 'Yahoo':
                $this->oauth_version        = '1.0a';
                $this->request_token_url    =
'https://api.login.yahoo.com/oauth/v2/get_request_token';
                $this->dialog_url           =
'https://api.login.yahoo.com/oauth/v2/request_auth';
                $this->access_token_url     =
'https://api.login.yahoo.com/oauth/v2/get_token';
                $this->authorization_header = false;
                break;

            default:
                if (!($json =
@file_get_contents($this->configuration_file))) {
                    if (!file_exists($this->configuration_file)) return
$this->SetError('the OAuth server configuration file ' .
$this->configuration_file . ' does not exist');

                    return $this->SetPHPError('could not read the
OAuth server configuration file ' . $this->configuration_file,
self::PHPErrorMessage());
                }
                $oauth_server = json_decode($json);
                if (!IsSet($oauth_server)) return
$this->SetPHPError('It was not possible to decode the OAuth server
configuration file ' . $this->configuration_file . '
eventually due to incorrect format', self::PHPErrorMessage());
                if (GetType($oauth_server) !== 'object') return
$this->SetError('It was not possible to decode the OAuth server
configuration file ' . $this->configuration_file . ' because
it does not correctly define a JSON object');
                if (!IsSet($oauth_server->servers) ||
GetType($oauth_server->servers) !== 'object') return
$this->SetError('It was not possible to decode the OAuth server
configuration file ' . $this->configuration_file . ' because
it does not correctly define a JSON object for servers');
                if
(!IsSet($oauth_server->servers->{$this->server})) return
($this->SetError($this->server . ' is not yet a supported type
of OAuth server. Please send a request in this class support forum
(preferred) http://www.phpclasses.org/oauth-api , or if it is a security or
private matter, contact the author Manuel Lemos mlemos@acm.org to request
adding built-in support to this type of OAuth server.'));
                $properties =
$oauth_server->servers->{$this->server};
                if (GetType($properties) !== 'object') return
$this->SetError('The OAuth server configuration file ' .
$this->configuration_file . ' for the "' .
$this->server . '" server does not correctly define a JSON
object');
                $types    = array(
                    'oauth_version'                =>
'string',
                    'request_token_url'            =>
'string',
                    'dialog_url'                   =>
'string',
                    'pin_dialog_url'               =>
'string',
                    'offline_dialog_url'           =>
'string',
                    'access_token_url'             =>
'string',
                    'append_state_to_redirect_uri' =>
'string',
                    'authorization_header'         =>
'boolean',
                    'url_parameters'               =>
'boolean',
                    'token_request_method'         =>
'string',
                    'signature_method'             =>
'string',
                    'access_token_authentication'  =>
'string',
                    'access_token_parameter'       =>
'string',
                    'default_access_token_type'    =>
'string',
                    'store_access_token_response'  =>
'boolean'
                );
                $required = array(
                    'oauth_version'     => array(),
                    'request_token_url' => array(
                        '1.0',
                        '1.0a'
                    ),
                    'dialog_url'        => array(),
                    'access_token_url'  => array(),
                );
                foreach ($properties as $property => $value) {
                    if (!IsSet($types[$property])) return
$this->SetError($property . ' is not a supported property for the
"' . $this->server . '" server in the OAuth server
configuration file ' . $this->configuration_file);
                    $type     = GetType($value);
                    $expected = $types[$property];
                    if ($type !== $expected) return
$this->SetError(' the property "' . $property .
'" for the "' . $this->server . '" server
is not of type "' . $expected . '", it is of type
"' . $type . '", in the OAuth server configuration file
' . $this->configuration_file);
                    $this->{$property} = $value;
                    UnSet($required[$property]);
                }
                foreach ($required as $property => $value) {
                    if (count($value) &&
in_array($this->oauth_version, $value)) return
$this->SetError('the property "' . $property .
'" is not defined for the "' . $this->server .
'" server in the OAuth server configuration file ' .
$this->configuration_file);
                }
                break;
        }

        return (true);
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>CheckAccessToken</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Check if the access token was retrieved and
if it is
                    valid.</purpose>
                <usage>Call this function when you need to check of
an access token
                    is valid without forcing to redirect the user to the
OAuth server
                    authorization page.<paragraphbreak />
                    If a previously retrieved access token has expired,
this function
                    may renew it automatically.</usage>
                <returnvalue>This function returns
<booleanvalue>1</booleanvalue> if
                    the OAuth protocol was checked without
errors.</returnvalue>
            </documentation>
            <argument>
                <name>redirect_url</name>
                <type>STRING</type>
                <out />
                <documentation>
                    <purpose>Return the URL of the OAuth server
authorization to
                        redirect the user if the access token was not yet
retrieved or
                        is not valid.</purpose>
                </documentation>
            </argument>
            <do>
    {/metadocument}
    */
    Function CheckAccessToken(&$redirect_url) {
        $redirect_url = null;
        if (strlen($this->access_token) ||
strlen($this->access_token_secret)) {
            if ($this->debug) $this->OutputDebug('The Process
function should not be called again if the OAuth token was already set
manually');

            return $this->SetError('the OAuth token was already
set');
        }
        switch (intval($this->oauth_version)) {
            case 1:
                $one_a = ($this->oauth_version === '1.0a');
                if ($this->debug) $this->OutputDebug('Checking
the OAuth token authorization state');
                if (!$this->GetAccessToken($access_token)) return false;
                if (IsSet($access_token['expiry']))
$this->access_token_expiry = $access_token['expiry'];
                if (IsSet($access_token['authorized']) &&
IsSet($access_token['value'])) {
                    $expired = (IsSet($access_token['expiry'])
&& strcmp($access_token['expiry'],
gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0);
                    if (!$access_token['authorized'] || $expired)
{
                        if ($this->debug) {
                            if ($expired) $this->OutputDebug('The
OAuth token expired on ' . $access_token['expiry'] .
'UTC'); else
                                $this->OutputDebug('The OAuth token
is not yet authorized');
                        }
                        if ($one_a && $this->redirect_uri ===
'oob' && strlen($this->pin)) {
                            if ($this->debug)
$this->OutputDebug('Checking the pin');
                            $this->access_token_secret =
$access_token['secret'];
                            $oauth                     = array(
                                'oauth_token'    =>
$access_token['value'],
                                'oauth_verifier' =>
$this->pin
                            );
                            if (!$this->ProcessToken1($oauth,
$access_token)) return false;
                            if ($this->debug)
$this->OutputDebug('The OAuth token was authorized');
                        } else {
                            if ($this->debug)
$this->OutputDebug('Checking the OAuth token and verifier');
                            if (!$this->GetRequestToken($token,
$verifier)) return false;
                            if (!IsSet($token) || ($one_a &&
!IsSet($verifier))) {
                                if (!$this->GetRequestDenied($denied))
return false;
                                if (IsSet($denied) && $denied ===
$access_token['value']) {
                                    if ($this->debug)
$this->OutputDebug('The authorization request was denied');
                                    $this->authorization_error =
'the request was denied';

                                    return true;
                                } else {
                                    if ($this->debug)
$this->OutputDebug('Reset the OAuth token state because token and
verifier are not both set');
                                    $access_token = array();
                                }
                            } elseif ($token !==
$access_token['value']) {
                                if ($this->debug)
$this->OutputDebug('Reset the OAuth token state because token does
not match what as previously retrieved');
                                $access_token = array();
                            } else {
                                $this->access_token_secret =
$access_token['secret'];
                                $oauth                     = array(
                                    'oauth_token' => $token,
                                );
                                if ($one_a)
$oauth['oauth_verifier'] = $verifier;
                                if (!$this->ProcessToken1($oauth,
$access_token)) return false;
                                if ($this->debug)
$this->OutputDebug('The OAuth token was authorized');
                            }
                        }
                    } elseif ($this->debug)
$this->OutputDebug('The OAuth token was already authorized');
                    if (IsSet($access_token['authorized'])
&& $access_token['authorized']) {
                        $this->access_token        =
$access_token['value'];
                        $this->access_token_secret =
$access_token['secret'];
                        if (IsSet($access_token['refresh']))
$this->refresh_token = $access_token['refresh'];

                        return true;
                    }
                } else {
                    if ($this->debug) $this->OutputDebug('The
OAuth access token is not set');
                    $access_token = array();
                }
                if (!IsSet($access_token['authorized'])) {
                    if ($this->debug)
$this->OutputDebug('Requesting the unauthorized OAuth token');
                    if (!$this->GetRequestTokenURL($url)) return false;
                    $url = str_replace('{SCOPE}',
UrlEncode($this->scope), $url);
                    if (!$this->GetRedirectURI($redirect_uri)) return
false;
                    $oauth   = array(
                        'oauth_callback' => $redirect_uri,
                    );
                    $options = array(
                        'Resource'          => 'OAuth
request token',
                        'FailOnAccessError' => true
                    );
                    $method  = strtoupper($this->token_request_method);
                    switch ($method) {
                        case 'GET':
                            break;
                        case 'POST':
                            $options['PostValuesInURI'] = true;
                            break;
                        default:
                            $this->error = $method . ' is not a
supported method to request tokens';
                            break;
                    }
                    if (!$this->SendAPIRequest($url, $method, array(),
$oauth, $options, $response)) return false;
                    if (strlen($this->access_token_error)) {
                        $this->authorization_error =
$this->access_token_error;

                        return true;
                    }
                    if (!IsSet($response['oauth_token']) ||
!IsSet($response['oauth_token_secret'])) {
                        $this->authorization_error = 'it was not
returned the requested token';

                        return true;
                    }
                    $access_token = array(
                        'value'      =>
$response['oauth_token'],
                        'secret'     =>
$response['oauth_token_secret'],
                        'authorized' => false
                    );
                    if (IsSet($response['login_url']))
$access_token['login_url'] = $response['login_url'];
                    if (!$this->StoreAccessToken($access_token)) return
false;
                }
                if (!$this->GetDialogURL($url)) return false;
                if ($url === 'automatic') {
                    if (!IsSet($access_token['login_url']))
return ($this->SetError('The request token response did not
automatically the login dialog URL as expected'));
                    if ($this->debug) $this->OutputDebug('Dialog
URL obtained automatically from the request token response: ' . $url);
                    $url = $access_token['login_url'];
                } else
                    $url .= (strpos($url, '?') === false ?
'?' : '&') . 'oauth_token=' .
$access_token['value'];
                if (!$one_a) {
                    if (!$this->GetRedirectURI($redirect_uri)) return
false;
                    $url .= '&oauth_callback=' .
UrlEncode($redirect_uri);
                }
                if ($this->debug)
$this->OutputDebug('Redirecting to OAuth authorize page ' .
$url);
                $redirect_url = $url;

                return true;

            case 2:
                if ($this->debug) {
                    if (!$this->GetAccessTokenURL($access_token_url))
return false;
                    $this->OutputDebug('Checking if OAuth access
token was already retrieved from ' . $access_token_url);
                }
                if (!$this->RetrieveToken($valid)) return false;
                $expired = (strlen($this->access_token_expiry)
&& strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d
%H:%M:%S')) <= 0 && strlen($this->refresh_token) === 0);
                if ($valid && !$expired) return true;
                if ($this->debug) {
                    if (!$valid) $this->OutputDebug('A valid access
token is not available'); elseif ($expired)
$this->OutputDebug('The access token expired');
                }
                switch ($this->grant_type) {
                    case 'authorization_code':
                        if ($this->redirect_uri === 'oob'
&& strlen($this->pin)) {
                            if ($this->debug)
$this->OutputDebug('Getting the access token using the pin');
                            if (!$this->ProcessToken2(null, false))
return false;
                            if (strlen($this->authorization_error))
return $this->SetError($this->authorization_error);

                            return true;
                        } elseif (strlen($this->oauth_username) === 0)
break;
                    case 'password':
                        if ($this->debug)
$this->OutputDebug('Getting the access token using the username and
password');
                        if (!$this->ProcessToken2(null, false)) return
false;
                        if (strlen($this->authorization_error)) return
$this->SetError($this->authorization_error);

                        return true;
                    case 'client_credentials':
                        if ($this->debug)
$this->OutputDebug('Getting the access token using the client
credentials');
                        if (!$this->ProcessToken2(null, false)) return
false;
                        if (strlen($this->authorization_error)) return
$this->SetError($this->authorization_error);

                        return true;
                    default:
                        return $this->SetError($this->grant_type .
' is not yet a supported OAuth 2 grant type');
                }
                if ($this->debug) $this->OutputDebug('Checking
the authentication state in URI ' .
$_SERVER['REQUEST_URI']);
                if (!$this->GetStoredState($stored_state)) return false;
                if (strlen($stored_state) == 0) return
($this->SetError('it was not set the OAuth state'));
                if (!$this->GetRequestState($state)) return false;
                if ($state === $stored_state) {
                    if ($this->debug)
$this->OutputDebug('Checking the authentication code');
                    if (!$this->GetRequestCode($code)) return false;
                    if (strlen($code) == 0) {
                        if
(!$this->GetRequestError($this->authorization_error)) return false;
                        if (IsSet($this->authorization_error)) {
                            if ($this->debug)
$this->OutputDebug('Authorization failed with error code ' .
$this->authorization_error);
                            switch ($this->authorization_error) {
                                case 'invalid_request':
                                case 'unauthorized_client':
                                case 'access_denied':
                                case 'unsupported_response_type':
                                case 'invalid_scope':
                                case 'server_error':
                                case 'temporarily_unavailable':
                                case 'user_denied':
                                    return true;
                                default:
                                    return ($this->SetError('it was
returned an unknown OAuth error code'));
                            }
                        }

                        return ($this->SetError('it was not
returned the OAuth dialog code'));
                    }
                    if (!$this->ProcessToken2($code, false)) return
false;
                    if (strlen($this->authorization_error)) return
$this->SetError($this->authorization_error);
                } else {
                    if (!$this->GetRedirectURI($redirect_uri)) return
false;
                    if (strlen($this->append_state_to_redirect_uri))
$redirect_uri .= (strpos($redirect_uri, '?') === false ?
'?' : '&') . $this->append_state_to_redirect_uri
. '=' . $stored_state;
                    if (!$this->GetDialogURL($url, $redirect_uri,
$stored_state)) return false;
                    if (strlen($url) == 0) return
($this->SetError('it was not set the OAuth dialog URL'));
                    if ($this->debug)
$this->OutputDebug('Redirecting to OAuth Dialog ' . $url);
                    $redirect_url = $url;
                }
                break;

            default:
                return ($this->SetError($this->oauth_version . '
is not a supported version of the OAuth protocol'));
        }

        return (true);
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>Process</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Process the OAuth protocol interaction with
the OAuth
                    server.</purpose>
                <usage>Call this function when you need to retrieve
the OAuth access
                    token. Check the
<variablelink>access_token</variablelink> to
                    determine if the access token was obtained
successfully.</usage>
                <returnvalue>This function returns
<booleanvalue>1</booleanvalue> if
                    the OAuth protocol was processed without
errors.</returnvalue>
            </documentation>
            <do>
    {/metadocument}
    */
    Function Process() {
        if (!$this->CheckAccessToken($redirect_url)) return false;
        if (IsSet($redirect_url)) {
            $this->Redirect($redirect_url);
            $this->exit = true;
        }

        return true;
    }

    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>Finalize</name>
            <type>BOOLEAN</type>
            <documentation>
                <purpose>Cleanup any resources that may have been
used during the
                    OAuth protocol processing or execution of API
calls.</purpose>
                <usage>Always call this function as the last step
after calling the
                    functions
<functionlink>Process</functionlink> or
                   
<functionlink>CallAPI</functionlink>.</usage>
                <returnvalue>This function returns
<booleanvalue>1</booleanvalue> if
                    the function cleaned up any resources
successfully.</returnvalue>
            </documentation>
            <argument>
                <name>success</name>
                <type>BOOLEAN</type>
                <documentation>
                    <purpose>Pass the last success state returned by
the class or any
                        external code processing the class function
results.</purpose>
                </documentation>
            </argument>
            <do>
    {/metadocument}
    */
    Function Finalize($success) {
        return ($success);
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

    /*
    {metadocument}
        <function>
            <name>Output</name>
            <type>VOID</type>
            <documentation>
                <purpose>Display the results of the OAuth protocol
processing.</purpose>
                <usage>Only call this function if you are debugging
the OAuth
                    authorization process and you need to view what was its
                    results.</usage>
            </documentation>
            <do>
    {/metadocument}
    */
    Function Output() {
        if (strlen($this->authorization_error) ||
strlen($this->access_token_error) || strlen($this->access_token)) {
            ?>
            <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN">
            <html>
            <head>
                <title>OAuth client result</title>
            </head>
            <body>
            <h1>OAuth client result</h1>
            <?php
            if (strlen($this->authorization_error)) {
                ?>
                <p>It was not possible to authorize the
application.<?php
                    if ($this->debug) {
                        ?>
                        <br>Authorization error: <?php echo
HtmlSpecialChars($this->authorization_error);
                    }
                    ?></p>
                <?php
            } elseif (strlen($this->access_token_error)) {
                ?>
                <p>It was not possible to use the application access
token.
                    <?php
                    if ($this->debug) {
                        ?>
                        <br>Error: <?php echo
HtmlSpecialChars($this->access_token_error);
                    }
                    ?></p>
                <?php
            } elseif (strlen($this->access_token)) {
                ?>
                <p>The application authorization was obtained
successfully.
                    <?php
                    if ($this->debug) {
                        ?>
                        <br>Access token: <?php echo
HtmlSpecialChars($this->access_token);
                        if (IsSet($this->access_token_secret)) {
                            ?>
                            <br>Access token secret: <?php echo
HtmlSpecialChars($this->access_token_secret);
                        }
                    }
                    ?></p>
                <?php
                if (strlen($this->access_token_expiry)) {
                    ?>
                    <p>Access token expiry: <?php echo
$this->access_token_expiry; ?> UTC</p>
                    <?php
                }
            }
            ?>
            </body>
            </html>
            <?php
        }
    }
    /*
    {metadocument}
            </do>
        </function>
    {/metadocument}
    */

}

/*

{metadocument}
</class>
{/metadocument}

*/Misc/OAuth/oauth_configuration.json000064400000041113151161172500013420
0ustar00{
  "version": "$Id: oauth_configuration.json,v 1.27
2015/07/23 20:45:00 mlemos Exp $",
  "comments": [
    "The servers entry should be an object with a list of
object",
    "entries, one for each server type. The server object entry name
is",
    "the name of the server type. Each server entry is an object
with",
    "some mandatory properties: oauth_version, dialog_url,",
    "access_token_url and request_token_url (just for Oauth 1.0
and",
    "1.0a). Check the OAuth client class for the complete list of
server",
    "properties."
  ],
  "servers": {
    "500px": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://api.500px.com/v1/oauth/request_token",
      "dialog_url":
"https://api.500px.com/v1/oauth/authorize",
      "access_token_url":
"https://api.500px.com/v1/oauth/access_token",
      "authorization_header": false
    },
    "37Signals": {
      "oauth_version": "2.0",
      "dialog_url":
"https://launchpad.37signals.com/authorization/new?type=web_server&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://launchpad.37signals.com/authorization/token?type=web_server"
    },
    "Amazon": {
      "oauth_version": "2.0",
      "dialog_url":
"https://www.amazon.com/ap/oa?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://api.amazon.com/auth/o2/token"
    },
    "AOL": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.screenname.aol.com/auth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://api.screenname.aol.com/auth/access_token"
    },
    "Bitbucket": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://bitbucket.org/!api/1.0/oauth/request_token",
      "dialog_url":
"https://bitbucket.org/!api/1.0/oauth/authenticate",
      "access_token_url":
"https://bitbucket.org/!api/1.0/oauth/access_token",
      "url_parameters": false
    },
    "Bitly": {
      "oauth_version": "2.0",
      "dialog_url":
"https://bitly.com/oauth/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://api-ssl.bitly.com/oauth/access_token"
    },
    "Box": {
      "oauth_version": "2.0",
      "dialog_url":
"https://www.box.com/api/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&scope={SCOPE}",
      "offline_dialog_url":
"https://www.box.com/api/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&access_type=offline&approval_prompt=force",
      "access_token_url":
"https://www.box.com/api/oauth2/token"
    },
    "Buffer": {
      "oauth_version": "2.0",
      "dialog_url":
"https://bufferapp.com/oauth2/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://api.bufferapp.com/1/oauth2/token.json"
    },
    "Copy": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://api.copy.com/oauth/request",
      "dialog_url":
"https://www.copy.com/applications/authorize",
      "access_token_url":
"https://api.copy.com/oauth/access"
    },
    "Dailymotion": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.dailymotion.com/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://api.dailymotion.com/oauth/token"
    },
    "Discogs": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://api.discogs.com/oauth/request_token",
      "dialog_url":
"https://www.discogs.com/oauth/authorize",
      "access_token_url":
"https://api.discogs.com/oauth/access_token"
    },
    "Disqus": {
      "oauth_version": "2.0",
      "dialog_url":
"https://disqus.com/api/oauth/2.0/authorize/?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "access_token_url":
"https://disqus.com/api/oauth/2.0/access_token/"
    },
    "Dribbble": {
      "oauth_version": "2.0",
      "dialog_url":
"https://dribbble.com/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://dribbble.com/oauth/token"
    },
    "Dropbox": {
      "oauth_version": "1.0",
      "request_token_url":
"https://api.dropbox.com/1/oauth/request_token",
      "dialog_url":
"https://www.dropbox.com/1/oauth/authorize",
      "access_token_url":
"https://api.dropbox.com/1/oauth/access_token",
      "authorization_header": false
    },
    "Dropbox2": {
      "oauth_version": "2.0",
      "dialog_url":
"https://www.dropbox.com/1/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "access_token_url":
"https://www.dropbox.com/1/oauth2/token"
    },
    "Etsy": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://openapi.etsy.com/v2/oauth/request_token?scope={SCOPE}",
      "dialog_url": "automatic",
      "access_token_url":
"https://openapi.etsy.com/v2/oauth/access_token"
    },
    "Eventful": {
      "oauth_version": "1.0a",
      "request_token_url":
"http://eventful.com/oauth/request_token",
      "dialog_url":
"http://eventful.com/oauth/authorize",
      "access_token_url":
"http://eventful.com/oauth/access_token",
      "authorization_header": false,
      "url_parameters": true,
      "token_request_method": "POST"
    },
    "Evernote": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://sandbox.evernote.com/oauth",
      "dialog_url":
"https://sandbox.evernote.com/OAuth.action",
      "access_token_url":
"https://sandbox.evernote.com/oauth",
      "url_parameters": true,
      "authorization_header": false
    },
    "Fitbit": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://api.fitbit.com/oauth/request_token",
      "dialog_url":
"https://api.fitbit.com/oauth/authorize",
      "access_token_url":
"https://api.fitbit.com/oauth/access_token"
    },
    "Fitbit2": {
      "oauth_version": "2.0",
      "dialog_url":
"https://www.fitbit.com/oauth2/authorize?client_id={CLIENT_ID}&response_type=code&state={STATE}&redirect_uri={REDIRECT_URI}&scope={SCOPE}",
      "access_token_url":
"https://api.fitbit.com/oauth2/token",
      "access_token_authentication": "basic"
    },
    "Flickr": {
      "oauth_version": "1.0a",
      "request_token_url":
"http://www.flickr.com/services/oauth/request_token",
      "dialog_url":
"http://www.flickr.com/services/oauth/authorize?perms={SCOPE}",
      "access_token_url":
"http://www.flickr.com/services/oauth/access_token",
      "authorization_header": false
    },
    "Foursquare": {
      "oauth_version": "2.0",
      "dialog_url":
"https://foursquare.com/oauth2/authorize?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}",
      "access_token_url":
"https://foursquare.com/oauth2/access_token",
      "access_token_parameter": "oauth_token"
    },
    "Google1": {
      "oauth_version": "1.0a",
      "dialog_url":
"https://www.google.com/accounts/OAuthAuthorizeToken",
      "access_token_url":
"https://www.google.com/accounts/OAuthGetAccessToken",
      "request_token_url":
"https://www.google.com/accounts/OAuthGetRequestToken?scope={SCOPE}"
    },
    "imgur": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.imgur.com/oauth2/authorize?client_id={CLIENT_ID}&response_type=code&state={STATE}&redirect_uri={REDIRECT_URI}&scope={SCOPE}",
      "pin_dialog_url":
"https://api.imgur.com/oauth2/authorize?client_id={CLIENT_ID}&response_type=pin&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://api.imgur.com/oauth2/token"
    },
    "Instagram": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.instagram.com/oauth/authorize/?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://api.instagram.com/oauth/access_token"
    },
    "Intuit": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://oauth.intuit.com/oauth/v1/get_request_token",
      "dialog_url":
"https://appcenter.intuit.com/Connect/Begin",
      "access_token_url":
"https://oauth.intuit.com/oauth/v1/get_access_token"
    },
    "Jawbone": {
      "oauth_version": "2.0",
      "dialog_url":
"https://jawbone.com/auth/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://jawbone.com/auth/oauth2/token"
    },
    "LinkedIn2": {
      "oauth_version": "2.0",
      "dialog_url":
"https://www.linkedin.com/uas/oauth2/authorization?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://www.linkedin.com/uas/oauth2/accessToken",
      "default_access_token_type": "Bearer"
    },
    "MailChimp": {
      "oauth_version": "2.0",
      "dialog_url":
"https://login.mailchimp.com/oauth2/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://login.mailchimp.com/oauth2/token"
    },
    "Mavenlink": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.mavenlink.com/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://api.mavenlink.com/oauth/token"
    },
    "mail.ru": {
      "oauth_version": "2.0",
      "dialog_url":
"https://connect.mail.ru/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}",
      "access_token_url":
"https://connect.mail.ru/oauth/token",
      "store_access_token_response": true
    },
    "Meetup": {
      "oauth_version": "2.0",
      "dialog_url":
"https://secure.meetup.com/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "access_token_url":
"https://secure.meetup.com/oauth2/access"
    },
    "Misfit": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.misfitwearables.com/auth/dialog/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "access_token_url":
"https://api.misfitwearables.com/auth/tokens/exchange"
    },
    "oDesk": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://www.odesk.com/api/auth/v1/oauth/token/request",
      "dialog_url":
"https://www.odesk.com/services/api/auth",
      "access_token_url":
"https://www.odesk.com/api/auth/v1/oauth/token/access",
      "token_request_method": "POST"
    },
    "Paypal": {
      "oauth_version": "2.0",
      "dialog_url":
"https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://api.paypal.com/v1/oauth2/token",
      "access_token_authentication": "basic"
    },
    "PaypalApplication": {
      "oauth_version": "2.0",
      "dialog_url": "use Paypal OAuth 2.0 for accessing its
API on behalf of a given user",
      "access_token_url":
"https://api.paypal.com/v1/oauth2/token",
      "access_token_authentication": "basic"
    },
    "Rdio": {
      "oauth_version": "1.0a",
      "request_token_url":
"http://api.rdio.com/oauth/request_token",
      "dialog_url":
"https://www.rdio.com/oauth/authorize",
      "access_token_url":
"http://api.rdio.com/oauth/access_token"
    },
    "Reddit": {
      "oauth_version": "2.0",
      "dialog_url":
"https://ssl.reddit.com/api/v1/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "offline_dialog_url":
"https://ssl.reddit.com/api/v1/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}&duration=permanent",
      "access_token_url":
"https://ssl.reddit.com/api/v1/access_token",
      "access_token_authentication": "basic"
    },
    "RightSignature": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://rightsignature.com/oauth/request_token",
      "dialog_url":
"https://rightsignature.com/oauth/authorize",
      "access_token_url":
"https://rightsignature.com/oauth/access_token",
      "authorization_header": false
    },
    "RunKeeper": {
      "oauth_version": "2.0",
      "dialog_url":
"https://runkeeper.com/apps/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://runkeeper.com/apps/token"
    },
    "Salesforce": {
      "oauth_version": "2.0",
      "dialog_url":
"https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "access_token_url":
"https://login.salesforce.com/services/oauth2/token",
      "default_access_token_type": "Bearer",
      "store_access_token_response": true
    },
    "Scoop.it": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://www.scoop.it/oauth/request",
      "dialog_url":
"https://www.scoop.it/oauth/authorize",
      "access_token_url":
"https://www.scoop.it/oauth/access",
      "authorization_header": false
    },
    "StockTwits": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.stocktwits.com/api/2/oauth/authorize?client_id={CLIENT_ID}&response_type=code&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "access_token_url":
"https://api.stocktwits.com/api/2/oauth/token"
    },
    "SurveyMonkey": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.surveymonkey.net/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}&api_key={API_KEY}&scope={SCOPE}",
      "access_token_url":
"https://api.surveymonkey.net/oauth/token?api_key={API_KEY}"
    },
    "TeamViewer": {
      "oauth_version": "2.0",
      "dialog_url":
"https://webapi.teamviewer.com/api/v1/oauth2/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}&api_key={API_KEY}&scope={SCOPE}",
      "access_token_url":
"https://webapi.teamviewer.com/api/v1/oauth2/token"
    },
    "Tumblr": {
      "oauth_version": "1.0a",
      "request_token_url":
"http://www.tumblr.com/oauth/request_token",
      "dialog_url":
"http://www.tumblr.com/oauth/authorize",
      "access_token_url":
"http://www.tumblr.com/oauth/access_token"
    },
    "Twitter2": {
      "oauth_version": "2.0",
      "dialog_url": "use Twitter OAuth 1.0a for accessing
its API on behalf of a given user",
      "access_token_url":
"https://api.twitter.com/oauth2/token"
    },
    "Vimeo": {
      "oauth_version": "2.0",
      "dialog_url":
"https://api.vimeo.com/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://api.vimeo.com/oauth/access_token"
    },
    "VK": {
      "oauth_version": "2.0",
      "dialog_url":
"https://oauth.vk.com/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}",
      "access_token_url":
"https://oauth.vk.com/access_token"
    },
    "Withings": {
      "oauth_version": "1.0",
      "request_token_url":
"https://oauth.withings.com/account/request_token",
      "dialog_url":
"https://oauth.withings.com/account/authorize",
      "access_token_url":
"https://oauth.withings.com/account/access_token",
      "authorization_header": false
    },
    "Wordpress": {
      "oauth_version": "2.0",
      "dialog_url":
"https://public-api.wordpress.com/oauth2/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://public-api.wordpress.com/oauth2/token"
    },
    "Xero": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://api.xero.com/oauth/RequestToken",
      "dialog_url":
"https://api.xero.com/oauth/Authorize",
      "access_token_url":
"https://api.xero.com/oauth/AccessToken"
    },
    "XING": {
      "oauth_version": "1.0a",
      "request_token_url":
"https://api.xing.com/v1/request_token",
      "dialog_url":
"https://api.xing.com/v1/authorize",
      "access_token_url":
"https://api.xing.com/v1/access_token",
      "authorization_header": false
    },
    "Yandex": {
      "oauth_version": "2.0",
      "dialog_url":
"https://oauth.yandex.com/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&scope={SCOPE}",
      "access_token_url":
"https://oauth.yandex.com/token"
    }
  }
}Misc/Str.php000064400000001675151161172500006730 0ustar00<?php


namespace Nextend\Framework\Misc;


use Nextend\Framework\Misc\StringPhp\MultiByte;
use Nextend\Framework\Misc\StringPhp\SingleByte;
use Nextend\Framework\Misc\StringPhp\StringInterface;
use Nextend\Framework\Pattern\SingletonTrait;

class Str {

    use SingletonTrait;

    /**
     * @var StringInterface
     */
    private static $engine;

    protected function init() {
        if (function_exists('mb_strpos')) {
            self::$engine = new MultiByte();
        } else {
            self::$engine = new SingleByte();
        }
    }

    public static function strpos($haystack, $needle, $offset = 0) {
        return self::$engine->strpos($haystack, $needle, $offset);
    }

    public static function substr($string, $start, $length = null) {
        return self::$engine->substr($string, $start, $length);
    }

    public static function strlen($string) {
        return self::$engine->strlen($string);
    }
}

Str::getInstance();Misc/StringPhp/MultiByte.php000064400000000647151161172500012012
0ustar00<?php

namespace Nextend\Framework\Misc\StringPhp;

class MultiByte implements StringInterface {

    public function strpos($haystack, $needle, $offset = 0) {
        return mb_strpos($haystack, $needle, $offset);
    }

    public function substr($string, $start, $length = null) {
        return mb_substr($string, $start, $length);
    }

    public function strlen($string) {
        return mb_strlen($string);
    }
}Misc/StringPhp/SingleByte.php000064400000000637151161172500012140
0ustar00<?php

namespace Nextend\Framework\Misc\StringPhp;

class SingleByte implements StringInterface {

    public function strpos($haystack, $needle, $offset = 0) {
        return strpos($haystack, $needle, $offset);
    }

    public function substr($string, $start, $length = null) {
        return substr($string, $start, $length);
    }

    public function strlen($string) {
        return strlen($string);
    }
}Misc/StringPhp/StringInterface.php000064400000000365151161172500013160
0ustar00<?php


namespace Nextend\Framework\Misc\StringPhp;


interface StringInterface {

    public function strpos($haystack, $needle, $offset = 0);

    public function substr($string, $start, $length = null);

    public function strlen($string);
}Misc/Zip/Creator.php000064400000014175151161172500010320 0ustar00<?php

namespace Nextend\Framework\Misc\Zip;


/**
 * Zip file creation class.
 * Makes zip files.
 *
 * @access  public
 * @package PhpMyAdmin
 * @see     Official ZIP file format:
http://www.pkware.com/support/zip-app-note
 */
class Creator {

    /**
     * Whether to echo zip as it's built or return as string from
-> file
     *
     * @var  boolean $doWrite
     */
    var $doWrite = false;

    /**
     * Array to store compressed data
     *
     * @var  array $datasec
     */
    var $datasec = array();

    /**
     * Central directory
     *
     * @var  array $ctrl_dir
     */
    var $ctrl_dir = array();

    /**
     * End of central directory record
     *
     * @var  string $eof_ctrl_dir
     */
    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";

    /**
     * Last offset position
     *
     * @var  integer $old_offset
     */
    var $old_offset = 0;


    /**
     * Sets member variable this -> doWrite to true
     * - Should be called immediately after class instantiantion
     * - If set to true, then ZIP archive are echo'ed to STDOUT as
each
     *   file is added via this -> addfile(), and central directories
are
     *   echoed to STDOUT on final call to this -> file().  Also,
     *   this -> file() returns an empty string so it is safe to issue a
     *   "echo $zipfile;" command
     *
     * @access public
     *
     * @return void
     */
    function setDoWrite() {
        $this->doWrite = true;
    } // end of the 'setDoWrite()' method

    /**
     * Converts an Unix timestamp to a four byte DOS date and time format
(date
     * in high two bytes, time in low two bytes allowing magnitude
comparison).
     *
     * @param integer $unixtime the current Unix timestamp
     *
     * @return integer the current date in a four byte DOS format
     *
     * @access private
     */
    function unix2DosTime($unixtime = 0) {
        $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);

        if ($timearray['year'] < 1980) {
            $timearray['year']    = 1980;
            $timearray['mon']     = 1;
            $timearray['mday']    = 1;
            $timearray['hours']   = 0;
            $timearray['minutes'] = 0;
            $timearray['seconds'] = 0;
        } // end if

        return (($timearray['year'] - 1980) << 25) |
($timearray['mon'] << 21) | ($timearray['mday']
<< 16) | ($timearray['hours'] << 11) |
($timearray['minutes'] << 5) |
($timearray['seconds'] >> 1);
    } // end of the 'unix2DosTime()' method


    /**
     * Adds "file" to archive
     *
     * @param string  $data file contents
     * @param string  $name name of the file in the archive (may contains
the path)
     * @param integer $time the current timestamp
     *
     * @access public
     *
     * @return void
     */
    function addFile($data, $name, $time = 0) {
        $name = str_replace('\\', '/', $name);

        $hexdtime = pack('V', $this->unix2DosTime($time));

        $fr = "\x50\x4b\x03\x04";
        $fr .= "\x14\x00"; // ver needed to extract
        $fr .= "\x00\x00"; // gen purpose bit flag
        $fr .= "\x08\x00"; // compression method
        $fr .= $hexdtime; // last mod time and date

        // "local file header" segment
        $unc_len = strlen($data);
        $crc     = crc32($data);
        $zdata   = gzcompress($data);
        $zdata   = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix
crc bug
        $c_len   = strlen($zdata);
        $fr      .= pack('V', $crc); // crc32
        $fr      .= pack('V', $c_len); // compressed filesize
        $fr      .= pack('V', $unc_len); // uncompressed filesize
        $fr      .= pack('v', strlen($name)); // length of
filename
        $fr      .= pack('v', 0); // extra field length
        $fr      .= $name;

        // "file data" segment
        $fr .= $zdata;

        // echo this entry on the fly, ...
        if ($this->doWrite) {
            echo $fr;
        } else { // ... OR add this entry to array
            $this->datasec[] = $fr;
        }

        // now add to central directory record
        $cdrec = "\x50\x4b\x01\x02";
        $cdrec .= "\x00\x00"; // version made by
        $cdrec .= "\x14\x00"; // version needed to extract
        $cdrec .= "\x00\x00"; // gen purpose bit flag
        $cdrec .= "\x08\x00"; // compression method
        $cdrec .= $hexdtime; // last mod time & date
        $cdrec .= pack('V', $crc); // crc32
        $cdrec .= pack('V', $c_len); // compressed filesize
        $cdrec .= pack('V', $unc_len); // uncompressed filesize
        $cdrec .= pack('v', strlen($name)); // length of filename
        $cdrec .= pack('v', 0); // extra field length
        $cdrec .= pack('v', 0); // file comment length
        $cdrec .= pack('v', 0); // disk number start
        $cdrec .= pack('v', 0); // internal file attributes
        $cdrec .= pack('V', 32); // external file attributes
        // - 'archive' bit set

        $cdrec            .= pack('V', $this->old_offset); //
relative offset of local header
        $this->old_offset += strlen($fr);

        $cdrec .= $name;

        // optional extra field, file comment goes here
        // save to central directory
        $this->ctrl_dir[] = $cdrec;
    } // end of the 'addFile()' method


    /**
     * Echo central dir if ->doWrite==true, else build string to return
     *
     * @return string  if ->doWrite {empty string} else the ZIP file
contents
     *
     * @access public
     */
    function file() {
        $ctrldir = implode('', $this->ctrl_dir);
        $header  = $ctrldir . $this->eof_ctrl_dir . pack('v',
sizeof($this->ctrl_dir)) . //total #of entries "on this disk"
            pack('v', sizeof($this->ctrl_dir)) . //total #of
entries overall
            pack('V', strlen($ctrldir)) . //size of central dir
            pack('V', $this->old_offset) . //offset to start
of central dir
            "\x00\x00"; //.zip file comment length

        if ($this->doWrite) { // Send central directory & end ctrl
dir to STDOUT
            echo $header;

            return ""; // Return empty string
        } else { // Return entire ZIP archive as string
            $data = implode('', $this->datasec);

            return $data . $header;
        }
    } // end of the 'file()' method
}Misc/Zip/Reader/Custom.php000064400000013100151161172500011360
0ustar00<?php

namespace Nextend\Framework\Misc\Zip\Reader;

use Nextend\Framework\Misc\Zip\ReaderInterface;
use Nextend\Framework\Notification\Notification;

class Custom implements ReaderInterface {

    private $fileHandle;

    private $file;

    public function read($path) {
        $this->file = $path;

        return $this->extract();
    }

    private function extract() {
        $extractedData = array();

        if (!is_readable(dirname($this->file))) {
            Notification::error(sprintf(n2_('%s is not
readable'), dirname($this->file)));

            return false;
        }

        if (!$this->file || !is_file($this->file)) return false;
        $filesize = sprintf('%u', filesize($this->file));

        $this->fileHandle = fopen($this->file, 'rb');

        $EofCentralDirData =
$this->_findEOFCentralDirectoryRecord($filesize);
        if (!is_array($EofCentralDirData)) return false;
        $centralDirectoryHeaderOffset =
$EofCentralDirData['centraldiroffset'];
        for ($i = 0; $i < $EofCentralDirData['totalentries'];
$i++) {
            rewind($this->fileHandle);
            fseek($this->fileHandle, $centralDirectoryHeaderOffset);
            $centralDirectoryData         =
$this->_readCentralDirectoryData();
            $centralDirectoryHeaderOffset += 46 +
$centralDirectoryData['filenamelength'] +
$centralDirectoryData['extrafieldlength'] +
$centralDirectoryData['commentlength'];
            if (!is_array($centralDirectoryData) ||
substr($centralDirectoryData['filename'], -1) == '/')
continue;
            $data =
$this->_readLocalFileHeaderAndData($centralDirectoryData);
            if (!$data) continue;

            $dir      =
dirname($centralDirectoryData['filename']);
            $fileName =
basename($centralDirectoryData['filename']);
            if ($dir != '.' && $dir != '') {
                if (!isset($extractedData[$dir])) {
                    $extractedData[$dir] = array();
                }
                $extractedData[$dir][$fileName] = $data;
            } else {
                $extractedData[$fileName] = $data;
            }
        }
        fclose($this->fileHandle);

        return $extractedData;
    }

    private function _findEOFCentralDirectoryRecord($filesize) {
        fseek($this->fileHandle, $filesize - 22);
        $EofCentralDirSignature = unpack('Vsignature',
fread($this->fileHandle, 4));
        if ($EofCentralDirSignature['signature'] != 0x06054b50) {
            $maxLength = 65535 + 22;
            $maxLength > $filesize && $maxLength = $filesize;
            fseek($this->fileHandle, $filesize - $maxLength);
            $searchPos = ftell($this->fileHandle);
            while ($searchPos < $filesize) {
                fseek($this->fileHandle, $searchPos);
                $sigData = unpack('Vsignature',
fread($this->fileHandle, 4));
                if ($sigData['signature'] == 0x06054b50) {
                    break;
                }
                $searchPos++;
            }
        }
        $EofCentralDirData =
unpack('vdisknum/vdiskstart/vcentraldirnum/vtotalentries/Vcentraldirsize/Vcentraldiroffset/vcommentlength',
fread($this->fileHandle, 18));

        return $EofCentralDirData;
    }

    private function _readCentralDirectoryData() {
        $centralDirectorySignature = unpack('Vsignature',
fread($this->fileHandle, 4));
        if ($centralDirectorySignature['signature'] !=
0x02014b50) return false;
        $centralDirectoryData = fread($this->fileHandle, 42);
        $centralDirectoryData =
unpack('vmadeversion/vextractversion/vflag/vcompressmethod/vmodtime/vmoddate/Vcrc/Vcompressedsize/Vuncompressedsize/vfilenamelength/vextrafieldlength/vcommentlength/vdiskstart/vinternal/Vexternal/Vlocalheaderoffset',
$centralDirectoryData);
        $centralDirectoryData['filenamelength'] &&
$centralDirectoryData['filename'] = fread($this->fileHandle,
$centralDirectoryData['filenamelength']);

        return $centralDirectoryData;
    }

    private function _readLocalFileHeaderAndData($centralDirectoryData) {
        fseek($this->fileHandle,
$centralDirectoryData['localheaderoffset']);
        $localFileHeaderSignature = unpack('Vsignature',
fread($this->fileHandle, 4));
        if ($localFileHeaderSignature['signature'] != 0x04034b50)
return false;
        $localFileHeaderData = fread($this->fileHandle, 26);
        $localFileHeaderData =
unpack('vextractversion/vflag/vcompressmethod/vmodtime/vmoddate/Vcrc/Vcompressedsize/Vuncompressedsize/vfilenamelength/vextrafieldlength',
$localFileHeaderData);
        $localFileHeaderData['filenamelength'] &&
$localFileHeaderData['filename'] = fread($this->fileHandle,
$localFileHeaderData['filenamelength']);
        if
(!$this->_checkLocalFileHeaderAndCentralDir($localFileHeaderData,
$centralDirectoryData)) return false;

        if ($localFileHeaderData['flag'] & 1) return false;
        $compressedData = fread($this->fileHandle,
$localFileHeaderData['compressedsize']);
        $data           = $this->_unCompressData($compressedData,
$localFileHeaderData['compressmethod']);

        if (crc32($data) != $localFileHeaderData['crc'] ||
strlen($data) != $localFileHeaderData['uncompressedsize']) return
false;

        return $data;
    }

    private function _unCompressData($data, $compressMethod) {
        if (!$compressMethod) return $data;
        switch ($compressMethod) {
            case 8 :
                $data = gzinflate($data);
                break;
            default :
                return false;
                break;
        }

        return $data;
    }

    private function
_checkLocalFileHeaderAndCentralDir($localFileHeaderData,
$centralDirectoryData) {
        return true;
    }
}Misc/Zip/Reader/ZipExtension.php000064400000001636151161172500012560
0ustar00<?php

namespace Nextend\Framework\Misc\Zip\Reader;

use Nextend\Framework\Misc\Zip\ReaderInterface;

class ZipExtension implements ReaderInterface {

    public function read($path) {

        $zip = new \ZipArchive();

        if (!$zip->open($path)) {
            return array();
        }

        $data = array();

        for ($i = 0; $i < $zip->numFiles; $i++) {

            $stat = $zip->statIndex($i);

            $this->recursiveRead($data, explode('/',
$stat['name']), $zip->getFromIndex($i));

        }

        $zip->close();

        return $data;
    }

    private function recursiveRead(&$data, $parts, $content) {
        if (count($parts) == 1) {
            $data[$parts[0]] = $content;
        } else {
            if (!isset($data[$parts[0]])) {
                $data[$parts[0]] = array();
            }
            $this->recursiveRead($data[array_shift($parts)], $parts,
$content);
        }
    }
}Misc/Zip/Reader.php000064400000000671151161172500010117 0ustar00<?php

namespace Nextend\Framework\Misc\Zip;

use Nextend\Framework\Misc\Zip\Reader\Custom;
use Nextend\Framework\Misc\Zip\Reader\ZipExtension;

class Reader {

    public static function read($path) {

        if (class_exists('ZipArchive') &&
strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
            $reader = new ZipExtension();
        } else {
            $reader = new Custom();
        }

        return $reader->read($path);
    }
}Misc/Zip/ReaderInterface.php000064400000000156151161172500011736
0ustar00<?php

namespace Nextend\Framework\Misc\Zip;


interface ReaderInterface {

    public function read($path);
}Model/AbstractModel.php000064400000000613151161172510011041
0ustar00<?php


namespace Nextend\Framework\Model;


use Nextend\Framework\Pattern\MVCHelperTrait;

abstract class AbstractModel {

    use MVCHelperTrait;

    /**
     * AbstractModel constructor.
     *
     * @param MVCHelperTrait $helper
     */
    public function __construct($helper) {

        $this->setMVCHelper($helper);
        $this->init();
    }

    protected function init() {

    }
}Model/AbstractModelTable.php000064400000001047151161172510012013
0ustar00<?php

namespace Nextend\Framework\Model;


use Nextend\Framework\Database\AbstractPlatformConnectorTable;

abstract class AbstractModelTable extends AbstractModel {

    /**
     * @var AbstractPlatformConnectorTable
     */
    protected $table;

    protected function init() {

        $this->table = $this->createConnectorTable();
    }

    /**
     * @return AbstractPlatformConnectorTable
     */
    protected abstract function createConnectorTable();

    public function getTableName() {
        return $this->table->getTableName();
    }
}Model/ApplicationSection.php000064400000004575151161172510012120
0ustar00<?php

namespace Nextend\Framework\Model;

class ApplicationSection {

    private $application = 'system';

    /**
     * Quick cache implementation to prevent duplicate queries. It might
have bugs.
     *
     * @var array
     */
    protected $cache = array();

    public function __construct($application) {
        $this->application = $application;
    }

    public function getById($id, $section) {
        return Section::getById($id, $section);
    }

    public function setById($id, $value) {
        $this->cache = array();

        return Section::setById($id, $value);
    }

    public function get($section, $referenceKey = null, $default = null) {

        if (isset($this->cache[$section . '///' .
$referenceKey])) {
            return $this->cache[$section . '///' .
$referenceKey];
        }

        $attributes = array(
            "application" => $this->application,
            "section"     => $section
        );

        if ($referenceKey !== null) {
            $attributes['referencekey'] = $referenceKey;
        }
        $result =
Section::$tableSectionStorage->findByAttributes($attributes);
        if (is_array($result)) {
            $this->cache[$section . '///' . $referenceKey] =
$result['value'];

            return $result['value'];
        }

        return $default;
    }

    public function getAll($section, $referenceKey = null) {
        return Section::getAll($this->application, $section,
$referenceKey);
    }

    public function set($section, $referenceKey, $value) {
        if (isset($this->cache[$section . '///' .
$referenceKey])) {
            unset($this->cache[$section . '///' .
$referenceKey]);
        }

        Section::set($this->application, $section, $referenceKey,
$value);
    }

    public function add($section, $referenceKey, $value) {
        if (isset($this->cache[$section . '///' .
$referenceKey])) {
            unset($this->cache[$section . '///' .
$referenceKey]);
        }

        return Section::add($this->application, $section, $referenceKey,
$value);
    }

    public function delete($section, $referenceKey = null) {
        if (isset($this->cache[$section . '///' .
$referenceKey])) {
            unset($this->cache[$section . '///' .
$referenceKey]);
        }

        return Section::delete($this->application, $section,
$referenceKey);
    }

    public function deleteById($id) {
        return Section::deleteById($id);
    }
}Model/Section.php000064400000011165151161172510007725 0ustar00<?php

namespace Nextend\Framework\Model;

use Nextend\Framework\Database\AbstractPlatformConnectorTable;
use Nextend\Framework\Database\Database;
use Nextend\Framework\Plugin;

class Section {

    /** @var AbstractPlatformConnectorTable */
    public static $tableSectionStorage;

    public function __construct() {

        self::$tableSectionStorage =
Database::getTable("nextend2_section_storage");
    }

    public static function get($application, $section, $referenceKey =
null) {
        $attributes = array(
            "application" => $application,
            "section"     => $section
        );

        if ($referenceKey !== null) {
            $attributes['referencekey'] = $referenceKey;
        }

        return
self::$tableSectionStorage->findByAttributes($attributes);
    }

    public static function getById($id, $section = null) {
        static $cache = array();
        if ($id === 0) {
            return null;
        }
        if (!isset($cache[$section])) {
            $cache[$section] = array();
        } else if (isset($cache[$section][$id])) {
            return $cache[$section][$id];
        }

        $cache[$section][$id] = null;
        if ($section) {
            Plugin::doAction($section, array(
                $id,
                &$cache[$section][$id]
            ));
            if ($cache[$section][$id]) {
                return $cache[$section][$id];
            }
        }

        $cache[$section][$id] =
self::$tableSectionStorage->findByAttributes(array(
            "id" => $id
        ));
        if ($section && $cache[$section][$id]['section']
!= $section) {
            $cache[$section][$id] = null;

            return $cache[$section][$id];
        }

        return $cache[$section][$id];
    }

    public static function getAll($application, $section, $referenceKey =
null) {
        $attributes = array(
            "application" => $application,
            "section"     => $section
        );

        if ($referenceKey !== null) {
            $attributes['referencekey'] = $referenceKey;
        }

        $rows =
self::$tableSectionStorage->findAllByAttributes($attributes, array(
            "id",
            "referencekey",
            "value",
            "system",
            "editable"
        ));

        Plugin::doAction($application . $section, array(
            $referenceKey,
            &$rows
        ));

        return $rows;
    }

    public static function add($application, $section, $referenceKey,
$value, $system = 0, $editable = 1) {
        $row = array(
            "application"  => $application,
            "section"      => $section,
            "referencekey" => '',
            "value"        => $value,
            "system"       => $system,
            "editable"     => $editable
        );

        if ($referenceKey !== null) {
            $row["referencekey"] = $referenceKey;
        }

        self::$tableSectionStorage->insert($row);

        return self::$tableSectionStorage->insertId();
    }


    public static function set($application, $section, $referenceKey,
$value, $system = 0, $editable = 1) {

        $result = self::getAll($application, $section, $referenceKey);

        if (empty($result)) {
            return self::add($application, $section, $referenceKey, $value,
$system, $editable);
        } else {
            $attributes = array(
                "application" => $application,
                "section"     => $section
            );

            if ($referenceKey !== null) {
                $attributes['referencekey'] = $referenceKey;
            }
            self::$tableSectionStorage->update(array('value'
=> $value), $attributes);

            return true;
        }
    }

    public static function setById($id, $value) {

        $result = self::getById($id);

        if ($result !== null && $result['editable']) {
            self::$tableSectionStorage->update(array('value'
=> $value), array(
                "id" => $id
            ));

            return true;
        }

        return false;
    }

    public static function delete($application, $section, $referenceKey =
null) {

        $attributes = array(
            "application" => $application,
            "section"     => $section,
            "system"      => 0
        );

        if ($referenceKey !== null) {
            $attributes['referencekey'] = $referenceKey;
        }

        self::$tableSectionStorage->deleteByAttributes($attributes);

        return true;
    }

    public static function deleteById($id) {

        self::$tableSectionStorage->deleteByAttributes(array(
            "id"     => $id,
            "system" => 0
        ));

        return true;
    }
}

new
Section();Model/StorageSectionManager.php000064400000000722151161172510012542
0ustar00<?php


namespace Nextend\Framework\Model;


class StorageSectionManager {

    /** @var ApplicationSection[] */
    private static $storageTypes = array();

    /**
     * @param $type
     *
     * @return ApplicationSection
     */
    public static function getStorage($type) {

        if (!isset(self::$storageTypes[$type])) {
            self::$storageTypes[$type] = new ApplicationSection($type);
        }

        return self::$storageTypes[$type];
    }
}Notification/Notification.php000064400000012224151161172510012332
0ustar00<?php

namespace Nextend\Framework\Notification;

use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Plugin;
use Nextend\Framework\Session\Session;

class Notification {

    /**
     * @var bool|array
     */
    private static $error = false;
    /**
     * @var bool|array
     */
    private static $success = false;
    /**
     * @var bool|array
     */
    private static $notice = false;

    private static $flushed = false;

    public function __construct() {

        Plugin::addAction('beforeSessionSave', array(
            '\\Nextend\\Framework\\Notification\\Notification',
            'storeInSession'
        ));
    }


    private static function loadSessionError() {
        if (self::$error === false) {
            if (Platform::isAdmin()) {
                self::$error = Session::get('error', array());
            } else {
                self::$error = array();
            }
        }
    }

    private static function loadSessionSuccess() {
        if (self::$success === false) {
            if (Platform::isAdmin()) {
                self::$success = Session::get('success',
array());
            } else {
                self::$success = array();
            }
        }
    }

    private static function loadSessionNotice() {
        if (self::$notice === false) {
            if (Platform::isAdmin()) {
                self::$notice = Session::get('notice', array());
            } else {
                self::$notice = array();
            }
        }
    }

    public static function hasErrors() {

        self::loadSessionError();

        return !empty(self::$error);
    }

    public static function error($message = '', $parameters =
array()) {
        self::loadSessionError();
        self::$error[] = array(
            $message,
            $parameters
        );
    }

    public static function displayPlainErrors() {

        if (Platform::isAdmin() && is_array(self::$error)
&& count(self::$error)) {
            foreach (self::$error as $error) {
                echo '<div style="border: 1px solid red;
margin-bottom: 20px; padding: 10px 20px; max-width: 400px;">'
. $error[0] . '</div>';
            }
            self::$error = array();
        }
    }

    public static function success($message = '', $parameters =
array()) {
        self::loadSessionSuccess();
        self::$success[] = array(
            $message,
            $parameters
        );
    }

    public static function notice($message = '', $parameters =
array()) {
        self::loadSessionNotice();
        self::$notice[] = array(
            $message,
            $parameters
        );
    }

    public static function show() {

        self::loadSessionError();

        if (is_array(self::$error) && count(self::$error)) {
            foreach (self::$error as $error) {
                Js::addInline("_N2.Notification.error(" .
json_encode($error[0]) . ", " . json_encode($error[1]) .
");");
            }
            self::$error = array();
        }

        self::loadSessionSuccess();

        if (is_array(self::$success) && count(self::$success)) {
            foreach (self::$success as $success) {

                Js::addInline("_N2.Notification.success(" .
json_encode($success[0]) . ", " . json_encode($success[1]) .
");");
            }
            self::$success = array();
        }

        self::loadSessionNotice();

        if (is_array(self::$notice) && count(self::$notice)) {
            foreach (self::$notice as $notice) {

                Js::addInline("_N2.Notification.notice(" .
json_encode($notice[0]) . ", " . json_encode($notice[1]) .
");");
            }
            self::$notice = array();
        }

        self::$flushed = true;

    }

    public static function showAjax() {

        self::loadSessionError();
        $messages = array();

        if (is_array(self::$error) && count(self::$error)) {
            $messages['error'] = array();
            foreach (self::$error as $error) {
                $messages['error'][] = $error;
            }
            self::$error = array();
        }

        self::loadSessionSuccess();

        if (is_array(self::$success) && count(self::$success)) {
            $messages['success'] = array();
            foreach (self::$success as $success) {
                $messages['success'][] = $success;
            }
            self::$success = array();
        }

        self::loadSessionNotice();

        if (is_array(self::$notice) && count(self::$notice)) {
            $messages['notice'] = array();
            foreach (self::$notice as $notice) {
                $messages['notice'][] = $notice;
            }
            self::$notice = array();
        }

        self::$flushed = true;
        if (count($messages)) {
            return $messages;
        }

        return false;
    }

    public static function storeInSession() {
        if (self::$flushed) {
            Session::delete('error');
            Session::delete('success');
            Session::delete('notice');
        } else {
            Session::set('error', self::$error);
            Session::set('success', self::$success);
            Session::set('notice', self::$notice);
        }
    }
}

new Notification();PageFlow.php000064400000001116151161172510006760
0ustar00<?php


namespace Nextend\Framework;


class PageFlow {

    public static function markApplicationEnd() {

        Plugin::doAction('exit');
    }

    public static function exitApplication() {

        self::markApplicationEnd();

        exit;
    }

    public static function cleanOutputBuffers() {
        $handlers = ob_list_handlers();
        while (count($handlers) > 0 &&
$handlers[count($handlers) - 1] != 'ob_gzhandler' &&
$handlers[count($handlers) - 1] != 'zlib output compression') {
            ob_end_clean();
            $handlers = ob_list_handlers();
        }
    }
}Parser/Color.php000064400000005755151161172510007603 0ustar00<?php

namespace Nextend\Framework\Parser;


/**
 *
 * Color values manipulation utilities. Provides methods to convert from
and to
 * Hex, RGB, HSV and HSL color representattions.
 *
 * Several color conversion logic are based on pseudo-code from
 * http://www.easyrgb.com/math.php
 *
 * @category Lux
 *
 * @package  Lux_Color
 *
 * @author   Rodrigo Moraes <rodrigo.moraes@gmail.com>
 *
 * @license  http://www.opensource.org/licenses/bsd-license.php BSD License
 *
 * @version  $Id$
 *
 */
class Color {

    public static function colorToRGBA($value) {
        $rgba = self::hex2rgba($value);

        return 'RGBA(' . $rgba[0] . ',' . $rgba[1] .
',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) .
')';
    }

    public static function hex2alpha($value) {
        if (strlen($value) == 6) {
            return 127;
        }

        return intval(hexdec(substr($value, 6, 2)) / 2);
    }

    public static function hex2opacity($value) {
        return self::hex2alpha($value) / 127;
    }

    public static function colorToSVG($value) {
        $rgba = self::hex2rgba($value);

        return array(
            substr($value, 0, 6),
            round($rgba[3] / 127, 2)
        );
    }

    /**
     *
     * Converts hexadecimal colors to RGB.
     *
     * @param string $hex Hexadecimal value. Accepts values with 3 or 6
numbers,
     *                    with or without #, e.g., CCC, #CCC, CCCCCC or
#CCCCCC.
     *
     * @return array RGB values: 0 => R, 1 => G, 2 => B
     *
     */
    public static function hex2rgb($hex) {


        // Remove #.
        if (strpos($hex, '#') === 0) {
            $hex = substr($hex, 1);
        }
        if (strlen($hex) == 3) {
            $hex .= $hex;
        }
        if (strlen($hex) != 6) {
            return false;
        }

        // Convert each tuple to decimal.
        $r = hexdec(substr($hex, 0, 2));
        $g = hexdec(substr($hex, 2, 2));
        $b = hexdec(substr($hex, 4, 2));

        return array(
            $r,
            $g,
            $b
        );
    }

    public static function hex2rgba($hex) {


        // Remove #.
        if (strpos($hex, '#') === 0) {
            $hex = substr($hex, 1);
        }
        if (strlen($hex) == 6) {
            $hex .= 'ff';
        }
        if (strlen($hex) != 8) {
            return false;
        }

        // Convert each tuple to decimal.
        $r = hexdec(substr($hex, 0, 2));
        $g = hexdec(substr($hex, 2, 2));
        $b = hexdec(substr($hex, 4, 2));
        $a = intval(hexdec(substr($hex, 6, 2)) / 2);

        return array(
            $r,
            $g,
            $b,
            $a
        );
    }

    public static function hex82hex($hex) {


        // Remove #.
        if (strpos($hex, '#') === 0) {
            $hex = substr($hex, 1);
        }
        if (strlen($hex) == 6) {
            $hex .= 'ff';
        }
        if (strlen($hex) != 8) {
            return false;
        }

        return array(
            substr($hex, 0, 6),
            substr($hex, 6, 2)
        );
    }

}Parser/Common.php000064400000001035151161172510007740 0ustar00<?php

namespace Nextend\Framework\Parser;

class Common {

    /**
     * @param      $str
     * @param bool $concat
     *
     * @return array
     */
    public static function parse($str, $concat = false) {

        $v = explode("|*|", $str);
        for ($i = 0; $i < count($v); $i++) {
            if (strpos($v[$i], "||") !== false) {
                if ($concat === false) $v[$i] = explode("||",
$v[$i]); else $v[$i] = str_replace("||", $concat, $v[$i]);
            }
        }

        return count($v) == 1 ? $v[0] : $v;
    }
}Parser/Font.php000064400000011103151161172510007413 0ustar00<?php

namespace Nextend\Framework\Parser;

use Nextend\Framework\Asset\Fonts\Google\Google;

class Font {

    /**
     * @var array
     */
    private $_font;

    public function __construct($font) {
        $this->_font = json_decode($font, true);
    }

    /**
     * @param string $tab
     *
     * @return string
     */
    public function printTab($tab = '') {
        if ($tab == '') $tab =
$this->_font['firsttab'];
        $style = '';
        if (isset($this->_font[$tab])) {
            $tab   = &$this->_font[$tab];
            $extra = '';
            if (isset($tab['extra'])) {
                $extra = $tab['extra'];
                unset($tab['extra']);
            }
            foreach ($tab AS $k => $v) {
                $style .= $this->parse($k, $v);
            }
            $style .= $this->parse('extra', $extra);
        }

        return $style;
    }

    /**
     * @param        $target
     * @param string $source
     */
    public function mixinTab($target, $source = '') {
        if ($source == '') $source =
$this->_font['firsttab'];
        $this->_font[$target] = array_merge($this->_font[$source],
$this->_font[$target]);
    }

    /**
     * @param $property
     * @param $value
     *
     * @return mixed
     */
    public function parse($property, $value) {
        $fn = 'parse' . $property;

        return $this->$fn($value);
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseColor($v) {

        $hex = Color::hex82hex($v);

        if ($hex[1] == 'ff') {
            return 'color: #' . $hex[0] . ';';
        }

        $rgba = Color::hex2rgba($v);

        return 'color: RGBA(' . $rgba[0] . ',' .
$rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127,
2) . ');';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseSize($v) {
        return 'font-size:' . Common::parse($v, '') .
';';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseTShadow($v) {
        $v    = Common::parse($v);
        $rgba = Color::hex2rgba($v[3]);
        if ($v[0] == 0 && $v[1] == 0 && $v[2] == 0) return
'text-shadow: none;';

        return 'text-shadow: ' . $v[0] . 'px ' . $v[1]
. 'px ' . $v[2] . 'px RGBA(' . $rgba[0] . ','
. $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] /
127, 2) . ');';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseAfont($v) {
        return 'font-family: ' . $this->loadFont($v) .
';';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseLineHeight($v) {
        if ($v == '') return '';

        return 'line-height: ' . $v . ';';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseBold($v) {
        if ($v == '1') return 'font-weight: bold;';

        return 'font-weight: normal;';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseItalic($v) {
        if ($v == '1') return 'font-style: italic;';

        return 'font-style: normal;';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseUnderline($v) {
        if ($v == '1') return 'text-decoration:
underline;';

        return 'text-decoration: none;';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parsePaddingLeft($v) {
        return '';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseAlign($v) {
        return 'text-align: ' . $v . ';';
    }

    /**
     * @param $v
     *
     * @return string
     */
    public function parseReset($v) {
        return '';
    }

    public function parseExtra($v) {
        return $v;
    }

    /**
     * @param $families
     *
     * @return mixed
     */
    public function loadFont($families) {
        preg_match_all("/google\(.*?family=(.*?)\);\)/",
$families, $out, PREG_SET_ORDER);
        foreach ($out AS $f) {
            preg_match('/(.*?)(:(.*?))?(&subset=(.*))?$/',
$f[1], $g);
            $family = str_replace('+', ' ', $g[1]);
            $styles = 400;
            if (isset($g[3]) && !empty($g[3])) {
                $styles = $g[3];
            }
            $subset = 'latin';
            if (isset($g[5])) {
                $subset = $g[5];
            }
            Google::addSubset($subset);
            foreach (explode(',', $styles) AS $style) {
                Google::addFont($family, $style);
            }
            $families = str_replace($f[0], "'" . $family .
"'", $families);
        }

        return $families;
    }
}Parser/Link/Lightbox.php000064400000006252151161172510011173
0ustar00<?php
/**
 * @required N2SSPRO
 */

namespace Nextend\Framework\Parser\Link;

use Nextend\Framework\Asset\Predefined;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;

class Lightbox implements ParserInterface {

    public function parse($argument, &$attributes) {
        if (!empty($argument)) {

            $attributes['data-n2-lightbox'] = '';

            if (!isset($attributes['class']))
$attributes['class'] = '';
            $attributes['class'] .= " n2-lightbox-trigger
nolightbox no-lightbox";

            Predefined::loadLiteBox();

            $realUrls = array();
            $titles   = array();

            //JSON V2 storage
            if ($argument[0] == '{') {
                $data = json_decode($argument, true);

                $argument =
ResourceTranslator::toUrl(array_shift($data['urls']));
                if (!empty($data['titles'][0])) {
                    $attributes['data-title'] =
array_shift($data['titles']);
                }

                if (count($data['urls'])) {
                    if ($data['autoplay'] > 0) {
                        $attributes['data-autoplay'] =
intval($data['autoplay']);
                    }

                    for ($i = 0; $i < count($data['urls']);
$i++) {
                        if (!empty($data['urls'][$i])) {
                            $realUrls[] =
ResourceTranslator::toUrl($data['urls'][$i]);
                            $titles[]   =
!empty($data['titles'][$i]) ? $data['titles'][$i] :
'';
                        }
                    }
                    $attributes['data-n2-lightbox-urls']   =
implode(',', $realUrls);
                    $attributes['data-n2-lightbox-titles'] =
implode('|||', $titles);
                    if (count($realUrls)) {
                        $attributes['data-litebox-group'] =
md5(uniqid(mt_rand(), true));
                    }
                }

            } else {

                $urls     = explode(',', $argument);
                $parts    = explode(';', array_shift($urls), 2);
                $argument = ResourceTranslator::toUrl($parts[0]);
                if (!empty($parts[1])) {
                    $attributes['data-title'] = $parts[1];
                }

                if (count($urls)) {
                    if (intval($urls[count($urls) - 1]) > 0) {
                        $attributes['data-autoplay'] =
intval(array_pop($urls));
                    }
                    for ($i = 0; $i < count($urls); $i++) {
                        if (!empty($urls[$i])) {
                            $parts      = explode(';', $urls[$i],
2);
                            $realUrls[] =
ResourceTranslator::toUrl($parts[0]);
                            $titles[]   = !empty($parts[1]) ? $parts[1] :
'';
                        }
                    }
                    $attributes['data-n2-lightbox-urls']   =
implode(',', $realUrls);
                    $attributes['data-n2-lightbox-titles'] =
implode('|||', $titles);
                    if (count($realUrls)) {
                        $attributes['data-litebox-group'] =
md5(uniqid(mt_rand(), true));
                    }
                }
            }
        }

        return $argument;
    }
}Parser/Link/ParserInterface.php000064400000000203151161172510012456
0ustar00<?php

namespace Nextend\Framework\Parser\Link;

interface ParserInterface {

    public function parse($argument, &$attributes);
}Parser/Link/ScrollTo.php000064400000003107151161172510011150
0ustar00<?php

namespace Nextend\Framework\Parser\Link;

use Nextend\Framework\Asset\Js\Js;
use Nextend\SmartSlider3\Settings;

class ScrollTo implements ParserInterface {

    public function __construct() {

        Js::addInline('window.n2ScrollSpeed=' .
json_encode(intval(Settings::get('smooth-scroll-speed', 400))) .
';');
    }

    public function parse($argument, &$attributes) {

        switch ($argument) {
            case 'top':
                $onclick = 'n2ss.scroll(event,
"top");';
                break;
            case 'bottom':
                $onclick = 'n2ss.scroll(event,
"bottom");';
                break;
            case 'beforeSlider':
                $onclick = 'n2ss.scroll(event, "before",
this.closest(".n2-ss-slider"));';
                break;
            case 'afterSlider':
                $onclick = 'n2ss.scroll(event, "after",
this.closest(".n2-ss-slider"));';
                break;
            case 'nextSlider':
                $onclick = 'n2ss.scroll(event, "next", this,
".n2-section-smartslider");';
                break;
            case 'previousSlider':
                $onclick = 'n2ss.scroll(event, "previous",
this, ".n2-section-smartslider");';
                break;
            default:
                if (is_numeric($argument)) {
                    $onclick = 'n2ss.scroll(event,
"element", "#n2-ss-' . $argument .
'");';
                } else {
                    $onclick = 'n2ss.scroll(event,
"element", "' . $argument . '");';
                }
                break;
        }
        $attributes['onclick'] = $onclick;

        return '#';
    }
}Parser/Link/ScrollToAlias.php000064400000000476151161172510012130
0ustar00<?php

namespace Nextend\Framework\Parser\Link;

use Nextend\Framework\Parser\Link;

class ScrollToAlias implements ParserInterface {

    public function parse($argument, &$attributes) {

        return Link::getParser('ScrollTo')
                   ->parse('[data-alias=\"' . $argument .
'\"]', $attributes);
    }
}Parser/Link.php000064400000003130151161172510007403 0ustar00<?php

namespace Nextend\Framework\Parser;

use Nextend\Framework\Parser\Link\ParserInterface;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;

class Link {

    /**
     * @var ParserInterface[]
     */
    private static $parsers = array();

    public static $registeredNamespaces = array(
        '\\Nextend\\Framework\\Parser\\Link\\',
        '\\Nextend\\SmartSlider3\\Parser\\Link\\'
    );

    public static function parse($url, &$attributes, $isEditor = false)
{
        if ($url == '#' || $isEditor) {
            $attributes['onclick'] = "return false;";
        } else {
            preg_match('/^([a-zA-Z]+)\[(.*)]$/', $url, $matches);
            if (!empty($matches)) {
                $matches[1] = ucfirst($matches[1]);
                $parser     = self::getParser($matches[1]);
                if ($parser) {
                    $url = $parser->parse($matches[2], $attributes);
                }
            } else {
                $url = ResourceTranslator::toUrl($url);
            }
        }

        return $url;
    }

    public static function getParser($className) {
        if (!isset(self::$parsers[$className])) {

            foreach (self::$registeredNamespaces AS $namespace) {
                $class = $namespace . $className;
                if (class_exists($class)) {
                    self::$parsers[$className] = new $class();
                    break;
                }
            }
            if (!isset(self::$parsers[$className])) {
                self::$parsers[$className] = false;
            }
        }

        return self::$parsers[$className];
    }
}Parser/Style.php000064400000005310151161172510007610 0ustar00<?php

namespace Nextend\Framework\Parser;

use Nextend\Framework\Misc\Base64;

class Style {

    private $_style;

    public function __construct($style) {
        $decoded = $style;
        if ($decoded[0] != '{') {
            $decoded = Base64::decode($decoded);
        }

        $this->_style = json_decode($decoded, true);
    }

    public function printTab($tab = '') {
        $style = '';
        if (isset($this->_style[$tab])) {
            $tab   = &$this->_style[$tab];
            $extra = '';
            if (isset($tab['extra'])) {
                $extra = $tab['extra'];
                unset($tab['extra']);
            }
            foreach ($tab AS $k => $v) {
                $style .= $this->parse($k, $v);
            }
            $style .= $this->parse('extra', $extra);
        }

        return $style;
    }

    public function parse($property, $value) {
        $fn = 'parse' . $property;

        return $this->$fn($value);
    }

    public function parseBackgroundColor($v) {
        $hex = Color::hex82hex($v);
        if ($hex[1] == 'ff') {
            return 'background: #' . $hex[0] . ';';
        }

        $rgba = Color::hex2rgba($v);

        return 'background: RGBA(' . $rgba[0] . ',' .
$rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127,
2) . ');';
    }

    public function parsePadding($v) {
        $padding   = explode('|*|', $v);
        $unit      = array_pop($padding);
        $padding[] = '';

        return 'padding:' . implode($unit . ' ',
$padding) . ';';
    }

    public function parseBoxShadow($v) {
        $boxShadow = explode('|*|', $v);

        if ($boxShadow[0] == '0' && $boxShadow[1] ==
'0' && $boxShadow[2] == '0' &&
$boxShadow[3] == '0') {
            return 'box-shadow: none;';
        } else {
            $rgba = Color::hex2rgba($boxShadow[4]);

            return 'box-shadow: ' . $boxShadow[0] . 'px
' . $boxShadow[1] . 'px ' . $boxShadow[2] . 'px '
. $boxShadow[3] . 'px RGBA(' . $rgba[0] . ',' .
$rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127,
2) . ');';
        }
    }

    public function parseBorder($v) {
        $border = explode('|*|', $v);
        $style  = 'border-width: ' . $border[0] . 'px';
        $style  .= 'border-style: ' . $border[1] . ';';
        $rgba   = Color::hex2rgba($border[2]);
        $style  .= 'border-color: #' . substr($border[2], 0, 6) .
"; border-color: RGBA(" . $rgba[0] . ',' . $rgba[1] .
',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) .
');';

        return $style;
    }

    public function parseBorderRadius($v) {
        $radius   = explode('|*|', $v);
        $radius[] = '';

        return 'border-radius:' . $v . 'px;';
    }

    public function parseExtra($v) {
        return str_replace("\n", '', $v);
    }
}Pattern/GetAssetsPathTrait.php000064400000000621151161172510012414
0ustar00<?php


namespace Nextend\Framework\Pattern;


use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Url\Url;

trait GetAssetsPathTrait {

    use GetPathTrait;

    public static function getAssetsPath() {

        return Platform::filterAssetsPath(self::getPath() .
'/Assets');
    }

    public static function getAssetsUri() {
        return Url::pathToUri(self::getAssetsPath());
    }
}Pattern/GetPathTrait.php000064400000000367151161172510011240
0ustar00<?php

namespace Nextend\Framework\Pattern;

use ReflectionClass;

trait GetPathTrait {

    public static function getPath() {

        $reflection = new ReflectionClass(static::class);

        return dirname($reflection->getFileName());
    }
}Pattern/MVCHelperTrait.php000064400000003431151161172510011464
0ustar00<?php


namespace Nextend\Framework\Pattern;


use Nextend\Framework\Application\AbstractApplication;
use Nextend\Framework\Application\AbstractApplicationType;
use Nextend\Framework\Router\Router;

trait MVCHelperTrait {

    /** @var MVCHelperTrait */
    protected $MVCHelper;

    /**
     * @return Router
     */
    public function getRouter() {
        return $this->MVCHelper->getRouter();
    }

    /**
     * @param array|string $url
     * @param bool         $isPost
     * @param bool         $isAjax
     *
     * @return string
     */
    public function createUrl($url, $isPost = false, $isAjax = false) {
        return $this->MVCHelper->getRouter()
                               ->createUrl($url, $isPost, $isAjax);
    }

    /**
     * @param array|string $url
     *
     * @return string
     */
    public function createAjaxUrl($url) {
        return $this->MVCHelper->getRouter()
                               ->createAjaxUrl($url);
    }

    /**
     * @return AbstractApplication
     */
    public function getApplication() {

        return $this->MVCHelper->getApplication();
    }

    /**
     * @return AbstractApplicationType
     */
    public function getApplicationType() {
        return $this->MVCHelper->getApplicationType();
    }

    /**
     * @param MVCHelperTrait $helper
     *
     */
    protected function setMVCHelper($helper) {
        $this->MVCHelper = $helper;

        if (!method_exists($helper, 'getRouter') ||
!method_exists($helper, 'getApplication') ||
!method_exists($helper, 'getApplicationType')) {
            debug_print_backtrace();
            echo 'Object should has MVCHelperTrait';
            exit;
        }
    }

    /**
     * @return MVCHelperTrait
     */
    public function getMVCHelper() {
        return $this->MVCHelper;
    }
}Pattern/OrderableTrait.php000064400000001125151161172510011574
0ustar00<?php

namespace Nextend\Framework\Pattern;

trait OrderableTrait {

    public function getOrdering() {

        return isset($this->ordering) ? $this->ordering : 1000000;
    }

    /**
     * @param OrderableTrait[] $items
     */
    public static function uasort(&$items) {
        uasort($items, array(
            OrderableTrait::class,
            'compare'
        ));
    }

    /**
     * @param OrderableTrait $a
     * @param OrderableTrait $b
     *
     * @return int
     */
    public static function compare($a, $b) {
        return $a->getOrdering() - $b->getOrdering();
    }
}Pattern/PluggableFactoryTrait.php000064400000000750151161172510013132
0ustar00<?php

namespace Nextend\Framework\Pattern;

trait PluggableFactoryTrait {

    use SingletonTrait;

    private static $types = array();

    public static function addType($name, $className) {
        self::$types[$name] = $className;
    }

    public static function getType($name) {

        if (isset(self::$types[$name])) {
            return self::$types[$name];
        }

        return false;
    }

    public static function getTypes() {

        return self::$types;
    }
}Pattern/PluggableTrait.php000064400000000334151161172510011600
0ustar00<?php


namespace Nextend\Framework\Pattern;


use Nextend\Framework\Plugin;

trait PluggableTrait {

    protected function makePluggable($id) {

        Plugin::doAction('PluggableFactory' . $id, array($this));
    }
}Pattern/SingletonTrait.php000064400000000703151161172510011640
0ustar00<?php


namespace Nextend\Framework\Pattern;


trait SingletonTrait {

    protected static $instance;

    final public static function getInstance() {
        return isset(static::$instance) ? static::$instance :
static::$instance = new static;
    }

    private function __construct() {
        $this->init();
    }

    protected function init() {
    }

    final public function __wakeup() {
    }

    final public function __clone() {
    }
}Pattern/VisualManagerTrait.php000064400000001352151161172510012435
0ustar00<?php


namespace Nextend\Framework\Pattern;


use Nextend\Framework\Plugin;

trait VisualManagerTrait {

    /** @var MVCHelperTrait */
    protected $MVCHelper;

    /**
     * StyleManager constructor.
     *
     * @param MVCHelperTrait $MVCHelper
     */
    public function __construct($MVCHelper) {
        $this->MVCHelper = $MVCHelper;

        Plugin::addAction('afterApplicationContent', array(
            $this,
            'display'
        ));
    }

    public abstract function display();

    /**
     * @param MVCHelperTrait $MVCHelper
     */
    public static function enqueue($MVCHelper) {
        static $enqueued;

        if (!$enqueued) {
            new self($MVCHelper);
            $enqueued = true;
        }
    }
}Platform/AbstractPlatform.php000064400000002304151161172510012310
0ustar00<?php


namespace Nextend\Framework\Platform;


use Nextend\Framework\Pattern\GetAssetsPathTrait;

abstract class AbstractPlatform {

    use GetAssetsPathTrait;

    protected $isAdmin = false;

    protected $hasPosts = false;

    public function isAdmin() {

        return $this->isAdmin;
    }

    public function setIsAdmin($isAdmin) {
        $this->isAdmin = $isAdmin;
    }

    public abstract function getName();

    public abstract function getLabel();

    public abstract function getVersion();

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

    public abstract function getSiteUrl();

    public function getCharset() {
        return 'UTF-8';
    }

    public function getMysqlDate() {
        return date("Y-m-d H:i:s");
    }

    public function getTimestamp() {

        return time();
    }

    /**
     * @return string
     */
    public abstract function getPublicDirectory();

    public function getUserEmail() {

        return '';
    }

    public function needStrongerCss() {

        return false;
    }

    public function getDebug() {

        return array();
    }

    public function filterAssetsPath($assetsPath) {

        return $assetsPath;
    }
}Platform/Joomla/PlatformJoomla.php000064400000010633151161172510013213
0ustar00<?php


namespace Nextend\Framework\Platform\Joomla;


use JComponentHelper;
use JDocument;
use JFactory;
use JURI;
use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Platform\AbstractPlatform;
use Nextend\Framework\Plugin;

class PlatformJoomla extends AbstractPlatform {

    protected $hasPosts = true;

    public function __construct() {

        if (JFactory::getApplication()
                    ->isClient('administrator')) {

            $this->isAdmin = true;
        }

        // Load required UTF-8 config from Joomla
        jimport('joomla.utilities.string');
        class_exists('JString');

        if (!defined('JPATH_NEXTEND_IMAGES')) {
            define('JPATH_NEXTEND_IMAGES', '/' .
trim(JComponentHelper::getParams('com_media')
                                                                     
->get('image_path', 'images'), "/"));
        }

        Plugin::addAction('exit', array(
            $this,
            'addKeepAlive'
        ));
    }

    public function getName() {

        return 'joomla';
    }

    public function getLabel() {

        return 'Joomla';
    }

    public function getVersion() {

        return JVERSION;
    }

    public function getSiteUrl() {

        return JURI::root();
    }

    public function getCharset() {

        return JDocument::getInstance()
                        ->getCharset();
    }

    public function getMysqlDate() {

        $config = JFactory::getConfig();

        return JFactory::getDate('now',
$config->get('offset'))
                       ->toSql(true);
    }

    public function getTimestamp() {

        return strtotime($this->getMysqlDate());
    }

    public function getPublicDirectory() {

        if (defined('JPATH_MEDIA')) {
            return rtrim(JPATH_SITE, '\\/') . JPATH_MEDIA;
        }

        return rtrim(JPATH_SITE, '\\/') . '/media';
    }

    public function getUserEmail() {

        return JFactory::getUser()->email;
    }

    public function getDebug() {
        $debug = array();

        $db    = JFactory::getDbo();
        $query = $db->getQuery(true);
        $query->select($db->quoteName(array(
            'template',
            'title'
        )))
              ->from($db->quoteName('#__template_styles'))
              ->where('client_id = 0 AND home = 1');

        $db->setQuery($query);
        $result = $db->loadObject();
        if (isset($result->template)) {
            $debug[] = '';
            $debug[] = 'Template: ' . $result->template .
' - ' . $result->title;
        }

        $query = $db->getQuery(true);
        $query->select($db->quoteName(array(
            'name',
            'manifest_cache'
        )))
              ->from($db->quoteName('#__extensions'));

        $db->setQuery($query);
        $result = $db->loadObjectList();

        $debug[] = '';
        $debug[] = 'Extensions:';
        foreach ($result as $extension) {
            $decode = json_decode($extension->manifest_cache);
            if (isset($extension->name) &&
isset($decode->version)) {
                $debug[] = $extension->name . ' : ' .
$decode->version;
            } else if (isset($extension->name)) {
                $debug[] = $extension->name;
            }
        }

        return $debug;
    }

    public function filterAssetsPath($assetsPath) {
        /**
         * Fix the error when Joomla installed in the system root / and
Joomla sets JPATH_* to //
         */
        $jpath_libraries = JPATH_LIBRARIES;
        if (strpos(JPATH_LIBRARIES, DIRECTORY_SEPARATOR .
DIRECTORY_SEPARATOR) === 0) {
            $jpath_libraries = substr(JPATH_LIBRARIES, 1);
        }
        if (strpos($assetsPath, $jpath_libraries) === 0) {

            $jpath_root = JPATH_ROOT;
            if (JPATH_ROOT === DIRECTORY_SEPARATOR) {
                $jpath_root = '';
            }

            return str_replace('/', DIRECTORY_SEPARATOR,
$jpath_root . '/media/' . ltrim(substr($assetsPath,
strlen($jpath_libraries)), '/\\'));
        }

        return $assetsPath;
    }

    public function addKeepAlive() {
        if ($this->isAdmin) {
            $lifetime = JFactory::getConfig()
                                ->get('lifetime');
            if (empty($lifetime)) {
                $lifetime = 60;
            }
            $lifetime = min(max(intval($lifetime) - 1, 9), 60 * 24);
            Js::addInline('setInterval(function(){$.ajax({url:
"' . JURI::current() . '", cache: false});}, ' .
($lifetime * 60 * 1000) . ');');
        }
    }
}Platform/Platform.php000064400000003443151161172510010631 0ustar00<?php


namespace Nextend\Framework\Platform;


use Nextend\Framework\Pattern\SingletonTrait;

class Platform {

    use SingletonTrait;

    /**
     * @var AbstractPlatform
     */
    private static $platform;

    public function __construct() {
        self::$platform = new Joomla\PlatformJoomla();
    
    }

    public static function getName() {
        return self::$platform->getName();
    }

    public static function getLabel() {
        return self::$platform->getLabel();
    }

    public static function getVersion() {
        return self::$platform->getVersion();
    }

    public static function isAdmin() {
        return self::$platform->isAdmin();
    }

    public static function setIsAdmin($isAdmin) {
        self::$platform->setIsAdmin($isAdmin);
    }

    public static function hasPosts() {
        return self::$platform->hasPosts();
    }

    public static function getSiteUrl() {
        return self::$platform->getSiteUrl();
    }

    public static function getCharset() {
        return self::$platform->getCharset();
    }

    public static function getMysqlDate() {
        return self::$platform->getMysqlDate();
    }

    public static function getTimestamp() {
        return self::$platform->getTimestamp();
    }

    public static function getPublicDirectory() {
        return self::$platform->getPublicDirectory();
    }

    public static function getUserEmail() {
        return self::$platform->getUserEmail();
    }

    public static function needStrongerCss() {
        return self::$platform->needStrongerCss();
    }

    public static function getDebug() {

        return self::$platform->getDebug();
    }

    public static function filterAssetsPath($assetsPath) {

        return self::$platform->filterAssetsPath($assetsPath);
    }
}

Platform::getInstance();Plugin.php000064400000002704151161172510006516
0ustar00<?php


namespace Nextend\Framework;

class Plugin {

    private static $classes = array();

    /**
     * @param          $eventName
     * @param callable $callable
     */
    public static function addAction($eventName, $callable) {
        if (!isset(self::$classes[$eventName])) self::$classes[$eventName]
= array();
        self::$classes[$eventName][] = $callable;
    }

    static function addFilter($eventName, $callable) {
        if (!isset(self::$classes[$eventName])) self::$classes[$eventName]
= array();
        self::$classes[$eventName][] = $callable;
    }

    public static function applyFilters($eventName, $value, $args =
array()) {
        if (self::hasAction($eventName)) {
            foreach (self::$classes[$eventName] AS $callable) {
                if (is_callable($callable)) {
                    $value = call_user_func_array($callable,
array_merge(array($value), $args));
                }
            }
        }

        return $value;
    }

    public static function doAction($eventName, $args = array()) {
        if (self::hasAction($eventName)) {
            foreach (self::$classes[$eventName] AS $callable) {
                if (is_callable($callable)) {
                    call_user_func_array($callable, $args);
                }
            }
        }
    }

    public static function hasAction($eventName) {
        if (isset(self::$classes[$eventName])) {
            return true;
        }

        return false;
    }
}Request/Parser/AbstractRequestParser.php000064400000000217151161172510014432
0ustar00<?php


namespace Nextend\Framework\Request\Parser;


abstract class AbstractRequestParser {

    public abstract function parseData($data);

}Request/Parser/JoomlaRequestParser.php000064400000000263151161172510014111
0ustar00<?php

namespace Nextend\Framework\Request\Parser;

class JoomlaRequestParser extends AbstractRequestParser {

    public function parseData($data) {
        return $data;
    }
}Request/Parser/WordPressRequestParser.php000064400000001034151161172510014615
0ustar00<?php

namespace Nextend\Framework\Request\Parser;

class WordPressRequestParser extends AbstractRequestParser {

    public function parseData($data) {
        if (is_array($data)) {
            return $this->stripslashesRecursive($data);
        }

        return stripslashes($data);
    }

    private function stripslashesRecursive($array) {
        foreach ($array as $key => $value) {
            $array[$key] = is_array($value) ?
$this->stripslashesRecursive($value) : stripslashes($value);
        }

        return $array;
    }
}Request/Request.php000064400000001604151161172510010336 0ustar00<?php


namespace Nextend\Framework\Request;

use Nextend\Framework\PageFlow;

class Request {

    /**
     * @var Storage
     */
    public static $REQUEST;

    /**
     * @var Storage
     */
    public static $GET;

    /**
     * @var Storage
     */
    public static $POST;

    private static $requestUri;

    public static $isAjax = false;

    public function __construct() {
        self::$REQUEST = new Storage($_REQUEST);
        self::$GET     = new Storage($_GET);
        self::$POST    = new Storage($_POST);
    }

    /**
     * @param array|string $url
     * @param integer      $statusCode
     * @param bool         $terminate
     */
    public static function redirect($url, $statusCode = 302, $terminate =
true) {

        header('Location: ' . $url, true, $statusCode);
        if ($terminate) {
            PageFlow::exitApplication();
        }
    }
}

new Request();Request/Storage.php000064400000003074151161172510010315
0ustar00<?php

namespace Nextend\Framework\Request;

use Nextend\Framework\Request\Parser\AbstractRequestParser;
use Nextend\Framework\Request\Parser\JoomlaRequestParser;
use Nextend\Framework\Request\Parser\WordPressRequestParser;

class Storage {

    public $originalStorage;
    public $storage;

    /**
     * @var AbstractRequestParser
     */
    public $parserInstance;

    public function __construct($data) {
        $this->parserInstance = new JoomlaRequestParser();
    


        $this->originalStorage = $data;
        $this->storage         = array();
    }

    public function set($var, $val) {
        $this->storage[$var] = $val;
    }

    protected function get($var, $default = false) {
        if (isset($this->storage[$var])) {
            return $this->storage[$var];
        } else if (isset($this->originalStorage[$var])) {

            $this->storage[$var] =
$this->parserInstance->parseData($this->originalStorage[$var]);

            return $this->storage[$var];
        }

        return $default;
    }

    public function getVar($var, $default = null) {
        return $this->get($var, $default);
    }

    public function getInt($var, $default = 0) {
        return intval($this->get($var, $default));
    }

    public function getCmd($var, $default = '') {
        return preg_replace("/[^\w_]/", "",
$this->get($var, $default));
    }

    public function exists($var) {

        if (isset($this->storage[$var])) {
            return true;
        } else if (isset($this->originalStorage[$var])) {
            return true;
        }

        return false;
    }
}ResourceTranslator/ResourceIdentifier.php000064400000002541151161172510014712
0ustar00<?php

namespace Nextend\Framework\ResourceTranslator;

class ResourceIdentifier {

    /**
     * @var string
     */
    protected $rawKeyword = '';

    /**
     * @var string
     */
    protected $keyword = '';

    /**
     * @var string
     */
    protected $path = '';

    /**
     * @var string
     */
    protected $url = '';

    public function __construct($keyword, $path, $url) {

        /**
         * Keyword must start and end with `$` sign
         */
        if (strlen($keyword) == 0) {
            $keyword = '$';
        } else {
            if ($keyword[0] != '$') {
                $keyword = '$' . $keyword;
            }

            if ($keyword[strlen($keyword) - 1] != '$') {
                $keyword .= '$';
            }
        }

        $this->rawKeyword = $keyword;
        $this->keyword    = $keyword . '/';
        $this->path       = rtrim($path, '/\\') .
DIRECTORY_SEPARATOR;
        $this->url        = rtrim($url, '/') . '/';
    }

    public function getRawKeyword() {
        return $this->rawKeyword;
    }

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

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

    /**
     * @return string
     */
    public function getUrl() {
        return $this->url;
    }
}ResourceTranslator/ResourceTranslator.php000064400000010207151161172510014757
0ustar00<?php

namespace Nextend\Framework\ResourceTranslator;

use Nextend\Framework\Filesystem\Filesystem;
use Nextend\Framework\Image\Image;
use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\Settings;
use Nextend\Framework\Url\Url;

class ResourceTranslator {

    use SingletonTrait;

    /**
     * @var ResourceIdentifier[]
     */
    private static $resources = array();

    private static $isProtocolRelative = true;

    private static $resourceIdentifierKeywords = array();

    protected function init() {

        self::$isProtocolRelative =
!!Settings::get('protocol-relative', 1);

        self::createResource('$', Filesystem::getBasePath(),
Url::getBaseUri());

        Image::getInstance();
    }

    /**
     * @param string $keyword
     * @param string $path
     * @param string $url
     */
    public static function createResource($keyword, $path, $url) {

        $resourceIdentifier = new ResourceIdentifier($keyword, $path,
self::convertUrl($url));

        array_unshift(self::$resources, $resourceIdentifier);

        self::$resourceIdentifierKeywords[] =
$resourceIdentifier->getKeyword();
    }

    public static function isResource($resourcePath) {

        return preg_match(self::getResourceIdentifierRegexp(),
$resourcePath);
    }

    public static function toUrl($resourcePath) {

        foreach (self::$resources as $resourceIdentifier) {

            $keyword = $resourceIdentifier->getKeyword();
            if (strpos($resourcePath, $keyword) === 0) {

                return $resourceIdentifier->getUrl() .
substr($resourcePath, strlen($keyword));
            }
        }

        return $resourcePath;
    }

    public static function toPath($resourcePath) {

        foreach (self::$resources as $resourceIdentifier) {

            $keyword = $resourceIdentifier->getKeyword();
            if (strpos($resourcePath, $keyword) === 0) {

                return str_replace('/', DIRECTORY_SEPARATOR,
$resourceIdentifier->getPath() . substr($resourcePath,
strlen($keyword)));
            }
        }

        return $resourcePath;
    }

    public static function urlToResource($url) {

        $url = self::convertUrl($url);

        foreach (self::$resources as $resourceIdentifier) {

            if (strpos($url, $resourceIdentifier->getUrl()) === 0) {

                return $resourceIdentifier->getKeyword() . substr($url,
strlen($resourceIdentifier->getUrl()));
            }
        }

        return $url;
    }

    public static function pathToResource($path) {

        foreach (self::$resources as $resourceIdentifier) {

            if (strpos($path, $resourceIdentifier->getPath()) === 0) {

                return $resourceIdentifier->getKeyword() . substr($path,
strlen($resourceIdentifier->getPath()));
            }
        }

        return $path;
    }

    /**
     * @return bool
     */
    public static function isProtocolRelative() {

        return self::$isProtocolRelative;
    }

    /**
     * @return string[]
     */
    public static function getResourceIdentifierKeywords() {

        $keywords = array();
        foreach (self::$resources as $resourceIdentifier) {

            $keywords[] = $resourceIdentifier->getKeyword();
        }

        return $keywords;
    }

    public static function getResourceIdentifierUrls() {

        $urls = array();
        foreach (self::$resources as $resourceIdentifier) {

            $urls[] = $resourceIdentifier->getUrl();
        }

        return $urls;
    }

    public static function exportData() {

        $data = array();

        foreach (self::$resources as $resourceIdentifier) {

            $data[$resourceIdentifier->getKeyword()] =
$resourceIdentifier->getUrl();
        }

        return $data;
    }

    private static function convertUrl($url) {

        if (self::$isProtocolRelative) {

            return preg_replace('/^http(s)?:\/\//',
'//', $url);
        }

        return $url;
    }

    private static function getResourceIdentifierRegexp() {

        return '/^' . join('|', array_map(function
($keyword) {
                return preg_quote($keyword, '/');
            }, self::$resourceIdentifierKeywords)) . '/';
    }
}

ResourceTranslator::getInstance();Response/ResponseAjax.php000064400000003341151161172510011456
0ustar00<?php

namespace Nextend\Framework\Response;

use Nextend\Framework\Application\AbstractApplicationType;
use Nextend\Framework\Notification\Notification;
use Nextend\Framework\PageFlow;

class ResponseAjax {

    /**
     * @var AbstractApplicationType
     */
    private $appType;

    private $isError = false;

    private $response = array(
        'data'         => null,
        'notification' => array()
    );

    public function __construct($appType) {
        $this->appType = $appType;
    }

    public function error($showNotification = true) {
        $this->isError = true;
        $this->respond(null, $showNotification);
    }

    public function respond($data = null, $showNotification = true) {
        $this->response['data'] = $data;

        self::fix_output_buffer();

        if ($showNotification) {
            $this->response['notification'] =
Notification::showAjax();
        }
        header("Content-Type: application/json");
        if ($this->isError) {
            header("HTTP/1.0 403 Forbidden");
        }
        echo json_encode($this->response);

        PageFlow::exitApplication();
    }

    public function redirect($url) {

        self::fix_output_buffer();

        $this->response['redirect'] = $url;
        echo json_encode($this->response);

        PageFlow::exitApplication();
    }

    private static function fix_output_buffer() {

        $ob_list_handlers       = ob_list_handlers();
        $ob_list_handlers_count = count($ob_list_handlers);

        $exclude = array(
            'ob_gzhandler',
            'zlib output compression'
        );

        if ($ob_list_handlers_count &&
!in_array($ob_list_handlers[$ob_list_handlers_count - 1], $exclude)) {
            ob_clean();
        }
    }
}Router/Base/PlatformRouter.php000064400000000605151161172510012375
0ustar00<?php

namespace Nextend\Framework\Router\Base;

use Nextend\Framework\Router\Router;

class PlatformRouter {

    protected $router;

    /**
     * Router constructor.
     *
     * @param $router Router
     */
    public function __construct($router) {
        $this->router = $router;
    }

    public function setMultiSite() {

    }

    public function unSetMultiSite() {

    }
}Router/Router.php000064400000006715151161172510010026 0ustar00<?php

namespace Nextend\Framework\Router;

use Nextend\Framework\Form\Form;
use Nextend\Framework\Router\Base\PlatformRouter;
use Nextend\Framework\Router\WordPress\WordPressRouter;
use Nextend\Framework\Url\UrlHelper;

class Router {

    /**
     * @var Base\PlatformRouter
     */
    private $platformRouter;

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

    /**
     * @var bool|string
     */
    protected $baseUrlAjax;

    /**
     * @var bool|string
     */
    protected $networkUrl = false;

    /**
     * Router constructor.
     *
     * @param string      $baseUrl
     * @param string|bool $baseUrlAjax
     * @param string|bool $networkUrl
     */
    public function __construct($baseUrl, $baseUrlAjax = false, $networkUrl
= false) {
        $this->platformRouter = new PlatformRouter($this);
    

        $this->baseUrl = $baseUrl;

        if ($baseUrlAjax === false) {
            $baseUrlAjax =
UrlHelper::add_query_arg(array('nextendajax' => 1),
$this->baseUrl);
        }
        $this->baseUrlAjax = $baseUrlAjax;

        $this->networkUrl = $networkUrl;
    }

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

    /**
     * @param string $baseUrl
     */
    public function setBaseUrl($baseUrl) {
        $this->baseUrl = $baseUrl;
    }

    /**
     * @return bool|string
     */
    public function getNetworkUrl() {

        return $this->networkUrl;
    }

    /**
     * @param array|string $url
     * @param bool         $isPost
     * @param bool         $isAjax
     *
     * @return string
     */
    public function createUrl($url, $isPost = false, $isAjax = false) {
        //create url from array
        // [0] = controller/method
        // [1] = query parameters
        if (is_array($url)) {
            $href = $this->route($url[0], (isset($url[1]) ? $url[1] :
array()), $isPost, $isAjax);
        } elseif (filter_var($url, FILTER_VALIDATE_URL)) {
            //completed url, no mods, just fun
            $href = $url;
        } elseif (strpos($url, "/") !== false) {
            //create url from string
            //format: controller/method
            $href = $this->route($url, array(), $isPost, $isAjax);
        } else {
            //fake link, replace to hashtag
            $href = "#";
        }

        return $href;
    }

    /**
     * @param array|string $url
     *
     * @return string
     */
    public function createAjaxUrl($url) {

        return $this->createUrl($url, false, true);
    }

    /**
     * @param       $url
     * @param array $queryArgs
     * @param bool  $isPost
     * @param bool  $isAjax
     *
     * @return string
     */
    private function route($url, $queryArgs = array(), $isPost = false,
$isAjax = false) {

        if ($isAjax) {
            $baseUrl = $this->baseUrlAjax;
        } else {
            $baseUrl = $this->baseUrl;
        }

        $parsedAction = explode("/", $url);

        $queryArgs = array(
                'nextendcontroller' =>
strtolower(trim($parsedAction[0])),
                'nextendaction'     =>
strtolower(trim($parsedAction[1]))
            ) + $queryArgs;

        if ($isPost || $isAjax) {
            $queryArgs += Form::tokenizeUrl();
        }

        return UrlHelper::add_query_arg($queryArgs, $baseUrl);
    }

    public function setMultiSite() {

        $this->platformRouter->setMultiSite();
    }

    public function unSetMultiSite() {

        $this->platformRouter->unSetMultiSite();
    }
}Sanitize.php000064400000034065151161172510007053 0ustar00<?php

namespace Nextend\Framework;

use Nextend\Framework\Platform\Platform;

global $allowedentitynames;
/**
 * @var string[] $allowedentitynames Array of KSES allowed HTML entitity
names.
 * @since 1.0.0
 */
$allowedentitynames = is_array($allowedentitynames) ? $allowedentitynames :
array(
    'nbsp',
    'iexcl',
    'cent',
    'pound',
    'curren',
    'yen',
    'brvbar',
    'sect',
    'uml',
    'copy',
    'ordf',
    'laquo',
    'not',
    'shy',
    'reg',
    'macr',
    'deg',
    'plusmn',
    'acute',
    'micro',
    'para',
    'middot',
    'cedil',
    'ordm',
    'raquo',
    'iquest',
    'Agrave',
    'Aacute',
    'Acirc',
    'Atilde',
    'Auml',
    'Aring',
    'AElig',
    'Ccedil',
    'Egrave',
    'Eacute',
    'Ecirc',
    'Euml',
    'Igrave',
    'Iacute',
    'Icirc',
    'Iuml',
    'ETH',
    'Ntilde',
    'Ograve',
    'Oacute',
    'Ocirc',
    'Otilde',
    'Ouml',
    'times',
    'Oslash',
    'Ugrave',
    'Uacute',
    'Ucirc',
    'Uuml',
    'Yacute',
    'THORN',
    'szlig',
    'agrave',
    'aacute',
    'acirc',
    'atilde',
    'auml',
    'aring',
    'aelig',
    'ccedil',
    'egrave',
    'eacute',
    'ecirc',
    'euml',
    'igrave',
    'iacute',
    'icirc',
    'iuml',
    'eth',
    'ntilde',
    'ograve',
    'oacute',
    'ocirc',
    'otilde',
    'ouml',
    'divide',
    'oslash',
    'ugrave',
    'uacute',
    'ucirc',
    'uuml',
    'yacute',
    'thorn',
    'yuml',
    'quot',
    'amp',
    'lt',
    'gt',
    'apos',
    'OElig',
    'oelig',
    'Scaron',
    'scaron',
    'Yuml',
    'circ',
    'tilde',
    'ensp',
    'emsp',
    'thinsp',
    'zwnj',
    'zwj',
    'lrm',
    'rlm',
    'ndash',
    'mdash',
    'lsquo',
    'rsquo',
    'sbquo',
    'ldquo',
    'rdquo',
    'bdquo',
    'dagger',
    'Dagger',
    'permil',
    'lsaquo',
    'rsaquo',
    'euro',
    'fnof',
    'Alpha',
    'Beta',
    'Gamma',
    'Delta',
    'Epsilon',
    'Zeta',
    'Eta',
    'Theta',
    'Iota',
    'Kappa',
    'Lambda',
    'Mu',
    'Nu',
    'Xi',
    'Omicron',
    'Pi',
    'Rho',
    'Sigma',
    'Tau',
    'Upsilon',
    'Phi',
    'Chi',
    'Psi',
    'Omega',
    'alpha',
    'beta',
    'gamma',
    'delta',
    'epsilon',
    'zeta',
    'eta',
    'theta',
    'iota',
    'kappa',
    'lambda',
    'mu',
    'nu',
    'xi',
    'omicron',
    'pi',
    'rho',
    'sigmaf',
    'sigma',
    'tau',
    'upsilon',
    'phi',
    'chi',
    'psi',
    'omega',
    'thetasym',
    'upsih',
    'piv',
    'bull',
    'hellip',
    'prime',
    'Prime',
    'oline',
    'frasl',
    'weierp',
    'image',
    'real',
    'trade',
    'alefsym',
    'larr',
    'uarr',
    'rarr',
    'darr',
    'harr',
    'crarr',
    'lArr',
    'uArr',
    'rArr',
    'dArr',
    'hArr',
    'forall',
    'part',
    'exist',
    'empty',
    'nabla',
    'isin',
    'notin',
    'ni',
    'prod',
    'sum',
    'minus',
    'lowast',
    'radic',
    'prop',
    'infin',
    'ang',
    'and',
    'or',
    'cap',
    'cup',
    'int',
    'sim',
    'cong',
    'asymp',
    'ne',
    'equiv',
    'le',
    'ge',
    'sub',
    'sup',
    'nsub',
    'sube',
    'supe',
    'oplus',
    'otimes',
    'perp',
    'sdot',
    'lceil',
    'rceil',
    'lfloor',
    'rfloor',
    'lang',
    'rang',
    'loz',
    'spades',
    'clubs',
    'hearts',
    'diams',
    'sup1',
    'sup2',
    'sup3',
    'frac14',
    'frac12',
    'frac34',
    'there4',
);

class Sanitize {

    private static function getCharset() {

        return Platform::getCharset();
    }

    /**
     * Checks for invalid UTF8 in a string.
     *
     * @param string $string The text which is to be checked.
     * @param bool   $strip  Optional. Whether to attempt to strip out
invalid UTF8. Default is false.
     *
     * @return string The checked text.
     * @since     2.8.0
     *
     * @staticvar bool $is_utf8
     * @staticvar bool $utf8_pcre
     *
     */
    private static function check_invalid_utf8($string, $strip = false) {
        $string = (string)$string;

        if (0 === strlen($string)) {
            return '';
        }

        // Store the site charset as a static to avoid multiple calls to
get_option()
        static $is_utf8 = null;
        if (!isset($is_utf8)) {
            $is_utf8 = in_array(self::getCharset(), array(
                'utf8',
                'utf-8',
                'UTF8',
                'UTF-8'
            ));
        }
        if (!$is_utf8) {
            return $string;
        }

        // Check for support for utf8 in the installed PCRE library once
and store the result in a static
        static $utf8_pcre = null;
        if (!isset($utf8_pcre)) {
            $utf8_pcre = @preg_match('/^./u', 'a');
        }
        // We can't demand utf8 in the PCRE installation, so just
return the string in those cases
        if (!$utf8_pcre) {
            return $string;
        }

        // preg_match fails when it encounters invalid UTF8 in $string
        if (1 === @preg_match('/^./us', $string)) {
            return $string;
        }

        // Attempt to strip the bad chars if requested (not recommended)
        if ($strip && function_exists('iconv')) {
            return iconv('utf-8', 'utf-8', $string);
        }

        return '';
    }

    /**
     * Converts a number of special characters into their HTML entities.
     *
     * Specifically deals with: &, <, >, ", and '.
     *
     * $quote_style can be set to ENT_COMPAT to encode " to
     * &quot;, or ENT_QUOTES to do both. Default is ENT_NOQUOTES where
no quotes are encoded.
     *
     * @param string      $string        The text which is to be encoded.
     * @param int|string  $quote_style   Optional. Converts double quotes
if set to ENT_COMPAT,
     *                                   both single and double if set to
ENT_QUOTES or none if set to ENT_NOQUOTES.
     *                                   Also compatible with old values;
converting single quotes if set to 'single',
     *                                   double if set to
'double' or both if otherwise set.
     *                                   Default is ENT_NOQUOTES.
     * @param string|bool $charset       Optional. The character encoding
of the string. Default is false.
     * @param bool        $double_encode Optional. Whether to encode
existing html entities. Default is false.
     *
     * @return string The encoded text with HTML entities.
     * @since     1.2.2
     * @access    private
     *
     * @staticvar string $_charset
     *
     */
    private static function _specialchars($string, $quote_style =
ENT_NOQUOTES, $charset = false, $double_encode = false) {
        $string = (string)$string;

        if (0 === strlen($string)) return '';

        // Don't bother if there are no specialchars - saves some
processing
        if (!preg_match('/[&<>"\']/',
$string)) return $string;

        // Account for the previous behaviour of the function when the
$quote_style is not an accepted value
        if (empty($quote_style)) $quote_style = ENT_NOQUOTES; else if
(!in_array($quote_style, array(
            0,
            2,
            3,
            'single',
            'double'
        ), true)) $quote_style = ENT_QUOTES;

        // Store the site charset as a static to avoid multiple calls to
wp_load_alloptions()
        if (!$charset) {
            static $_charset = null;
            if (!isset($_charset)) {
                $_charset = self::getCharset();
            }
            $charset = $_charset;
        }

        if (in_array($charset, array(
            'utf8',
            'utf-8',
            'UTF8'
        ))) $charset = 'UTF-8';

        $_quote_style = $quote_style;

        if ($quote_style === 'double') {
            $quote_style  = ENT_COMPAT;
            $_quote_style = ENT_COMPAT;
        } else if ($quote_style === 'single') {
            $quote_style = ENT_NOQUOTES;
        }

        if (!$double_encode) {
            // Guarantee every &entity; is valid, convert &garbage;
into &amp;garbage;
            // This is required for PHP < 5.4.0 because ENT_HTML401 flag
is unavailable.
            $string = self::kses_normalize_entities($string);
        }

        $string = @htmlspecialchars($string, $quote_style, $charset,
$double_encode);

        // Back-compat.
        if ('single' === $_quote_style) $string =
str_replace("'", '&#039;', $string);

        return $string;
    }

    /**
     * Converts and fixes HTML entities.
     *
     * This function normalizes HTML entities. It will convert `AT&T`
to the correct
     * `AT&amp;T`, `&#00058;` to `&#58;`, `&#XYZZY;` to
`&amp;#XYZZY;` and so on.
     *
     * @param string $string Content to normalize entities
     *
     * @return string Content with normalized entities
     * @since 1.0.0
     *
     */
    private static function kses_normalize_entities($string) {
        // Disarm all entities by converting & to &amp;
        $string = str_replace('&', '&amp;',
$string);

        // Change back the allowed entities in our entity whitelist
        $string =
preg_replace_callback('/&amp;([A-Za-z]{2,8}[0-9]{0,2});/',
array(
            self::class,
            'kses_named_entities'
        ), $string);
        $string =
preg_replace_callback('/&amp;#(0*[0-9]{1,7});/', array(
            self::class,
            'kses_normalize_entities2'
        ), $string);
        $string =
preg_replace_callback('/&amp;#[Xx](0*[0-9A-Fa-f]{1,6});/',
array(
            self::class,
            'kses_normalize_entities3'
        ), $string);

        return $string;
    }

    /**
     * Callback for kses_normalize_entities() regular expression.
     *
     * This function only accepts valid named entity references, which are
finite,
     * case-sensitive, and highly scrutinized by HTML and XML validators.
     *
     * @param array  $matches preg_replace_callback() matches array
     *
     * @return string Correctly encoded entity
     * @since 3.0.0
     *
     * @global array $allowedentitynames
     *
     */
    public static function kses_named_entities($matches) {
        global $allowedentitynames;

        if (empty($matches[1])) return '';

        $i = $matches[1];

        return (!in_array($i, $allowedentitynames)) ?
"&amp;$i;" : "&$i;";
    }

    /**
     * Callback for kses_normalize_entities() regular expression.
     *
     * This function helps kses_normalize_entities() to only accept 16-bit
     * values and nothing more for `&#number;` entities.
     *
     * @access private
     *
     * @param array $matches preg_replace_callback() matches array
     *
     * @return string Correctly encoded entity
     * @since  1.0.0
     *
     */
    public static function kses_normalize_entities2($matches) {
        if (empty($matches[1])) return '';

        $i = $matches[1];
        if (self::valid_unicode($i)) {
            $i = str_pad(ltrim($i, '0'), 3, '0',
STR_PAD_LEFT);
            $i = "&#$i;";
        } else {
            $i = "&amp;#$i;";
        }

        return $i;
    }

    /**
     * Callback for kses_normalize_entities() for regular expression.
     *
     * This function helps kses_normalize_entities() to only accept valid
Unicode
     * numeric entities in hex form.
     *
     * @access private
     *
     * @param array $matches preg_replace_callback() matches array
     *
     * @return string Correctly encoded entity
     */
    public static function kses_normalize_entities3($matches) {
        if (empty($matches[1])) return '';

        $hexchars = $matches[1];

        return (!self::valid_unicode(hexdec($hexchars))) ?
"&amp;#x$hexchars;" : '&#x' . ltrim($hexchars,
'0') . ';';
    }

    /**
     * Helper function to determine if a Unicode value is valid.
     *
     * @param int $i Unicode value
     *
     * @return bool True if the value was a valid Unicode number
     */
    private static function valid_unicode($i) {
        return ($i == 0x9 || $i == 0xa || $i == 0xd || ($i >= 0x20
&& $i <= 0xd7ff) || ($i >= 0xe000 && $i <= 0xfffd)
|| ($i >= 0x10000 && $i <= 0x10ffff));
    }

    /**
     * Escape single quotes, htmlspecialchar " < > &, and
fix line endings.
     *
     * Escapes text strings for echoing in JS. It is intended to be used
for inline JS
     * (in a tag attribute, for example onclick="..."). Note that
the strings have to
     * be in single quotes. The {@see 'js_escape'} filter is also
applied here.
     *
     * @param string $text The text to be escaped.
     *
     * @return string Escaped text.
     * @since 2.8.0
     *
     */
    public static function esc_js($text) {
        $safe_text = self::check_invalid_utf8($text);
        $safe_text = self::_specialchars($safe_text, ENT_COMPAT);
        $safe_text = preg_replace('/&#(x)?0*(?(1)27|39);?/i',
"'", stripslashes($safe_text));
        $safe_text = str_replace("\r", '', $safe_text);
        $safe_text = str_replace("\n", '\\n',
addslashes($safe_text));

        return $safe_text;
    }

    /**
     * Escaping for HTML blocks.
     *
     * @param string $text
     *
     * @return string
     * @since 2.8.0
     *
     */
    public static function esc_html($text) {
        $safe_text = self::check_invalid_utf8($text);
        $safe_text = self::_specialchars($safe_text, ENT_QUOTES);

        return $safe_text;
    }

    /**
     * Escaping for HTML attributes.
     *
     * @param string $text
     *
     * @return string
     * @since 2.8.0
     *
     */
    public static function esc_attr($text) {
        $safe_text = self::check_invalid_utf8($text);
        $safe_text = self::_specialchars($safe_text, ENT_QUOTES);

        return $safe_text;
    }

    /**
     * Escaping for textarea values.
     *
     * @param string $text
     *
     * @return string
     * @since 3.1.0
     *
     */
    public static function esc_textarea($text) {
        $safe_text = htmlspecialchars($text, ENT_QUOTES,
self::getCharset());

        return $safe_text;
    }

    public static function esc_css_value($text) {
        $safe_text = self::check_invalid_utf8($text);

        return preg_replace_callback('/<\/style.*?>/i',
array(
            self::class,
            'esc_css_value_callback'
        ), $safe_text);
    }

    public static function esc_css_value_callback($a) {
        return self::esc_html($a[0]);
    }
}Session/AbstractStorage.php000064400000003727151161172510012001
0ustar00<?php

namespace Nextend\Framework\Session;

use Nextend\Framework\Plugin;

abstract class AbstractStorage {

    protected static $expire = 86400; // 1 day

    protected static $salt = 'nextendSalt';

    protected $hash;

    protected $storage = array();

    public $storageChanged = false;

    public function __construct($userIdentifier) {

        $this->register();
        if (!isset($_COOKIE['nextendsession']) ||
substr($_COOKIE['nextendsession'], 0, 2) != 'n2' ||
!preg_match('/^[a-f0-9]{32}$/',
substr($_COOKIE['nextendsession'], 2))) {
            $this->hash = 'n2' . md5(self::$salt .
$userIdentifier);
            setcookie('nextendsession', $this->hash, time() +
self::$expire, $_SERVER["HTTP_HOST"]);
            $_COOKIE['nextendsession'] = $this->hash;
        } else {
            $this->hash = $_COOKIE['nextendsession'];
        }

        $this->load();
    }

    /**
     * Load the whole session
     * $this->storage = json_decode(result for $this->hash);
     */
    protected abstract function load();

    /**
     * Store the whole session
     * $this->hash json_encode($this->storage);
     */
    protected abstract function store();

    public function get($key, $default = '') {
        return isset($this->storage[$key]) ? $this->storage[$key] :
$default;
    }

    public function set($key, $value) {
        $this->storageChanged = true;

        $this->storage[$key] = $value;
    }

    public function delete($key) {
        $this->storageChanged = true;
        unset($this->storage[$key]);
    }

    /**
     * Register our method for PHP shut down
     */
    protected function register() {
        Plugin::addAction('exit', array(
            $this,
            'shutdown'
        ));
    }

    /**
     * When PHP shuts down, we have to save our session's data if the
data changed
     */
    public function shutdown() {
        Plugin::doAction('beforeSessionSave');
        if ($this->storageChanged) {
            $this->store();
        }
    }
}Session/Joomla/JoomlaStorage.php000064400000001511151161172510012665
0ustar00<?php

namespace Nextend\Framework\Session\Joomla;

use JFactory;
use Nextend\Framework\Session\AbstractStorage;

class JoomlaStorage extends AbstractStorage {

    public function __construct() {

        parent::__construct(JFactory::getUser()->id);
    }

    /**
     * Load the whole session
     */
    protected function load() {
        $stored = JFactory::getSession()
                          ->get($this->hash);

        if (!is_array($stored)) {
            $stored = array();
        }
        $this->storage = $stored;
    }

    /**
     * Store the whole session
     */
    protected function store() {
        $session = JFactory::getSession();
        if (count($this->storage) > 0) {
            $session->set($this->hash, $this->storage);
        } else {
            $session->set($this->hash, null);
        }
    }
}Session/Session.php000064400000001446151161172510010330 0ustar00<?php

namespace Nextend\Framework\Session;


use Nextend\Framework\Session\Joomla\JoomlaStorage;
use Nextend\Framework\Session\WordPress\WordPressStorage;

class Session {

    /**
     * @var $storage AbstractStorage
     */
    private static $storage = false;

    private static function getStorage() {
        if (!self::$storage) {
            self::$storage = new JoomlaStorage();
        
        }

        return self::$storage;
    }

    public static function get($key, $default = null) {
        return self::getStorage()
                   ->get($key, $default);
    }

    public static function set($key, $value) {

        self::getStorage()
            ->set($key, $value);
    }

    public static function delete($key) {

        self::getStorage()
            ->delete($key);
    }
}Settings.php000064400000003173151161172510007061 0ustar00<?php


namespace Nextend\Framework;


use Nextend\Framework\Model\Section;

class Settings {

    private static $data;

    public function __construct() {

        $config = array(
            'jquery'                 => 1,
            'scriptattributes'       => '',
            'javascript-inline'      => 'head',
            'protocol-relative'      => 1,
            'force-english-backend'  => 0,
            'frontend-accessibility' => 1,
            'curl'                   => 1,
            'curl-clean-proxy'       => 0,
            'async-non-primary-css'     => 0,
            'icon-fa'                => 1,
            'header-preload'         => 0
        );

        if (!defined('NEXTEND_INSTALL')) {
            foreach (Section::getAll('system',
'global') as $data) {
                $config[$data['referencekey']] =
$data['value'];
            }
        }

        self::$data = new Data\Data();
        self::$data->loadArray($config);
    }

    public static function get($key, $default = '') {
        return self::$data->get($key, $default);
    }

    public static function getAll() {
        return self::$data->toArray();
    }

    public static function set($key, $value) {
        self::$data->set($key, $value);
        Section::set('system', 'global', $key, $value,
1, 1);
    }

    public static function setAll($data) {
        if (is_array($data)) {
            foreach ($data as $key => $value) {
                if (self::$data->get($key, null) !== null) {
                    self::set($key, $value);
                }
            }

            return true;
        }

        return false;
    }
}

new
Settings();Style/Block/StyleManager/BlockStyleManager.php000064400000002762151161172510015357
0ustar00<?php


namespace Nextend\Framework\Style\Block\StyleManager;


use Nextend\Framework\Asset\Js\Js;
use Nextend\Framework\Localization\Localization;
use Nextend\Framework\Style\ModelStyle;
use Nextend\Framework\Style\StyleRenderer;
use Nextend\Framework\Visual\AbstractBlockVisual;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonApply;
use
Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonCancel;

class BlockStyleManager extends AbstractBlockVisual {

    /** @var ModelStyle */
    protected $model;

    /**
     * @return ModelStyle
     */
    public function getModel() {
        return $this->model;
    }

    public function display() {

        $this->model = new ModelStyle($this);

        $this->renderTemplatePart('Index');
    }

    public function displayTopBar() {

        $buttonCancel = new BlockButtonCancel($this);
       
$buttonCancel->addClass('n2_fullscreen_editor__cancel');
        $buttonCancel->display();

        $buttonApply = new BlockButtonApply($this);
        $buttonApply->addClass('n2_fullscreen_editor__save');
        $buttonApply->display();
    }

    public function displayContent() {
        $model = $this->getModel();

        Js::addFirstCode("
            _N2.CSSRendererStyle.rendererModes =  " .
json_encode(StyleRenderer::$mode) . ";
            _N2.CSSRendererStyle.pre =  " .
json_encode(StyleRenderer::$pre) . ";
            new _N2.NextendStyleManager();
        ");

        $model->renderForm();
    }
}Style/Block/StyleManager/Index.php000064400000001501151161172510013046
0ustar00<?php

namespace Nextend\Framework\Style\Block\StyleManager;

/**
 * @var BlockStyleManager $this
 */
?>
<div id="n2-lightbox-style"
class="n2_fullscreen_editor">
    <div class="n2_fullscreen_editor__overlay"></div>
    <div class="n2_fullscreen_editor__window">
        <div class="n2_fullscreen_editor__nav_bar">
            <div
class="n2_fullscreen_editor__nav_bar_label">
                <?php n2_e('Style manager'); ?>
            </div>
            <div
class="n2_fullscreen_editor__nav_bar_actions">
                <?php $this->displayTopBar(); ?>
            </div>
        </div>
        <div class="n2_fullscreen_editor__content">
            <div class="n2_fullscreen_editor__content_content
n2_container_scrollable">
                <?php $this->displayContent(); ?>
            </div>
        </div>
    </div>
</div>Style/ControllerAjaxStyle.php000064400000000454151161172510012330
0ustar00<?php


namespace Nextend\Framework\Style;


use Nextend\Framework\Controller\Admin\AdminVisualManagerAjaxController;

class ControllerAjaxStyle extends AdminVisualManagerAjaxController {

    protected $type = 'style';

    public function getModel() {

        return new ModelStyle($this);
    }
}Style/ModelCss.php000064400000002245151161172510010071 0ustar00<?php


namespace Nextend\Framework\Style;


use Nextend\Framework\Model\AbstractModel;
use Nextend\Framework\Model\StorageSectionManager;

class ModelCss extends AbstractModel {

    public $storage;

    protected function init() {

        $this->storage =
StorageSectionManager::getStorage('system');
    }

    public function addVisual($type, $visual) {

        $visualId = $this->storage->add($type, '',
$visual);

        $visual = $this->storage->getById($visualId, $type);
        if (!empty($visual) && $visual['section'] ==
$type) {
            return $visual;
        }

        return false;
    }

    public function deleteVisual($type, $id) {
        $visual = $this->storage->getById($id, $type);
        if (!empty($visual) && $visual['section'] ==
$type) {
            $this->storage->deleteById($id);

            return $visual;
        }

        return false;
    }

    public function changeVisual($type, $id, $value) {
        if ($this->storage->setById($id, $value)) {
            return $this->storage->getById($id, $type);
        }

        return false;
    }

    public function getVisuals($type) {
        return $this->storage->getAll($type);
    }

}Style/ModelStyle.php000064400000005615151161172510010445 0ustar00<?php

namespace Nextend\Framework\Style;

use Nextend\Framework\Form\Container\ContainerTable;
use Nextend\Framework\Form\Element\Button;
use Nextend\Framework\Form\Element\MarginPadding;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\Tab;
use Nextend\Framework\Form\Element\Text\Color;
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;
use Nextend\Framework\Form\Element\Textarea;
use Nextend\Framework\Form\Element\Unit;
use Nextend\Framework\Form\Form;
use Nextend\Framework\Visual\ModelVisual;

class ModelStyle extends ModelVisual {

    protected $type = 'style';

    public function renderForm() {

        $form = new Form($this, 'n2-style-editor');

        $table = new ContainerTable($form->getContainer(),
'style', n2_('Style settings'));

        $table->setFieldsetPositionEnd();

        new Button($table->getFieldsetLabel(),
'style-clear-tab', false, n2_('Clear tab'));

        new Tab($table->getFieldsetLabel(), 'style-state');

        $row1 = $table->createRow('style-row-1');

        new Color($row1, 'backgroundcolor', n2_('Background
color'), '000000FF', array(
            'alpha' => true
        ));

        new NumberAutoComplete($row1, 'opacity',
n2_('Opacity'), '100', array(
            'values' => array(
                0,
                50,
                90,
                100
            ),
            'unit'   => '%',
            'wide'   => 3
        ));

        $padding = new MarginPadding($row1, 'padding',
n2_('Padding'), '0|*|0|*|0|*|0|*|px');
        for ($i = 1; $i < 5; $i++) {
            new NumberAutoComplete($padding, 'padding-' . $i,
false, '', array(
                'values' => array(
                    0,
                    5,
                    10,
                    20,
                    30
                ),
                'wide'   => 3
            ));
        }

        new Unit($padding, 'padding-5', '',
'', array(
            'units' => array(
                'px',
                'em',
                '%'
            )
        ));

        new MixedField\Border($row1, 'border',
n2_('Border'), '0|*|solid|*|000000ff');

        new NumberAutoComplete($row1, 'borderradius',
n2_('Border radius'), '0', array(
            'values' => array(
                0,
                3,
                5,
                10,
                99
            ),
            'unit'   => 'px',
            'wide'   => 3
        ));


        new MixedField\BoxShadow($row1, 'boxshadow',
n2_('Box shadow'), '0|*|0|*|0|*|0|*|000000ff');

        new Textarea($row1, 'extracss', 'CSS',
'', array(
            'width'  => 200,
            'height' => 26
        ));

        $previewTable = new ContainerTable($form->getContainer(),
'style-preview', n2_('Preview'));

        $previewTable->setFieldsetPositionEnd();

        new Color($previewTable->getFieldsetLabel(),
'preview-background', false, 'ced3d5');

        $form->render();
    }
}Style/Style.php000064400000004767151161172510007473 0ustar00<?php


namespace Nextend\Framework\Style;


use Nextend\Framework\Parser\Color;

class Style {

    /**
     * @param string $tab
     *
     * @return string
     */
    public function style($tab) {
        $style = '';
        $extra = '';
        if (isset($tab['extra'])) {
            $extra = $tab['extra'];
            unset($tab['extra']);
        }
        foreach ($tab AS $k => $v) {
            $style .= $this->parse($k, $v);
        }
        $style .= $this->parse('extra', $extra);

        return $style;
    }

    /**
     * @param $property
     * @param $value
     *
     * @return mixed
     */
    public function parse($property, $value) {
        $fn = 'parse' . $property;

        return $this->$fn($value);
    }

    public function parseBackgroundColor($v) {
        $hex = Color::hex82hex($v);
        if ($hex[1] == 'ff') {
            return 'background: #' . $hex[0] . ';';
        }

        $rgba = Color::hex2rgba($v);

        return 'background: RGBA(' . $rgba[0] . ',' .
$rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127,
2) . ');';
    }

    public function parseOpacity($v) {
        return 'opacity:' . (intval($v) / 100) . ';';
    }

    public function parsePadding($v) {
        $padding   = explode('|*|', $v);
        $unit      = array_pop($padding);
        $padding[] = '';

        return 'padding:' . implode($unit . ' ',
$padding) . ';';
    }

    public function parseBoxShadow($v) {
        $boxShadow = explode('|*|', $v);

        if ($boxShadow[0] == '0' && $boxShadow[1] ==
'0' && $boxShadow[2] == '0' &&
$boxShadow[3] == '0') {
            return 'box-shadow: none;';
        } else {
            $rgba = Color::hex2rgba($boxShadow[4]);

            return 'box-shadow: ' . $boxShadow[0] . 'px
' . $boxShadow[1] . 'px ' . $boxShadow[2] . 'px '
. $boxShadow[3] . 'px RGBA(' . $rgba[0] . ',' .
$rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127,
2) . ');';
        }
    }

    public function parseBorder($v) {
        $border = explode('|*|', $v);
        $style  = 'border-width: ' . $border[0] .
'px;';
        $style  .= 'border-style: ' . $border[1] . ';';
        $rgba   = Color::hex2rgba($border[2]);
        $style  .= 'border-color: #' . substr($border[2], 0, 6) .
"; border-color: RGBA(" . $rgba[0] . ',' . $rgba[1] .
',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) .
');';

        return $style;
    }

    public function parseBorderRadius($v) {
        return 'border-radius:' . $v . 'px;';
    }

    public function parseExtra($v) {
        return $v;
    }
}Style/StyleManager.php000064400000000550151161172510010750
0ustar00<?php


namespace Nextend\Framework\Style;


use Nextend\Framework\Pattern\VisualManagerTrait;
use Nextend\Framework\Style\Block\StyleManager\BlockStyleManager;

class StyleManager {

    use VisualManagerTrait;

    public function display() {

        $fontManagerBlock = new BlockStyleManager($this->MVCHelper);
        $fontManagerBlock->display();
    }
}Style/StyleParser.php000064400000002442151161172510010634 0ustar00<?php


namespace Nextend\Framework\Style;


use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Model\Section;

class StyleParser {

    /**
     * @param $data
     *
     * @return string
     */
    public static function parse($data) {
        if (empty($data)) {
            return '';
        } else if (is_numeric($data)) {
            /**
             * Linked style
             */

            $style = Section::getById($data, 'style');

            if (!$style) {
                /**
                 * Linked style not exists anymore
                 */
                return '';
            }


            if (is_string($style['value'])) {
                /**
                 * Old format when value stored as Base64
                 */
                $decoded = $style['value'];
                if ($decoded[0] != '{') {
                    $decoded = Base64::decode($decoded);
                }

                return $decoded;
            }

            /**
             * Value stored as array
             */
            $value = json_encode($style['value']);
            if ($value == false) {
                return '';
            }

            return $value;
        } else if ($data[0] != '{') {
            return Base64::decode($data);
        }

        return $data;
    }

}Style/StyleRenderer.php000064400000017407151161172510011155
0ustar00<?php

namespace Nextend\Framework\Style;

use Nextend\Framework\Settings;

class StyleRenderer {

    public static $pre = '';

    /**
     * @var Style
     */
    public static $style;

    public static $mode;

    public static function render($style, $mode, $pre = '') {
        self::$pre = $pre;

        if (!empty($style)) {

            $value = json_decode($style, true);
            if ($value) {
                $selector = 'n2-style-' . md5($style) .
'-' . $mode;

                return array(
                    $selector . ' ',
                    self::renderStyle($mode, $pre, $selector,
$value['data'])
                );
            }
        }

        return false;
    }

    private static function renderStyle($mode, $pre, $selector, $tabs) {
        $search  = array(
            '@pre',
            '@selector'
        );
        $replace = array(
            $pre,
            '.' . $selector
        );
        $tabs[0] = array_merge(array(
            'backgroundcolor' => 'ffffff00',
            'opacity'         => 100,
            'padding'         =>
'0|*|0|*|0|*|0|*|px',
            'boxshadow'       =>
'0|*|0|*|0|*|0|*|000000ff',
            'border'          =>
'0|*|solid|*|000000ff',
            'borderradius'    => '0',
            'extra'           => '',
        ), $tabs[0]);

        foreach ($tabs AS $k => $tab) {
            $search[]  = '@tab' . $k;
            $replace[] = self::$style->style($tab);
        }

        $template = '';
        foreach (self::$mode[$mode]['selectors'] AS $s =>
$style) {
            $key = array_search($style, $search);
            if (is_numeric($key) && !empty($replace[$key])) {
                $template .= $s . "{" . $style . "}";
            }
        }

        return str_replace($search, $replace, $template);
    }
}


$frontendAccessibility =
intval(Settings::get('frontend-accessibility', 1));

StyleRenderer::$mode = array(
    '0'              => array(
        'id'            => '0',
        'label'         => n2_('Single'),
        'tabs'          => array(
            n2_('Text')
        ),
        'renderOptions' => array(
            'combined' => false
        ),
        'preview'       => '<div
class="{styleClassName}">Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.</div>',
        'selectors'     => array(
            '@pre@selector' => '@tab'
        )
    ),
    'simple'         => array(
        'id'            => 'simple',
        'label'         => n2_('Simple'),
        'tabs'          => array(
            n2_('Normal')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div
class="{styleClassName}" style="width: 200px;
height:100px;"></div>',
        'selectors'     => array(
            '@pre@selector' => '@tab0'
        )
    ),
    'box'            => array(
        'id'            => 'box',
        'label'         => n2_('Box'),
        'tabs'          => array(
            n2_('Normal'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div
class="{styleClassName}" style="width: 200px;
height:100px;"></div>',
        'selectors'     => array(
            '@pre@selector'       => '@tab0',
            '@pre@selector:HOVER' => '@tab1'
        )
    ),
    'button'         => array(
        'id'            => 'button',
        'label'         => n2_('Button'),
        'tabs'          => array(
            n2_('Normal'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div><a
style="display:inline-block; margin:20px;"
class="{styleClassName}" href="#" onclick="return
false;">Button</a></div>',
        'selectors'     => $frontendAccessibility ? array(
            '@pre@selector'                                      
           => '@tab0',
            '@pre@selector:Hover, @pre@selector:ACTIVE,
@pre@selector:FOCUS' => '@tab1'
        ) : array(
            '@pre@selector, @pre@selector:FOCUS'        =>
'@tab0',
            '@pre@selector:Hover, @pre@selector:ACTIVE' =>
'@tab1'
        )
    ),
    'heading'        => array(
        'id'            => 'heading',
        'label'         => n2_('Heading'),
        'tabs'          => array(
            n2_('Normal'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div
class="{styleClassName}">Heading</div>',
        'selectors'     => $frontendAccessibility ? array(
            '@pre@selector'                                      
           => '@tab0',
            '@pre@selector:Hover, @pre@selector:ACTIVE,
@pre@selector:FOCUS' => '@tab1'
        ) : array(
            '@pre@selector, @pre@selector:FOCUS'        =>
'@tab0',
            '@pre@selector:Hover, @pre@selector:ACTIVE' =>
'@tab1'
        )
    ),
    'heading-active' => array(
        'id'            => 'heading-active',
        'label'         => n2_('Heading active'),
        'tabs'          => array(
            n2_('Normal'),
            n2_('Active')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div
class="{styleClassName}">Heading</div>',
        'selectors'     => array(
            '@pre@selector'           => '@tab0',
            '@pre@selector.n2-active' => '@tab1'
        )
    ),
    'dot'            => array(
        'id'            => 'dot',
        'label'         => n2_('Dot'),
        'tabs'          => array(
            n2_('Normal'),
            n2_('Active')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div><div
class="{styleClassName}" style="display: inline-block;
margin: 3px;"></div><div class="{styleClassName}
n2-active" style="display: inline-block; margin:
3px;"></div><div class="{styleClassName}"
style="display: inline-block; margin:
3px;"></div></div>',
        'selectors'     => array(
            '@pre@selector'                                      
              => '@tab0',
            '@pre@selector.n2-active, @pre@selector:HOVER,
@pre@selector:FOCUS' => '@tab1'
        )
    ),
    'highlight'      => array(
        'id'            => 'highlight',
        'label'         => n2_('Highlight'),
        'tabs'          => array(
            n2_('Normal'),
            n2_('Highlight'),
            n2_('Hover')
        ),
        'renderOptions' => array(
            'combined' => true
        ),
        'preview'       => '<div
class="{fontClassName}">' . n2_('Button') .
'</div>',
        'selectors'     => $frontendAccessibility ? array(
            '@pre@selector'                                      
                                                           =>
'@tab0',
            '@pre@selector .n2-highlighted'                      
                                                           =>
'@tab1',
            '@pre@selector .n2-highlighted:HOVER, @pre@selector
.n2-highlighted:ACTIVE, @pre@selector .n2-highlighted:FOCUS' =>
'@tab2'
        ) : array(
            '@pre@selector'                                      
                      => '@tab0',
            '@pre@selector .n2-highlighted, @pre@selector
.n2-highlighted:FOCUS'        => '@tab1',
            '@pre@selector .n2-highlighted:HOVER, @pre@selector
.n2-highlighted:ACTIVE' => '@tab2'
        )
    ),
);


StyleRenderer::$style = new
Style();Style/StyleStorage.php000064400000004513151161172510011005
0ustar00<?php

namespace Nextend\Framework\Style;

use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\Plugin;

class StyleStorage {

    use SingletonTrait;

    private $sets = array();

    private $styles = array();

    private $stylesBySet = array();

    private $stylesById = array();

    protected function init() {


        Plugin::addAction('systemstyleset', array(
            $this,
            'styleSet'
        ));
        Plugin::addAction('systemstyle', array(
            $this,
            'styles'
        ));
        Plugin::addAction('style', array(
            $this,
            'style'
        ));
    }

    private function load() {
        static $loaded;
        if (!$loaded) {
            Plugin::doAction('styleStorage', array(
                &$this->sets,
                &$this->styles
            ));

            for ($i = 0; $i < count($this->styles); $i++) {
                if
(!isset($this->stylesBySet[$this->styles[$i]['referencekey']]))
{
                   
$this->stylesBySet[$this->styles[$i]['referencekey']] =
array();
                }
               
$this->stylesBySet[$this->styles[$i]['referencekey']][] =
&$this->styles[$i];
                $this->stylesById[$this->styles[$i]['id']] 
            = &$this->styles[$i];
            }
            $loaded = true;
        }
    }

    public function styleSet($referenceKey, &$sets) {

        $this->load();

        for ($i = count($this->sets) - 1; $i >= 0; $i--) {
            $this->sets[$i]['system']   = 1;
            $this->sets[$i]['editable'] = 0;
            array_unshift($sets, $this->sets[$i]);
        }

    }

    public function styles($referenceKey, &$styles) {

        $this->load();

        if (isset($this->stylesBySet[$referenceKey])) {
            $_styles = &$this->stylesBySet[$referenceKey];
            for ($i = count($_styles) - 1; $i >= 0; $i--) {
                $_styles[$i]['system']   = 1;
                $_styles[$i]['editable'] = 0;
                array_unshift($styles, $_styles[$i]);
            }

        }
    }

    public function style($id, &$style) {

        $this->load();

        if (isset($this->stylesById[$id])) {
            $this->stylesById[$id]['system']   = 1;
            $this->stylesById[$id]['editable'] = 0;
            $style                             = $this->stylesById[$id];
        }
    }
}Translation/AbstractTranslation.php000064400000000324151161172510013534
0ustar00<?php

namespace Nextend\Framework\Translation;

abstract class AbstractTranslation {

    public function _($text) {
        return $text;
    }

    public function getLocale() {
        return 'en_US';
    }
}Translation/Joomla/JoomlaTranslation.php000064400000000450151161172510014433
0ustar00<?php

namespace Nextend\Framework\Translation\Joomla;

use JFactory;
use Nextend\Framework\Translation\AbstractTranslation;

class JoomlaTranslation extends AbstractTranslation {

    public function getLocale() {
        return JFactory::getLanguage()
                       ->getTag();
    }
}Translation/Translation.php000064400000001113151161172510012045
0ustar00<?php

namespace Nextend\Framework\Translation;

use Nextend\Framework\Pattern\SingletonTrait;

class Translation {

    use SingletonTrait;

    /**
     * @var AbstractTranslation
     */
    private static $platformTranslation;

    public function __construct() {
        self::$platformTranslation = new Joomla\JoomlaTranslation();
    
    }

    public static function _($text) {
        return self::$platformTranslation->_($text);
    }

    public static function getCurrentLocale() {
        return self::$platformTranslation->getLocale();
    }
}

Translation::getInstance();Url/AbstractPlatformUrl.php000064400000004166151161172510011761
0ustar00<?php

namespace Nextend\Framework\Url;

use Nextend\Framework\Filesystem\Filesystem;

abstract class AbstractPlatformUrl {

    public $uris = array();

    protected $siteUrl;

    /**
     * @var string It can be relative or absolute uri. It must not end with
/
     * @example https://asd.com/wordpress
     * @example /wordpress
     */
    protected $_baseuri;

    protected $_currentbase = '';

    protected $scheme = 'http';

    public function getUris() {

        return $this->uris;
    }

    protected function getUriByIndex($i, $protocol = true) {
        if (!$protocol) {
            return preg_replace('/^http:/', '',
$this->uris[$i]);
        }

        return $this->uris[$i];
    }

    public function setBaseUri($uri) {
        $this->_baseuri = $uri;
    }

    public function getSiteUri() {
        return $this->siteUrl;
    }

    public function getBaseUri() {

        return $this->_baseuri;
    }

    public function getFullUri() {

        return $this->_baseuri;
    }

    public function pathToUri($path, $protocol = true) {

        $from = array();
        $to   = array();

        $basePath = Filesystem::getBasePath();
        if ($basePath != '/' && $basePath !=
"\\") {
            $from[] = $basePath;
            $to[]   = '';
        }
        $from[] = DIRECTORY_SEPARATOR;
        $to[]   = '/';

        return ($protocol ? $this->_baseuri :
preg_replace('/^http:/', '', $this->_baseuri)) .
str_replace($from, $to, str_replace('/', DIRECTORY_SEPARATOR,
$path));
    }

    public function ajaxUri($query = '') {

        return $this->_baseuri;
    }

    public function fixrelative($uri) {
        if (substr($uri, 0, 1) == '/' || strpos($uri,
'://') !== false) return $uri;

        return $this->_baseuri . $uri;
    }

    public function relativetoabsolute($uri) {

        if (strpos($uri, '://') !== false) return $uri;
        if (!empty($this->_baseuri) && strpos($uri,
$this->_baseuri) === 0) {
            $uri = substr($uri, strlen($this->_baseuri));
        }

        return $this->_currentbase . $uri;
    }

    public function addScheme($url) {
        return $this->scheme . ':' . $url;
    }
}Url/Joomla/JoomlaUrl.php000064400000001170151161172510011143
0ustar00<?php

namespace Nextend\Framework\Url\Joomla;

use JUri;
use Nextend\Framework\Url\AbstractPlatformUrl;

class JoomlaUrl extends AbstractPlatformUrl {

    private $fullUri;

    function __construct() {

        $this->siteUrl = JURI::root();

        $this->fullUri  = rtrim(JURI::root(), '/');
        $this->_baseuri = rtrim(JURI::root(true), '/');

        $this->_currentbase = $this->fullUri;

        $this->scheme = parse_url($this->fullUri, PHP_URL_SCHEME);
    }

    public function getFullUri() {

        return $this->fullUri;
    }

    public function ajaxUri($query = '') {
        return JUri::current();
    }
}Url/Url.php000064400000003001151161172510006553 0ustar00<?php

namespace Nextend\Framework\Url;

use Nextend\Framework\Url\Joomla\JoomlaUrl;
use Nextend\Framework\Url\WordPress\WordPressUrl;

class Url {

    /**
     * @var AbstractPlatformUrl
     */
    private static $platformUrl;

    public function __construct() {
        self::$platformUrl = new JoomlaUrl();
    
    }

    /**
     * @return AbstractPlatformUrl
     */
    public static function get() {

        return self::$platformUrl;
    }

    public static function getUris() {

        return self::$platformUrl->getUris();
    }

    public static function setBaseUri($uri) {
        self::$platformUrl->setBaseUri($uri);
    }

    public static function getSiteUri() {
        return self::$platformUrl->getSiteUri();
    }

    public static function getBaseUri() {

        return self::$platformUrl->getBaseUri();
    }

    public static function getFullUri() {

        return self::$platformUrl->getFullUri();
    }

    public static function pathToUri($path, $protocol = true) {

        return self::$platformUrl->pathToUri($path, $protocol);
    }

    public static function ajaxUri($query = '') {

        return self::$platformUrl->ajaxUri($query);
    }

    public static function fixrelative($uri) {

        return self::$platformUrl->fixrelative($uri);
    }

    public static function relativetoabsolute($uri) {

        return self::$platformUrl->relativetoabsolute($uri);
    }

    public static function addScheme($url) {

        return self::$platformUrl->addScheme($url);
    }
}

new Url();Url/UrlHelper.php000064400000021653151161172510007730
0ustar00<?php


namespace Nextend\Framework\Url;


class UrlHelper {


    /**
     * Retrieves a modified URL query string.
     *
     * You can rebuild the URL and append query variables to the URL query
by using this function.
     * There are two ways to use this function; either a single key and
value, or an associative array.
     *
     * Using a single key and value:
     *
     *     add_query_arg( 'key', 'value',
'http://example.com' );
     *
     * Using an associative array:
     *
     *     add_query_arg( array(
     *         'key1' => 'value1',
     *         'key2' => 'value2',
     *     ), 'http://example.com' );
     *
     * Omitting the URL from either use results in the current URL being
used
     * (the value of `$_SERVER['REQUEST_URI']`).
     *
     * Values are expected to be encoded appropriately with urlencode() or
rawurlencode().
     *
     * Setting any query variable's value to boolean false removes the
key (see remove_query_arg()).
     *
     * Important: The return value of add_query_arg() is not escaped by
default. Output should be
     * late-escaped with esc_url() or similar to help prevent vulnerability
to cross-site scripting
     * (XSS) attacks.
     *
     * @param string|array $key   Either a query variable key, or an
associative array of query variables.
     * @param string       $value Optional. Either a query variable value,
or a URL to act upon.
     * @param string       $url   Optional. A URL to act upon.
     *
     * @return string New URL query string (unescaped).
     *
     */
    public static function add_query_arg() {
        $args = func_get_args();
        if (is_array($args[0])) {
            if (count($args) < 2 || false === $args[1]) {
                $uri = $_SERVER['REQUEST_URI'];
            } else {
                $uri = $args[1];
            }
        } else {
            if (count($args) < 3 || false === $args[2]) {
                $uri = $_SERVER['REQUEST_URI'];
            } else {
                $uri = $args[2];
            }
        }

        if ($frag = strstr($uri, '#')) {
            $uri = substr($uri, 0, -strlen($frag));
        } else {
            $frag = '';
        }

        if (0 === stripos($uri, 'http://')) {
            $protocol = 'http://';
            $uri      = substr($uri, 7);
        } elseif (0 === stripos($uri, 'https://')) {
            $protocol = 'https://';
            $uri      = substr($uri, 8);
        } else {
            $protocol = '';
        }

        if (strpos($uri, '?') !== false) {
            list($base, $query) = explode('?', $uri, 2);
            $base .= '?';
        } elseif ($protocol || strpos($uri, '=') === false) {
            $base  = $uri . '?';
            $query = '';
        } else {
            $base  = '';
            $query = $uri;
        }

        self::wp_parse_str($query, $qs);
        $qs = self::urlencode_deep($qs); // this re-URL-encodes things that
were already in the query string
        if (is_array($args[0])) {
            foreach ($args[0] as $k => $v) {
                $qs[$k] = $v;
            }
        } else {
            $qs[$args[0]] = $args[1];
        }

        foreach ($qs as $k => $v) {
            if ($v === false) {
                unset($qs[$k]);
            }
        }

        $ret = self::build_query($qs);
        $ret = trim($ret, '?');
        $ret = preg_replace('#=(&|$)#', '$1',
$ret);
        $ret = $protocol . $base . $ret . $frag;
        $ret = rtrim($ret, '?');

        return $ret;
    }

    private static function wp_parse_str($string, &$array) {
        parse_str($string, $array);
        if (version_compare(PHP_VERSION, '7.4.0',
'<')) {
            if (get_magic_quotes_gpc()) {
                $array = self::stripslashes_deep($array);
            }
        }

    }

    static function urlencode_deep($value) {
        return self::map_deep($value, 'urlencode');
    }

    /**
     * Build URL query based on an associative and, or indexed array.
     *
     * This is a convenient function for easily building url queries. It
sets the
     * separator to '&' and uses _http_build_query()
function.
     *
     * @param array $data URL-encode key/value pairs.
     *
     * @return string URL-encoded string.
     * @link 
https://secure.php.net/manual/en/function.http-build-query.php for more on
what
     *        http_build_query() does.
     *
     * @since 2.3.0
     *
     * @see   _http_build_query() Used to build the query
     */
    private static function build_query($data) {
        return self::_http_build_query($data, null, '&',
'', false);
    }

    /**
     * From php.net (modified by Mark Jaquith to behave like the native
PHP5 function).
     *
     * @param array|object $data        An array or object of data.
Converted to array.
     * @param string       $prefix      Optional. Numeric index. If set,
start parameter numbering with it.
     *                                  Default null.
     * @param string       $sep         Optional. Argument separator;
defaults to 'arg_separator.output'.
     *                                  Default null.
     * @param string       $key         Optional. Used to prefix key name.
Default empty.
     * @param bool         $urlencode   Optional. Whether to use
urlencode() in the result. Default true.
     *
     * @return string The query string.
     * @since  3.2.0
     * @access private
     *
     * @see   
https://secure.php.net/manual/en/function.http-build-query.php
     *
     */
    private static function _http_build_query($data, $prefix = null, $sep =
null, $key = '', $urlencode = true) {
        $ret = array();

        foreach ((array)$data as $k => $v) {
            if ($urlencode) {
                $k = urlencode($k);
            }
            if (is_int($k) && $prefix != null) {
                $k = $prefix . $k;
            }
            if (!empty($key)) {
                $k = $key . '%5B' . $k . '%5D';
            }
            if ($v === null) {
                continue;
            } elseif ($v === false) {
                $v = '0';
            }

            if (is_array($v) || is_object($v)) {
                array_push($ret, self::_http_build_query($v, '',
$sep, $k, $urlencode));
            } elseif ($urlencode) {
                array_push($ret, $k . '=' . urlencode($v));
            } else {
                array_push($ret, $k . '=' . $v);
            }
        }

        if (null === $sep) {
            $sep = ini_get('arg_separator.output');
        }

        return implode($sep, $ret);
    }

    /**
     * Parses a string into variables to be stored in an array.
     *
     * Uses {@link https://secure.php.net/parse_str parse_str()} and
stripslashes if
     * {@link https://secure.php.net/magic_quotes magic_quotes_gpc} is on.
     *
     * @param string $string The string to be parsed.
     * @param array  $array  Variables will be stored in this array.
     *
     * @since 2.2.1
     *
     */
    private static function parse_str($string, &$array) {
        parse_str($string, $array);
        if (version_compare(PHP_VERSION, '7.4.0',
'<')) {
            if (get_magic_quotes_gpc()) {
                $array = self::stripslashes_deep($array);
            }
        }
    }

    /**
     * Navigates through an array, object, or scalar, and removes slashes
from the values.
     *
     * @param mixed $value The value to be stripped.
     *
     * @return mixed Stripped value.
     * @since 2.0.0
     *
     */
    private static function stripslashes_deep($value) {
        return self::map_deep($value, array(
            self::class,
            'stripslashes_from_strings_only'
        ));
    }

    /**
     * Callback function for `stripslashes_deep()` which strips slashes
from strings.
     *
     * @param mixed $value The array or string to be stripped.
     *
     * @return mixed $value The stripped value.
     * @since 4.4.0
     *
     */
    public static function stripslashes_from_strings_only($value) {
        return is_string($value) ? stripslashes($value) : $value;
    }

    /**
     * Maps a function to all non-iterable elements of an array or an
object.
     *
     * This is similar to `array_walk_recursive()` but acts upon objects
too.
     *
     * @param mixed    $value    The array, object, or scalar.
     * @param callable $callback The function to map onto $value.
     *
     * @return mixed The value with the callback applied to all non-arrays
and non-objects inside it.
     * @since 4.4.0
     *
     */
    private static function map_deep($value, $callback) {
        if (is_array($value)) {
            foreach ($value as $index => $item) {
                $value[$index] = self::map_deep($item, $callback);
            }
        } elseif (is_object($value)) {
            $object_vars = get_object_vars($value);
            foreach ($object_vars as $property_name => $property_value)
{
                $value->$property_name = self::map_deep($property_value,
$callback);
            }
        } else {
            $value = call_user_func($callback, $value);
        }

        return $value;
    }
}View/AbstractBlock.php000064400000001536151161172510010712
0ustar00<?php


namespace Nextend\Framework\View;


use Nextend\Framework\Pattern\GetPathTrait;
use Nextend\Framework\Pattern\MVCHelperTrait;

abstract class AbstractBlock {

    use GetPathTrait;
    use MVCHelperTrait;

    /**
     * AbstractBlock constructor.
     *
     * @param MVCHelperTrait $MVCHelper
     */
    final public function __construct($MVCHelper) {

        $this->setMVCHelper($MVCHelper);

        $this->init();
    }

    protected function init() {

    }

    protected function renderTemplatePart($templateName) {

        include self::getPath() . '/' . $templateName .
'.php';
    }

    /**
     * Returns the HTML code of the display method
     *
     * @return string
     */
    public function toHTML() {

        ob_start();

        $this->display();

        return ob_get_clean();
    }

    public abstract function display();
}View/AbstractLayout.php000064400000003106151161172510011130
0ustar00<?php


namespace Nextend\Framework\View;


use Nextend\Framework\Pattern\GetPathTrait;
use Nextend\Framework\Pattern\MVCHelperTrait;

abstract class AbstractLayout {

    use GetPathTrait;
    use MVCHelperTrait;

    /** @var AbstractView */
    protected $view;

    /**
     * @var AbstractBlock[]|string[]|array[]
     */
    protected $contentBlocks = array();

    protected $state = array();

    /**
     * AbstractLayout constructor.
     *
     * @param AbstractView $view
     *
     */
    public function __construct($view) {
        $this->view = $view;

        $this->setMVCHelper($view);

        $this->getApplicationType()
             ->setLayout($this);

        $this->enqueueAssets();
    }

    protected function enqueueAssets() {

        $this->getApplicationType()
             ->enqueueAssets();
    }

    /**
     * @param string $html
     */
    public function addContent($html) {

        $this->contentBlocks[] = $html;
    }

    /**
     * @param AbstractBlock $block
     */
    public function addContentBlock($block) {

        $this->contentBlocks[] = $block;
    }

    public function displayContent() {
        foreach ($this->contentBlocks AS $content) {
            if (is_string($content)) {
                echo $content;
            } else if (is_array($content)) {
                echo call_user_func_array($content[0], $content[1]);
            } else {
                $content->display();
            }
        }
    }

    public function setState($name, $value) {
        $this->state[$name] = $value;
    }

    public abstract function render();
}View/AbstractView.php000064400000001723151161172510010570 0ustar00<?php


namespace Nextend\Framework\View;


use Nextend\Framework\Controller\AbstractController;
use Nextend\Framework\Pattern\GetPathTrait;
use Nextend\Framework\Pattern\MVCHelperTrait;

abstract class AbstractView {

    use GetPathTrait;
    use MVCHelperTrait;

    /** @var AbstractController */
    protected $controller;

    /** @var AbstractLayout */
    protected $layout;

    /**
     * AbstractView constructor.
     *
     * @param AbstractController $controller
     *
     */
    public function __construct($controller) {
        $this->controller = $controller;

        $this->setMVCHelper($controller);
    }

    protected function render($templateName) {
        ob_start();
        include self::getPath() . '/Template/' . $templateName .
'.php';

        return ob_get_clean();
    }

    /**
     * @return AbstractController
     */
    public function getController() {
        return $this->controller;
    }

    public abstract function display();
}View/AbstractViewAjax.php000064400000001511151161172510011367
0ustar00<?php


namespace Nextend\Framework\View;


use Nextend\Framework\Controller\AbstractController;
use Nextend\Framework\Pattern\GetPathTrait;
use Nextend\Framework\Pattern\MVCHelperTrait;

abstract class AbstractViewAjax {

    use GetPathTrait;
    use MVCHelperTrait;

    /** @var AbstractController */
    protected $controller;

    /**
     * AbstractViewAjax constructor.
     *
     * @param AbstractController $controller
     *
     */
    public function __construct($controller) {
        $this->controller = $controller;

        $this->setMVCHelper($controller);
    }

    protected function render($templateName) {
        ob_start();
        include self::getPath() . '/Template/' . $templateName .
'.php';

        return ob_get_clean();
    }

    /**
     * @return string
     */
    public abstract function display();
}View/Html.php000064400000024172151161172510007101 0ustar00<?php

namespace Nextend\Framework\View;

use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Settings;

class Html {

    private static $closeSingleTags = true;

    /**
     * @var boolean whether to render special attributes value. Defaults to
true. Can be set to false for HTML5.
     * @since 1.1.13
     */
    private static $renderSpecialAttributesValue = true;

    /**
     * Generates an HTML element.
     *
     * @param string  $tag         the tag name
     * @param array   $htmlOptions the element attributes. The values will
be HTML-encoded using
     *                             {@link encodeAttribute()}. If an
'encode' attribute is given and its value is false,
     *                             the rest of the attribute values will
NOT be HTML-encoded. Since version 1.1.5,
     *                             attributes whose value is null will not
be rendered.
     * @param mixed   $content     the content to be enclosed between open
and close element tags. It will not be
     *                             HTML-encoded. If false, it means there
is no body content.
     * @param boolean $closeTag    whether to generate the close tag.
     *
     * @return string the generated HTML element tag
     */
    public static function tag($tag, $htmlOptions = array(), $content =
"", $closeTag = true) {
        $html = '<' . $tag .
self::renderAttributes($htmlOptions);
        if ($content === false) return $closeTag &&
self::$closeSingleTags ? $html . ' />' : $html .
'>'; else
            return $closeTag ? $html . '>' . $content .
'</' . $tag . '>' : $html . '>' .
$content;
    }

    /**
     * Generates an open HTML element.
     *
     * @param string $tag         the tag name
     * @param array  $htmlOptions the element attributes. The values will
be HTML-encoded using
     *                            {@link encodeAttribute()}.
     *                            If an 'encode' attribute is
given and its value is false,
     *                            the rest of the attribute values will NOT
be HTML-encoded.
     *                            Since version 1.1.5, attributes whose
value is null will not be rendered.
     *
     * @return string the generated HTML element tag
     */
    public static function openTag($tag, $htmlOptions = array()) {
        return '<' . $tag .
self::renderAttributes($htmlOptions) . '>';
    }

    /**
     * Generates a close HTML element.
     *
     * @param string $tag the tag name
     *
     * @return string the generated HTML element tag
     */
    public static function closeTag($tag) {
        return '</' . $tag . '>';
    }

    /**
     * Generates an image tag.
     *
     * @param string $src         the image URL
     * @param string $alt         the alternative text display
     * @param array  $htmlOptions additional HTML attributes (see {@link
tag}).
     *
     * @return string the generated image tag
     */
    public static function image($src, $alt = '', $htmlOptions =
array()) {
        $htmlOptions['src'] = $src;
        $htmlOptions['alt'] = $alt;

        return self::tag('img', $htmlOptions, false, false);
    }

    /**
     * Renders the HTML tag attributes.
     * Since version 1.1.5, attributes whose value is null will not be
rendered.
     * Special attributes, such as 'checked',
'disabled', 'readonly', will be rendered
     * properly based on their corresponding boolean value.
     *
     * @param array $htmlOptions attributes to be rendered
     *
     * @return string the rendering result
     */
    public static function renderAttributes($htmlOptions = array()) {
        static $specialAttributes = array(
            'autofocus'          => 1,
            'autoplay'           => 1,
            'controls'           => 1,
            'declare'            => 1,
            'default'            => 1,
            'disabled'           => 1,
            'ismap'              => 1,
            'loop'               => 1,
            'muted'              => 1,
            'playsinline'        => 1,
            'webkit-playsinline' => 1,
            'nohref'             => 1,
            'noresize'           => 1,
            'novalidate'         => 1,
            'open'               => 1,
            'reversed'           => 1,
            'scoped'             => 1,
            'seamless'           => 1,
            'selected'           => 1,
            'typemustmatch'      => 1,
            'lazyload'           => 1,
        ), $specialAttributesNoValue = array(
            'defer' => 1,
            'async' => 1
        );

        if (empty($htmlOptions)) {
            return '';
        }

        if (isset($htmlOptions['style']) &&
empty($htmlOptions['style'])) {
            unset($htmlOptions['style']);
        }

        $html = '';
        if (isset($htmlOptions['encode'])) {
            $raw = !$htmlOptions['encode'];
            unset($htmlOptions['encode']);
        } else
            $raw = false;

        foreach ($htmlOptions as $name => $value) {
            if (isset($specialAttributes[$name])) {
                if ($value) {
                    $html .= ' ' . $name;
                    if (self::$renderSpecialAttributesValue) $html .=
'="' . $name . '"';
                }
            } else if (isset($specialAttributesNoValue[$name])) {
                $html .= ' ' . $name;
            } else if ($value !== null) $html .= ' ' . $name .
'="' . ($raw ? $value : self::encodeAttribute($value)) .
'"';
        }

        return $html;
    }

    /**
     * @param $text
     *
     * @return string
     */
    public static function encode($text) {
        return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
    }

    /**
     * @param $text
     *
     * @return string
     */
    public static function encodeAttribute($text) {

        /**
         * Do not encode: '
         */
        return htmlspecialchars($text, ENT_COMPAT | ENT_HTML5,
'UTF-8');
    }

    public static function link($name, $url = '#', $htmlOptions =
array()) {
        $htmlOptions["href"] = $url;

        $url = self::openTag("a", $htmlOptions);
        if (isset($htmlOptions["encode"]) &&
$htmlOptions["encode"]) {
            $url .= self::encode($name);
        } else {
            $url .= $name;
        }

        $url .= self::closeTag("a");

        return $url;
    }

    /**
     * Insert stylesheet
     *
     * @param string $script
     * @param bool   $file
     * @param array  $scriptOptions
     *
     * @return string
     */
    public static function style($script, $file = false, $scriptOptions =
array()) {
        if ($file) {
            $options = array(
                "rel"  => "stylesheet",
                "type" => "text/css",
                "href" => $script
            );
            $options = array_merge($options, $scriptOptions);

            return self::tag('link', $options, false, false);
        }

        return self::tag("style", $scriptOptions, $script);
    }

    /**
     * Insert script
     *
     * @param string $script
     *
     * @return string
     */
    public static function script($script) {

        return self::tag('script', array(
            'encode' => false
        ), $script);
    }

    public static function scriptFile($script, $attributes = array()) {
        return self::tag('script', array(
                'src' => $script
            ) + self::getScriptAttributes() + $attributes, '');
    }

    private static function getScriptAttributes() {
        static $attributes = null;

        if (Platform::isAdmin()) {
            return array();
        }

        if ($attributes === null) {
            if (class_exists('\\Nextend\\Framework\\Settings',
false)) {
                $value       =
trim(html_entity_decode(strip_tags(Settings::get('scriptattributes',
''))));
                $_attributes = explode(' ',
str_replace('\'', "",
str_replace("\"", "", $value)));
                if (!empty($value) && !empty($_attributes)) {
                    foreach ($_attributes as $attr) {
                        if (strpos($attr, '=') !== false) {
                            $atts = explode("=", $attr);
                            if (count($atts) <= 2) {
                                $attributes[$atts[0]] = $atts[1];
                            } else {
                                $attributes[$attr] = $attr;
                            }
                        } else {
                            $attributes[$attr] = $attr;
                        }
                    }
                } else {
                    $attributes = array();
                }
            } else {
                return array();
            }
        }

        return $attributes;
    }

    /**
     * @param array $array1
     * @param array $array2 [optional]
     * @param array $_      [optional]
     *
     * @return array the resulting array.
     * @since 4.0
     * @since 5.0
     */
    public static function mergeAttributes($array1, $array2 = null, $_ =
null) {
        $arguments = func_get_args();
        $target    = array_shift($arguments);
        foreach ($arguments as $array) {
            if (isset($array['style'])) {
                if (!isset($target['style']))
$target['style'] = '';
                $target['style'] .= $array['style'];
                unset($array['style']);
            }
            if (isset($array['class'])) {
                if (empty($target['class'])) {
                    $target['class'] = $array['class'];
                } else {
                    $target['class'] .= ' ' .
$array['class'];
                }
                unset($array['class']);
            }

            $target = array_merge($target, $array);
        }

        return $target;
    }

    public static function addExcludeLazyLoadAttributes($target = array())
{

        return self::mergeAttributes($target,
self::getExcludeLazyLoadAttributes());
    }

    public static function getExcludeLazyLoadAttributes() {
        static $attrs;
        if ($attrs === null) {
            $attrs = array(
                'class'          => 'skip-lazy',
                'data-skip-lazy' => 1
            );

            if (defined('JETPACK__VERSION')) {
                $attrs['class'] .= '
jetpack-lazy-image';
            }
        }

        return $attrs;
    }
}Visual/AbstractBlockVisual.php000064400000000307151161172510012422
0ustar00<?php


namespace Nextend\Framework\Visual;


use Nextend\Framework\Localization\Localization;
use Nextend\Framework\View\AbstractBlock;

abstract class AbstractBlockVisual extends AbstractBlock {

}Visual/ModelVisual.php000064400000005640151161172510010751
0ustar00<?php


namespace Nextend\Framework\Visual;


use Nextend\Framework\Model\AbstractModel;
use Nextend\Framework\Model\ApplicationSection;
use Nextend\Framework\Model\StorageSectionManager;

class ModelVisual extends AbstractModel {

    protected $type = '';

    /** @var ApplicationSection */
    protected $storage;

    protected function init() {

        $this->storage =
StorageSectionManager::getStorage('system');
    }

    public function getType() {
        return $this->type;
    }

    public function renderSetsForm() {

    }

    public function getSets() {
        return $this->storage->getAll($this->type .
'set');
    }

    public function getSetByVisualId($visualId) {
        $visual = $this->storage->getById($visualId, $this->type);
        if (!empty($visual)) {
            return array(
                'setId'   =>
$visual['referencekey'],
                'visuals' =>
$this->getVisuals($visual['referencekey'])
            );
        }

        return false;
    }

    public function createSet($name) {

        $setId = $this->storage->add($this->type .
'set', '', $name);

        $set = $this->storage->getById($setId, $this->type .
'set');
        if (!empty($set) && $set['section'] ==
$this->type . 'set') {
            return $set;
        }

        return false;
    }

    public function renameSet($setId, $name) {
        $set = $this->storage->getById($setId, $this->type .
'set');
        if (!empty($set) && $set['section'] ==
$this->type . 'set' && $set['editable']) {
            if ($this->storage->setById($setId, $name)) {
                $set['value'] = $name;

                return $set;
            }
        }

        return false;
    }

    public function deleteSet($setId) {
        $set = $this->storage->getById($setId, $this->type .
'set');
        if (!empty($set) && $set['section'] ==
$this->type . 'set' && $set['editable']
&& $set['system'] == 0) {
            if ($this->storage->deleteById($setId)) {
                return $set;
            }
        }

        return false;
    }

    public function addVisual($setId, $visual) {

        $visualId = $this->storage->add($this->type, $setId,
$visual);

        $visual = $this->storage->getById($visualId, $this->type);
        if (!empty($visual) && $visual['section'] ==
$this->type) {
            return $visual;
        }

        return false;
    }

    public function deleteVisual($id) {
        $visual = $this->storage->getById($id, $this->type);
        if (!empty($visual) && $visual['section'] ==
$this->type) {
            $this->storage->deleteById($id);

            return $visual;
        }

        return false;
    }

    public function changeVisual($id, $value) {
        if ($this->storage->setById($id, $value)) {
            return $this->storage->getById($id, $this->type);
        }

        return false;
    }

    public function getVisuals($setId) {
        return $this->storage->getAll($this->type, $setId);
    }
}