Your IP : 216.73.217.112


Current Path : /home/annegardxb/www/so-assurances/
Upload File :
Current File : /home/annegardxb/www/so-assurances/plugins.zip

PK��#]�)��actionlog/joomla/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�>[>�s�sactionlog/joomla/joomla.phpnu�[���<?php
/**
 * @package     Joomla.Plugins
 * @subpackage  System.actionlogs
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\User\User;
use Joomla\CMS\Version;
use Joomla\Utilities\ArrayHelper;

JLoader::register('ActionLogPlugin', JPATH_ADMINISTRATOR . '/components/com_actionlogs/libraries/actionlogplugin.php');
JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR . '/components/com_actionlogs/helpers/actionlogs.php');

/**
 * Joomla! Users Actions Logging Plugin.
 *
 * @since  3.9.0
 */
class PlgActionlogJoomla extends ActionLogPlugin
{
	/**
	 * Array of loggable extensions.
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $loggableExtensions = array();

	/**
	 * Context aliases
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $contextAliases = array('com_content.form' => 'com_content.article');

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$params = ComponentHelper::getComponent('com_actionlogs')->getParams();

		$this->loggableExtensions = $params->get('loggable_extensions', array());
	}

	/**
	 * After save content logging method
	 * This method adds a record to #__action_logs contains (message, date, context, user)
	 * Method is called right after the content is saved
	 *
	 * @param   string   $context  The context of the content passed to the plugin
	 * @param   object   $article  A JTableContent object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onContentAfterSave($context, $article, $isNew)
	{
		if (isset($this->contextAliases[$context]))
		{
			$context = $this->contextAliases[$context];
		}

		$option = $this->app->input->getCmd('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		list(, $contentType) = explode('.', $params->type_alias);

		if ($isNew)
		{
			$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_ADDED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
		}
		else
		{
			$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_UPDATED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
		}

		// If the content type doesn't has it own language key, use default language key
		if (!$this->app->getLanguage()->hasKey($messageLanguageKey))
		{
			$messageLanguageKey = $defaultLanguageKey;
		}

		$id = empty($params->id_holder) ? 0 : $article->get($params->id_holder);

		$message = array(
			'action'   => $isNew ? 'add' : 'update',
			'type'     => $params->text_prefix . '_TYPE_' . $params->type_title,
			'id'       => $id,
			'title'    => $article->get($params->title_holder),
			'itemlink' => ActionlogsHelper::getContentTypeLink($option, $contentType, $id, $params->id_holder, $article),
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * After delete content logging method
	 * This method adds a record to #__action_logs contains (message, date, context, user)
	 * Method is called right after the content is deleted
	 *
	 * @param   string  $context  The context of the content passed to the plugin
	 * @param   object  $article  A JTableContent object
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onContentAfterDelete($context, $article)
	{
		$option = $this->app->input->get('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		// If the content type has it own language key, use it, otherwise, use default language key
		if ($this->app->getLanguage()->hasKey(strtoupper($params->text_prefix . '_' . $params->type_title . '_DELETED')))
		{
			$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_DELETED';
		}
		else
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';
		}

		$id = empty($params->id_holder) ? 0 : $article->get($params->id_holder);

		$message = array(
			'action' => 'delete',
			'type'   => $params->text_prefix . '_TYPE_' . $params->type_title,
			'id'     => $id,
			'title'  => $article->get($params->title_holder)
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On content change status logging method
	 * This method adds a record to #__action_logs contains (message, date, context, user)
	 * Method is called when the status of the article is changed
	 *
	 * @param   string   $context  The context of the content passed to the plugin
	 * @param   array    $pks      An array of primary key ids of the content that has changed state.
	 * @param   integer  $value    The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onContentChangeState($context, $pks, $value)
	{
		$option = $this->app->input->getCmd('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		list(, $contentType) = explode('.', $params->type_alias);

		switch ($value)
		{
			case 0:
				$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_UNPUBLISHED';
				$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UNPUBLISHED';
				$action             = 'unpublish';
				break;
			case 1:
				$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_PUBLISHED';
				$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_PUBLISHED';
				$action             = 'publish';
				break;
			case 2:
				$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_ARCHIVED';
				$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ARCHIVED';
				$action             = 'archive';
				break;
			case -2:
				$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_TRASHED';
				$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_TRASHED';
				$action             = 'trash';
				break;
			default:
				$messageLanguageKey = '';
				$defaultLanguageKey = '';
				$action             = '';
				break;
		}

		// If the content type doesn't has it own language key, use default language key
		if (!$this->app->getLanguage()->hasKey($messageLanguageKey))
		{
			$messageLanguageKey = $defaultLanguageKey;
		}

		$db    = $this->db;
		$query = $db->getQuery(true)
			->select($db->quoteName(array($params->title_holder, $params->id_holder)))
			->from($db->quoteName($params->table_name))
			->where($db->quoteName($params->id_holder) . ' IN (' . implode(',', ArrayHelper::toInteger($pks)) . ')');
		$db->setQuery($query);

		try
		{
			$items = $db->loadObjectList($params->id_holder);
		}
		catch (RuntimeException $e)
		{
			$items = array();
		}

		$messages = array();

		foreach ($pks as $pk)
		{
			$message = array(
				'action'      => $action,
				'type'        => $params->text_prefix . '_TYPE_' . $params->type_title,
				'id'          => $pk,
				'title'       => $items[$pk]->{$params->title_holder},
				'itemlink'    => ActionlogsHelper::getContentTypeLink($option, $contentType, $pk, $params->id_holder, null)
			);

			$messages[] = $message;
		}

		$this->addLog($messages, $messageLanguageKey, $context);
	}

	/**
	 * On Saving application configuration logging method
	 * Method is called when the application config is being saved
	 *
	 * @param   JRegistry  $config  JRegistry object with the new config
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onApplicationAfterSave($config)
	{
		$option = $this->app->input->getCmd('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_APPLICATION_CONFIG_UPDATED';
		$action             = 'update';

		$message = array(
			'action'         => $action,
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_APPLICATION_CONFIG',
			'extension_name' => 'com_config.application',
			'itemlink'       => 'index.php?option=com_config'
		);

		$this->addLog(array($message), $messageLanguageKey, 'com_config.application');
	}

	/**
	 * On installing extensions logging method
	 * This method adds a record to #__action_logs contains (message, date, context, user)
	 * Method is called when an extension is installed
	 *
	 * @param   JInstaller  $installer  Installer object
	 * @param   integer     $eid        Extension Identifier
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterInstall($installer, $eid)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$manifest      = $installer->get('manifest');

		if ($manifest === null)
		{
			return;
		}

		$extensionType = $manifest->attributes()->type;

		// If the extension type has it own language key, use it, otherwise, use default language key
		if ($this->app->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_INSTALLED')))
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_INSTALLED';
		}
		else
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_EXTENSION_INSTALLED';
		}

		$message = array(
			'action'         => 'install',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_' . $extensionType,
			'id'             => $eid,
			'name'           => (string) $manifest->name,
			'extension_name' => (string) $manifest->name
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On uninstalling extensions logging method
	 * This method adds a record to #__action_logs contains (message, date, context, user)
	 * Method is called when an extension is uninstalled
	 *
	 * @param   JInstaller  $installer  Installer instance
	 * @param   integer     $eid        Extension id
	 * @param   integer     $result     Installation result
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterUninstall($installer, $eid, $result)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		// If the process failed, we don't have manifest data, stop process to avoid fatal error
		if ($result === false)
		{
			return;
		}

		$manifest      = $installer->get('manifest');

		if ($manifest === null)
		{
			return;
		}

		$extensionType = $manifest->attributes()->type;

		// If the extension type has it own language key, use it, otherwise, use default language key
		if ($this->app->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UNINSTALLED')))
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UNINSTALLED';
		}
		else
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_EXTENSION_UNINSTALLED';
		}

		$message = array(
			'action'         => 'install',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_' . $extensionType,
			'id'             => $eid,
			'name'           => (string) $manifest->name,
			'extension_name' => (string) $manifest->name
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On updating extensions logging method
	 * This method adds a record to #__action_logs contains (message, date, context, user)
	 * Method is called when an extension is updated
	 *
	 * @param   JInstaller  $installer  Installer instance
	 * @param   integer     $eid        Extension id
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterUpdate($installer, $eid)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$manifest      = $installer->get('manifest');

		if ($manifest === null)
		{
			return;
		}

		$extensionType = $manifest->attributes()->type;

		// If the extension type has it own language key, use it, otherwise, use default language key
		if ($this->app->getLanguage()->hasKey('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UPDATED'))
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UPDATED';
		}
		else
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_EXTENSION_UPDATED';
		}

		$message = array(
			'action'         => 'update',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_' . $extensionType,
			'id'             => $eid,
			'name'           => (string) $manifest->name,
			'extension_name' => (string) $manifest->name
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On Saving extensions logging method
	 * Method is called when an extension is being saved
	 *
	 * @param   string   $context  The extension
	 * @param   JTable   $table    DataBase Table object
	 * @param   boolean  $isNew    If the extension is new or not
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterSave($context, $table, $isNew)
	{
		$option = $this->app->input->getCmd('option');

		if ($table->get('module') != null)
		{
			$option = 'com_modules';
		}

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		list(, $contentType) = explode('.', $params->type_alias);

		if ($isNew)
		{
			$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_ADDED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
		}
		else
		{
			$messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_UPDATED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
		}

		// If the extension type doesn't have it own language key, use default language key
		if (!$this->app->getLanguage()->hasKey($messageLanguageKey))
		{
			$messageLanguageKey = $defaultLanguageKey;
		}

		$message = array(
			'action'         => $isNew ? 'add' : 'update',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_' . $params->type_title,
			'id'             => $table->get($params->id_holder),
			'title'          => $table->get($params->title_holder),
			'extension_name' => $table->get($params->title_holder),
			'itemlink'       => ActionlogsHelper::getContentTypeLink($option, $contentType, $table->get($params->id_holder), $params->id_holder, null)
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On Deleting extensions logging method
	 * Method is called when an extension is being deleted
	 *
	 * @param   string  $context  The extension
	 * @param   JTable  $table    DataBase Table object
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterDelete($context, $table)
	{
		if (!$this->checkLoggable($this->app->input->get('option')))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';

		$message = array(
			'action' => 'delete',
			'type'   => 'PLG_ACTIONLOG_JOOMLA_TYPE_' . $params->type_title,
			'title'  => $table->get($params->title_holder)
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On saving user data logging method
	 *
	 * Method is called after user data is stored in the database.
	 * This method logs who created/edited any user's data
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the database.
	 * @param   string   $msg      Message.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		$context = $this->app->input->get('option');
		$task    = $this->app->input->get->getCmd('task');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$jUser = Factory::getUser();

		if (!$jUser->id)
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_REGISTERED';
			$action             = 'register';

			// Reset request
			if ($task === 'reset.request')
			{
				$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_RESET_REQUEST';
				$action             = 'resetrequest';
			}

			// Reset complete
			if ($task === 'reset.complete')
			{
				$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_RESET_COMPLETE';
				$action             = 'resetcomplete';
			}

			// Registration Activation
			if ($task === 'registration.activate')
			{
				$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_REGISTRATION_ACTIVATE';
				$action             = 'activaterequest';
			}
		}
		elseif ($isnew)
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
			$action             = 'add';
		}
		else
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
			$action             = 'update';
		}

		$userId   = $jUser->id ?: $user['id'];
		$username = $jUser->username ?: $user['username'];

		$message = array(
			'action'      => $action,
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user['id'],
			'title'       => $user['name'],
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $user['id'],
			'userid'      => $userId,
			'username'    => $username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $userId,
		);

		$this->addLog(array($message), $messageLanguageKey, $context, $userId);
	}

	/**
	 * On deleting user data logging method
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the database
	 * @param   string   $msg      Message
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';

		$message = array(
			'action'      => 'delete',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user['id'],
			'title'       => $user['name']
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On after save user group data logging method
	 *
	 * Method is called after user group is stored into the database
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $table    DataBase Table object
	 * @param   boolean  $isNew    Is new or not
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSaveGroup($context, $table, $isNew)
	{
		// Override context (com_users.group) with the component context (com_users) to pass the checkLoggable
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		if ($isNew)
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
			$action             = 'add';
		}
		else
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
			$action             = 'update';
		}

		$message = array(
			'action'      => $action,
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER_GROUP',
			'id'          => $table->id,
			'title'       => $table->title,
			'itemlink'    => 'index.php?option=com_users&task=group.edit&id=' . $table->id
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On deleting user group data logging method
	 *
	 * Method is called after user group is deleted from the database
	 *
	 * @param   array    $group    Holds the group data
	 * @param   boolean  $success  True if user was successfully stored in the database
	 * @param   string   $msg      Message
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDeleteGroup($group, $success, $msg)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';

		$message = array(
			'action'      => 'delete',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER_GROUP',
			'id'          => $group['id'],
			'title'       => $group['title']
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * Method to log user login success action
	 *
	 * @param   array  $options  Array holding options (user, responseType)
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterLogin($options)
	{
		$context = 'com_users';

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$loggedInUser       = $options['user'];
		$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_LOGGED_IN';

		$message = array(
			'action'      => 'login',
			'userid'      => $loggedInUser->id,
			'username'    => $loggedInUser->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $loggedInUser->id,
			'app'         => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->app->getName(),
		);

		$this->addLog(array($message), $messageLanguageKey, $context, $loggedInUser->id);
	}

	/**
	 * Method to log user login failed action
	 *
	 * @param   array  $response  Array of response data.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserLoginFailure($response)
	{
		$context = 'com_users';

		if (!$this->checkLoggable($context))
		{
			return;
		}

		// Get the user id for the given username
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('id', 'username')))
			->from($this->db->quoteName('#__users'))
			->where($this->db->quoteName('username') . ' = ' . $this->db->quote($response['username']));
		$this->db->setQuery($query);

		try
		{
			$loggedInUser = $this->db->loadObject();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return;
		}

		// Not a valid user, return
		if (!isset($loggedInUser->id))
		{
			return;
		}

		$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_LOGIN_FAILED';

		$message = array(
			'action'      => 'login',
			'id'          => $loggedInUser->id,
			'userid'      => $loggedInUser->id,
			'username'    => $loggedInUser->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $loggedInUser->id,
			'app'         => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->app->getName(),
		);

		$this->addLog(array($message), $messageLanguageKey, $context, $loggedInUser->id);
	}

	/**
	 * Method to log user's logout action
	 *
	 * @param   array  $user     Holds the user data
	 * @param   array  $options  Array holding options (remember, autoregister, group)
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserLogout($user, $options = array())
	{
		$context = 'com_users';

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$loggedOutUser = User::getInstance($user['id']);

		if ($loggedOutUser->block)
		{
			return;
		}

		$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_LOGGED_OUT';

		$message = array(
			'action'      => 'logout',
			'id'          => $loggedOutUser->id,
			'userid'      => $loggedOutUser->id,
			'username'    => $loggedOutUser->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $loggedOutUser->id,
			'app'         => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->app->getName(),
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * Function to check if a component is loggable or not
	 *
	 * @param   string  $extension  The extension that triggered the event
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	protected function checkLoggable($extension)
	{
		return in_array($extension, $this->loggableExtensions);
	}

	/**
	 * On after Remind username request
	 *
	 * Method is called after user request to remind their username.
	 *
	 * @param   array  $user  Holds the user data.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterRemind($user)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$message = array(
			'action'      => 'remind',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->name,
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'userid'      => $user->id,
			'username'    => $user->name,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
		);

		$this->addLog(array($message), 'PLG_ACTIONLOG_JOOMLA_USER_REMIND', $context, $user->id);
	}

	/**
	 * On after Check-in request
	 *
	 * Method is called after user request to check-in items.
	 *
	 * @param   array  $table  Holds the table name.
	 *
	 * @return  void
	 *
	 * @since   3.9.3
	 */
	public function onAfterCheckin($table)
	{
		$context = 'com_checkin';
		$user    = Factory::getUser();

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$message = array(
			'action'      => 'checkin',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'table'       => $table,
		);

		$this->addLog(array($message), 'PLG_ACTIONLOG_JOOMLA_USER_CHECKIN', $context, $user->id);
	}

	/**
	 * On after log action purge
	 *
	 * Method is called after user request to clean action log items.
	 *
	 * @param   array  $group  Holds the group name.
	 *
	 * @return  void
	 *
	 * @since   3.9.4
	 */
	public function onAfterLogPurge($group = '')
	{
		$context = $this->app->input->get('option');
		$user    = Factory::getUser();
		$message = array(
			'action'      => 'actionlogs',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
		);
		$this->addLog(array($message), 'PLG_ACTIONLOG_JOOMLA_USER_LOG', $context, $user->id);
	}

	/**
	 * On after log export
	 *
	 * Method is called after user request to export action log items.
	 *
	 * @param   array  $group  Holds the group name.
	 *
	 * @return  void
	 *
	 * @since   3.9.4
	 */
	public function onAfterLogExport($group = '')
	{
		$context = $this->app->input->get('option');
		$user    = Factory::getUser();
		$message = array(
			'action'      => 'actionlogs',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
		);
		$this->addLog(array($message), 'PLG_ACTIONLOG_JOOMLA_USER_LOGEXPORT', $context, $user->id);
	}

	/**
	 * On after Cache purge
	 *
	 * Method is called after user request to clean cached items.
	 *
	 * @param   string  $group  Holds the group name.
	 *
	 * @return  void
	 *
	 * @since   3.9.4
	 */
	public function onAfterPurge($group = 'all')
	{
		$context = $this->app->input->get('option');
		$user    = JFactory::getUser();

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$message = array(
			'action'      => 'cache',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'group'       => $group,
		);
		$this->addLog(array($message), 'PLG_ACTIONLOG_JOOMLA_USER_CACHE', $context, $user->id);
	}

	/**
	 * On after CMS Update
	 *
	 * Method is called after user update the CMS.
	 *
	 * @param   string  $oldVersion  The Joomla version before the update
	 *
	 * @return  void
	 *
	 * @since   3.9.21
	 */
	public function onJoomlaAfterUpdate($oldVersion = null)
	{
		$context = $this->app->input->get('option');
		$user    = JFactory::getUser();

		if (empty($oldVersion))
		{
			$oldVersion = JText::_('JLIB_UNKNOWN');
		}

		$message = array(
			'action'      => 'joomlaupdate',
			'type'        => 'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
			'version'     => JVERSION,
			'oldversion'  => $oldVersion,
		);
		$this->addLog(array($message), 'PLG_ACTIONLOG_JOOMLA_USER_UPDATE', $context, $user->id);
	}
}
PK��#]7K�Xactionlog/joomla/joomla.xmlnu�[���<?xml version="1.0" encoding="UTF-8"?>
<extension version="3.9" type="plugin" group="actionlog" method="upgrade">
	<name>PLG_ACTIONLOG_JOOMLA</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_ACTIONLOG_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_actionlog_joomla.ini</language>
		<language tag="en-GB">en-GB.plg_actionlog_joomla.sys.ini</language>
	</languages>
</extension>
PK��#]�)��actionlog/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]|��N!actionlog/akeebabackup/web.confignu�[���<?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>PK��#]�)�� actionlog/akeebabackup/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]NH���!actionlog/akeebabackup/script.phpnu�[���<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

use FOF40\InstallScript\Plugin;

defined('_JEXEC') || die;

// Load FOF if not already loaded
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
	throw new RuntimeException('This extension requires FOF 4.');
}

class plgActionlogAkeebabackupInstallerScript extends Plugin
{
}
PK��#]�/���*�*'actionlog/akeebabackup/akeebabackup.phpnu�[���<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

use Akeeba\Engine\Platform;
use FOF40\Container\Container;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Plugin\CMSPlugin;

defined('_JEXEC') || die();

class plgActionlogAkeebabackup extends CMSPlugin
{
	/** @var Container */
	private $container;

	/**
	 * Constructor
	 *
	 * @param   object  $subject  The object to observe
	 * @param   array   $config   An array that holds the plugin configuration
	 *
	 * @since       6.4.0
	 */
	public function __construct(&$subject, $config)
	{
		// Make sure Akeeba Backup is installed
		if (!file_exists(JPATH_ADMINISTRATOR . '/components/com_akeeba'))
		{
			return;
		}

		// Make sure Akeeba Backup is enabled
		if (!ComponentHelper::isEnabled('com_akeeba'))
		{
			return;
		}

		// Load FOF
		if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
		{
			return;
		}

		$this->container = Container::getInstance('com_akeeba');

		// No point in logging guest actions
		if ($this->container->platform->getUser()->guest)
		{
			return;
		}

		// If any of the above statement returned, our plugin is not attached to the subject, so it's basically disabled
		parent::__construct($subject, $config);
	}

	/**
	 * Logs the creation of a new backup profile
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Profiles  $controller
	 * @param   array                                     $data
	 * @param   int                                       $id
	 */
	public function onComAkeebaControllerProfilesAfterApplySave($controller, $data, $id)
	{
		// If I have an ID in the request and it's the same of the model, I'm just editing a record
		if (isset($data['id']) && $data['id'] == $id)
		{
			return;
		}

		$profile_title = $data['description'];

		$this->container->platform->logUserAction($profile_title, 'COM_AKEEBA_LOGS_PROFILE_ADD', 'com_akeeba');
	}

	/**
	 * Logs deletion of a backup profile
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Profiles  $controller
	 */
	public function onComAkeebaControllerProfilesAfterRemove($controller)
	{
		$ids           = $controller->input->get('cid', [], 'array', 2);
		$profile_title = '# ' . implode(', ', $ids);

		$this->container->platform->logUserAction($profile_title, 'COM_AKEEBA_LOGS_PROFILE_DELETE', 'com_akeeba');
	}

	/**
	 * Log configuration edit (apply)
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Configuration  $controller
	 */
	public function onComAkeebaControllerConfigurationAfterApply($controller)
	{
		$this->logConfigurationChange();
	}

	/**
	 * Log configuration edit (save and close)
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Configuration  $controller
	 */
	public function onComAkeebaControllerConfigurationAfterSave($controller)
	{
		$this->logConfigurationChange();
	}

	/**
	 * Log configuration edit (save and new)
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Configuration  $controller
	 */
	public function onComAkeebaControllerConfigurationAfterSavenew($controller)
	{
		$this->logConfigurationChange();
	}

	/**
	 * Log starting a new backup
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Backup  $controller
	 */
	public function onComAkeebaControllerBackupBeforeAjax($controller)
	{
		$ajaxTask = $this->container->input->get('ajax', '', 'cmd');

		// Log only starting the backup
		if ($ajaxTask != 'start')
		{
			return;
		}

		$profile_id = $this->container->platform->getSessionVar('profile', -10, 'akeeba');

		if ($profile_id < 1)
		{
			return;
		}

		$profile_id = '#' . $profile_id;

		$this->container->platform->logUserAction($profile_id, 'COM_AKEEBA_LOGS_BACKUP_RUN', 'com_akeeba');
	}

	/**
	 * Log downloading a backup using Joomla interface
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Manage  $controller
	 */
	public function onComAkeebaControllerManageBeforeDownload($controller)
	{
		$id   = $this->container->input->getInt('id');
		$part = $this->container->input->getInt('part', -1);

		// This should never happens, but better be safe
		if (!$id)
		{
			return;
		}

		$stat         = Platform::getInstance()->get_statistics($id);
		$profile_name = Platform::getInstance()->get_profile_name($stat['profile_id']);

		$title = 'Profile: "' . $profile_name . '" ID: ' . $id;

		if ($part > -1)
		{
			$title .= ' part: ' . $part;
		}

		$this->container->platform->logUserAction($title, 'COM_AKEEBA_LOGS_MANAGE_DOWNLOAD', 'com_akeeba');
	}

	/**
	 * Logs deleting backup files
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Manage  $controller
	 */
	public function onComAkeebaControllerManageBeforeDeletefiles($controller)
	{
		$ids = $this->getIDsFromRequest();

		foreach ($ids as $id)
		{
			$this->container->platform->logUserAction('ID: ' . $id, 'COM_AKEEBA_LOGS_MANAGE_DELETEFILES', 'com_akeeba');
		}
	}

	/**
	 * Logs deleting backup stat entry
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Manage  $controller
	 */
	public function onComAkeebaControllerManageBeforeRemove($controller)
	{
		$ids = $this->getIDsFromRequest();

		foreach ($ids as $id)
		{
			$this->container->platform->logUserAction($id, 'COM_AKEEBA_LOGS_MANAGE_DELETE', 'com_akeeba');
		}
	}

	/**
	 * Logs downloading remote archives to browser
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\RemoteFiles  $controller
	 */
	public function onComAkeebaControllerRemoteFilesBeforeDlfromremote($controller)
	{
		$id   = $this->container->input->getInt('id');
		$part = $this->container->input->getInt('part', -1);

		// This should never happens, but better be safe
		if (!$id)
		{
			return;
		}

		$stat         = Platform::getInstance()->get_statistics($id);
		$profile_name = Platform::getInstance()->get_profile_name($stat['profile_id']);

		$title = 'Profile: "' . $profile_name . '" ID: ' . $id;

		if ($part > -1)
		{
			$title .= ' part: ' . $part;
		}

		$this->container->platform->logUserAction($title, 'COM_AKEEBA_LOGS_REMOTEFILE_DOWNLOAD', 'com_akeeba');
	}

	/**
	 * Logs downloading remote archives back to the server
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\RemoteFiles  $controller
	 */
	public function onComAkeebaControllerRemoteFilesBeforeDltoserver($controller)
	{
		$id   = $this->container->input->getInt('id');
		$part = $this->container->input->getInt('part', -1);
		$frag = $this->container->input->getInt('frag', -1);

		// Log only the first step
		if ($frag > -1 || $part > -1)
		{
			return;
		}

		// This should never happens, but better be safe
		if (!$id)
		{
			return;
		}

		$stat         = Platform::getInstance()->get_statistics($id);
		$profile_name = Platform::getInstance()->get_profile_name($stat['profile_id']);

		$title = 'Profile: "' . $profile_name . '" ID: ' . $id;

		$this->container->platform->logUserAction($title, 'COM_AKEEBA_LOGS_REMOTEFILE_FETCH', 'com_akeeba');
	}

	/**
	 * Logs downloading remote archives to browser
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\RemoteFiles  $controller
	 */
	public function onComAkeebaControllerRemoteFilesBeforeDelete($controller)
	{
		$id   = $this->container->input->getInt('id');
		$part = $this->container->input->getInt('part', -1);

		// This should never happens, but better be safe
		if (!$id)
		{
			return;
		}

		$stat         = Platform::getInstance()->get_statistics($id);
		$profile_name = Platform::getInstance()->get_profile_name($stat['profile_id']);

		$title = 'Profile: "' . $profile_name . '" ID: ' . $id;

		if ($part > -1)
		{
			$title .= ' part: ' . $part;
		}

		$this->container->platform->logUserAction($title, 'COM_AKEEBA_LOGS_REMOTEFILE_DELETE', 'com_akeeba');
	}

	/**
	 * Logs downloading remote archives to browser
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Upload  $controller
	 */
	public function onComAkeebaControllerUploadBeforeStart($controller)
	{
		$id = $this->container->input->getInt('id');

		// This should never happens, but better be safe
		if (!$id)
		{
			return;
		}

		$stat         = Platform::getInstance()->get_statistics($id);
		$profile_name = Platform::getInstance()->get_profile_name($stat['profile_id']);

		$title = 'Profile: "' . $profile_name . '" ID: ' . $id;

		$this->container->platform->logUserAction($title, 'COM_AKEEBA_LOGS_UPLOADS_ADD', 'com_akeeba');
	}

	/**
	 * Log starting a site transfer wizard (connections valid, just before starting to actually transfer files)
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Transfer  $controller
	 */
	public function onComAkeebaControllerTransferBeforeUpload($controller)
	{
		$start = $this->container->input->getBool('start', false);

		if (!$start)
		{
			return;
		}

		$title = $this->container->platform->getSessionVar('transfer.url', '', 'akeeba');

		if (!$title)
		{
			return;
		}

		$this->container->platform->logUserAction($title, 'COM_AKEEBA_LOGS_TRANSFER_RUN', 'com_akeeba');
	}

	/**
	 * Logs downloading a backup log
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Log  $controller
	 */
	public function onComAkeebaControllerLogBeforeDownload($controller)
	{
		$tag = $this->container->input->get('tag', null, 'cmd');;

		$this->container->platform->logUserAction($tag, 'COM_AKEEBA_LOGS_LOG_DOWNLOAD', 'com_akeeba');
	}

	/**
	 * Log importing a backup archive
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Discover  $controller
	 */
	public function onComAkeebaControllerDiscoverBeforeImport($controller)
	{
		$files = $this->container->input->get('files', [], 'array');

		foreach ($files as $file)
		{
			$this->container->platform->logUserAction($file, 'COM_AKEEBA_LOGS_DISCOVER_IMPORT', 'com_akeeba');
		}
	}

	/**
	 * Log importing a backup archive from S3
	 *
	 * @param   \Akeeba\Backup\Admin\Controller\Discover  $controller
	 */
	public function onComAkeebaControllerS3ImportBeforeDltoserver($controller)
	{
		$file = $this->container->input->get('file', '', 'string');

		// Log only the initial download step
		$part = $this->container->input->getInt('part', -1);
		$frag = $this->container->input->getInt('frag', -1);
		$step = $this->container->input->getInt('step', -1);

		if ($part > -1 || $frag > -1 || $step > -1)
		{
			return;
		}

		$this->container->platform->logUserAction($file, 'COM_AKEEBA_LOGS_S3IMPORT_IMPORT', 'com_akeeba');
	}

	private function logConfigurationChange()
	{
		$profileName = $this->container->input->getString('profilename', null);

		$this->container->platform->logUserAction('"' . $profileName . '"', 'COM_AKEEBA_LOGS_CONFIGURATION_EDIT', 'com_akeeba');
	}

	/**
	 * Gets the list of IDs from the request data
	 *
	 * @return array
	 */
	private function getIDsFromRequest()
	{
		// Get the ID or list of IDs from the request or the configuration
		$cid = $this->container->input->get('cid', [], 'array');
		$id  = $this->container->input->getInt('id', 0);

		$ids = [];

		if (is_array($cid) && !empty($cid))
		{
			$ids = $cid;
		}
		elseif (!empty($id))
		{
			$ids = [$id];
		}

		return $ids;
	}
}
PK��#]���/��'actionlog/akeebabackup/akeebabackup.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<extension version="3.9.0" type="plugin" group="actionlog" method="upgrade">
	<name>PLG_ACTIONLOG_AKEEBABACKUP</name>
	<author>Nicholas K. Dionysopoulos</author>
	<authorEmail>nicholas@dionysopoulos.me</authorEmail>
	<authorUrl>https://www.akeeba.com</authorUrl>
	<copyright>Copyright (c)2006-2023 Nicholas K. Dionysopoulos</copyright>
	<license>GNU General Public License version 3, or later</license>
	<creationDate>2023-02-08</creationDate>
	<version>8.2.7</version>
	<description>PLG_ACTIONLOG_AKEEBABACKUP_XML_DESCRIPTION</description>
	<files>
		<filename plugin="akeebabackup">akeebabackup.php</filename>
		<filename>.htaccess</filename>
		<filename>web.config</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_actionlog_akeebabackup.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_actionlog_akeebabackup.sys.ini</language>
	</languages>

	<scriptfile>script.php</scriptfile>
</extension>PK��#]�)��console/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�fɯfinder/tags/tags.xmlnu�[���<?xml version="1.0" encoding="UTF-8"?>
<extension version="3.1" type="plugin" group="finder" method="upgrade">
	<name>plg_finder_tags</name>
	<author>Joomla! Project</author>
	<creationDate>February 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_TAGS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="tags">tags.php</filename>
	</files>
	<languages>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_tags.ini</language>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_tags.sys.ini</language>
	</languages>
</extension>
PK��#]���5%5%finder/tags/tags.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Tags
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer/adapter.php');

/**
 * Finder adapter for Joomla Tag.
 *
 * @since  3.1
 */
class PlgFinderTags extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $context = 'Tags';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $extension = 'com_tags';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $layout = 'tag';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $type_title = 'Tag';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $table = '#__tags';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $state_field = 'published';

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_tags.tag')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove the items.
		return $this->remove($id);
	}

	/**
	 * Method to determine if the access level of an item changed.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content has just been created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle tags here.
		if ($context === 'com_tags.tag')
		{
			// Check if the access levels are different
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item
			$this->reindex($row->id);
		}

		return true;
	}

	/**
	 * Method to reindex the link information for an item that has been saved.
	 * This event is fired before the data is actually saved so we are going
	 * to queue the item to be indexed later.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle news feeds here
		if ($context === 'com_tags.tag')
		{
			// Query the database for the old access level if the item isn't new
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the plugin.
	 * @param   array    $pks      A list of primary key ids of the content that has changed state.
	 * @param   integer  $value    The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   3.1
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle tags here
		if ($context === 'com_tags.tag')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a FinderIndexerResult object.
	 * @param   string               $format  The item format
	 *
	 * @return  void
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format = 'html')
	{
		// Check if the extension is enabled
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		// Initialize the item parameters.
		$registry = new Registry($item->params);
		$item->params = clone JComponentHelper::getParams('com_tags', true);
		$item->params->merge($registry);

		$item->metadata = new Registry($item->metadata);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension, $this->layout);
		$item->route = TagsHelperRoute::getTagRoute($item->slug);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) && $this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Handle the link to the metadata.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'link');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'author');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'created_by_alias');

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Tag');

		// Add the author taxonomy data.
		if (!empty($item->author) || !empty($item->created_by_alias))
		{
			$item->addTaxonomy('Author', !empty($item->created_by_alias) ? $item->created_by_alias : $item->author);
		}

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('TagsHelperRoute', JPATH_SITE . '/components/com_tags/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   3.1
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query : $db->getQuery(true)
			->select('a.id, a.title, a.alias, a.description AS summary')
			->select('a.created_time AS start_date, a.created_user_id AS created_by')
			->select('a.metakey, a.metadesc, a.metadata, a.language, a.access')
			->select('a.modified_time AS modified, a.modified_user_id AS modified_by')
			->select('a.published AS state, a.access, a.created_time AS start_date, a.params');

		// Handle the alias CASE WHEN portion of the query
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias', '!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias)
			->from('#__tags AS a');

		// Join the #__users table
		$query->select('u.name AS author')
			->join('LEFT', '#__users AS u ON u.id = a.created_user_id');

		// Exclude the ROOT item
		$query->where($db->quoteName('a.id') . ' > 1');

		return $query;
	}

	/**
	 * Method to get a SQL query to load the published and access states for the given tag.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   3.1
	 */
	protected function getStateQuery()
	{
		$query = $this->db->getQuery(true);
		$query->select($this->db->quoteName('a.id'))
			->select($this->db->quoteName('a.' . $this->state_field, 'state') . ', ' . $this->db->quoteName('a.access'))
			->select('NULL AS cat_state, NULL AS cat_access')
			->from($this->db->quoteName($this->table, 'a'));

		return $query;
	}

	/**
	 * Method to get the query clause for getting items to update by time.
	 *
	 * @param   string  $time  The modified timestamp.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   3.1
	 */
	protected function getUpdateQueryByTime($time)
	{
		// Build an SQL query based on the modified time.
		$query = $this->db->getQuery(true)
			->where('a.date >= ' . $this->db->quote($time));

		return $query;
	}
}
PK��#]�)��finder/tags/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��finder/content/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]m�jk++finder/content/content.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Content
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer/adapter.php');

/**
 * Smart Search adapter for com_content.
 *
 * @since  2.5
 */
class PlgFinderContent extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Content';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_content';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'article';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'Article';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__content';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to update the item link information when the item category is
	 * changed. This is fired when the item category is published or unpublished
	 * from the list view.
	 *
	 * @param   string   $extension  The extension whose category has been updated.
	 * @param   array    $pks        A list of primary key ids of the content that has changed state.
	 * @param   integer  $value      The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderCategoryChangeState($extension, $pks, $value)
	{
		// Make sure we're handling com_content categories.
		if ($extension === 'com_content')
		{
			$this->categoryStateChange($pks, $value);
		}
	}

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_content.article')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove item from the index.
		return $this->remove($id);
	}

	/**
	 * Smart Search after save content method.
	 * Reindexes the link information for an article that has been saved.
	 * It also makes adjustments if the access level of an item or the
	 * category to which it belongs has changed.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the content has just been created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle articles here.
		if ($context === 'com_content.article' || $context === 'com_content.form')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item.
			$this->reindex($row->id);
		}

		// Check for access changes in the category.
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Smart Search before content save method.
	 * This event is fired before the data is actually saved.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    If the content is just about to be created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle articles here.
		if ($context === 'com_content.article' || $context === 'com_content.form')
		{
			// Query the database for the old access level if the item isn't new.
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		// Check for access levels from the category.
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level if the item isn't new.
			if (!$isNew)
			{
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the plugin.
	 * @param   array    $pks      An array of primary key ids of the content that has changed state.
	 * @param   integer  $value    The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle articles here.
		if ($context === 'com_content.article' || $context === 'com_content.form')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled.
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a FinderIndexerResult object.
	 * @param   string               $format  The item format.  Not used.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format = 'html')
	{
		$item->setLanguage();

		// Check if the extension is enabled.
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->context = 'com_content.article';

		// Initialise the item parameters.
		$registry = new Registry($item->params);
		$item->params = clone JComponentHelper::getParams('com_content', true);
		$item->params->merge($registry);

		$item->metadata = new Registry($item->metadata);

		// Trigger the onContentPrepare event.
		$item->summary = FinderIndexerHelper::prepareContent($item->summary, $item->params, $item);
		$item->body    = FinderIndexerHelper::prepareContent($item->body, $item->params, $item);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension, $this->layout);
		$item->route = ContentHelperRoute::getArticleRoute($item->slug, $item->catid, $item->language);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) && $this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Add the metadata processing instructions.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'author');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'created_by_alias');

		// Translate the state. Articles should only be published if the category is published.
		$item->state = $this->translateState($item->state, $item->cat_state);

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Article');

		// Add the author taxonomy data.
		if (!empty($item->author) || !empty($item->created_by_alias))
		{
			$item->addTaxonomy('Author', !empty($item->created_by_alias) ? $item->created_by_alias : $item->author);
		}

		// Add the category taxonomy data.
		$item->addTaxonomy('Category', $item->category, $item->cat_state, $item->cat_access);

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query : $db->getQuery(true)
			->select('a.id, a.title, a.alias, a.introtext AS summary, a.fulltext AS body')
			->select('a.images')
			->select('a.state, a.catid, a.created AS start_date, a.created_by')
			->select('a.created_by_alias, a.modified, a.modified_by, a.attribs AS params')
			->select('a.metakey, a.metadesc, a.metadata, a.language, a.access, a.version, a.ordering')
			->select('a.publish_up AS publish_start_date, a.publish_down AS publish_end_date')
			->select('c.title AS category, c.published AS cat_state, c.access AS cat_access');

		// Handle the alias CASE WHEN portion of the query
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias', '!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$case_when_category_alias = ' CASE WHEN ';
		$case_when_category_alias .= $query->charLength('c.alias', '!=', '0');
		$case_when_category_alias .= ' THEN ';
		$c_id = $query->castAsChar('c.id');
		$case_when_category_alias .= $query->concatenate(array($c_id, 'c.alias'), ':');
		$case_when_category_alias .= ' ELSE ';
		$case_when_category_alias .= $c_id . ' END as catslug';
		$query->select($case_when_category_alias)

			->select('u.name AS author')
			->from('#__content AS a')
			->join('LEFT', '#__categories AS c ON c.id = a.catid')
			->join('LEFT', '#__users AS u ON u.id = a.created_by');

		return $query;
	}
}
PK��#]n��!((finder/content/content.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="finder" method="upgrade">
	<name>plg_finder_content</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_CONTENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="content">content.php</filename>
	</files>
	<languages>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_content.ini</language>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_content.sys.ini</language>
	</languages>
</extension>
PK��#]�)��finder/contacts/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�m�7070finder/contacts/contacts.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Contacts
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer/adapter.php');

/**
 * Finder adapter for Joomla Contacts.
 *
 * @since  2.5
 */
class PlgFinderContacts extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Contacts';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_contact';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'contact';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'Contact';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__contact_details';

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $state_field = 'published';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to update the item link information when the item category is
	 * changed. This is fired when the item category is published or unpublished
	 * from the list view.
	 *
	 * @param   string   $extension  The extension whose category has been updated.
	 * @param   array    $pks        A list of primary key ids of the content that has changed state.
	 * @param   integer  $value      The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderCategoryChangeState($extension, $pks, $value)
	{
		// Make sure we're handling com_contact categories
		if ($extension === 'com_contact')
		{
			$this->categoryStateChange($pks, $value);
		}
	}

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * This event will fire when contacts are deleted and when an indexed item is deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_contact.contact')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove the items.
		return $this->remove($id);
	}

	/**
	 * Method to determine if the access level of an item changed.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content has just been created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle contacts here
		if ($context === 'com_contact.contact')
		{
			// Check if the access levels are different
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item
			$this->reindex($row->id);
		}

		// Check for access changes in the category
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Method to reindex the link information for an item that has been saved.
	 * This event is fired before the data is actually saved so we are going
	 * to queue the item to be indexed later.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle contacts here
		if ($context === 'com_contact.contact')
		{
			// Query the database for the old access level if the item isn't new
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		// Check for access levels from the category
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level if the item isn't new
			if (!$isNew)
			{
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the plugin.
	 * @param   array    $pks      A list of primary key ids of the content that has changed state.
	 * @param   integer  $value    The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle contacts here
		if ($context === 'com_contact.contact')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a FinderIndexerResult object.
	 * @param   string               $format  The item format
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format = 'html')
	{
		// Check if the extension is enabled
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		// Initialize the item parameters.
		$item->params = new Registry($item->params);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension, $this->layout);
		$item->route = ContactHelperRoute::getContactRoute($item->slug, $item->catslug, $item->language);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) && $this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		/*
		 * Add the metadata processing instructions based on the contact
		 * configuration parameters.
		 */
		// Handle the contact position.
		if ($item->params->get('show_position', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'position');
		}

		// Handle the contact street address.
		if ($item->params->get('show_street_address', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'address');
		}

		// Handle the contact city.
		if ($item->params->get('show_suburb', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'city');
		}

		// Handle the contact region.
		if ($item->params->get('show_state', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'region');
		}

		// Handle the contact country.
		if ($item->params->get('show_country', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'country');
		}

		// Handle the contact zip code.
		if ($item->params->get('show_postcode', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'zip');
		}

		// Handle the contact telephone number.
		if ($item->params->get('show_telephone', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'telephone');
		}

		// Handle the contact fax number.
		if ($item->params->get('show_fax', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'fax');
		}

		// Handle the contact email address.
		if ($item->params->get('show_email', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'email');
		}

		// Handle the contact mobile number.
		if ($item->params->get('show_mobile', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'mobile');
		}

		// Handle the contact webpage.
		if ($item->params->get('show_webpage', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'webpage');
		}

		// Handle the contact user name.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'user');

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Contact');

		// Add the category taxonomy data.
		$item->addTaxonomy('Category', $item->category, $item->cat_state, $item->cat_access);

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Add the region taxonomy data.
		if (!empty($item->region) && $this->params->get('tax_add_region', true))
		{
			$item->addTaxonomy('Region', $item->region);
		}

		// Add the country taxonomy data.
		if (!empty($item->country) && $this->params->get('tax_add_country', true))
		{
			$item->addTaxonomy('Country', $item->country);
		}

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('ContactHelperRoute', JPATH_SITE . '/components/com_contact/helpers/route.php');

		// This is a hack to get around the lack of a route helper.
		FinderIndexerHelper::getContentPath('index.php?option=com_contact');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query : $db->getQuery(true)
			->select('a.id, a.name AS title, a.alias, a.con_position AS position, a.address, a.created AS start_date')
			->select('a.created_by_alias, a.modified, a.modified_by')
			->select('a.metakey, a.metadesc, a.metadata, a.language')
			->select('a.sortname1, a.sortname2, a.sortname3')
			->select('a.publish_up AS publish_start_date, a.publish_down AS publish_end_date')
			->select('a.suburb AS city, a.state AS region, a.country, a.postcode AS zip')
			->select('a.telephone, a.fax, a.misc AS summary, a.email_to AS email, a.mobile')
			->select('a.webpage, a.access, a.published AS state, a.ordering, a.params, a.catid')
			->select('c.title AS category, c.published AS cat_state, c.access AS cat_access');

		// Handle the alias CASE WHEN portion of the query
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias', '!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$case_when_category_alias = ' CASE WHEN ';
		$case_when_category_alias .= $query->charLength('c.alias', '!=', '0');
		$case_when_category_alias .= ' THEN ';
		$c_id = $query->castAsChar('c.id');
		$case_when_category_alias .= $query->concatenate(array($c_id, 'c.alias'), ':');
		$case_when_category_alias .= ' ELSE ';
		$case_when_category_alias .= $c_id . ' END as catslug';
		$query->select($case_when_category_alias)

			->select('u.name')
			->from('#__contact_details AS a')
			->join('LEFT', '#__categories AS c ON c.id = a.catid')
			->join('LEFT', '#__users AS u ON u.id = a.user_id');

		return $query;
	}
}
PK��#]���..finder/contacts/contacts.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="finder" method="upgrade">
	<name>plg_finder_contacts</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_CONTACTS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contacts">contacts.php</filename>
	</files>
	<languages>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_contacts.ini</language>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_contacts.sys.ini</language>
	</languages>
</extension>
PK��#]2���*�* finder/categories/categories.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Categories
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer/adapter.php');

/**
 * Smart Search adapter for Joomla Categories.
 *
 * @since  2.5
 */
class PlgFinderCategories extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Categories';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_categories';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'category';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'Category';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__categories';

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $state_field = 'published';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderDelete($context, $table)
	{
		if ($context === 'com_categories.category')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove item from the index.
		return $this->remove($id);
	}

	/**
	 * Smart Search after save content method.
	 * Reindexes the link information for a category that has been saved.
	 * It also makes adjustments if the access level of the category has changed.
	 *
	 * @param   string   $context  The context of the category passed to the plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the category has just been created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle categories here.
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the category item.
			$this->reindex($row->id);

			// Check if the parent access level is different.
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Smart Search before content save method.
	 * This event is fired before the data is actually saved.
	 *
	 * @param   string   $context  The context of the category passed to the plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the category is just about to be created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle categories here.
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level and the parent if the item isn't new.
			if (!$isNew)
			{
				$this->checkItemAccess($row);
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the category passed to the plugin.
	 * @param   array    $pks      An array of primary key ids of the category that has changed state.
	 * @param   integer  $value    The value of the state that the category has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle categories here.
		if ($context === 'com_categories.category')
		{
			/*
			 * The category published state is tied to the parent category
			 * published state so we need to look up all published states
			 * before we change anything.
			 */
			foreach ($pks as $pk)
			{
				$query = clone $this->getStateQuery();
				$query->where('a.id = ' . (int) $pk);

				$this->db->setQuery($query);
				$item = $this->db->loadObject();

				// Translate the state.
				$state = null;

				if ($item->parent_id != 1)
				{
					$state = $item->cat_state;
				}

				$temp = $this->translateState($value, $state);

				// Update the item.
				$this->change($pk, 'state', $temp);

				// Reindex the item.
				$this->reindex($pk);
			}
		}

		// Handle when the plugin is disabled.
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a FinderIndexerResult object.
	 * @param   string               $format  The item format.  Not used.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format = 'html')
	{
		// Check if the extension is enabled.
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		// Check if the extension that owns the category is also enabled.
		if (JComponentHelper::isEnabled($item->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		$extension = ucfirst(substr($item->extension, 4));

		// Initialize the item parameters.
		$item->params = new Registry($item->params);

		$item->metadata = new Registry($item->metadata);

		/*
		 * Add the metadata processing instructions based on the category's
		 * configuration parameters.
		 */
		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Handle the link to the metadata.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'link');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'author');

		// Deactivated Methods
		// $item->addInstruction(FinderIndexer::META_CONTEXT, 'created_by_alias');

		// Trigger the onContentPrepare event.
		$item->summary = FinderIndexerHelper::prepareContent($item->summary, $item->params);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $item->extension, $this->layout);

		$class = $extension . 'HelperRoute';

		// Need to import component route helpers dynamically, hence the reason it's handled here.
		JLoader::register($class, JPATH_SITE . '/components/' . $item->extension . '/helpers/route.php');

		if (class_exists($class) && method_exists($class, 'getCategoryRoute'))
		{
			$item->route = $class::getCategoryRoute($item->id, $item->language);
		}
		else
		{
			$item->route = ContentHelperRoute::getCategoryRoute($item->id, $item->language);
		}

		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) && $this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		// Translate the state. Categories should only be published if the parent category is published.
		$item->state = $this->translateState($item->state);

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Category');

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load com_content route helper as it is the fallback for routing in the indexer in this instance.
		JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query : $db->getQuery(true)
			->select('a.id, a.title, a.alias, a.description AS summary, a.extension')
			->select('a.created_user_id AS created_by, a.modified_time AS modified, a.modified_user_id AS modified_by')
			->select('a.metakey, a.metadesc, a.metadata, a.language, a.lft, a.parent_id, a.level')
			->select('a.created_time AS start_date, a.published AS state, a.access, a.params');

		// Handle the alias CASE WHEN portion of the query.
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias', '!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias)
			->from('#__categories AS a')
			->where($db->quoteName('a.id') . ' > 1');

		return $query;
	}

	/**
	 * Method to get a SQL query to load the published and access states for
	 * a category and its parents.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getStateQuery()
	{
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName('a.id'))
			->select($this->db->quoteName('a.parent_id'))
			->select('a.' . $this->state_field . ' AS state, c.published AS cat_state')
			->select('a.access, c.access AS cat_access')
			->from($this->db->quoteName('#__categories') . ' AS a')
			->join('LEFT', '#__categories AS c ON c.id = a.parent_id');

		return $query;
	}
}
PK��#]�y~:: finder/categories/categories.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="finder" method="upgrade">
	<name>plg_finder_categories</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_CATEGORIES_XML_DESCRIPTION</description>
	<files>
		<filename plugin="categories">categories.php</filename>
	</files>
	<languages>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_categories.ini</language>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_categories.sys.ini</language>
	</languages>
</extension>
PK��#]�)��finder/categories/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��finder/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�
=��'�'finder/newsfeeds/newsfeeds.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Newsfeeds
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR . '/components/com_finder/helpers/indexer/adapter.php');

/**
 * Smart Search adapter for Joomla Newsfeeds.
 *
 * @since  2.5
 */
class PlgFinderNewsfeeds extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Newsfeeds';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_newsfeeds';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'newsfeed';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'News Feed';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__newsfeeds';

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $state_field = 'published';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to update the item link information when the item category is
	 * changed. This is fired when the item category is published or unpublished
	 * from the list view.
	 *
	 * @param   string   $extension  The extension whose category has been updated.
	 * @param   array    $pks        An array of primary key ids of the content that has changed state.
	 * @param   integer  $value      The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderCategoryChangeState($extension, $pks, $value)
	{
		// Make sure we're handling com_newsfeeds categories.
		if ($extension === 'com_newsfeeds')
		{
			$this->categoryStateChange($pks, $value);
		}
	}

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be deleted.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_newsfeeds.newsfeed')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove the item from the index.
		return $this->remove($id);
	}

	/**
	 * Smart Search after save content method.
	 * Reindexes the link information for a newsfeed that has been saved.
	 * It also makes adjustments if the access level of a newsfeed item or
	 * the category to which it belongs has been changed.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the content has just been created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle newsfeeds here.
		if ($context === 'com_newsfeeds.newsfeed')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item.
			$this->reindex($row->id);
		}

		// Check for access changes in the category.
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Smart Search before content save method.
	 * This event is fired before the data is actually saved.
	 *
	 * @param   string   $context  The context of the content passed to the plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the content is just about to be created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle newsfeeds here.
		if ($context === 'com_newsfeeds.newsfeed')
		{
			// Query the database for the old access level if the item isn't new.
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		// Check for access levels from the category.
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level if the item isn't new.
			if (!$isNew)
			{
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the plugin.
	 * @param   array    $pks      An array of primary key ids of the content that has changed state.
	 * @param   integer  $value    The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle newsfeeds here.
		if ($context === 'com_newsfeeds.newsfeed')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled.
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a FinderIndexerResult object.
	 * @param   string               $format  The item format.  Not used.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format = 'html')
	{
		// Check if the extension is enabled.
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		// Initialize the item parameters.
		$item->params = new Registry($item->params);

		$item->metadata = new Registry($item->metadata);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension, $this->layout);
		$item->route = NewsfeedsHelperRoute::getNewsfeedRoute($item->slug, $item->catslug, $item->language);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		/*
		 * Add the metadata processing instructions based on the newsfeeds
		 * configuration parameters.
		 */
		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Handle the link to the metadata.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'link');

		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'author');
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'created_by_alias');

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'News Feed');

		// Add the category taxonomy data.
		$item->addTaxonomy('Category', $item->category, $item->cat_state, $item->cat_access);

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('NewsfeedsHelperRoute', JPATH_SITE . '/components/com_newsfeeds/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query : $db->getQuery(true)
			->select('a.id, a.catid, a.name AS title, a.alias, a.link AS link')
			->select('a.published AS state, a.ordering, a.created AS start_date, a.params, a.access')
			->select('a.publish_up AS publish_start_date, a.publish_down AS publish_end_date')
			->select('a.metakey, a.metadesc, a.metadata, a.language')
			->select('a.created_by, a.created_by_alias, a.modified, a.modified_by')
			->select('c.title AS category, c.published AS cat_state, c.access AS cat_access');

		// Handle the alias CASE WHEN portion of the query.
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias', '!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$case_when_category_alias = ' CASE WHEN ';
		$case_when_category_alias .= $query->charLength('c.alias', '!=', '0');
		$case_when_category_alias .= ' THEN ';
		$c_id = $query->castAsChar('c.id');
		$case_when_category_alias .= $query->concatenate(array($c_id, 'c.alias'), ':');
		$case_when_category_alias .= ' ELSE ';
		$case_when_category_alias .= $c_id . ' END as catslug';
		$query->select($case_when_category_alias)

			->from('#__newsfeeds AS a')
			->join('LEFT', '#__categories AS c ON c.id = a.catid');

		return $query;
	}
}
PK��#]���44finder/newsfeeds/newsfeeds.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="finder" method="upgrade">
	<name>plg_finder_newsfeeds</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_NEWSFEEDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="newsfeeds">newsfeeds.php</filename>
	</files>
	<languages>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_newsfeeds.ini</language>
		<language tag="en-GB">language/en-GB/en-GB.plg_finder_newsfeeds.sys.ini</language>
	</languages>
</extension>
PK��#]�)��finder/newsfeeds/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��captcha/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��
�
3captcha/recaptcha_invisible/recaptcha_invisible.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="captcha" method="upgrade">
	<name>plg_captcha_recaptcha_invisible</name>
	<version>3.8</version>
	<creationDate>November 2017</creationDate>
	<author>Joomla! Project</author>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<description>PLG_CAPTCHA_RECAPTCHA_INVISIBLE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="recaptcha_invisible">recaptcha_invisible.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_captcha_recaptcha_invisible.ini</language>
		<language tag="en-GB">en-GB.plg_captcha_recaptcha_invisible.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">

				<field
					name="public_key"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="private_key"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="badge"
					type="list"
					label="PLG_RECAPTCHA_INVISIBLE_BADGE_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_BADGE_DESC"
					default="bottomright"
					>
					<option value="bottomright">PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMRIGHT</option>
					<option value="bottomleft">PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMLEFT</option>
					<option value="inline">PLG_RECAPTCHA_INVISIBLE_BADGE_INLINE</option>
				</field>

				<field
					name="tabindex"
					type="number"
					label="PLG_RECAPTCHA_INVISIBLE_TABINDEX_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_TABINDEX_DESC"
					default="0"
					min="0"
					filter="integer"
				/>

				<field
					name="callback"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_CALLBACK_DESC"
					default=""
					filter="string"
				/>

				<field
					name="expired_callback"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_DESC"
					default=""
					filter="string"
				/>

				<field
					name="error_callback"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_DESC"
					default=""
					filter="string"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]��y��3captcha/recaptcha_invisible/recaptcha_invisible.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Captcha
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Captcha\Google\HttpBridgePostRequestMethod;
use Joomla\Utilities\IpHelper;

/**
 * Invisible reCAPTCHA Plugin.
 *
 * @since  3.9.0
 */
class PlgCaptchaRecaptcha_Invisible extends \JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Reports the privacy related capabilities for this plugin to site administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_CAPTCHA_RECAPTCHA_INVISIBLE') => array(
				JText::_('PLG_RECAPTCHA_INVISIBLE_PRIVACY_CAPABILITY_IP_ADDRESS'),
			)
		);
	}

	/**
	 * Initialise the captcha
	 *
	 * @param   string  $id  The id of the field.
	 *
	 * @return  boolean	True on success, false otherwise
	 *
	 * @since   3.9.0
	 * @throws  \RuntimeException
	 */
	public function onInit($id = 'dynamic_recaptcha_invisible_1')
	{
		$pubkey = $this->params->get('public_key', '');

		if ($pubkey === '')
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PUBLIC_KEY'));
		}

		// Load callback first for browser compatibility
		\JHtml::_(
			'script',
			'plg_captcha_recaptcha_invisible/recaptcha.min.js',
			array('version' => 'auto', 'relative' => true),
			array('async' => 'async', 'defer' => 'defer')
		);

		// Load Google reCAPTCHA api js
		$file = 'https://www.google.com/recaptcha/api.js'
			. '?onload=JoomlaInitReCaptchaInvisible'
			. '&render=explicit'
			. '&hl=' . \JFactory::getLanguage()->getTag();
		\JHtml::_(
			'script',
			$file,
			array(),
			array('async' => 'async', 'defer' => 'defer')
		);

		return true;
	}

	/**
	 * Gets the challenge HTML
	 *
	 * @param   string  $name   The name of the field. Not Used.
	 * @param   string  $id     The id of the field.
	 * @param   string  $class  The class of the field.
	 *
	 * @return  string  The HTML to be embedded in the form.
	 *
	 * @since  3.9.0
	 */
	public function onDisplay($name = null, $id = 'dynamic_recaptcha_invisible_1', $class = '')
	{
		$dom = new \DOMDocument('1.0', 'UTF-8');
		$ele = $dom->createElement('div');
		$ele->setAttribute('id', $id);
		$ele->setAttribute('class', ((trim($class) == '') ? 'g-recaptcha' : ($class . ' g-recaptcha')));
		$ele->setAttribute('data-sitekey', $this->params->get('public_key', ''));
		$ele->setAttribute('data-badge', $this->params->get('badge', 'bottomright'));
		$ele->setAttribute('data-size', 'invisible');
		$ele->setAttribute('data-tabindex', $this->params->get('tabindex', '0'));
		$ele->setAttribute('data-callback', $this->params->get('callback', ''));
		$ele->setAttribute('data-expired-callback', $this->params->get('expired_callback', ''));
		$ele->setAttribute('data-error-callback', $this->params->get('error_callback', ''));
		$dom->appendChild($ele);

		return $dom->saveHTML($ele);
	}

	/**
	 * Calls an HTTP POST function to verify if the user's guess was correct
	 *
	 * @param   string  $code  Answer provided by user. Not needed for the Recaptcha implementation
	 *
	 * @return  boolean  True if the answer is correct, false otherwise
	 *
	 * @since   3.9.0
	 * @throws  \RuntimeException
	 */
	public function onCheckAnswer($code = null)
	{
		$input      = \JFactory::getApplication()->input;
		$privatekey = $this->params->get('private_key');
		$remoteip   = IpHelper::getIp();

		$response  = $input->get('g-recaptcha-response', '', 'string');

		// Check for Private Key
		if (empty($privatekey))
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PRIVATE_KEY'));
		}

		// Check for IP
		if (empty($remoteip))
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_IP'));
		}

		// Discard spam submissions
		if (trim($response) == '')
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_EMPTY_SOLUTION'));
		}

		return $this->getResponse($privatekey, $remoteip, $response);
	}

	/**
	 * Method to react on the setup of a captcha field. Gives the possibility
	 * to change the field and/or the XML element for the field.
	 *
	 * @param   \Joomla\CMS\Form\Field\CaptchaField  $field    Captcha field instance
	 * @param   \SimpleXMLElement                    $element  XML form definition
	 *
	 * @return void
	 *
	 * @since 3.9.0
	 */
	public function onSetupField(\Joomla\CMS\Form\Field\CaptchaField $field, \SimpleXMLElement $element)
	{
		// Hide the label for the invisible recaptcha type
		$element['hiddenLabel'] = true;
	}

	/**
	 * Get the reCaptcha response.
	 *
	 * @param   string  $privatekey  The private key for authentication.
	 * @param   string  $remoteip    The remote IP of the visitor.
	 * @param   string  $response    The response received from Google.
	 *
	 * @return  boolean  True if response is good | False if response is bad.
	 *
	 * @since   3.9.0
	 * @throws  \RuntimeException
	 */
	private function getResponse($privatekey, $remoteip, $response)
	{
		$reCaptcha = new \ReCaptcha\ReCaptcha($privatekey, new HttpBridgePostRequestMethod);
		$response = $reCaptcha->verify($response, $remoteip);

		if (!$response->isSuccess())
		{
			foreach ($response->getErrorCodes() as $error)
			{
				throw new \RuntimeException($error);
			}

			return false;
		}

		return true;
	}
}
PK��#]�)��%captcha/recaptcha_invisible/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�-4�)captcha/recaptcha/postinstall/actions.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Captcha
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 *
 * This file contains the functions used by the com_postinstall code to deliver
 * the necessary post-installation messages for the end of life of reCAPTCHA V1.
 */

/**
 * Checks if the plugin is enabled and reCAPTCHA V1 is being used. If true then the
 * message about reCAPTCHA v1 EOL should be displayed.
 *
 * @return  boolean
 *
 * @since  3.8.6
 */
function recaptcha_postinstall_condition()
{
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->select('1')
		->from($db->qn('#__extensions'))
		->where($db->qn('name') . ' = ' . $db->q('plg_captcha_recaptcha'))
		->where($db->qn('enabled') . ' = 1')
		->where($db->qn('params') . ' LIKE ' . $db->q('%1.0%'));
	$db->setQuery($query);
	$enabled_plugins = $db->loadObjectList();

	return count($enabled_plugins) === 1;
}

/**
 * Open the reCAPTCHA plugin so that they can update the settings to V2 and new keys.
 *
 * @return  void
 *
 * @since   3.8.6
 */
function recaptcha_postinstall_action()
{
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->select('extension_id')
		->from($db->qn('#__extensions'))
		->where($db->qn('name') . ' = ' . $db->q('plg_captcha_recaptcha'));
	$db->setQuery($query);
	$e_id = $db->loadResult();

	$url = 'index.php?option=com_plugins&task=plugin.edit&extension_id=' . $e_id;
	JFactory::getApplication()->redirect($url);
}
PK��#]�)��captcha/recaptcha/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��captcha/recaptcha/recaptcha.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.4" type="plugin" group="captcha" method="upgrade">
	<name>plg_captcha_recaptcha</name>
	<version>3.4.0</version>
	<creationDate>December 2011</creationDate>
	<author>Joomla! Project</author>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<description>PLG_CAPTCHA_RECAPTCHA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="recaptcha">recaptcha.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_captcha_recaptcha.ini</language>
		<language tag="en-GB">en-GB.plg_captcha_recaptcha.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="message"
					type="note"
					label="PLG_RECAPTCHA_VERSION_1_WARNING_LABEL"
					showon="version:1.0"
				/>

				<field
					name="version"
					type="list"
					label="PLG_RECAPTCHA_VERSION_LABEL"
					description="PLG_RECAPTCHA_VERSION_DESC"
					default="2.0"
					size="1"
					>
					<option value="1.0">PLG_RECAPTCHA_VERSION_V1</option>
					<option value="2.0">PLG_RECAPTCHA_VERSION_V2</option>
				</field>

				<field
					name="public_key"
					type="text"
					label="PLG_RECAPTCHA_PUBLIC_KEY_LABEL"
					description="PLG_RECAPTCHA_PUBLIC_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="private_key"
					type="text"
					label="PLG_RECAPTCHA_PRIVATE_KEY_LABEL"
					description="PLG_RECAPTCHA_PRIVATE_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="theme"
					type="list"
					label="PLG_RECAPTCHA_THEME_LABEL"
					description="PLG_RECAPTCHA_THEME_DESC"
					default="clean"
					showon="version:1.0"
					filter=""
					>
					<option value="clean">PLG_RECAPTCHA_THEME_CLEAN</option>
					<option value="white">PLG_RECAPTCHA_THEME_WHITE</option>
					<option value="blackglass">PLG_RECAPTCHA_THEME_BLACKGLASS</option>
					<option value="red">PLG_RECAPTCHA_THEME_RED</option>
				</field>

				<field
					name="theme2"
					type="list"
					label="PLG_RECAPTCHA_THEME_LABEL"
					description="PLG_RECAPTCHA_THEME_DESC"
					default="light"
					showon="version:2.0"
					filter=""
					>
					<option value="light">PLG_RECAPTCHA_THEME_LIGHT</option>
					<option value="dark">PLG_RECAPTCHA_THEME_DARK</option>
				</field>

				<field
					name="size"
					type="list"
					label="PLG_RECAPTCHA_SIZE_LABEL"
					description="PLG_RECAPTCHA_SIZE_DESC"
					default="normal"
					showon="version:2.0"
					filter=""
					>
					<option value="normal">PLG_RECAPTCHA_THEME_NORMAL</option>
					<option value="compact">PLG_RECAPTCHA_THEME_COMPACT</option>
				</field>

				<field
					name="tabindex"
					type="number"
					label="PLG_RECAPTCHA_TABINDEX_LABEL"
					description="PLG_RECAPTCHA_TABINDEX_DESC"
					default="0"
					showon="version:2.0"
					min="0"
				/>

				<field
					name="callback"
					type="text"
					label="PLG_RECAPTCHA_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_CALLBACK_DESC"
					default=""
					showon="version:2.0"
					filter="string"
				/>

				<field
					name="expired_callback"
					type="text"
					label="PLG_RECAPTCHA_EXPIRED_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_EXPIRED_CALLBACK_DESC"
					default=""
					showon="version:2.0"
					filter="string"
				/>

				<field
					name="error_callback"
					type="text"
					label="PLG_RECAPTCHA_ERROR_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_ERROR_CALLBACK_DESC"
					default=""
					showon="version:2.0"
					filter="string"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]9t�V&V&captcha/recaptcha/recaptcha.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Captcha
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Captcha\Google\HttpBridgePostRequestMethod;
use Joomla\Utilities\IpHelper;

/**
 * Recaptcha Plugin
 * Based on the official recaptcha library( https://packagist.org/packages/google/recaptcha )
 *
 * @since  2.5
 */
class PlgCaptchaRecaptcha extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Reports the privacy related capabilities for this plugin to site administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_CAPTCHA_RECAPTCHA') => array(
				JText::_('PLG_RECAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS'),
			)
		);
	}

	/**
	 * Initialise the captcha
	 *
	 * @param   string  $id  The id of the field.
	 *
	 * @return  Boolean	True on success, false otherwise
	 *
	 * @since   2.5
	 * @throws  \RuntimeException
	 */
	public function onInit($id = 'dynamic_recaptcha_1')
	{
		$pubkey = $this->params->get('public_key', '');

		if ($pubkey === '')
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_NO_PUBLIC_KEY'));
		}

		if ($this->params->get('version', '1.0') === '1.0')
		{
			JHtml::_('jquery.framework');

			$theme  = $this->params->get('theme', 'clean');
			$file   = 'https://www.google.com/recaptcha/api/js/recaptcha_ajax.js';

			JHtml::_('script', $file);
			JFactory::getDocument()->addScriptDeclaration('jQuery( document ).ready(function()
				{Recaptcha.create("' . $pubkey . '", "' . $id . '", {theme: "' . $theme . '",' . $this->_getLanguage() . 'tabindex: 0});});');
		}
		else
		{
			// Load callback first for browser compatibility
			JHtml::_('script', 'plg_captcha_recaptcha/recaptcha.min.js', array('version' => 'auto', 'relative' => true));

			$file = 'https://www.google.com/recaptcha/api.js?onload=JoomlaInitReCaptcha2&render=explicit&hl=' . JFactory::getLanguage()->getTag();
			JHtml::_('script', $file);
		}

		return true;
	}

	/**
	 * Gets the challenge HTML
	 *
	 * @param   string  $name   The name of the field. Not Used.
	 * @param   string  $id     The id of the field.
	 * @param   string  $class  The class of the field.
	 *
	 * @return  string  The HTML to be embedded in the form.
	 *
	 * @since  2.5
	 */
	public function onDisplay($name = null, $id = 'dynamic_recaptcha_1', $class = '')
	{
		$dom = new \DOMDocument('1.0', 'UTF-8');
		$ele = $dom->createElement('div');
		$ele->setAttribute('id', $id);

		if ($this->params->get('version', '1.0') === '1.0')
		{
			$ele->setAttribute('class', $class);
		}
		else
		{
			$ele->setAttribute('class', ((trim($class) == '') ? 'g-recaptcha' : ($class . ' g-recaptcha')));
			$ele->setAttribute('data-sitekey', $this->params->get('public_key', ''));
			$ele->setAttribute('data-theme', $this->params->get('theme2', 'light'));
			$ele->setAttribute('data-size', $this->params->get('size', 'normal'));
			$ele->setAttribute('data-tabindex', $this->params->get('tabindex', '0'));
			$ele->setAttribute('data-callback', $this->params->get('callback', ''));
			$ele->setAttribute('data-expired-callback', $this->params->get('expired_callback', ''));
			$ele->setAttribute('data-error-callback', $this->params->get('error_callback', ''));
		}

		$dom->appendChild($ele);
		return $dom->saveHTML($ele);
	}

	/**
	 * Calls an HTTP POST function to verify if the user's guess was correct
	 *
	 * @param   string  $code  Answer provided by user. Not needed for the Recaptcha implementation
	 *
	 * @return  True if the answer is correct, false otherwise
	 *
	 * @since   2.5
	 * @throws  \RuntimeException
	 */
	public function onCheckAnswer($code = null)
	{
		$input      = \JFactory::getApplication()->input;
		$privatekey = $this->params->get('private_key');
		$version    = $this->params->get('version', '1.0');
		$remoteip   = IpHelper::getIp();

		switch ($version)
		{
			case '1.0':
				$challenge = $input->get('recaptcha_challenge_field', '', 'string');
				$response  = $code ? $code : $input->get('recaptcha_response_field', '', 'string');
				$spam      = ($challenge === '' || $response === '');
				break;
			case '2.0':
				// Challenge Not needed in 2.0 but needed for getResponse call
				$challenge = null;
				$response  = $code ? $code : $input->get('g-recaptcha-response', '', 'string');
				$spam      = ($response === '');
				break;
		}

		// Check for Private Key
		if (empty($privatekey))
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_NO_PRIVATE_KEY'));
		}

		// Check for IP
		if (empty($remoteip))
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_NO_IP'));
		}

		// Discard spam submissions
		if ($spam)
		{
			throw new \RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_EMPTY_SOLUTION'));
		}

		return $this->getResponse($privatekey, $remoteip, $response, $challenge);
	}

	/**
	 * Get the reCaptcha response.
	 *
	 * @param   string  $privatekey  The private key for authentication.
	 * @param   string  $remoteip    The remote IP of the visitor.
	 * @param   string  $response    The response received from Google.
	 * @param   string  $challenge   The challenge field from the reCaptcha. Only for 1.0
	 *
	 * @return bool True if response is good | False if response is bad.
	 *
	 * @since   3.4
	 * @throws  \RuntimeException
	 */
	private function getResponse($privatekey, $remoteip, $response, $challenge = null)
	{
		$version = $this->params->get('version', '1.0');

		switch ($version)
		{
			case '1.0':
				$response = $this->_recaptcha_http_post(
					'www.google.com', '/recaptcha/api/verify',
					array(
						'privatekey' => $privatekey,
						'remoteip'   => $remoteip,
						'challenge'  => $challenge,
						'response'   => $response
					)
				);

				$answers = explode("\n", $response[1]);

				if (trim($answers[0]) !== 'true')
				{
					// @todo use exceptions here
					$this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_' . strtoupper(str_replace('-', '_', $answers[1]))));

					return false;
				}
				break;
			case '2.0':
				$reCaptcha = new \ReCaptcha\ReCaptcha($privatekey, new HttpBridgePostRequestMethod);
				$response = $reCaptcha->verify($response, $remoteip);

				if (!$response->isSuccess())
				{
					foreach ($response->getErrorCodes() as $error)
					{
						throw new \RuntimeException($error);
					}

					return false;
				}
				break;
		}

		return true;
	}

	/**
	 * Encodes the given data into a query string format.
	 *
	 * @param   array  $data  Array of string elements to be encoded
	 *
	 * @return  string  Encoded request
	 *
	 * @since  2.5
	 */
	private function _recaptcha_qsencode($data)
	{
		$req = '';

		foreach ($data as $key => $value)
		{
			$req .= $key . '=' . urlencode(stripslashes($value)) . '&';
		}

		// Cut the last '&'
		$req = rtrim($req, '&');

		return $req;
	}

	/**
	 * Submits an HTTP POST to a reCAPTCHA server.
	 *
	 * @param   string  $host  Host name to POST to.
	 * @param   string  $path  Path on host to POST to.
	 * @param   array   $data  Data to be POSTed.
	 * @param   int     $port  Optional port number on host.
	 *
	 * @return  array   Response
	 *
	 * @since  2.5
	 */
	private function _recaptcha_http_post($host, $path, $data, $port = 80)
	{
		$req = $this->_recaptcha_qsencode($data);

		$http_request  = "POST $path HTTP/1.0\r\n";
		$http_request .= "Host: $host\r\n";
		$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
		$http_request .= "Content-Length: " . strlen($req) . "\r\n";
		$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
		$http_request .= "\r\n";
		$http_request .= $req;

		$response = '';

		if (($fs = @fsockopen($host, $port, $errno, $errstr, 10)) === false)
		{
			die('Could not open socket');
		}

		fwrite($fs, $http_request);

		while (!feof($fs))
		{
			// One TCP-IP packet
			$response .= fgets($fs, 1160);
		}

		fclose($fs);
		$response = explode("\r\n\r\n", $response, 2);

		return $response;
	}

	/**
	 * Get the language tag or a custom translation
	 *
	 * @return  string
	 *
	 * @since  2.5
	 */
	private function _getLanguage()
	{
		$language = JFactory::getLanguage();

		$tag = explode('-', $language->getTag());
		$tag = $tag[0];
		$available = array('en', 'pt', 'fr', 'de', 'nl', 'ru', 'es', 'tr');

		if (in_array($tag, $available))
		{
			return "lang : '" . $tag . "',";
		}

		// If the default language is not available, let's search for a custom translation
		if ($language->hasKey('PLG_RECAPTCHA_CUSTOM_LANG'))
		{
			$custom[] = 'custom_translations : {';
			$custom[] = "\t" . 'instructions_visual : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_VISUAL') . '",';
			$custom[] = "\t" . 'instructions_audio : "' . JText::_('PLG_RECAPTCHA_INSTRUCTIONS_AUDIO') . '",';
			$custom[] = "\t" . 'play_again : "' . JText::_('PLG_RECAPTCHA_PLAY_AGAIN') . '",';
			$custom[] = "\t" . 'cant_hear_this : "' . JText::_('PLG_RECAPTCHA_CANT_HEAR_THIS') . '",';
			$custom[] = "\t" . 'visual_challenge : "' . JText::_('PLG_RECAPTCHA_VISUAL_CHALLENGE') . '",';
			$custom[] = "\t" . 'audio_challenge : "' . JText::_('PLG_RECAPTCHA_AUDIO_CHALLENGE') . '",';
			$custom[] = "\t" . 'refresh_btn : "' . JText::_('PLG_RECAPTCHA_REFRESH_BTN') . '",';
			$custom[] = "\t" . 'help_btn : "' . JText::_('PLG_RECAPTCHA_HELP_BTN') . '",';
			$custom[] = "\t" . 'incorrect_try_again : "' . JText::_('PLG_RECAPTCHA_INCORRECT_TRY_AGAIN') . '",';
			$custom[] = '},';
			$custom[] = "lang : '" . $tag . "',";

			return implode("\n", $custom);
		}

		// If nothing helps fall back to english
		return '';
	}
}
PK��#]�)��content/pagebreak/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]f ph��content/pagebreak/tmpl/toc.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagebreak
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;
?>
<div class="pull-right article-index">

	<?php if ($headingtext) : ?>
	<h3><?php echo $headingtext; ?></h3>
	<?php endif; ?>

	<ul class="nav nav-tabs nav-stacked">
	<?php foreach ($list as $listItem) : ?>
		<?php $class = $listItem->liClass ? ' class="' . $listItem->liClass . '"' : ''; ?>
		<li<?php echo $class; ?>>
			<a href="<?php echo $listItem->link; ?>" class="<?php echo $listItem->class; ?>">
				<?php echo $listItem->title; ?>
			</a>
		</li>
	<?php endforeach; ?>
	</ul>
</div>
PK��#]�54س�%content/pagebreak/tmpl/navigation.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagebreak
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

$lang = JFactory::getLanguage();
?>
<ul>
	<li>
		<?php if ($links['previous']) :
		$direction = $lang->isRtl() ? 'right' : 'left';
		$title = htmlspecialchars($this->list[$page]->title, ENT_QUOTES, 'UTF-8');
		$ariaLabel = JText::_('JPREVIOUS') . ': ' . $title . ' (' . JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', $page, $n) . ')';
		?>
		<a href="<?php echo $links['previous']; ?>" title="<?php echo $title; ?>" aria-label="<?php echo $ariaLabel; ?>" rel="prev">
			<?php echo '<span class="icon-chevron-' . $direction . '" aria-hidden="true"></span> ' . JText::_('JPREV'); ?>
		</a>
		<?php endif; ?>
	</li>
	<li>
		<?php if ($links['next']) :
		$direction = $lang->isRtl() ? 'left' : 'right';
		$title = htmlspecialchars($this->list[$page + 2]->title, ENT_QUOTES, 'UTF-8');
		$ariaLabel = JText::_('JNEXT') . ': ' . $title . ' (' . JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', ($page + 2), $n) . ')';
		?>
		<a href="<?php echo $links['next']; ?>" title="<?php echo $title; ?>" aria-label="<?php echo $ariaLabel; ?>" rel="next">
			<?php echo JText::_('JNEXT') . ' <span class="icon-chevron-' . $direction . '" aria-hidden="true"></span>'; ?>
		</a>
		<?php endif; ?>
	</li>
</ul>
PK��#]��^content/pagebreak/pagebreak.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="content" method="upgrade">
	<name>plg_content_pagebreak</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_PAGEBREAK_XML_DESCRIPTION</description>
	<files>
		<filename plugin="pagebreak">pagebreak.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_pagebreak.ini</language>
		<language tag="en-GB">en-GB.plg_content_pagebreak.sys.ini</language>
	</languages>
	<config>
		<fields name="params">

			<fieldset name="basic">
				<field
					name="title"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_SITE_TITLE_LABEL"
					description="PLG_CONTENT_PAGEBREAK_SITE_TITLE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="article_index"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEX_LABEL"
					description="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEX_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="article_index_text"
					type="text"
					label="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEXTEXT"
					description="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEXTEXT_DESC"
					showon="article_index:1"
				/>

				<field
					name="multipage_toc"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_TOC_LABEL"
					description="PLG_CONTENT_PAGEBREAK_TOC_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="showall"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_SHOW_ALL_LABEL"
					description="PLG_CONTENT_PAGEBREAK_SHOW_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="style"
					type="list"
					label="PLG_CONTENT_PAGEBREAK_STYLE_LABEL"
					description="PLG_CONTENT_PAGEBREAK_STYLE_DESC"
					default="pages"
					>
					<option value="pages">PLG_CONTENT_PAGEBREAK_PAGES</option>
					<option value="sliders">PLG_CONTENT_PAGEBREAK_SLIDERS</option>
					<option value="tabs">PLG_CONTENT_PAGEBREAK_TABS</option>
				</field>
			</fieldset>

		</fields>
	</config>
</extension>
PK��#]}$*�%�%content/pagebreak/pagebreak.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagebreak
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\String\StringHelper;

jimport('joomla.utilities.utility');

JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php');

/**
 * Page break plugin
 *
 * <b>Usage:</b>
 * <code><hr class="system-pagebreak" /></code>
 * <code><hr class="system-pagebreak" title="The page title" /></code>
 * or
 * <code><hr class="system-pagebreak" alt="The first page" /></code>
 * or
 * <code><hr class="system-pagebreak" title="The page title" alt="The first page" /></code>
 * or
 * <code><hr class="system-pagebreak" alt="The first page" title="The page title" /></code>
 *
 * @since  1.6
 */
class PlgContentPagebreak extends JPlugin
{
	/**
	 * The navigation list with all page objects if parameter 'multipage_toc' is active.
	 *
	 * @var    array
	 * @since  3.9.2
	 */
	protected $list = array();

	/**
	 * Plugin that adds a pagebreak into the text and truncates text at that point
	 *
	 * @param   string   $context  The context of the content being passed to the plugin.
	 * @param   object   &$row     The article object.  Note $article->text is also available
	 * @param   mixed    &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  mixed  Always returns void or true
	 *
	 * @since   1.6
	 */
	public function onContentPrepare($context, &$row, &$params, $page = 0)
	{
		$canProceed = $context === 'com_content.article';

		if (!$canProceed)
		{
			return;
		}

		$style = $this->params->get('style', 'pages');

		// Expression to search for.
		$regex = '#<hr(.*)class="system-pagebreak"(.*)\/>#iU';

		$input = JFactory::getApplication()->input;

		$print = $input->getBool('print');
		$showall = $input->getBool('showall');

		if (!$this->params->get('enabled', 1))
		{
			$print = true;
		}

		if ($print)
		{
			$row->text = preg_replace($regex, '<br />', $row->text);

			return true;
		}

		// Simple performance check to determine whether bot should process further.
		if (StringHelper::strpos($row->text, 'class="system-pagebreak') === false)
		{
			if ($page > 0)
			{
				throw new Exception(JText::_('JERROR_PAGE_NOT_FOUND'), 404);
			}

			return true;
		}

		$view = $input->getString('view');
		$full = $input->getBool('fullview');

		if (!$page)
		{
			$page = 0;
		}

		if ($full || $view !== 'article' || $params->get('intro_only') || $params->get('popup'))
		{
			$row->text = preg_replace($regex, '', $row->text);

			return;
		}

		// Load plugin language files only when needed (ex: not needed if no system-pagebreak class exists).
		$this->loadLanguage();

		// Find all instances of plugin and put in $matches.
		$matches = array();
		preg_match_all($regex, $row->text, $matches, PREG_SET_ORDER);

		if ($showall && $this->params->get('showall', 1))
		{
			$hasToc = $this->params->get('multipage_toc', 1);

			if ($hasToc)
			{
				// Display TOC.
				$page = 1;
				$this->_createToc($row, $matches, $page);
			}
			else
			{
				$row->toc = '';
			}

			$row->text = preg_replace($regex, '<br />', $row->text);

			return true;
		}

		// Split the text around the plugin.
		$text = preg_split($regex, $row->text);

		if (!isset($text[$page]))
		{
			throw new Exception(JText::_('JERROR_PAGE_NOT_FOUND'), 404);
		}

		// Count the number of pages.
		$n = count($text);

		// We have found at least one plugin, therefore at least 2 pages.
		if ($n > 1)
		{
			$title  = $this->params->get('title', 1);
			$hasToc = $this->params->get('multipage_toc', 1);

			// Adds heading or title to <site> Title.
			if ($title && $page && isset($matches[$page - 1][0]))
			{
				$attrs = JUtility::parseAttributes($matches[$page - 1][0]);

				if (isset($attrs['title']))
				{
					$row->page_title = $attrs['title'];
				}
			}

			// Reset the text, we already hold it in the $text array.
			$row->text = '';

			if ($style === 'pages')
			{
				// Display TOC.
				if ($hasToc)
				{
					$this->_createToc($row, $matches, $page);
				}
				else
				{
					$row->toc = '';
				}

				// Traditional mos page navigation
				$pageNav = new JPagination($n, $page, 1);

				// Flag indicates to not add limitstart=0 to URL
				$pageNav->hideEmptyLimitstart = true;

				// Page counter.
				$row->text .= '<div class="pagenavcounter">';
				$row->text .= $pageNav->getPagesCounter();
				$row->text .= '</div>';

				// Page text.
				$text[$page] = str_replace('<hr id="system-readmore" />', '', $text[$page]);
				$row->text .= $text[$page];

				// $row->text .= '<br />';
				$row->text .= '<div class="pager">';

				// Adds navigation between pages to bottom of text.
				if ($hasToc)
				{
					$this->_createNavigation($row, $page, $n);
				}

				// Page links shown at bottom of page if TOC disabled.
				if (!$hasToc)
				{
					$row->text .= $pageNav->getPagesLinks();
				}

				$row->text .= '</div>';
			}
			else
			{
				$t[] = $text[0];

				$t[] = (string) JHtml::_($style . '.start', 'article' . $row->id . '-' . $style);

				foreach ($text as $key => $subtext)
				{
					if ($key >= 1)
					{
						$match = $matches[$key - 1];
						$match = (array) JUtility::parseAttributes($match[0]);

						if (isset($match['alt']))
						{
							$title = stripslashes($match['alt']);
						}
						elseif (isset($match['title']))
						{
							$title = stripslashes($match['title']);
						}
						else
						{
							$title = JText::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $key + 1);
						}

						$t[] = (string) JHtml::_($style . '.panel', $title, 'article' . $row->id . '-' . $style . $key);
					}

					$t[] = (string) $subtext;
				}

				$t[] = (string) JHtml::_($style . '.end');

				$row->text = implode(' ', $t);
			}
		}

		return true;
	}

	/**
	 * Creates a Table of Contents for the pagebreak
	 *
	 * @param   object   &$row      The article object.  Note $article->text is also available
	 * @param   array    &$matches  Array of matches of a regex in onContentPrepare
	 * @param   integer  &$page     The 'page' number
	 *
	 * @return  void
	 *
	 * @since  1.6
	 */
	protected function _createToc(&$row, &$matches, &$page)
	{
		$heading     = isset($row->title) ? $row->title : JText::_('PLG_CONTENT_PAGEBREAK_NO_TITLE');
		$input       = JFactory::getApplication()->input;
		$limitstart  = $input->getUInt('limitstart', 0);
		$showall     = $input->getInt('showall', 0);
		$headingtext = '';

		if ($this->params->get('article_index', 1) == 1)
		{
			$headingtext = JText::_('PLG_CONTENT_PAGEBREAK_ARTICLE_INDEX');

			if ($this->params->get('article_index_text'))
			{
				$headingtext = htmlspecialchars($this->params->get('article_index_text'), ENT_QUOTES, 'UTF-8');
			}
		}

		// TOC first Page link.
		$this->list[1]          = new stdClass;
		$this->list[1]->liClass = ($limitstart === 0 && $showall === 0) ? 'toclink active' : 'toclink';
		$this->list[1]->class   = $this->list[1]->liClass;
		$this->list[1]->link    = JRoute::_(ContentHelperRoute::getArticleRoute($row->slug, $row->catid, $row->language));
		$this->list[1]->title   = $heading;

		$i = 2;

		foreach ($matches as $bot)
		{
			if (@$bot[0])
			{
				$attrs2 = JUtility::parseAttributes($bot[0]);

				if (@$attrs2['alt'])
				{
					$title = stripslashes($attrs2['alt']);
				}
				elseif (@$attrs2['title'])
				{
					$title = stripslashes($attrs2['title']);
				}
				else
				{
					$title = JText::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $i);
				}
			}
			else
			{
				$title = JText::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $i);
			}

			$this->list[$i]          = new stdClass;
			$this->list[$i]->link    = JRoute::_(ContentHelperRoute::getArticleRoute($row->slug, $row->catid, $row->language) . '&limitstart=' . ($i - 1));
			$this->list[$i]->title   = $title;
			$this->list[$i]->liClass = ($limitstart === $i - 1) ? 'active' : '';
			$this->list[$i]->class   = ($limitstart === $i - 1) ? 'toclink active' : 'toclink';

			$i++;
		}

		if ($this->params->get('showall'))
		{
			$this->list[$i]          = new stdClass;
			$this->list[$i]->link    = JRoute::_(ContentHelperRoute::getArticleRoute($row->slug, $row->catid, $row->language) . '&showall=1');
			$this->list[$i]->liClass = ($showall === 1) ? 'active' : '';
			$this->list[$i]->class   = ($showall === 1) ? 'toclink active' : 'toclink';
			$this->list[$i]->title   = JText::_('PLG_CONTENT_PAGEBREAK_ALL_PAGES');
		}

		$list = $this->list;
		$path = JPluginHelper::getLayoutPath('content', 'pagebreak', 'toc');
		ob_start();
		include $path;
		$row->toc = ob_get_clean();
	}

	/**
	 * Creates the navigation for the item
	 *
	 * @param   object  &$row  The article object.  Note $article->text is also available
	 * @param   int     $page  The page number
	 * @param   int     $n     The total number of pages
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	protected function _createNavigation(&$row, $page, $n)
	{
		$links = array(
			'next' => '',
			'previous' => ''
		);

		if ($page < $n - 1)
		{
			$links['next'] = JRoute::_(ContentHelperRoute::getArticleRoute($row->slug, $row->catid, $row->language) . '&limitstart=' . ($page + 1));
		}

		if ($page > 0)
		{
			$links['previous'] = ContentHelperRoute::getArticleRoute($row->slug, $row->catid, $row->language);

			if ($page > 1)
			{
				$links['previous'] .= '&limitstart=' . ($page - 1);
			}

			$links['previous'] = JRoute::_($links['previous']);
		}

		$path = JPluginHelper::getLayoutPath('content', 'pagebreak', 'navigation');
		ob_start();
		include $path;
		$row->text .= ob_get_clean();
	}
}
PK��#]�)��content/contact/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]=�S���content/contact/contact.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.Contact
 *
 * @copyright   (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

/**
 * Contact Plugin
 *
 * @since  3.2
 */
class PlgContentContact extends JPlugin
{
	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.3
	 */
	protected $db;

	/**
	 * Plugin that retrieves contact information for contact
	 *
	 * @param   string   $context  The context of the content being passed to the plugin.
	 * @param   mixed    &$row     An object with a "text" property
	 * @param   mixed    $params   Additional parameters. See {@see PlgContentContent()}.
	 * @param   integer  $page     Optional page number. Unused. Defaults to zero.
	 *
	 * @return  boolean	True on success.
	 */
	public function onContentPrepare($context, &$row, $params, $page = 0)
	{
		$allowed_contexts = array('com_content.category', 'com_content.article', 'com_content.featured');

		if (!in_array($context, $allowed_contexts))
		{
			return true;
		}

		// Return if we don't have valid params or don't link the author
		if (!($params instanceof Registry) || !$params->get('link_author'))
		{
			return true;
		}

		// Return if an alias is used
		if ((int) $this->params->get('link_to_alias', 0) === 0 && $row->created_by_alias != '')
		{
			return true;
		}

		// Return if we don't have a valid article id
		if (!isset($row->id) || !(int) $row->id)
		{
			return true;
		}

		$contact        = $this->getContactData($row->created_by);
		$row->contactid = $contact->contactid;
		$row->webpage   = $contact->webpage;
		$row->email     = $contact->email_to;
		$url            = $this->params->get('url', 'url');

		if ($row->contactid && $url === 'url')
		{
			JLoader::register('ContactHelperRoute', JPATH_SITE . '/components/com_contact/helpers/route.php');
			$row->contact_link = JRoute::_(ContactHelperRoute::getContactRoute($contact->contactid . ':' . $contact->alias, $contact->catid));
		}
		elseif ($row->webpage && $url === 'webpage')
		{
			$row->contact_link = $row->webpage;
		}
		elseif ($row->email && $url === 'email')
		{
			$row->contact_link = 'mailto:' . $row->email;
		}
		else
		{
			$row->contact_link = '';
		}

		return true;
	}

	/**
	 * Retrieve Contact
	 *
	 * @param   int  $userId  Id of the user who created the article
	 *
	 * @return  mixed|null|integer
	 */
	protected function getContactData($userId)
	{
		static $contacts = array();

		if (isset($contacts[$userId]))
		{
			return $contacts[$userId];
		}

		$query = $this->db->getQuery(true);

		$query->select('MAX(contact.id) AS contactid, contact.alias, contact.catid, contact.webpage, contact.email_to');
		$query->from($this->db->quoteName('#__contact_details', 'contact'));
		$query->where('contact.published = 1');
		$query->where('contact.user_id = ' . (int) $userId);

		if (JLanguageMultilang::isEnabled() === true)
		{
			$query->where('(contact.language in '
				. '(' . $this->db->quote(JFactory::getLanguage()->getTag()) . ',' . $this->db->quote('*') . ') '
				. ' OR contact.language IS NULL)');
		}

		$this->db->setQuery($query);

		$contacts[$userId] = $this->db->loadObject();

		return $contacts[$userId];
	}
}
PK��#]�=�bbcontent/contact/contact.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin" group="content" method="upgrade">
	<name>plg_content_contact</name>
	<author>Joomla! Project</author>
	<creationDate>January 2014</creationDate>
	<copyright>(C) 2014 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.2.2</version>
	<description>PLG_CONTENT_CONTACT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contact">contact.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_contact.ini</language>
		<language tag="en-GB">en-GB.plg_content_contact.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="url"
					type="list"
					label="PLG_CONTENT_CONTACT_PARAM_URL_LABEL"
					description="PLG_CONTENT_CONTACT_PARAM_URL_DESCRIPTION"
					default="url"
					>
					<option value="url">PLG_CONTENT_CONTACT_PARAM_URL_URL</option>
					<option value="webpage">PLG_CONTENT_CONTACT_PARAM_URL_WEBPAGE</option>
					<option value="email">PLG_CONTENT_CONTACT_PARAM_URL_EMAIL</option>
				</field>

				<field
					name="link_to_alias"
					type="radio"
					label="PLG_CONTENT_CONTACT_PARAM_ALIAS_LABEL"
					description="PLG_CONTENT_CONTACT_PARAM_ALIAS_DESCRIPTION"
					default="0"
					class="btn-group btn-group-yesno"
					filter="integer"
					>
					<option value="0">JNO</option>
					<option value="1">JYES</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��content/loadmodule/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�[z6��!content/loadmodule/loadmodule.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="content" method="upgrade">
	<name>plg_content_loadmodule</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_LOADMODULE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="loadmodule">loadmodule.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_loadmodule.ini</language>
		<language tag="en-GB">en-GB.plg_content_loadmodule.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="style"
					type="list"
					label="PLG_LOADMODULE_FIELD_STYLE_LABEL"
					description="PLG_LOADMODULE_FIELD_STYLE_DESC"
					default="table"
					>
					<option value="table">PLG_LOADMODULE_FIELD_VALUE_TABLE</option>
					<option value="horz">PLG_LOADMODULE_FIELD_VALUE_HORIZONTAL</option>
					<option value="xhtml">PLG_LOADMODULE_FIELD_VALUE_DIVS</option>
					<option value="rounded">PLG_LOADMODULE_FIELD_VALUE_MULTIPLEDIVS</option>
					<option value="none">PLG_LOADMODULE_FIELD_VALUE_RAW</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]Ձ�$��!content/loadmodule/loadmodule.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.loadmodule
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plugin to enable loading modules into content (e.g. articles)
 * This uses the {loadmodule} syntax
 *
 * @since  1.5
 */
class PlgContentLoadmodule extends JPlugin
{
	protected static $modules = array();

	protected static $mods = array();

	/**
	 * Plugin that loads module positions within content
	 *
	 * @param   string   $context   The context of the content being passed to the plugin.
	 * @param   object   &$article  The article object.  Note $article->text is also available
	 * @param   mixed    &$params   The article params
	 * @param   integer  $page      The 'page' number
	 *
	 * @return  mixed   true if there is an error. Void otherwise.
	 *
	 * @since   1.6
	 */
	public function onContentPrepare($context, &$article, &$params, $page = 0)
	{
		// Don't run this plugin when the content is being indexed
		if ($context === 'com_finder.indexer')
		{
			return true;
		}

		// Simple performance check to determine whether bot should process further
		if (strpos($article->text, 'loadposition') === false && strpos($article->text, 'loadmodule') === false)
		{
			return true;
		}

		// Expression to search for (positions)
		$regex = '/{loadposition\s(.*?)}/i';
		$style = $this->params->def('style', 'none');

		// Expression to search for(modules)
		$regexmod = '/{loadmodule\s(.*?)}/i';
		$stylemod = $this->params->def('style', 'none');

		// Expression to search for(id)
		$regexmodid = '/{loadmoduleid\s([1-9][0-9]*)}/i';

		// Find all instances of plugin and put in $matches for loadposition
		// $matches[0] is full pattern match, $matches[1] is the position
		preg_match_all($regex, $article->text, $matches, PREG_SET_ORDER);

		// No matches, skip this
		if ($matches)
		{
			foreach ($matches as $match)
			{
				$matcheslist = explode(',', $match[1]);

				// We may not have a module style so fall back to the plugin default.
				if (!array_key_exists(1, $matcheslist))
				{
					$matcheslist[1] = $style;
				}

				$position = trim($matcheslist[0]);
				$style    = trim($matcheslist[1]);

				$output = $this->_load($position, $style);

				// We should replace only first occurrence in order to allow positions with the same name to regenerate their content:
				if (($start = strpos($article->text, $match[0])) !== false)
				{
					$article->text = substr_replace($article->text, $output, $start, strlen($match[0]));
				}

				$style = $this->params->def('style', 'none');
			}
		}

		// Find all instances of plugin and put in $matchesmod for loadmodule
		preg_match_all($regexmod, $article->text, $matchesmod, PREG_SET_ORDER);

		// If no matches, skip this
		if ($matchesmod)
		{
			foreach ($matchesmod as $matchmod)
			{
				$matchesmodlist = explode(',', $matchmod[1]);

				// We may not have a specific module so set to null
				if (!array_key_exists(1, $matchesmodlist))
				{
					$matchesmodlist[1] = null;
				}

				// We may not have a module style so fall back to the plugin default.
				if (!array_key_exists(2, $matchesmodlist))
				{
					$matchesmodlist[2] = $stylemod;
				}

				$module = trim($matchesmodlist[0]);
				$name   = htmlspecialchars_decode(trim($matchesmodlist[1]));
				$stylemod  = trim($matchesmodlist[2]);

				// $match[0] is full pattern match, $match[1] is the module,$match[2] is the title
				$output = $this->_loadmod($module, $name, $stylemod);

				// We should replace only first occurrence in order to allow positions with the same name to regenerate their content:
				if (($start = strpos($article->text, $matchmod[0])) !== false)
				{
					$article->text = substr_replace($article->text, $output, $start, strlen($matchmod[0]));
				}

				$stylemod = $this->params->def('style', 'none');
			}
		}

		// Find all instances of plugin and put in $matchesmodid for loadmoduleid
		preg_match_all($regexmodid, $article->text, $matchesmodid, PREG_SET_ORDER);

		// If no matches, skip this
		if ($matchesmodid)
		{
			foreach ($matchesmodid as $match)
			{
				$id     = trim($match[1]);
				$output = $this->_loadid($id);

				// We should replace only first occurrence in order to allow positions with the same name to regenerate their content:
				if (($start = strpos($article->text, $match[0])) !== false)
				{
					$article->text = substr_replace($article->text, $output, $start, strlen($match[0]));
				}

				$style = $this->params->def('style', 'none');
			}
		}
	}

	/**
	 * Loads and renders the module
	 *
	 * @param   string  $position  The position assigned to the module
	 * @param   string  $style     The style assigned to the module
	 *
	 * @return  mixed
	 *
	 * @since   1.6
	 */
	protected function _load($position, $style = 'none')
	{
		self::$modules[$position] = '';
		$document = JFactory::getDocument();
		$renderer = $document->loadRenderer('module');
		$modules  = JModuleHelper::getModules($position);
		$params   = array('style' => $style);
		ob_start();

		foreach ($modules as $module)
		{
			echo $renderer->render($module, $params);
		}

		self::$modules[$position] = ob_get_clean();

		return self::$modules[$position];
	}

	/**
	 * This is always going to get the first instance of the module type unless
	 * there is a title.
	 *
	 * @param   string  $module  The module title
	 * @param   string  $title   The title of the module
	 * @param   string  $style   The style of the module
	 *
	 * @return  mixed
	 *
	 * @since   1.6
	 */
	protected function _loadmod($module, $title, $style = 'none')
	{
		self::$mods[$module] = '';
		$document = JFactory::getDocument();
		$renderer = $document->loadRenderer('module');
		$mod      = JModuleHelper::getModule($module, $title);

		// If the module without the mod_ isn't found, try it with mod_.
		// This allows people to enter it either way in the content
		if (!isset($mod))
		{
			$name = 'mod_' . $module;
			$mod  = JModuleHelper::getModule($name, $title);
		}

		$params = array('style' => $style);
		ob_start();

		if ($mod->id)
		{
			echo $renderer->render($mod, $params);
		}

		self::$mods[$module] = ob_get_clean();

		return self::$mods[$module];
	}

	/**
	 * Loads and renders the module
	 *
	 * @param   string  $id  The id of the module
	 *
	 * @return  mixed
	 *
	 * @since   3.9.0
	 */
	protected function _loadid($id)
	{
		self::$modules[$id] = '';
		$document = JFactory::getDocument();
		$renderer = $document->loadRenderer('module');
		$modules  = JModuleHelper::getModuleById($id);
		$params   = array('style' => 'none');
		ob_start();

		if ($modules->id > 0)
		{
			echo $renderer->render($modules, $params);
		}

		self::$modules[$id] = ob_get_clean();

		return self::$modules[$id];
	}
}
PK��#]�)��content/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�F�3content/jce/jce.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2015 Ryan Demmer. All rights reserved
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

/**
 * JCE.
 *
 * @since       2.5.20
 */
class PlgContentJce extends JPlugin
{
    public function onContentPrepareForm($form, $data)
    {
        JFactory::getApplication()->triggerEvent('onPlgSystemJceContentPrepareForm', array($form, $data));
    }
}
PK��#]�Ȭ��content/jce/jce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="1.6" type="plugin" group="content" method="upgrade">
  <name>plg_content_jce</name>
  <version>2.9.38</version>
  <creationDate>27-06-2023</creationDate>
  <author>Ryan Demmer</author>
  <authorEmail>info@joomlacontenteditor.net</authorEmail>
  <authorUrl>http://www.joomlacontenteditor.net</authorUrl>
  <copyright>Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved</copyright>
  <license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
  <description>PLG_CONTENT_JCE_XML_DESCRIPTION</description>
  <files folder="plugins/content/jce">
    <file plugin="jce">jce.php</file>
  </files>

  <languages folder="administrator/language/en-GB">
      <language tag="en-GB">en-GB.plg_content_jce.ini</language>
      <language tag="en-GB">en-GB.plg_content_jce.sys.ini</language>
  </languages>
</extension>
PK��#]�)��content/jce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�<��content/jce/css/media.cssnu&1i�.field-media-wrapper .modal{height:90vh}.field-media-wrapper .modal .modal-body{max-height:100%!important}.field-media-wrapper .modal .modal-body iframe{height:calc(90vh - 120px)!important}PK��#]�#o,,content/jce/css/index.htmlnu&1i�<html><body bgcolor="#FFFFFF"></body></html>PK��#]�)��content/readlesstext/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]q��e�]�]*content/readlesstext/readlesstextthumb.phpnu�[���<?php
/**
 * @package readlesstext
 * @copyright 2008-2014 Parvus
 * @license http://www.gnu.org/licenses/gpl-3.0.html
 * @link http://joomlacode.org/gf/project/cutoff/
 * @author Parvus
 *
 * readless is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * readless is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with readless. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version $Id$
 */

defined( '_JEXEC' ) or die;
jimport( 'joomla.plugin.plugin' );
jimport( 'joomla.utilities.date' );

class ReadLessTextThumb
{
  /**
   * Checks if the given url is still a valid thumbnail url.
   * Determines the correct url to the corresponding thumbnail.
   * If the thumbnail does not exist, it is created
   * @param string $url The url to the thumbnail image
   * @param dict $minimum Associative array as given to @c GetThumbnail().
   *   used to recreate the expected thumbnail url.
   * @param dict $crop Associative array as given to @c GetThumbnail().
   *   used to recreate the expected thumbnail url.
   * @param int $thumbWidth A number. May be zero or negative. When positive, it
   *   indicates the maximum width of the resized thumbnail. Else, there is no
   *   restriction on image width, and will be chosen in function of the
   *   height.
   *   OUT: If @c true is returned, this variable will contain the extact thumbnail width, in pixels.
   * @param int $thumbHeight A number. May be zero or negative. When positive, it
   *   indicates the maximum height of the resized thumbnail. Else, there is
   *   no restriction on image height, and will be chosen in function of the
   *   width.
   *   OUT: If @c true is returned, this variable will contain the exact thumbnail height, in pixels.
   * @return @c true if the given thumbnail url is still correct. @c false
   *   when some checks failed or could not be performed.
   * @see GetThumbnail
   */
  public static function ValidateThumbnail( $imageUrl, $thumbnailUrl, $minimum, $crop, & $thumbWidth, & $thumbHeight )
  {
    $success = false;

    $ext = strrchr( $thumbnailUrl, '.'); /* e.g.: .png */
    $expectedThumbnailPath = self::_DetermineThumbnailPath( $imageUrl, $minimum, $crop, $thumbWidth, $thumbHeight, $ext );
    $expectedThumbnailUrl = self::_DetermineUrlFromPath( $expectedThumbnailPath );

    if ( $thumbnailUrl == $expectedThumbnailUrl )
    {
      if ( @file_exists( $expectedThumbnailPath ) )
      {
        /* The given thumbnail exists, is located in the cache, and
         * the minimum configuration settings haven't been changed since.
         * we can re-use it.
         */
        $sizeArray = @getimagesize( $expectedThumbnailPath );
        $thumbWidth = $sizeArray[ 0 ];
        $thumbHeight = $sizeArray[ 1 ];

        $success = true;
      }
    }

    return $success;
  }

  private static function _DetermineImageType( $url )
  {
    $type = false;
    if ( function_exists( 'exif_imagetype' ) )
    {
      $type = @exif_imagetype( $url );
    }
    else if ( function_exists( 'getimagesize' ) )
    {
      $list = @getimagesize( $url );
      if ( $list )
      {
        $type = $list[2];
      }
    }

    if ( !/*NOT*/$type )
    {
      /* Fallback: try to determine the correct image type by checking for an extension in the url. */
      $ext = '';
      $parts = explode( '.', $url );
      if ( count( $parts ) > 1 )
      {
        $parts = explode( '?', $parts[ count( $parts ) - 1 ], 2 );
        $ext = JString::strtolower( $parts[ 0 ] );
      }
      if ( array_key_exists( $ext, ReadLessTextThumb::$_extToType ) )
      {
        $type = ReadLessTextThumb::$_extToType[ $ext ];
      }
    }

    return $type;
  }

  private static function _DetermineThumbnailPath( $imageUrl, $minimum, $crop, $thumbWidth, $thumbHeight, $ext )
  {
    $path = JPATH_CACHE . '/plg_readlesstext/';
    if ( !/*NOT*/@file_exists( $path ) )
    {
      @mkdir( $path );
    }

    if ( !/*NOT*/@is_dir( $path ) or !/*NOT*/@is_writable( $path ) )
    {
      /* Insufficient write permissions. Use fall-back. */
      $thumbnailUrl = $imageUrl;
    }
    else
    {
      $string = $imageUrl . $minimum[ 'width' ] . $minimum[ 'height' ] . $minimum[ 'ratio' ]
        . $crop[ 'horizontal_position' ] . $crop[ 'vertical_position' ]
        . $thumbWidth . $thumbHeight . 'v5.2 (r274)';
      $thumbnailPath = $path . md5( $string ) . $ext;
    }
    return $thumbnailPath;
  }

  private static function _DetermineUrlFromPath( $path )
  {
    $host = parse_url( $path, PHP_URL_HOST );
    if ( $host )
    {
      /* $path is already a url. */
      $url = false;
    }
    else if ( JString::strpos( $path, JPATH_BASE . '/' ) === 0 )
    {
      $url = JString::str_ireplace( JPATH_BASE . '/', JURI::base(), $path );
    }
    else
    {
      $url = JURI::base() . $path;
    }
    return $url;
  }

  private static function _DeterminePathFromUrl( $url )
  {
    $host = parse_url( $url, PHP_URL_HOST );
    if ( $host )
    {
      if ( JString::strpos( $url, JURI::base() . '/' ) === 0 )
      {
        $url = JString::str_ireplace( JURI::base(), JPATH_BASE . '/', $path );
      }
      else
      {
        $path = false; /* Can not be converted to a local path. */
      }
    }
    else
    {
      $path = JPATH_BASE . '/' . $url;
      $path = JString::str_ireplace( '//', '/', $path );
    }
    return $path;
  }

  /**
   * Find the resized dimensions, keeping the proportions.
   * @param uint $width
   * @param uint $height
   * @param uint $thumbWidth
   * @param uint $thumbHeight
   * @param dict $crop Associative array, with keys 'horizontal_position',
   *   'vertical_position' and values 'left', 'right', 'center' or 'no'.
   */
  private static function _DetermineResizeFactor( $width, $height, $thumbWidth, $thumbHeight, $crop )
  {
    /* There are four different ways to resize:
     * A: resize full width to thumbnail width,
     *     resize height with same ratio,
     *      crop height to thumbnail height (top, bottom, evenly both)
     * B: resize full height to thumbnail height,
     *     resize width with same ratio,
     *      crop width to thumbnail width (left, right, evenly both)
     * C: resize full width to thumbnail width,
     *     resize height with same ratio,
     *      resized height <= thumbnail height
     * D: resize full height to thumbnail height,
     *     resize width with same ratio,
     *      resized width <= thumbnail width
     *
     *  Based on
     * - the actual image dimensions: ix, iy
     * - the desired thumbnail dimensions: tx, ty
     *  - the crop options:
     *     crop horizontal: yes (left/right/evenly) or no (do not crop horizontally)
     *      crop vertical: yes (left/right/evenly) or no (do not crop vertically)
     * we need to determine the resize factor.
     *
     * Determine the horizontal and vertical ratio's: rx, ry
     * - If rx < ry: If resized using ry, the horizontal width will be
     *     greater than the thumbnail width. So either the width must
     *     be cropped (if allowed), either the image must be resized
     *     using rx (and thus the resized height will be less than the
     *     desired thumbnail height ty).
     * - If rx == ry: highly unlikely. Crop options are not needed here.
     *     Just resize using the single resize factor that was calculated.
     * - If rx > ry: Similar to the first case.
     *     Replace width <> height, rx <> ry and ty <> tx
     * Thus:
     * rx, ry = tx/ix, ty/iy
     * rx < ry
     *   ? crop horizontal ? r = ry : r = rx
     *   : crop vertical ? r = rx : r = ry
     */

    if ( $thumbWidth > 0 )
    {
      $resizeFactorWidth = min( 1, $thumbWidth / $width );
    }
    else
    {
      $thumbWidth = $width;
      $resizeFactorWidth = 1;
    }
    if ( $thumbHeight > 0 )
    {
      $resizeFactorHeight = min( 1, $thumbHeight / $height );
    }
    else
    {
      $thumbHeight = $height;
      $resizeFactorHeight = 1;
    }
    $resizeFactor = 1; /* Default value */
    if ( $resizeFactorWidth < $resizeFactorHeight )
    {
      /* Width is (relatively) greater than the height. */
      if ( in_array( $crop[ 'horizontal_position' ], array( 'left', 'right', 'center' ) ) )
      {
        /* Horizontal cropping is allowed. We may resize less,
         * and crop the extraneous part.
        */
        $resizeFactor = $resizeFactorHeight;
      }
      else
      {
        /* Horizontal cropping is not allowed. The full width must be
         * resized: the resized height will be less than the intended
        * thumbnail height.
        */
        $resizeFactor = $resizeFactorWidth;
      }
    }
    else
    {
      /* Vertical cropping is allowed. We may resize less,
       * and crop the extraneous part.
      */
      if ( in_array( $crop[ 'vertical_position' ], array( 'top', 'bottom', 'center' ) ) )
      {
        $resizeFactor = $resizeFactorWidth;
      }
      else
      {
        /* Vertical cropping is not allowed. The full height must be
         * resized: the resized width will be less than the intended
        * thumbnail width.
        */
        $resizeFactor = $resizeFactorHeight;
      }
    }
    return $resizeFactor;
  }

  /**
   * Determine the start positions sx, sy: everything lower and
   * everything higher than that plus the image width/height will be
   * thrown away (cropped).
   * @param uint $width
   * @param uint $height
   * @param uint $thumbWidth
   * @param uint $thumbHeight
   * @param dict $crop Associative array, with keys 'horizontal_position',
   *   'vertical_position' and values 'left', 'right', 'center' or 'no'.
   * @param unknown_type $resizeFactor
   */
  private static function _DetermineCroppedRectangle( $width, $height, & $thumbWidth, & $thumbHeight, $crop, $resizeFactor )
  {
    /*
     * Default value is 0, 0, to be used when cutting on the
     * right/bottom, or when cropping is disabled.
     *
     * If there is something to be thrown away, i.e.
     * if r * ix > tx
     *   cut left, retain right ? sx = ix - tx / r
     *   cut right, retain left ? sx = 0
     *   cut evenly ? sx = (ix - tx / r) / 2
     *
     * Likewise for sy
     */

    $horizontalStart = 0; /* Default value */
    $usedWidth = min( $width, $thumbWidth / $resizeFactor );
    $thumbWidth = intval( ( $usedWidth * $resizeFactor ) + 0.01 );
    if ( $usedWidth + 1 < $width )
    {
      switch ( $crop[ 'horizontal_position' ] )
      {
        case 'center':
          $horizontalStart = max( 0, ( $width - $usedWidth ) / 2 );
          break;

        case 'right':
          $horizontalStart = max( 0, $width - $usedWidth );
          break;

        case 'left':
          /* $horizontalStart remains 0 */
          break;

        default:
          /* Do not crop the width after all. We should never get here! */
          break;
      }
    }

    $verticalStart = 0; /* Default value */
    $usedHeight = min( $height, $thumbHeight / $resizeFactor );
    $thumbHeight = intval( ( $usedHeight * $resizeFactor ) + 0.01 );
    if ( $usedHeight + 1 < $height )
    {
      switch ( $crop[ 'vertical_position' ] )
      {
        case 'center':
          $verticalStart = max( 0, ( $height - $usedHeight ) / 2 );
          break;

        case 'bottom':
          $verticalStart = max( 0, $height - $usedHeight );
          break;

        case 'top':
          /* $verticalStart remains 0 */
          break;

        default:
          /* Do not crop the height after all. We should never get here! */
          break;
      }
    }

    return array( $horizontalStart, $verticalStart, $usedWidth, $usedHeight );
  }

  private static function _LoadImageUsingCurl( $url, $maxImageLoadTime )
  {
    $image = false;
    $curl = false;
    if ( function_exists( 'curl_init' ) )
    {
      $curl = curl_init();
    }
    if ( $curl )
    {
      curl_setopt( $curl, CURLOPT_URL, $url );
      curl_setopt( $curl, CURLOPT_HEADER, false );
      curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
      curl_setopt( $curl, CURLOPT_CONNECTTIMEOUT, $maxImageLoadTime );
      if ( ( ini_get( 'open_basedir' ) == '') and
          ( ( ini_get( 'safe_mode' ) == 'Off' ) or ( !/*NOT*/ini_get( 'safe_mode' ) ) ) )
      {
        /* The follow location option can not be activated when either dafe_mode or open_basedir
         * is set in php.ini - as a security measure. Trying to set it anyway results in a warning.
         * @todo If this is not set, redirection is not possible. A workaround for this is
         *   described here: http://stackoverflow.com/a/6918742/911550
         *   To implement?
         */
        curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
      }
      curl_setopt( $curl, CURLOPT_MAXREDIRS, 11/*just a number that seems plenty enough*/ );
      curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER,  FALSE );
      $contents = curl_exec( $curl );
      curl_close( $curl );
      $image = @imagecreatefromstring( $contents );
    }
    return $image;
  }

  /**
   * Tries various ways to open an image and read its contents.
   * @param string $url References a local image with relative or full path, or a remote image.
   * @param function $loadFunction
   * @return resource image upon success, false on failure.
   */
  private static function _LoadImage( $url, $loadFunction, $maxImageLoadTime )
  {
    $originalDefaultSocketTimeoutValue = false;

    /* Always first try the url as given.
     * If that fails, try to convert the url to a local absolute path.
     * If that can not be done, or loading fails again, try to convert to a full url.
     * Try loading both using imagecreatefrom.+, and using curl combined with imagecreatefromstring.
     * If that all fails, give up.
     */

    $fullPath = self::_DeterminePathFromUrl( $url );
    $fullUrl = self::_DetermineUrlFromPath( $url );

    $tries = array();
    $tries[] = 'curl';
    $tries[] = 'normal';
    if ( $fullPath )
    {
      $tries[] = 'fullPath';
    }
    /* Always include at least one way to fetch an image based on the full url. I had a report from a user who
     * apparently couldn't load images referenced locally, but could load images referenced via a url (???).
     */
    if ( $fullUrl and ini_get( 'allow_url_fopen' ) )
    {
      $tries[] = 'fullUrl';
      if ( $maxImageLoadTime > 0 )
      {
        $originalDefaultSocketTimeoutValue = ini_set( 'default_socket_timeout', $maxImageLoadTime );
      }
    }
    $tries[] = 'curl';

    $image = false;
    foreach ( $tries as $try )
    {
      if ( !/*NOT*/$image )
      {
        switch ( $try )
        {
          case 'normal':
            $image = @call_user_func( $loadFunction, $url );
            break;

          case 'fullPath':
            $image = @call_user_func( $loadFunction, $fullPath );
            break;

          case 'fullUrl':
            $image = @call_user_func( $loadFunction, $fullUrl );
            break;

          case 'curl':
            if ( $fullUrl )
            {
              $image = self::_LoadImageUsingCurl( $fullUrl, $maxImageLoadTime );
            }
            else
            {
              $image = self::_LoadImageUsingCurl( $url, $maxImageLoadTime );
            }
            break;

          default:
            /* May never come here. */
            break;
        }
      }
    }

    if ( $originalDefaultSocketTimeoutValue /* is FALSE when ini_set failed or was not executed */ )
    {
      ini_set( 'default_socket_timeout', $originalDefaultSocketTimeoutValue );
    }

    return $image;
  }

  /**
   * Determines the correct url to the corresponding thumbnail.
   * If the thumbnail does not exist, it is created
   * @param string $url The path to the image
   * @param dict $minimum Associative array, with keys 'width', 'height', 'ratio',
   *   and values 0 or positive numbers, expressed in pixels.
   *   Looked at both to find a previously created thumbnail; and when the
   *   thumbnail does not exist yet and has to be created.
   * @param dict $crop Associative array, with keys 'horizontal_position',
   *   'vertical_position' and values 'left', 'right', 'center' or 'no'.
   * @param int $thumbWidth A number. May be zero or negative. When positive, it
   *   indicates the maximum width of the resized thumbnail. Else, there is no
   *   restriction on image width, and will be chosen in function of the
   *   height.
   *   OUT: If the path to the thumbnail is returned, this variable will contain
   *   the extact thumbnail width, in pixels.
   * @param int $thumbHeight A number. May be zero or negative. When positive, it
   *   indicates the maximum height of the resized thumbnail. Else, there is
   *   no restriction on image height, and will be chosen in function of the
   *   width.
   *   OUT: If the path to the thumbnail is returned, this variable will contain
   *   the extact thumbnail height, in pixels.
   * @param int $lifetime The lifetime of the thumbnail in seconds to set when it
   *   is created by calling this function. Not used to check if the existing
   *   thumbnail is still valid. Default: 4 weeks (2419200 seconds).
   * @return false if an error occurred or if the given $url is incorrect. The
   *   path to the thumbnail otherwise.
   */
  public static function GetThumbnail( $url, $minimum, $crop, & $thumbWidth, & $thumbHeight, $lifetime = 2419200, $maxImageLoadTime = 60 )
  {
    $type = self::_DetermineImageType( $url );
    if ( $type and array_key_exists( $type, ReadLessTextThumb::$_image ) )
    {
      $ext = ReadLessTextThumb::$_image[ $type ][ 'ext' ];
      $thumbnailPath = self::_DetermineThumbnailPath( $url, $minimum, $crop, $thumbWidth, $thumbHeight, $ext );
      $thumbnailUrl = self::_DetermineUrlFromPath( $thumbnailPath );

      if ( @file_exists( $thumbnailPath ) )
      {
        /* Thumbnail already exists.
         * The image resource $url has been examined during a previous execution;
         * and according to the settings, it is fit to serve as a thumbnail.
         */
        $sizeArray = @getimagesize( $thumbnailPath );
        $thumbWidth = $sizeArray[ 0 ];
        $thumbHeight = $sizeArray[ 1 ];
      }
      else
      {
        $image = self::_LoadImage( $url, ReadLessTextThumb::$_image[ $type ][ 'load' ], $maxImageLoadTime );
        $width = -1;
        $height = -1;
        if ( $image )
        {
          $width = max( 1, @imagesx( $image ) ); /* Ensure a division is possible. */
          $height = max( 1, @imagesy( $image ) ); /* Ensure a division is possible. */
        }
        $ratio = min( $width / $height, $height / $width );
        if ( !/*NOT*/$image
                or ( $width < $minimum[ 'width' ] )
                or ( $height < $minimum[ 'height' ] )
                or ( $ratio < $minimum[ 'ratio' ] ) )
        {
          /* Thumbnail may not be created.
           * According to the settings, it is not fit to serve as a thumbnail.
          */
          $thumbnailUrl = false;
        }
        else
        {
          $resizeFactor = self::_DetermineResizeFactor( $width, $height, $thumbWidth, $thumbHeight, $crop );
          /* $thumbWidth and $thumbHeight is now updated as well. */

          /* The image width to use is equal to r * tx
           * The image height to use is equal to r * ty
           */

          $start = self::_DetermineCroppedRectangle( $width, $height, $thumbWidth, $thumbHeight, $crop, $resizeFactor );
          $horizontalStart = $start[0];
          $verticalStart = $start[1];
          $usedWidth = $start[2];
          $usedHeight = $start[3];
          /* $thumbWidth and $thumbHeight is now updated as well. */

          /* Create thumbnail */
          $thumbnail = call_user_func( ReadLessTextThumb::$_image[ $type ][ 'create' ], $thumbWidth, $thumbHeight );
          if ( $type == 1 /* IMAGETYPE_GIF */ )
          {
            /* Make the thumbnail initially transparent if the original was transparent too.
             * Otherwise, fill it initially up with all white.
             */
            $transparentColorIdentifier = @imagecolortransparent( $image );
            if ( $transparentColorIdentifier >= 0 )
            {
              $colors = @imagecolorsforindex( $image, $transparentColorIdentifier );
              $transcolorindex = @imagecolorallocate( $thumbnail, $colors[ 'red' ], $colors[ 'green' ], $colors[ 'blue' ] );
              @imagefill( $thumbnail, 0, 0, $transcolorindex );
              @imagecolortransparent( $thumbnail, $transcolorindex ); /* Needed? */
            }
            else
            {
              $whiteColorIdentifier = @imagecolorallocate( $thumbnail, 255, 255, 255 );
              @imagefill( $thumbnail, 0, 0, $whitecolorindex);
            }
          }

          if ( ReadLessTextThumb::$_image[ $type ][ 'create_alpha' ] )
          {
            call_user_func( ReadLessTextThumb::$_image[ $type ][ 'create_alpha' ], $thumbnail, false );
          }
          call_user_func( ReadLessTextThumb::$_image[ $type ][ 'copy' ], $thumbnail, $image,
              0, 0, $horizontalStart, $verticalStart,
              $thumbWidth, $thumbHeight, $usedWidth, $usedHeight );
          if ( ReadLessTextThumb::$_image[ $type ][ 'save_alpha' ] )
          {
            call_user_func( ReadLessTextThumb::$_image[ $type ][ 'save_alpha' ], $thumbnail, true );
          }
          call_user_func( ReadLessTextThumb::$_image[ $type ][ 'save' ], $thumbnail, $thumbnailPath );

          /* The expiration information is not used directly, but it is still
           * added to allow Joomla's core garbage collection functionality to work.
           */
          $expirePath = $thumbnailPath . '_expire';
          @file_put_contents( $expirePath, ( time() + $lifetime) );
        }
      }
    }
    else
    {
      /* To me, the remaining image types are esoteric. Some of them I never
       * even heard of.
       * OR
       * Determining the image type failed.
       */
      $thumbnailUrl = false;
    }

    return $thumbnailUrl;
  }

  private static $_extToType = array(
      'gif' => 1 /* IMAGETYPE_GIF */,
      'jpg' => 2 /* IMAGETYPE_JPEG */,
      'jpeg' => 2 /* IMAGETYPE_JPEG */,
      'png' => 3 /* IMAGETYPE_PNG */,
      'bmp' => 6 /* IMAGETYPE_PNG */
  );

  private static $_image = array(
      1 /* IMAGETYPE_GIF */ => array(
          'ext' => '.gif',
          'load' => 'imagecreatefromgif',
          'create' => 'imagecreate',
          'create_alpha' => '',
          'copy' => 'imagecopyresampled',
          'save_alpha' => '',
          'save' => 'imagegif'
      ),
      2 /* IMAGETYPE_JPEG */ => array(
          'ext' => '.jpg',
          'load' => 'imagecreatefromjpeg',
          'create' => 'imagecreatetruecolor',
          'create_alpha' => '',
          'copy' => 'imagecopyresampled',
          'save_alpha' => '',
          'save' => 'imagejpeg'
      ),
      3 /* IMAGETYPE_PNG */ => array(
          'ext' => '.png',
          'load' => 'imagecreatefrompng',
          'create' => 'imagecreatetruecolor',
          'create_alpha' => 'imagealphablending',
          'copy' => 'imagecopyresampled',
          'save_alpha' => 'imagesavealpha',
          'save' => 'imagepng'
      ),
      6000 /* IMAGETYPE_BMP */ => array(
          'ext' => '.bmp',
          'load' => 'imagecreatefromwbmp',
          'create' => 'imagecreate',
          'create_alpha' => '',
          'copy' => 'imagecopyresampled',
          'save_alpha' => '',
          'save' => 'imagewbmp'
      ) );
}
?>
PK��#]Jp!��m�m+content/readlesstext/readlesstexthelper.phpnu�[���<?php
/**
 * @package readlesstext
 * @copyright 2008-2014 Parvus
 * @license http://www.gnu.org/licenses/gpl-3.0.html
 * @link http://joomlacode.org/gf/project/cutoff/
 * @author Parvus
 *
 * readless is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * readless is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with readless. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version $Id$
 */

defined( '_JEXEC' ) or die;
jimport( 'joomla.plugin.plugin' );
jimport( 'joomla.utilities.date' );

class ReadLessTextHelper
{
  /**
   * Checks whether it is allowed to run.
   * This function does not make any modification, except when in discover
   * mode: @c $article->text will then be set to the discover information.
   * @param JTableContent $article the item fetched from the database
   * @param params $params the parameters to use
   * @param dict $options OUT the key 'discover' with a boolean value will be
   *   filled in.
   * @param bool $activeByDefaultOnAllContentItems True if all content items
   *   must be shortened by 'read less', unless explicitly disallowed.
   * @param string $pluginName When Discover mode is active, this string
   *   will be added to the discover information.
   * @param string $extraDiscoverInfo When Discover mode is active, this string
   *   will be added to the discover information.
   * @return Boolean value
   */
  public static function Filter( &$callCount, $article, $params, &$options,
      $activeByDefaultOnAllContentItems = false, $pluginName, $extraDiscoverInfo = '' )
  {
    $app = JFactory::getApplication();

    $current = array();
    $current[ 'component' ] = JRequest::getWord( 'option' );
    $current[ 'scope' ] = $app->scope;
    $current[ 'view' ] = JRequest::getWord( 'view' );
    $current[ 'viewId' ] = JRequest::getInt( 'id' );
    $current[ 'layout' ] = JRequest::getWord( 'layout' );
    $current[ 'articleId' ] = self::GetArticleId( $article );
    $current[ 'articleSlug' ] = self::GetArticleSlug( $article );
    $current[ 'articleCategoryId' ] = self::GetCategoryId( $article );

    $articleNumberSkipCount = max( 0, $params->get( 'articleNumberSkipCount' ) );
    $articleNumberShortenCount = max( 0, $params->get( 'articleNumberShortenCount' ) );

    $discoverTextAboutScopeType = '';
    $discoverTextAboutCallCount = '';
    $lastMatchingContext = false;
    $contexts = array(); /* Used to contain all contexts that match the item for this code is executed. */
    $contextDescriptions = array(); /* Only used to facilitate Discover mode. */
    $possiblyInterchangeable = array(); /* Only used to facilitate Discover mode. */

    $scope = array( 'com_' => $params->get( 'componentScope' ), 'mod_' => $params->get( 'moduleScope' ) );
    $key = JString::substr( $current[ 'scope' ], 0, 4 /* com_ or mod_ */ );
    if ( !/*NOT*/key_exists( $key, $scope ) )
    {
      $scope[ $key ] = 'never';
    }

    switch ( $scope[ $key ] )
    {
      case 'always':
        $discoverTextAboutScopeType .= "<br/>This plugin must always be active on <tt>" . $current[ 'scope' ] . "</tt>.";
        $allowed = true;
        break;

      case 'never':
        $discoverTextAboutScopeType .= "<br/>This plugin may never be active on <tt>" . $current[ 'scope' ] . "</tt>.";
        $allowed = false;
        break;

      case 'accordingToContexts':
      default:
        $allowed = self::_CheckCallCount( $callCount, $articleNumberSkipCount, $articleNumberShortenCount, $discoverTextAboutCallCount );
        $callCount++;

        if ( $allowed )
        {
          if ( $params->get( 'when', '0' ) == '0' )
          {
            /* common usage */

            if ( $activeByDefaultOnAllContentItems )
            {
              $allowedFilters = 'com_content';
              $disallowedFilters = '';
            }
            else
            {
              $allowedFilters = 'com_content:blog, com_content:categories, com_content:category, com_content:featured, com_content:frontpage, com_content:section';
              $disallowedFilters = '';
            }
          }
          else
          {
            /* specific usage */
            $allowedFilters = $params->get( 'allowed', '' );
            $disallowedFilters = $params->get( 'disallowed', '' );
          }

          if ( $activeByDefaultOnAllContentItems and ( $current[ 'component' ] == 'com_content' ) )
          {
            $allowedFilters = 'com_content, ' . $allowedFilters;
          }

          $contexts = self::_GetContexts( $current, $contextDescriptions, $possiblyInterchangeable );
          $allowed = self::_CheckContexts( $contexts, $allowedFilters, $disallowedFilters, $lastMatchingContext );
        }
        break;
    }

    /* An extra performance penalty is present in Joomla 2.5.5+
     * Since that version, all articles on a page are processed by content plugins,
     * even when it is known their content is not going to be visible.
     * See http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=28591
     * Examples are the list of article titles at the bottom of an article category blog,
     * or an article list page.
     * For read less text (again), these articles can better be skipped immediately.
     * Both view and layout are checked to see if one of these two situations occur.
     * It is also limited for component articles of com_content, as I'm uncertain whether other components
     * behave the same. Better the (for most people small) performance penalty than a faulty behavior.
     * * Thank you for this, gabs087. *
     */
    if ( ( $key == 'com_' ) and ( $current[ 'component' ] == 'com_content' ) )
    {
      if ( ( $current[ 'view' ] == 'category' ) and ( $current[ 'layout' ] != 'blog' ) )
      {
        /* Don't process articles in category lists. */
        $allowed = false;
      }
      if ( ( $current[ 'view' ] == 'featured' ) or ( $current[ 'layout' ] == 'blog' ) )
      {
        $maxVisibleArticleCount = $article->params->get( 'num_leading_articles', 0 )
            + $article->params->get( 'num_intro_articles', 0 );
        if ( ( $maxVisibleArticleCount > 0 ) and ( $callCount > $maxVisibleArticleCount ) )
        {
          /* Don't process articles on blog pages whose content will not be part of the page. */
          $allowed = false;
        }
      }
    }

    $discover = $params->get( 'discover', false );
    if ( $discover )
    {
      $version = new JVersion();
      $discover = JFactory::getUser()->authorise( 'core.login.admin' );
    }
    if ( $options !== NULL )
    {
      /* Store this value so that the same logic in this function doen't need to be performed later on. */
      $options[ 'discover' ] = $discover;
    }
    if ( $discover )
    {
      $article->text = self::_GetDiscoverText( $pluginName, $allowed, $current, $contexts, $contextDescriptions,
          $possiblyInterchangeable, $lastMatchingContext, $discoverTextAboutScopeType, $discoverTextAboutCallCount,
          $extraDiscoverInfo );
      $article->introtext = $article->text;
      $article->fulltext = "";
    }

    return $allowed;
  }

  private static function _CheckContexts( $contexts, $allowedFilters, $disallowedFilters, &$lastMatchingContext )
  {
    $allowed = true;

    /* Loop over key (may be active if filter does not match) value (parameter name) pairs */
    $loop = array( false => $allowedFilters, true => $disallowedFilters);
    foreach ( $loop as $defaultAllowed => $filters )
    {
      if ( $filters )
      {
        /* A bit more manipulation is required here: $filters can be given in
         * different formats
         * @li {component}:{view}:id targets a specific article displayed in all the views of the given type.
         * @li {component}:{view}=nr:id targets a specific article displayed in the given view only.
         * @li {component}:id targets a specific article displayed in any view.
         * @li {component}:{view} targets all articles displayed in all the views of the given type.
         * @li {component}:{view}=nr targets all articles displayed in the given view .
         * @li {component} targets all articles of that component.
         * @note If {component}: is not given, com_content: is assumed.
         * @note If {view} is not given, it is not checked for.
         * Plus contexts may be given on different lines.
         * The string manipulations below ensure that all filters start with a component name
         * followed by a view (with or without nr) and/or an id.
         */
        $filters = ',' . JString::strtolower( $filters );
        $filters = preg_replace( '/[\r\n]+/', ',', $filters );
        $search = array(  ' ', ',',  '+com_', '+all', '+' );
        $replace = array( '',  ',+', 'com_',  'all',  'com_content:' );
        /*                  A    BB    CCCCC    DDDD    EEEEEEEEEEE
         * A: remove all whitespaces
         * B: append a + (a character that can not occur in a correct context) after each ,
         * C: remove all + if it was already followed by a component name
         * D: remove all + if it was already followed by the special keyword all
         * E: all remaining + chars indicate the absence of a component name. Fill in the default
         */
        $filters = JString::str_ireplace( $search, $replace, $filters );
        $filterList = explode( ',', $filters );

        $filterAllows = $defaultAllowed;
        foreach ( $contexts as $c )
        {
          if ( in_array( $c, $filterList ) !== FALSE )
          {
            $filterAllows = !/*NOT*/$defaultAllowed;
            $lastMatchingContext = $c;
            break;
          }
        }
        $allowed &= $filterAllows;
      }
      else
      {
        /* There is no restriction set. Retain the default or already determined value for $allowed. */
      }
    }

    return $allowed;
  }

  private static function _GetContexts( $current, &$contextDescriptions, &$possiblyInterchangeable )
  {
    $contexts = array();

    /* Category/section/other descriptions have to be explicitly enabled.
     * Do not include the more general compact indications of the current
     * page/article in that case.
     */
    if ( $current[ 'articleId' ] != 0 )
    {
      $contexts[] = $current[ 'component' ];
      $contextDescriptions[] = 'all pages of this component';

      $contexts[] = $current[ 'component' ] . ':' . $current[ 'view' ];
      $contextDescriptions[] = 'all similar pages';

      if ( $current[ 'viewId' ] )
      {
        $contexts[] = $current[ 'component' ] . ':' . $current[ 'view' ] . '=' . $current[ 'viewId' ];
        $contextDescriptions[] = 'all items on this page only';
        $possiblyInterchangeable[] = $contexts[ count( $contexts ) - 1 ];
      }
    }
    $contexts[] = $current[ 'component' ] . ':' . $current[ 'articleId' ];
    $contextDescriptions[] = 'this item only on all pages';

    $contexts[] = $current[ 'component' ] . ':' . 'all-in-' . $current[ 'articleCategoryId' ];
    $contextDescriptions[] = 'all items from category ' . $current[ 'articleCategoryId' ] . ' on all pages';
    $contexts[] = $current[ 'component' ] . ':' . $current[ 'view' ] . ':' . $current[ 'articleId' ];
    $contextDescriptions[] = 'this item only on all similar pages';
    $contexts[] = $current[ 'component' ] . ':' . $current[ 'view' ] . ':' . 'all-in-' . $current[ 'articleCategoryId' ];
    $contextDescriptions[] = 'all items from category ' . $current[ 'articleCategoryId' ] . ' on all similar pages';
    $possiblyInterchangeable[] = $contexts[ count( $contexts ) - 1 ];
    if ( $current[ 'viewId' ] )
    {
      $contexts[] = $current[ 'component' ] . ':' . $current[ 'view' ] . '=' . $current[ 'viewId' ] . ':' . $current[ 'articleId' ];
      $contextDescriptions[] = 'this item only on this page only';
      $contexts[] = $current[ 'component' ] . ':' . $current[ 'view' ] . '=' . $current[ 'viewId' ] . ':' . 'all-in-' . $current[ 'articleCategoryId' ];
      $contextDescriptions[] = 'all items from category ' . $current[ 'articleCategoryId' ] . ' on this page only';
      $possiblyInterchangeable[] = $contexts[ count( $contexts ) - 1 ];
    }

    return $contexts;
  }

  private static function _CheckCallCount( $callCount, $articleNumberSkipCount, $articleNumberShortenCount, &$discoverTextAboutCallCount )
  {
    $allowed = false;

    if ( $callCount < $articleNumberSkipCount )
    {
      $discoverTextAboutCallCount .= "<br/>This plugin may only become active on this page after skipping "
          . $articleNumberSkipCount . " article(s) or item(s) on this page (still "
          . ( $articleNumberSkipCount - $callCount ) . " to skip).";
    }
    else if ( ( $articleNumberShortenCount == 0 )
        or ( $callCount < $articleNumberSkipCount + $articleNumberShortenCount ) )
    {
      $allowed = true;
    }
    else
    {
      $discoverTextAboutCallCount .= "<br/>This plugin may only become active on this page for "
          . $articleNumberShortenCount . " articles or items on this page.";
    }

    return $allowed;
  }

  private static function _GetDiscoverText( $pluginName, $allowed, $current, $contexts, $contextDescriptions,
      $possiblyInterchangeable, $lastMatchingContext, $discoverTextAboutScopeType, $discoverTextAboutCallCount,
      $extraDiscoverInfo )
  {
    $enableOrDisable = array( true => "disable", false => "enable" );
    $activeOrNot = array( true => "<strong>active</strong>", false => "<strong>not active</strong>" );

    $text = "<p>";
    $text .= "<tt>" . $pluginName . "</tt> is " . $activeOrNot[ $allowed ] . " on this item ";
    if ( $allowed )
    {
      $text .= "(provided the contents' length is large enough).";
    }
    $text .= "</dt><dd>";
    $text .= "&nbsp;&nbsp;" . $discoverTextAboutScopeType . "<br>";
    $text .= "&nbsp;&nbsp;" . $discoverTextAboutCallCount . "<br>";
    $text .= "</p>";

    $text .= "<dl><dt><strong>Information</strong> you can use to create your own contexts:</dt><dd>";
    $text .= "&nbsp;&nbsp;component: <tt>" . $current[ 'component' ] . "</tt></br>";
    $text .= "&nbsp;&nbsp;scope: <tt>" . $current[ 'scope' ] . "</tt></br>";
    $text .= "&nbsp;&nbsp;layout: <tt>" . $current[ 'layout' ] . "</tt></br>";
    $text .= "&nbsp;&nbsp;view: <tt>" . $current[ 'view' ] . "</tt></br>";
    $text .= "&nbsp;&nbsp;view id: <tt>" . $current[ 'viewId' ] . "</tt></br>";
    $text .= "&nbsp;&nbsp;item id: <tt>" . $current[ 'articleId' ] . "</tt></br>";
    $text .= "&nbsp;&nbsp;category id of item: <tt>" . $current[ 'articleCategoryId' ] . "</tt>";
    $text .= "</dd></dl>";

    if ( $lastMatchingContext )
    {
      /* Maybe active, maybe not, but at least one context matched. */
      $text .= "<strong>The last context you configured that matched the current item is <tt>" . $lastMatchingContext . "</tt></strong>";
      if ( !/*NOT*/$allowed )
      {
        $text .= "<br/>If you want to enable the plugin on this item on this page, you minimally need to remove or change this context.";
      }
    }
    else if ( $allowed )
    {
      /* Active, but no context ever matched. */
      $text .= "<br/>There are no contexts listed where <tt>" . $pluginName . "</tt> is allowed to be active, so it is <strong>active by default</strong>.";
    }
    else
    {
      if ( count( $contexts ) == 0 )
      {
        /* Not active, and no contexts have been reseaRched. Do not print anything about contexts. */
      }
      else
      {
        /* Not active, but no context ever matched. */
        $text .= "<br/>No context matches the current item, so it is <strong>not active by default</strong>.";
      }
    }
    $text .= "</p>";
    if ( count( $contexts ) == 0 )
    {
      /* Not active, and no contexts have been reserached. Do not print anything about contexts. */
    }
    else
    {
      $text .= "<dl><dt><strong>Contexts matching this article</strong>: to " . $enableOrDisable[ $allowed ] . " <tt>" . $pluginName . "</tt> on</dt><dd>";
      for ( $i = 0; $i < count( $contexts ); $i++)
      {
        $text .= "&nbsp;&nbsp;" . $contextDescriptions[$i] . ", use <tt>" . $contexts[$i] . "</tt><br/>";
      }
      $text .= "</dd></dl>";
    }

    $text .= "<p>";
    if ( $current[ 'articleId' ] == $current[ 'viewId' ] )
    {
    $text .= "<strong>Note</strong>: if the view name <tt>"
        . $current[ 'view' ]
        . "</tt> serves to display a single item/article, the contexts <tt>"
        . implode( '</tt>, <tt>n', $possiblyInterchangeable )
        . "</tt> may yield the same result and are interchangeable.<br/>";
    }
    $text .= "<strong>Note</strong>: this discover information is only displayed to users with back-end permissions and can be disabled in the back-end.<br/>";
    if ( count( $contexts ) == 0 )
    {
      /* Not active, and no contexts have been researched. Do not print anything about contexts. */
    }
    else
    {
      $text .= "<dl><dt><strong>General</strong>: all contexts follow this syntax: <tt>component:view:item</tt></dt><dd>";
          $text .= "&nbsp;&nbsp;if the <tt>ncomponent</tt> is left out, <tt>com_content:</tt> is assumed;<br/>";
          $text .= "&nbsp;&nbsp;if the <tt>nview</tt> is left out, <tt>all</tt> views match;<br/>";
          $text .= "&nbsp;&nbsp;if the <tt>item</tt> is left out, <tt>all</tt> items match.<br/>";
          $text .= "</dd></dl>";
    }
    if ( $extraDiscoverInfo )
    {
      $text .= "<br/>";
      $text .= "<strong>" . $extraDiscoverInfo . "</strong>";
    }
    $text .= "</p>";

    return $text;
  }

  public static function Trim( $str )
  {
    return preg_replace( "/(^\s+)|(\s+$)/us", "", $string );
  }

  public static function Rtrim( $string )
  {
    return preg_replace( "/\s+$/us", "", $string );
  }

  /**
   * Determines if @c $string ends with $lastPart.
   * @param string $string The string to examine
   * @param string $lastPart The substring to find at the end of @c $string
   * @return true if @c $string ends with @c $lastPart, false otherwise
   */
  private static function _EndsWith( $string, $lastPart )
  {
    if ( strlen( $string ) < strlen( $lastPart ) )
    {
      $endsWith = false;
    }
    else
    {
      if ( substr_compare( $string, $lastPart, -1 * strlen( $lastPart ) ) )
      {
        $endsWith = false;
      }
      else
      {
        $endsWith = true;
      }
    }
    return $endsWith;
  }

  /**
   * Determines the length of the given article text.
   * @param string $htmltext The html text to consider.
   * @param string $lengthUnit Unit of the length to determine. One of 'char',
   *   'word', 'sentence', 'paragraph'.
   * @param bool $end OUT If true, the last part of @c htmlText ends the
   *   ongoing length unit.
   * @return the length expressed in the given unit.
   * @pre it is assumed subsequent whitespace has already been removed.
   */
  public static function DetermineLength( $htmltext, $lengthUnit, &$end )
  {
    switch ( $lengthUnit )
    {
      case 'sentence':
        /* Calculation is done using a list of sentences.
         * Exclude empty sentences, exclude sentences with only markup,
         * exclude consecutive punctuation characters.
         * The text is also trimmed to determine afterwards whether the last
         * sentence has ended.
         * Paragraph, row and list item demarcations also mark the end of a sentence.
         *
         * Ensure that all sentence endings can be treated alike.
         */
        $search = array( '</p>', '</li>', '</dt>', '</dl>', '</tr>', '#', '.', '?', '!', '¿' );
        $replace = array( '.', '.', '.', '.', '.', '_', '#', '#', '#', '#' );
        $htmltext = JString::str_ireplace( $search, $replace, $htmltext );
        $text = rtrim( strip_tags( $htmltext ) );
        $length = 0;
        foreach ( explode( '#', $text ) as $sentence )
        {
          if ( preg_split( '/\s+/', $sentence, 1, PREG_SPLIT_NO_EMPTY ) )
          {
            $length++;
          }
        }
        $end = self::_EndsWith( $text, '#' );
        break;

      case 'paragraph':
        /* Calculation is done using a list of non-empty paragraphs.
         * Exclude empty paragraphs, exclude paragraps with only markup.
         * The text is trimmed first to determine whether the last paragraph
         * has ended afterwards.
         * Table and list demarcations also mark the end of a sentence.
         * Ensure that all paragraph endings can be treated alike.
         */
        $search = array( '</ul>', '</ol>', '</dl>' );
        $replace = array( '</p>', '</p>', '</p>' );
        $htmltext = JString::str_ireplace( $search, $replace, $htmltext );
        $htmltext = rtrim( $htmltext );
        $length = 0;
        foreach ( explode( '</p>', $htmltext ) as $paragraph )
        {
          $paragraph = strip_tags( $paragraph );
          if ( preg_split( '/\s+/', $paragraph, 1, PREG_SPLIT_NO_EMPTY ) )
          {
            $length++;
          }
        }
        $end = self::_EndsWith( $htmltext, '</p>' );
        break;

      case 'word':
        /* Paragraph, row and list item demarcations also mark the end of a word.
         * Ensure that all word endings can be treated alike.
         */
        $search = array( '</p>', '</li>', '</dt>', '</dl>', '</tr>', '.', '?', '!', '¿' );
        $replace = array( ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' );
        $htmltext = JString::str_ireplace( $search, $replace, $htmltext );

        /* Calculation only needs the plaintext. */
        $text = strip_tags( $htmltext );

        $length = count( preg_split( '/\s+/', $text, -1, PREG_SPLIT_NO_EMPTY ) );
        $end = self::_EndsWith( $text, ' ' );
        break;

      case 'char':
      default:
        /* Calculation only needs the plaintext. */
        $text = strip_tags( $htmltext );

        /* Subsequent whitespace must be counted as one when $lengthUnit equals 'char' */
        $text = preg_replace( '/\s+/mis', ' ', $text );

        $length = JString::strlen( $text );
        $end = true;
        break;
    }

    return $length;
  }

  /**
   * Returns the id of the article this plugin is being called upon.
   * Works for com_content and com_eventlist items,
   * and others (list?)
   * @param JTableContent $article IN The item/article being prepared for display.
   * @return A number.
   */
  public static function GetArticleId( $article )
  {
    $id = 0;
    foreach ( array( 'id', 'did', 'cid' ) as $field )
    {
      if ( isset( $article->$field ) )
      {
        $id = (int)$article->$field;
        break;
      }
    }

    return $id;
  }

  /**
   * Returns the slug of the article this plugin is being called upon.
   * Works for com_content and com_eventlist items,
   * and others (list?)
   * @param JTableContent $article IN The item/article being prepared for display.
   * @return A string.
   */
  public static function GetArticleSlug( $article )
  {
    $id = self::GetArticleId( $article );

    if ( isset( $article->slug ) and $article->slug )
    {
      $slug = $article->slug;
    }
    else if ( isset( $article->alias ) and $article->alias )
    {
      $slug = $id . ':' . $article->alias;
    }
    else
    {
      if ( isset( $article->title ) and $article->title )
      {
        $slug = $id . ':' . JApplication::stringURLSafe( $article->title );
      }
      else if ( isset( $article->name ) and $article->name )
      {
        $slug = $id . ':' . JApplication::stringURLSafe( $article->name );
      }
      else
      {
        $slug = $id;
      }
    }

    return $slug;
  }

  /**
   * Returns the id of the category of the article this plugin is being called
   * upon.
   * Works for com_content and com_eventlist items,
   * and others (list?)
   * @param JTableContent $article The item/article being prepared for display.
   * @return A number.
   */
  public static function GetCategoryId( &$article )
  {
    $id = 0;
    foreach ( array( 'catid', 'catsid' ) as $field )
    {
      if ( isset( $article->$field ) )
      {
        $id = (int)$article->$field;
        break;
      }
    }
    return $id;
  }

  /**
   * Returns the slug of the category of the article this plugin is being called
   * upon.
   * Works for com_content and com_eventlist items,
   * and others (list?)
   * @param JTableContent $article The item/article being prepared for display.
   * @return A string.
   */
  public static function GetCategorySlug( &$article )
  {
    $id = self::GetCategoryId( $article );

    if ( isset( $article->catslug ) and $article->catslug )
    {
      $slug = $article->catslug;
    }
    else if ( isset( $article->category_alias ) and $article->category_alias )
    {
      $slug = $id . ':' . $article->category_alias;
    }
    else
    {
      $slug = $id;
    }

    return $slug;
  }

  /**
   *
   * @param string $plainText
   * @param integer $length
   * @param string $lengthUnit Unit of the length. One of 'char',
   *   'word', 'sentence', 'paragraph'.
   * @param bool $retainWholeWords Only used when $lengthUnit equals 'char'
   */
  public static function Substr( $plainText, $length, $lengthUnit, $retainWholeWords = false )
  {
    $substr = $plainText;
    switch ( $lengthUnit )
    {
      case 'sentence':
        $substrByteLength = 0;
        $matches = preg_split( '/([.?!¿]+)/mis', $plainText, $length + 1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE );

        /* Retain $length sentences and the line ending of each sentence. */
        $i = min( count( $matches ), $length * 2 );
        $substrByteLength = $matches[ $i ][1]; /* Start position of first match not to retain. */

        $substr = substr( $plainText, 0, $substrByteLength);
        break;

      case 'paragraph':
        /* Default value is correct. Nothing to do. */
        break;

      case 'word':
        $words = preg_split( '/\s+/mis', $plainText, $length + 1, PREG_SPLIT_NO_EMPTY );
        $words = array_slice( $words, 0, $length );
        $substr = implode( ' ', $words );
        break;

      case 'char':
      default:
        $words = preg_split( '/(\s+)/mis', $plainText, $length + 1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
        $i = 0;
        while ( $i < count( $words ) )
        {
          if ( ctype_space( $words[ $i ] ) )
          {
            $wordLength = 1; /* Count whitespace separating the words as one char. */
          }
          else
          {
            $wordLength = JString::strlen( $words[ $i ] );
          }

          if ( $length >= $wordLength )
          {
            $length -= $wordLength;
            $i++;
          }
          else
          {
            break;
          }
        }

        $lastChars = '';
        if ( ( $length > 0 ) and ( $i < count( $words ) ) )
        {
          if ( $retainWholeWords )
          {
            /* The $i-th word is to be cut in half.
             * Retain the whole word if it is the first to retain,
             * Toss it completely away otherwise.
             */
            $i = max( 1, $i );
          }
          else
          {
             $lastChars = JString::substr( $words[ $i ], 0, $length );
          }
        }

        /* $i represents the number of words to retain fully,
         * $lastChars contains a few characters of the last word that is retained only partially.
         */
        $words = array_slice( $words, 0, $i );
        $words[] = $lastChars;
        $substr = implode( ' ', $words );
        break;
    }

    return $substr;
  }
}
?>
PK��#]Q�=�� � content/readlesstext/script.phpnu�[���<?php
/**
 * @package readlesstext
 * @copyright 2008-2014 Parvus
 * @license http://www.gnu.org/licenses/gpl-3.0.html
 * @link http://joomlacode.org/gf/project/cutoff/
 * @author Parvus
 *
 * readless is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * readless is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with readless. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version $Id$
 */

defined( '_JEXEC' ) or die;

class plgContentReadlesstextInstallerScript
{
  /**
   * Constructor
   * @param JAdapterInstance $adapter The object responsible for running this script1
   */
  public function __constructor(JAdapterInstance $adapter)
  {
    //void
  }

  /**
   * Called before any type of action
   * @param string $route Which action is happening (install|uninstall|discover_install)
   * @param JAdapterInstance $adapter The object responsible for running this script
   * @return boolean True on success
   */
  public function preflight($route, JAdapterInstance $adapter)
  {
    return true;
  }

  /**
   * Called after any type of action
   * @param string $route Which action is happening (install|uninstall|discover_install)
   * @param JAdapterInstance $adapter The object responsible for running this script
   * @return boolean True on success
   */
  public function postflight($route, JAdapterInstance $adapter)
  {
    echo "
        <h2>v5.2 (r274)</h2>
        <dl>
        <dt><em>read less text</em> will control the article text:</dt>
        <dd>preview size, formatting and image placement can be adjusted to your liking, precisely on those pages and
          for those articles or items you want. <em>read less text</em> will not alter your article table in any way.
          Only the display is controlled: uninstalling or disabling will bring back the original text.</dd>
        <dt>Take your time</dt>
        <dd>to read all the helpful tooltips and fully configure
          <a href='index.php?option=com_plugins&view=plugins&filter_search=read'><em>read less text</em></a>
          to your liking. Use the discover mode if you need extreme flexibility in controlling which articles get
          shortened - and when.</dd>
        <dt>This version does not affect the article&acute;s titles.</dt>
        <dd>If you want to control the title length, prepend or append specific information, and adjust the casing of
          the title, you can install and use the separate extension
          <a href='http://extensions.joomla.org/extensions/style-a-design/titles/16619/'><em>read less title.</em></a>
          </dd>
        </dl>

        <h2>Important notes affecting your configuration:</h2>
        <dl>

        <dt><strong>Since v5.2</strong></dt>
        <dd><em>Experimental</em> support has been added for some image gallery plugins. When gallery plugins
          are used in an article, some text that looks like<code>{gallery}path/to/images{/gallery}</code> is inserted.
          You can instruct <em>read less text</em> to scan that referenced location for images as well.<br/>
          The list of content gallery plugins that is recognized is: <tt>SIGE</tt>, <tt>sigplus</tt>,
          <tt>VSIG (Very Simple Image gallery)</tt>, <tt>pPGallery</tt>, <tt>CSS Gallery</tt><br/>
          There are also quite some limitations:
          <ul>
            <li>Can not link to the gallery with a word, used at the article</li>
            <li>Can not load image information from a file.</li>
            <li>The option 'root' is not supported (sigplus)</li>
            <li>Picasaweb albums are not supported</li>
            <li>Paths with spaces are not supported.</li>
            </ul>
          </dd>

        <dt><strong>Since v5.1</strong></dt>
        <dd>The option <code>Show Intro Text</code> as set in the
          <a href='index.php?option=com_content'>Article Manager</a> &gt; <code>Options</code> &gt;
          <code>Show Intro Text</code> &gt; <code>Articles</code> can now be used to determine whether the full article
          or only the intro text may be considered for shortening.
          <br />See also the tooltip that comes with the option
          <code>Length</code> &gt; <code>Respect Position Existing Read More</code>.
          <br/><strong>You may want to check that setting</strong>.</dd>

        <dt><strong>Since v5.1</strong></dt>
        <dd>The field that replaces the default 'Read more' value - in the <em>Read More (Suffix)</em> section - has
          been split in two.
          The first field is added at the end of the text, before the paragraph is closed;
          the other field is added at the end of article, after all HTML tags (including the paragraph tag
          <code>p</code>) have been closed.
          <br/><strong>You may want to (re-)configure these fields</strong>.</dd>

        <dt><strong>Since v5.0</strong></dt>
        <dd><em>read less text</em> provides two <code>Date Format</code> fields, used while replacing tokens in the
          prefix and suffix fields. The way these date formats must be constructed has been changed. You can review
          <a href='http://php.net/manual/en/function.date.php'>the manual for the function date</a>
          for a list of formatting characters and their explanation, and for a list of examples.
          <br/><strong>You may want to review these fields, or clear them to load the new, correct, default value.
          </strong>
        </dd>

        </dl>";
    return true;
  }

  /**
   * Called on installation
   * @param JAdapterInstance $adapter The object responsible for running this script
   * @return boolean True on success
   */
  public function install(JAdapterInstance $adapter)
  {
    $this->_CreateTable();
    return true;
  }

  /**
   * Called on update
   * @param JAdapterInstance $adapter The object responsible for running this script
   * @return boolean True on success
   */
  public function update(JAdapterInstance $adapter)
  {
    $this->_CreateTable();
    return true;
  }

  /**
   * Called on uninstallation
   * @param JAdapterInstance $adapter The object responsible for running this script
   */
  public function uninstall(JAdapterInstance $adapter)
  {
    $this->_DestroyTable();
    return true;
  }

  private function _CreateTable()
  {
    $db = JFactory::getDBO();
    $db->setQuery( self::_createTableSql );
    $db->query();
  }

  private function _DestroyTable()
  {
    $db = JFactory::getDBO();
    $db->setQuery( self::_destroyTableSql );
    $db->query();
  }

  const _createTableSql = "CREATE TABLE IF NOT EXISTS `#__readlesstext` (
    `id` INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `rtable` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'The component name where the item resides in. Also called option',
    `rid` INT(10) NOT NULL COMMENT 'The unique id of the item in that component. e.g. the article id for com_content',
    `hash` VARCHAR(255) DEFAULT '' COMMENT 'The fingerprint of the full item text.',
    `char` INTEGER UNSIGNED DEFAULT 0 COMMENT 'Count in the full item text.',
    `word` INTEGER UNSIGNED DEFAULT 0 COMMENT 'Count in the full item text.',
    `sentence` INTEGER UNSIGNED DEFAULT 0 COMMENT 'Count in the full item text.',
    `paragraph` INTEGER UNSIGNED DEFAULT 0 COMMENT 'Count in the full item text.',
    `image_tag_start_pos` INTEGER UNSIGNED DEFAULT 0 COMMENT 'Start position of the image tag where the thumbnail was created from.',
    `image_tag_length` INTEGER UNSIGNED DEFAULT 0 COMMENT 'Length of the image tag in nr of UTF8 chars.',
    `image_url` VARCHAR(1023) NOT NULL DEFAULT '' COMMENT 'Url to the image where the thumbnail was created from.',
    `thumbnail_url` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'Url to the thumbnail.',
    `last_update` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Debug information.',
    UNIQUE (`rtable`, `rid`) ) DEFAULT CHARSET=utf8;";

  const _destroyTableSql = "DROP TABLE IF EXISTS `#__readlesstext`";
}

?>
PK��#]b%J�^�^�)content/readlesstext/readlesstextmain.phpnu�[���<?php
/**
 * @package readlesstext
 * @copyright 2008-2014 Parvus
 * @license http://www.gnu.org/licenses/gpl-3.0.html
 * @link http://joomlacode.org/gf/project/cutoff/
 * @author Parvus
 *
 * readless is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * readless is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with readless. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version $Id$
 */

defined( '_JEXEC' ) or die;
require_once 'readlesstextcache.php';
require_once 'readlesstextexpand.php';
require_once 'readlesstexthelper.php';
require_once 'readlesstextthumb.php';

if ( !/*NOT*/ class_exists( 'ContentHelperRoute' ) )
{
  /* There have been some reports of people that somehow got errors by having
   * this class not being included by default (not only with this plugin; also
   * with other completely unrelated plugins.
   * Although this block should never be entered, it serves as a workaround
   * for those people having this issue.
   */
  require_once( JPATH_SITE . '/components/com_content/helpers/route.php' );
}

class ReadLessTextMain extends JPlugin
{
  /**
   * Constructor
   * @param object &$subject The object to observe
   * @param array $config An optional associative array of configuration settings.
   */
  public function __construct( &$subject, $config = array() )
  {
    parent::__construct( $subject, $config );
  }

  /**
   * Main entry function. The configuration parameters set in the constructor are used to fully exert read less text's
   * functionality.
   * @param JTableContent $article The item/article being prepared for display.
   * @param number $callCount The number of times this function has been
   *   called by the same plugin. This value is used to determine whether
   *   the given article may be shortened.
   *   Will have been incremented by one when this function returns.
   * @param string $pluginName
   */
  public function ReadLessText( &$article, &$callCount, $pluginName = 'plg_content_readlesstext', $cacheTable = '#__readlesstext' )
  {
//    jimport( 'joomla.error.profiler' );
//    $this->profiler = new JProfiler();
//    $this->profiles = array();
//    $this->profiles[] = $this->profiler->mark( ' IN ' . $article->id );

    JPlugin::loadLanguage( $pluginName );

    /* The two blocks below are a workaround for issues in the Joomla core.
     * - In a 'featured' view, the fulltext is not set or empty, even when it
     *   is present in the database
     * - In a single article view, the readmore property is not set.
     * Seen in 1.6.6, 1.7.2 & 2.5.4
     *
     * It also ensures that when this plugin is invoked on other components (e.g. com_media),
     * There are no php notices.
     */
    foreach ( array( 'fulltext', 'readmore' ) as $var )
    {
      if ( !/*NOT*/ isset( $article->$var ) )
      {
        $article->$var = '';
      }
    }
    if ( isset( $article->id ) and $article->readmore and ( !/*NOT*/ $article->fulltext ) )
    {
      $db = JFactory::getDBO();
      $query = "SELECT c.fulltext
          FROM #__content c
          WHERE c.id = " . $article->id;
      $db->setQuery( $query );
      $article->fulltext = $db->loadResult();
    }

    $this->_isShortened = false;
    $this->_prefix = '';
    $this->_suffix = '';

    $alwaysActiveForGuests = $this->params->get( 'alwaysActiveForGuests', '0' );
    if ( $alwaysActiveForGuests )
    {
      $extraDiscoverInfo = 'Guests can only see the shortened article, unless a context in the <em>Disallowed</em> field matches this item.';
      $activeByDefaultOnAllContentItems = ( JFactory::getUser()->guest == 1 );
    }
    else
    {
      $extraDiscoverInfo = '';
      $activeByDefaultOnAllContentItems = false;
    }

//    $this->profiles[] = $this->profiler->mark( ' before filter ' );
    $options = array();
    if ( ReadLessTextHelper::Filter( $callCount, $article, $this->params, $options,
        $activeByDefaultOnAllContentItems, $pluginName, $extraDiscoverInfo ) )
    {
      /* Entering this block means: read less text must be active. */
//      $this->profiles[] = $this->profiler->mark( ' after filter ' );

      if ( $options[ 'discover' ] )
      {
        /* Discover mode is active: the article's text has been replaced with
         * discover information and may not be altered.
         * No need to update the private variables - they will not be used.
         */
      }
      else
      {
//        $this->profiles[] = $this->profiler->mark( ' before prepare ' );
        $length = $this->_PrepareArticleText( $article, $this->params, $cacheTable );
//        $this->profiles[] = $this->profiler->mark( ' after prepare ' );

        $imageHtml = '';
        $prefix = '';
        $shortened = $article->text;
        $inlineSuffix = '';
        $closingTags = '';
        $suffix = '';

        $expand = new ReadLessTextExpand();
        $expand->SetExpandables( $article, $this->_plaintext, Null, Null );
        $this->_GetParams( $article, $length, $expand );

        if ( ( $this->_applyFormatting == 'when_active' )
            or ( ( $this->_applyFormatting == 'when_long_enough' ) and $length ) )
        {
//          $this->profiles[] = $this->profiler->mark( ' before strip ' );
          $article->text = $this->_StripTokens( $article->text );
//          $this->profiles[] = $this->profiler->mark( ' after strip ' );

//          $this->profiles[] = $this->profiler->mark( ' before cutoff ' );
           $a = $this->_CutOff( $article->text, $length );
           $shortened = $a[0];
           $closingTags = $a[1];
//          $this->profiles[] = $this->profiler->mark( ' after cutoff ' );
        }

        if ( ( $this->_createThumbnail == 'when_active' )
            or ( ( $this->_createThumbnail == 'when_shortened' ) and $this->_isShortened ) )
        {
//          $this->profiles[] = $this->profiler->mark( ' before thumbnail ' );
          $imageHtml = $this->_GetThumbnailHtml( $article );
//          $this->profiles[] = $this->profiler->mark( ' after thumbnail ' );
        }

        if ( ( $this->_addPrefix == 'when_active' )
            or ( ( $this->_addPrefix == 'when_shortened' ) and $this->_isShortened ) )
        {
          $prefix = $this->_prefix;
        }
        if ( ( $this->_addInlineSuffix == 'when_active' )
            or ( ( $this->_addInlineSuffix == 'when_shortened' ) and $this->_isShortened ) )
        {
          $inlineSuffix = $this->_inlineSuffix;
        }
        if ( ( $this->_addSuffix == 'when_active' )
            or ( ( $this->_addSuffix == 'when_shortened' ) and $this->_isShortened ) )
        {
          $suffix = $this->_suffix;
        }

        if ( $this->_cache )
        {
          $this->_cache->Store();
        }

        $article->text = $this->_wrapperTag[ 'open' ] . $imageHtml . $prefix
            . $shortened
            . $inlineSuffix . $closingTags . $suffix . $this->_wrapperTag[ 'close' ];
      }

      $article->introtext = $article->text;
      $article->fulltext = '';

//       $this->profiles[] = $this->profiler->mark( ' OUT ' . $article->id );
//       $article->text .= '<div>';
//       foreach ( $this->profiles as $profile )
//       {
//         $article->text .= "<br/>" . $profile;
//       }
//       $article->text .= '<br/></div>';
//       $article->introtext = $article->text;
//       $article->fulltext = '';
    }
  }

  /**
   * Determines the html version of the intro and the full field,
   * irrespective the component.
   * @param JTableContent $article The item/article being prepared for display.
   * @return An array, with the first element containing the intro text,
   *   if any, and the second element the remainder of the text.
   */
  private static function _DetermineArticleText( $article )
  {
    /* Be extra careful, so that other components do not give PHP notices
     * and warnings.
     * - Some components do not have the introtext and/or the fulltext field
     *   but only the text field,
     *   e.g. ??
     * - Others have none of the three, but use a special name (why o why),
     *   e.g. in com_eventlist:
     *     datdescription for an event.
     *     catdescription for a category.
     *     locdescription for a venue.
     *     description for a group.
     * - whereas others have all three of them, and full info is to be
     *   fetched from introtext and fulltext.
     */
    $introtext = '';
    $fulltext = '';
    if ( isset( $article->introtext ) )
    {
      $introtext = $article->introtext;
    }
    if ( isset( $article->fulltext ) )
    {
      $fulltext = $article->fulltext;
    }
    if ( !/*NOT*/ $introtext and !/*NOT*/ $fulltext)
    {
      if ( isset( $article->text ) and $article->text )
      {
        $fulltext = $article->text;
      }
    }
    if ( !/*NOT*/ $introtext and !/*NOT*/ $fulltext)
    {
      /* No text has been found yet. Check if it is stored in a variable named
       * xxxdescription, like eventlist does.
       */
      $values = array();
      foreach ( get_object_vars( $article ) as $key => $value )
      {
        if ( strstr( $key, 'description') !== false )
        {
          $values[] = $value;
        }
      }
      /* Only accept the text from a xxxdescription when it is the only one
       * found: e.g. eventlist uses one object to store the text of both
       * the event and the venue, and it is impossible to choose the correct
       * one.
       */
      if ( count( $values ) == 1 )
      {
        $fulltext = $values[0];
      }
    }

    $readmoreStartPos = JString::strpos( $introtext, '<p class="readmore">' );
    if ( $readmoreStartPos !== false )
    {
      /* Another plugin has already tampered with this article, and somehow a readmore token got included.
       * e.g. NoNumber's ArticleAnywhere can cause this.
       * Consider only the part before that token as the intro text.
       */
      $introtext = JString::substr_replace( $introtext, '', $readmoreStartPos );
    }

    return array( $introtext, $fulltext );
  }

  /**
   * Determines the length of @c $this->_htmltext in the given unit.
   * The length is fetched from the cache. If it is not available in the cache, it is calculated and then added to the
   * cache - but not yet committed in the cache, use @c Store() for that.
   * @param string $lengthUnit One of 'char', 'word', 'sentence', 'paragraph'
   * @return int the requested length, in number of @c lengthUnit's
   */
  private function _DetermineLength( $string, $lengthUnit )
  {
    $length = $this->_cache->Get( $lengthUnit );
    if ( !/*NOT*/ $length )
    {
      $end = true; /* Just to define it; it is used as output parameter in the next call, but ignored by us. */
      $length = ReadLessTextHelper::DetermineLength( $this->_htmltext, $lengthUnit, $end );
      if ( $length )
      {
        $this->_cache->Set( $lengthUnit, $length );
      }
    }
    return $length;
  }

  /**
   * Determines the correct text to operate on. Sets the private variables plaintext and htmltext.
   * @param JTableContent $article IN OUT. The item/article being prepared for display. The properties introtext, text,
   *   fulltext and readmore will have been set or adapted.
   * @param params $params the parameters to use
   * @return mixed boolean false to indicate article may not be shortened, or a number indicating the nr of units to
   *   retain. It is still possible this number is greater than the entire article text length.
   * @post @c $article->text contains the text to be shortened or to display.
   * @note Even when @c false is returned, @c $article->text may have been changed - a manually inserted read more
   *   request is then overridden.
   */
  private function _PrepareArticleText( &$article, $params, $cacheTable )
  {
    $a = self::_DetermineArticleText( $article );
    $introtext = $a[0];
    $fulltext = $a[1];
    $plainintrotext = strip_tags( $introtext );
    $plainfulltext = strip_tags( $fulltext );
    $this->_plaintext = $plainintrotext . ' ' . $plainfulltext;
    $this->_htmltext = $introtext . ' ' . $fulltext;

    /* It is tempting to execute the line below, but this yields wrong results.
     * There are Russian (e.g. Р 0xd0 0xa0) and Greek (e.g. Π 0xce 0xa0) multi-byte characters
     * that are stripped from the 0xa0 byte, giving a rubbish character.
     * $this->_htmltext will - after further adaptation - eventually be output,
     * so all characters must at all times remain intact.
     * - btw, at the very least, the u modifier should be used. See e.g. ReadLessTextHelper::Rtrim()
     */
    //$this->_htmltext = preg_replace( '/\s+/muis', ' ', $this->_htmltext )

    $this->_cache = new ReadLessTextCache( $cacheTable, JRequest::getWord( 'option' ), $article->id,
        'v5.2 (r274)' . md5( $this->_htmltext ) );

    $this->_wordCount = $this->_DetermineLength( $this->_htmltext, 'word' );
    $this->_lengthUnit = $params->get( 'lengthUnit', 'char' );

    /* True when a 'read more' link has been explicitly inserted, and fulltext is not empty.
     * - the full text is made by combining introtext, (closing the paragraph), a
     *   hr tag (id 'system-readmore') (opening the paragraph) and fulltext.
     */
    $readmoreMarkerPresent = ( $fulltext and isset( $article->readmore ) and $article->readmore );
    if ( $readmoreMarkerPresent and ( $this->_respectExistingReadmoreLink == 'respectShowIntro' ) )
    {
      /* Shorten the article's intro text. */
      $article->text = $introtext;
      $cutOffLength = $params->get( 'cutOffTextLength', 1 );
    }
    else if ( $readmoreMarkerPresent and $this->_respectExistingReadmoreLink ) /* 1 / true */
    {
      /* Use the article's full intro text; do not try to shorten it. This is
       * accomplished by requesting to cut off at a ridiculously high value.
       */
      $article->text = $introtext;
      $this->_isShortened = true;
      $cutOffLength = PHP_INT_MAX;
    }
    else /* No read more present, or 0 / false */
    {
      $minimumLength = $params->get( 'minimumTextLength', 1 );
      $cutOffLength = $params->get( 'cutOffTextLength', 1 );
      $length = $this->_DetermineLength( $this->_htmltext, $this->_lengthUnit );
      if ( $length < $minimumLength )
      {
        $cutOffLength = false;
      }
      else if ( $length <= $cutOffLength )
      {
        $cutOffLength = false;
      }
      else
      {
        /* Shorten the article's full text. */
        $article->text = $this->_htmltext;
      }
    }

    $article->readmore = 0; /* We do not want Joomla to insert his own 'read more' token */
    if ( !/*NOT*/ $cutOffLength )
    {
      /* The article may not be shortened. Ensure the full article is present,
       * even when a manual to-be-ignored read more is present.
       */
      $article->text = $this->_htmltext;
    }

    $this->_wrapperTag = array( 'open' => '', 'close' => '' );
    $wrapperTag = $params->get( 'wrapperTag', '' );
    if ( $wrapperTag )
    {
      $wrapperClass = $params->get( 'wrapperClass', '' );
      if ( $wrapperClass )
      {
        $this->_wrapperTag[ 'open' ] = '<' . $wrapperTag . ' class="' . $wrapperClass . '">';
      }
      else
      {
        $this->_wrapperTag[ 'open' ] = '<' . $wrapperTag . '>';
      }

      $this->_wrapperTag[ 'close' ] = '</' . $wrapperTag . '>';
    }

    return $cutOffLength;
  }

  /**
   * Determines various options, which are stored in the private variables.
   * @note Not all private variables will be set. Those are covered in the @c _PrepareArticleText function
   * @param JTableContent $article RO. The item/article being prepared for display.
   * @params mixed $length Boolean false or a positive number. Indicates whether it is already determined if the article
   *   is to be shortened and how long the shortened article must become.
   * @param class $expand Instance of ReadLessTextExpand.
   * @pre _PrepareArticleText() must have been called beforehand: e.g. @c _plaintext is used (while expanding).
   */
  private function _GetParams( &$article, $length, $expand )
  {
    $this->_applyFormatting = $this->params->get( 'applyFormatting', 'when_active' );
    $this->_addPrefix = $this->params->get( 'addPrefix', 'when_active' );
    $this->_addInlineSuffix = $this->params->get( 'addInlineSuffix', 'when_active' );
    if ( $this->_addInlineSuffix == 'when_active_use_article_manager_option' )
    {
      if ( JComponentHelper::getParams( 'com_content' )->get( 'show_readmore' ) )
      {
        $this->_addInlineSuffix = 'when_active';
      }
      else
      {
        $this->_addInlineSuffix = 'no';
      }
    }
    $this->_addSuffix = $this->params->get( 'addSuffix', 'when_active' );
    if ( $this->_addSuffix == 'when_active_use_article_manager_option' )
    {
      if ( JComponentHelper::getParams( 'com_content' )->get( 'show_readmore' ) )
      {
        $this->_addSuffix = 'when_active';
      }
      else
     {
        $this->_addSuffix = 'no';
      }
    }
    $this->_respectExistingReadmoreLink = $this->params->get( 'respectExistingReadmoreLink', true );
    if ( $this->_respectExistingReadmoreLink == 'respectShowIntro')
    {
      if ( JComponentHelper::getParams( 'com_content' )->get( 'show_intro' ) )
      {
        $this->_respectExistingReadmoreLink = false;
      }
      else
      {
        /* The user does _not_ want to resepect an existing 'read more' token,
         * and likes to have the intro text separated from the full text after it.
         * Only shorten the intro text
         */
        $this->_respectExistingReadmoreLink = 'shortenIntroOnly';
      }
    }

    /* An array of tags or tokens which are used later on. */
    if ( ( $this->_applyFormatting == 'when_active' )
        or ( ( $this->_applyFormatting == 'when_long_enough' ) and $length ) )
    {
      $list = array(
          'extraSelfClosingTags',
          'tagsToRemove',
          'tagsToRemoveWithContents',
          'squareTokensToRemove',
          'curlyTokensToRemove',
          'squareTokensToRemoveWithContents',
          'curlyTokensToRemoveWithContents' );
    }
    else
    {
      $list = array(
          'extraSelfClosingTags');
    }
    foreach ( $list as $parameter )
    {
      $string = JString::strtolower( $this->params->get( $parameter, '' ) );
      $string = JString::str_ireplace( ' ', '', $string );
      if ( $string )
      {
        $parameter = '_' . $parameter;
        $this->$parameter = explode( ',', $string );
      }
    }

    $this->_articleUrl = JRoute::_( ContentHelperRoute::getArticleRoute(
        ReadLessTextHelper::GetArticleSlug( $article ), ReadLessTextHelper::GetCategorySlug( $article ) ) );
    $expand->SetExpandables( Null, Null, Null, array( '{url}' => $this->_articleUrl, '{words}' => $this->_wordCount ) );

    /* prefix */
    $translateAdditions = $this->params->get( 'translateAdditions', false );
    $prefixLinksToFullArticle = false;
    if ( JFactory::getUser()->guest == 0 )
    {
      $this->_prefix = $this->params->get( 'userPrefix', '' );
      $prefixLinksToFullArticle = $this->params->get( 'userPrefixLinksToFullArticle', true );
    }
    else
    {
      $this->_prefix = $this->params->get( 'guestPrefix', '' );
      $prefixLinksToFullArticle = $this->params->get( 'guestPrefixLinksToFullArticle', true);
    }
    if ( $translateAdditions )
    {
      $this->_prefix = JText::_( $this->_prefix );
    }
    $expand->SetExpandables( Null, Null, $this->params->get( 'prefixDateFormat', '%m/%d' ), null );
    $this->_prefix = $expand->expand( $this->_prefix );
    if ( $prefixLinksToFullArticle and $this->_prefix )
    {
      $this->_prefix = '<a href="' . $this->_articleUrl . '">' . $this->_prefix . '</a>';
    }

    /* inline suffix */
    $inlineSuffixLinksToFullArticle = false;
    if ( JFactory::getUser()->guest == 0 )
    {
      $this->_inlineSuffix = $this->params->get( 'userInlineSuffix', '' );
      $inlineSuffixLinksToFullArticle = $this->params->get( 'userInlineSuffixLinksToFullArticle', true );
    }
    else
    {
      $this->_inlineSuffix = $this->params->get( 'guestInlineSuffix', '' );
      $inlineSuffixLinksToFullArticle = $this->params->get( 'guestInlineSuffixLinksToFullArticle', true );
    }
    if ( $translateAdditions )
    {
      $this->_inlineSuffix = JText::_( $this->_inlineSuffix );
    }
    $expand->SetExpandables( Null, Null, $this->params->get( 'suffixDateFormat', '%m/%d' ), null );
    $this->_inlineSuffix = $expand->expand( $this->_inlineSuffix );
    if ( $inlineSuffixLinksToFullArticle and $this->_inlineSuffix )
    {
      $this->_inlineSuffix = '<a href="' . $this->_articleUrl . '">' . $this->_inlineSuffix . '</a>';
    }

    /* suffix */
    $suffixLinksToFullArticle = false;
    if ( JFactory::getUser()->guest == 0 )
    {
      $this->_suffix = $this->params->get( 'userSuffix', '' );
      $suffixLinksToFullArticle = $this->params->get( 'userSuffixLinksToFullArticle', true );
    }
    else
    {
      $this->_suffix = $this->params->get( 'guestSuffix', '' );
      $suffixLinksToFullArticle = $this->params->get( 'guestSuffixLinksToFullArticle', true );
    }
    if ( $translateAdditions )
    {
      $this->_suffix = JText::_( $this->_suffix );
    }
    $expand->SetExpandables( Null, Null, $this->params->get( 'suffixDateFormat', '%m/%d' ), null );
    $this->_suffix = $expand->expand( $this->_suffix );
    if ( $suffixLinksToFullArticle and $this->_suffix )
    {
      $this->_suffix = '<a href="' . $this->_articleUrl . '">' . $this->_suffix . '</a>';
    }

    /* Use the title or one of the -fixes as thumbnail tooltip. */
    switch ( $this->params->get( 'thumbnailTitle', 'articleTitle' ) )
    {
      case '0':
        $this->_thumbnailTitle = '';

      case 'prefix':
        $this->_thumbnailTitle = $this->_prefix;
        break;

      case 'suffix':
        $this->_thumbnailTitle = $this->_suffix;
        break;

      case 'inlineSuffix':
        $this->_thumbnailTitle = $this->_inlineSuffix;
        break;

      case 'articleTitle':
      default:
        $this->_thumbnailTitle = $article->title;
        break;
    }
    $this->_thumbnailTitle = strip_tags( $this->_thumbnailTitle );

    $this->_createThumbnail = $this->params->get( 'createThumbnail', 'when_active' );
    $this->_linkThumbnail = $this->params->get( 'linkThumbnail', true );
    $this->_defaultThumbnail = $this->params->get( 'defaultThumbnailTemplate', '' );
    $this->_defaultThumbnail = $expand->expand( $this->_defaultThumbnail );

    $this->_retainWholeWords = $this->params->get( 'retainWholeWords', false );

    $this->_crop[ 'horizontal_position' ] = $this->params->get( 'cropHorizontalPosition', 'no' );
    $this->_crop[ 'vertical_position' ] = $this->params->get( 'cropVerticalPosition', 'no' );

    $this->_cacheTime = $this->params->get( 'thumbCacheTime', 2419200 /* 4 weeks */ );
    $this->_maxImageLoadTime = $this->params->get( 'maxImageLoadTime', 0 );
    if ( $this->_maxImageLoadTime <= 0 )
    {
      $this->_maxImageLoadTime = 9999; /* Ridicously high: clamped below. */
    }
    $this->_maxImageLoadTime = max( 1, min( 11 /* seconds */, $this->_maxImageLoadTime ) );
    $this->_thumbWidth = $this->params->get( 'thumbWidth', 0 );
    $this->_thumbHeight = $this->params->get( 'thumbHeight', 0 );
    $this->_minimum[ 'width' ] = $this->params->get( 'minimumImageWidth', 0 );
    $this->_minimum[ 'height' ] = $this->params->get( 'minimumImageHeight', 0 );
    $this->_minimum[ 'ratio' ] = max( 0.05, min( 0.95, $this->params->get( 'minimumImageRatio', 0 ) ) );
  }

  /**
   * Searches for an image that passes all constraints set in the configuration settings; removes that image from the
   * article's text - if present - and returns HTML code containing a thumbnail to that image, readily suitable for
   * display.
   * @param JTableContent $article IN OUT. The item/article being prepared for display.
   * @param string $articleText IN, OUT. $article->text may have been adapted when this function returns.
   * @return String. The HTML code for displaying the styled, resized and linked first image according to the
   *   configuration settings, the empty string otherwise.
   */
  private function _GetThumbnailHtml( $article )
  {
    /* - First try to get all data from the cached information. If this succeeds, we can avoid using regular expressions.
     * - Else, try to find one in the full unshortened article.
     * - Else, try to find one in a possibly referenced gallery.
     * - Else, try to find a default thumbnail.
     */
    $thumbnailUrl = $this->_GetCachedThumbnail( $article->text );
    if ( !/*NOT*/ $thumbnailUrl )
    {
      $thumbnailUrl = $this->_PopImage( $this->_htmltext );
      if ( !/*NOT*/ $thumbnailUrl )
      {
        $thumbnailUrl = $this->_PopGalleryImage( $this->_htmltext );
        if ( !/*NOT*/ $thumbnailUrl )
        {
          $thumbnailUrl = $this->_GetDefaultThumbnail();
        }
      }
    }

    if ( $thumbnailUrl )
    {
      $attributes = $this->_GetImageAttributes( $this->_thumbnailTitle, $this->_thumbWidth, $this->_thumbHeight );
      if ( $this->_linkThumbnail )
      {
        $thumbnailHtml = '<a href="' . $this->_articleUrl . '"><img src="' . $thumbnailUrl. '"' . $attributes . '/></a>';
      }
      else
      {
        $thumbnailHtml = '<img src="' . $thumbnailUrl. '"' . $attributes . '/>';
      }
    }
    else
    {
      $thumbnailHtml = false;
    }

    return $thumbnailHtml;
  }

  /**
   * Fetches all cached image information. If the cached information is valid, it is used to construct the HTML code
   * containing a thumbnail, readily suitable for display. The image used to create the thumbnail, if present in the
   * article, will be stripped from the article's text.
   * @param string $articleText OUT. the string to adapt.
   * @return String. The HTML code for displaying the styled, resized and
   *   linked image according to the configuration settings, the empty
   *   string otherwise.
   */
  private function _GetCachedThumbnail( &$articleText )
  {
    $isValid = false;
    if ( $this->_cache )
    {
      $imageTagStartPos = $this->_cache->Get( 'image_tag_start_pos' );
      $imageTagLength = $this->_cache->Get( 'image_tag_length' );
      $imageUrl = $this->_cache->Get( 'image_url' );
      $thumbnailUrl = $this->_cache->Get( 'thumbnail_url' );

      if ( $thumbnailUrl )
      {
        $isValid = ReadLessTextThumb::ValidateThumbnail( $imageUrl, $thumbnailUrl, $this->_minimum, $this->_crop,
            $this->_thumbWidth, $this->_thumbHeight );
      }
    }

    if ( $isValid )
    {
      /* Check if the thumbnail was derived from an image referenced in the article text
       * i.e., check if it is not a default thumbnail.
       */
      if ( ( $imageTagStartPos >= 0 ) and ( $imageTagLength > 0 ) )
      {
        /* Remove the code for the image on the old location.
         * Don't do this blindly: it can be (it is likely, as I think it is a often used option)
         * that all images already have been removed from the given text.
         */
        if ( ( JString::substr( $articleText, $imageTagStartPos, 1 ) == '<' )
            and ( JString::substr( $articleText, $imageTagStartPos + $imageTagLength, 1 ) == '>' ) )
        {
          $imageUrlStartPos = strpos( $articleText, $imageUrl );
          if ( ( $imageTagStartPos < $imageUrlStartPos )
              and ( $imageUrlStartPos < $imageTagStartPos + $imageTagLength ) )
          {
            /* Ok, the portion we want to strip down does contain the url, and
             * does start and end with an opening resp. closing tag.
             * That's all we do to ascertain we will remove the correct portion.
             */
            $articleText = JString::substr_replace( $articleText, '', $imageTagStartPos, $imageTagLength );
          }
        }
      }
    }
    else
    {
      $thumbnailUrl = false;
    }

    return $thumbnailUrl;
  }

  /**
   * Searches for an image according to the default thumbnail template, and
   * returns HTML code containing a thumbnail to that image, readily
   * suitable for display.
   * @return String. The HTML code for displaying the styled, resized and
   *   linked image according to the configuration settings, the empty
   *   string otherwise.
   */
  private function _GetDefaultThumbnail()
  {
    if ( $this->_defaultThumbnail )
    {
      /* Be more lenient with respect to the default thumbnail: ensure it does not get rejected due to size and
       * dimension constraints.
       * The minimum contraints are not used any more after this (so no need to restore them afterwards).
       */
      $minimum[ 'width' ] = 0;
      $minimum[ 'height' ] = 0;
      $minimum[ 'ratio' ] = 0;
      $thumbnailUrl = ReadLessTextThumb::GetThumbnail( $this->_defaultThumbnail, $minimum, $this->_crop,
          $this->_thumbWidth, $this->_thumbHeight, $this->_cacheTime );

      if ( $thumbnailUrl )
      {
        $this->_cache->Set( 'image_tag_start_pos', -1 );
        $this->_cache->Set( 'image_tag_length', 0 );
        $this->_cache->Set( 'image_url', $this->_defaultThumbnail );
        $this->_cache->Set( 'thumbnail_url', $thumbnailUrl );
      }
    }
    else
    {
      $thumbnailUrl = false;
    }
    return $thumbnailUrl;
  }

  /**
   * Searches for an image in the article's text which is big enough according
   * to the configuration settings; removes that image from the article's
   * text, and returns HTML code containing a thumbnail to that image, readily
   * suitable for display.
   * @param string $articleText IN, OUT. the string to search in and to adapt.
   * @return String. The HTML code for displaying the styled, resized and
   *   linked first image according to the configuration settings, the empty
   *   string otherwise.
   * @note When an image is found, the results will have been cached when this function returns.
   */
  private function _PopImage( &$articleText )
  {
    $thumbnailUrl = false;
    $matchCount = preg_match( self::_imgPattern, $articleText, $matches, PREG_OFFSET_CAPTURE, 0 );
    while ( $matchCount )
    {
      $imageCode = $matches[0][0];
      $imageUrl = $matches[1][0];

      /* No acceptable image has been found yet, try this one. */
      $thumbnailUrl = ReadLessTextThumb::GetThumbnail( $imageUrl, $this->_minimum, $this->_crop, $this->_thumbWidth,
          $this->_thumbHeight, $this->_cacheTime, $this->_maxImageLoadTime );
      if ( $thumbnailUrl )
      {
        $imageTagStartPos = JString::strpos( $articleText, $imageCode );
        $imageTagLength = JString::strlen( $imageCode );

        /* Remove the code for the image on the old location. */
        $articleText = JString::substr_replace( $articleText, '', $imageTagStartPos, $imageTagLength );

        $this->_cache->Set( 'image_tag_start_pos', $imageTagStartPos );
        $this->_cache->Set( 'image_tag_length', $imageTagLength );
        $this->_cache->Set( 'image_url', $imageUrl );
        $this->_cache->Set( 'thumbnail_url', $thumbnailUrl );

        $matchCount = false; /* end the loop */
      }
      else
      {
        /* Prepare the next iteration
         * - The value of $offset determines where the next search starts.
         */
        $offset = $matches[ count( $matches ) - 1 ][1] + 1;
        $matchCount = preg_match( self::_imgPattern, $articleText, $matches, PREG_OFFSET_CAPTURE, $offset );
      }
    }

    return $thumbnailUrl;
  }

  /**
   * Searches for a tag which indicates a content gallery plugin is running. If one is found, it will search through the
   * content gallery for a suitable image (i.e. an image that satisfies the configuration constraints), and returns HTML
   * code containing a thumbnail to that image, readily suitable for display.
   * @param string $articleText IN, OUT. the string to search in and to adapt.
   * @return String. The HTML code for displaying the styled, resized and linked first image according to the
   *   configuration settings, the empty string otherwise.
   * @note When an image is found, the results will have been cached when this function returns.
   */
  private function _PopGalleryImage( &$articleText )
  {
    $thumbnailUrl = false;
    $matchCount = preg_match( self::_galleryPattern, $articleText, $matches, PREG_OFFSET_CAPTURE, 0 );
    while ( $matchCount )
    {
      $galleryCode = $matches[0][0];
      $galleryPath = $matches[2][0];

      /* No acceptable image has been found yet, try this one. */
      if ( $directoryContents = @dir( JPATH_SITE . '/images/' . $galleryPath ) )
      {
        while ( !/*NOT*/ $thumbnailUrl and $imagePath = $directoryContents->read() )
        {
          $imagePath = JPATH_SITE . '/images/' . $imagePath;
          $thumbnailUrl = ReadLessTextThumb::GetThumbnail( $imagePath, $this->_minimum, $this->_crop,
              $this->_thumbWidth, $this->_thumbHeight, $this->_cacheTime, $this->_maxImageLoadTime );
        }
        $directoryContents->close();
      }

      if ( $thumbnailUrl )
      {
        $imageTagStartPos = JString::strpos( $articleText, $galleryCode );
        $imageTagLength = JString::strlen( $galleryCode );

        /* Remove the code for the image on the old location. */
        $articleText = JString::substr_replace( $articleText, '', $imageTagStartPos, $imageTagLength );

        $this->_cache->Set( 'image_tag_start_pos', $imageTagStartPos );
        $this->_cache->Set( 'image_tag_length', $imageTagLength );
        $this->_cache->Set( 'image_url', $imagePath );
        $this->_cache->Set( 'thumbnail_url', $thumbnailUrl );

        $matchCount = false; /* end the loop */
      }
      else
      {
        /* Prepare the next iteration
         * - The value of $offset determines where the next search starts.
        */
        $offset = $matches[ count( $matches ) - 1 ][1] + 1;
        $matchCount = preg_match( self::_imgPattern, $articleText, $matches, PREG_OFFSET_CAPTURE, $offset );
      }
    }

    return $thumbnailUrl;
  }

  /**
   * Composes the attributes for the moved image, inclusive the inline CSS
   * attribute @c style.
   * This function does not make any modification.
   * @param alt: A string. The alternative text to be used for the image. Is also used as image title
   * @param $width: A Number. The size of the image in pixels. If 0 or negative, this value is not set.
   * @param $height: A Number. The size of the image in pixels. If 0 or negative, this value is not set.
   * @return string: Either the empty string when no attributes are needed;
   *   either a string ready for insertion as an attribute in a HTML tag.
   * @note Double quotes are used to quote the value.
   */
  private function _GetImageAttributes( $alt, $width = 0, $height = 0 )
  {
    $attributes = '';
    $styleValue = '';

    $attributes .= ' alt="' . $alt . '"';
    $attributes .= ' title="' . $alt . '"';
    if ( $width > 0 )
    {
      $attributes .= ' width="' . $width . '"';
    }
    if ( $height > 0 )
    {
      $attributes .= ' height="' . $height . '"';
    }

    $class = $this->params->get( 'thumbClass', '' );
    if ( $class )
    {
      $attributes .= ' class="' . $class . '"';
    }

    $imagePosition = $this->params->get( 'thumbPosition', 'left' );
    if ( $imagePosition )
    {
      $styleValue .= ' float:' . $imagePosition . ';';
    }
    $padding = $this->params->get( 'thumbPadding', -1 );
    if ( $padding >= 0 )
    {
      $styleValue .= ' padding:' . $padding . 'px;';
    }
    $margin = $this->params->get( 'thumbMargin', '' );
    if ( $margin and ( $margin[0] !== '-' /* a negative number starts with - */ ) )
    {
      $margin = JString::strtolower( $margin );
      $search = array( ' ', ';' );
      $replace = array( ',', ',' );
      $margin = JString::str_ireplace( $search, $replace, $margin );
      $marginList = explode( ',', $margin );
      $n = 0;
      while ( $n < count( $marginList ) )
      {
        if ( $marginList[ $n ] or ( $marginList[ $n ] === '0' ) )
        {
          if ( JString::strpos( '0123456789', $marginList[ $n ][ JString::strlen( $marginList[ $n ] ) - 1 ] ) === FALSE )
          {
            /* Ok, a unit is already appended */
          }
          else
          {
            $marginList[ $n ] .= "px";
          }
          $marginList[ $n ] = ' ' . $marginList[ $n ];
          $n++;
        }
        else
        {
          unset( $marginList[ $n ] );
          $marginList = array_values( $marginList ); /* re-index */
        }
      }
      $margin = implode( '', $marginList );
      $styleValue .= ' margin:' . $margin . ';';
    }
    $borderWidth = $this->params->get ( 'thumbBorderWidth', - 1 );
    if ($borderWidth >= 0) {
      $borderColor = $this->params->get ( 'thumbBorderColor', '#cccccc' );
      $borderStyle = $this->params->get ( 'thumbBorderStyle', '' );
      $styleValue .= ' border: ' . $borderWidth . 'px ' . $borderStyle . ' ' . $borderColor . ';';
    }
    if ( $styleValue )
    {
      $attributes .= ' style="' . $styleValue . '"';
    }

    return $attributes;
  }

  /**
   * Searches the given text for [token]...[/token] or {token}...{/token} constructs that must be removed.
   * @param string $text The text too operate on.
   * @note Possibly writes isShortened.
   * @return The stripped text.
   */
  private function _StripTokens( $text )
  {
    $settings = array (
        array ( 'pattern' => self::_tokenPattern,
            'opening' => '\[',
            'closing' => '\]',
            'tokens' => $this->_squareTokensToRemove
        ),
        array ( 'pattern' => self::_tokenPatternWithContents,
            'opening' => '\[',
            'closing' => '\]',
            'tokens' => $this->_squareTokensToRemoveWithContents
        ),
        array ( 'pattern' => self::_tokenPattern,
            'opening' => '{',
            'closing' => '}',
            'tokens' => $this->_curlyTokensToRemove
        ),
        array ( 'pattern' => self::_tokenPatternWithContents,
            'opening' => '{',
            'closing' => '}',
            'tokens' => $this->_curlyTokensToRemoveWithContents
        ) );
    /* Remove first without contents, then remove with contents. */
    foreach ( $settings as $setting )
    {
      foreach ( $setting[ 'tokens' ] as $token )
      {
        $search = array( self::_tokenOpeningReplacer, self::_tokenClosingReplacer, self::_tokenReplacer );
        $replace = array( $setting[ 'opening' ], $setting[ 'closing' ], $token );
        $pattern = JString::str_ireplace( $search, $replace, $setting[ 'pattern' ] );
        $count = 0;
        $text = preg_replace( $pattern, '', $text, -1, $count );
        if ( $count )
        {
          /* We have stripped away a - likely fancy - part of the article. The user must
           * get the possibility to access the full article - and thus that fancy part.
           */
          $this->_isShortened = true;
        }
      }
    }
    return $text;
  }

  /**
   * Cuts off the article text, retaining the full formatting. It uses regular expressions to find tags, and a simple
   * push/pop system to retain the opened but still-unclosed tags. When the text has been cut off after a
   * admin-configurable unit count, all the opened and still-unclosed tags are then closed.
   * @note No prefix nor suffix will be added in this function.
   * @post If the shortened string differs from the given @c text, @c _isShortened is set to @c true.
   * @param string $text RO. The HTML text to shorten.
   * @param integer $cutOffLength The size in number of @c _lengthUnit units of the plain text to retain, or @c false
   *   to indicate all text must be retained (safe the tags that must be removed according to the configuraion
   *   settings).
   * @return An array of strings: first 'the shortened text', second all 'the closing tags'. The second string may be
   *   empty - this indicates all text was to be retained, safe for the @c _tagsToRemove and
   *   @c _tagsToRemoveWithContents.
   */
  private function _CutOff( $text, $cutOffLength )
  {
    /* Treated as a fifo stack. A list of tags that have been opened but not yet closed. */
    $openTags = array();

    /* Portions of $text is continuously appended until the $cutOffLength is reached.
     * Will be returned as 'the shortened text'.
     */
    $shortened = array();

    /* Also the tag that follows whitespace is not immediately added to $shortened.
     * It is first stored in here.
     * When a new portion is found, this string is fully appended to $shortened.
     * When the loops ends, this string is expanded with all closing tags that still
     * need to be added (one for each opened tag that is still not yet closed) are
     * appended here at the end of this fucmtion, before returning.
     * Will be returned as 'the closing tags'
     */
    $closingTags = '';

    /* The total length of the plain text strings may not be bigger than the
     * maximum article length setting.
     */
    if ( $cutOffLength )
    {
      $nrOfUnitsYetToRetain = $cutOffLength;
    }
    else
    {
      $nrOfUnitsYetToRetain = PHP_INT_MAX;
    }

    /* Use an integer here, not a boolean.
     * If a tag is found which has to be removed with its content - i.e. it is
     * listed in @c _tagsToRemoveWithContents - we search for that specific
     * tagin the next loop. If can be that that same tag is nested, and that
     * an opening tag is found again. By using a counter we can be sure when
     * the outer closing tag has been found.
     */
    $removeAllUntilEndOfTag = 0;

    /* The position in bytes from where the search for the next match of the regular expression must start. */
    $offset = 0;

    /* A tag does not necessarily indicate the end of the 'word', 'sentence', or 'paragraph'.
     * When this boolean is false, the (first portion of the) next plaintext indicates the start of a new unit.
     * When this boolean is true, the (first portion of the) next plaintext belongs to the same 'word', etc.
     */
    $currentUnitIsOngoing = false;

    /* This is not a constant: normally we search for any tag, but when we know we have to skip portions
     * we can as well directly search for the corresponding end tag. This can be achieved by adapting the
     * tag pattern.
     */
    $tagPattern = JString::str_ireplace( self::_tagReplacer, self::_anyTag, self::_tagPattern );

    $continue = true;
    while ( $continue )
    {
      /* Find HTML tags. Each match is an array of (mostly) interesting data
       * about the tag - see @c _tagPattern. Using that, we can find the plain
       * text in front of it.
       */
      /* By using PREG_OFFSET_CAPTURE, each entry in the array returned will
       * be an array itself, containing the matched (sub)string and the starting
       * offset.
       */
      $matchCount = preg_match( $tagPattern, $text, $matches, PREG_OFFSET_CAPTURE, $offset );
      if ( !/*NOT*/ $matchCount or ( count( $matches ) < 4 ) )
      {
        /* No (more) HTML tags were found. We can not just assume that the last part
         * of the string is always a HTML tag, especially not when no wysiwig editor
         * has been used to create this article.
         * Fetch the remainder of text, and set the needed variables to some dummy value,
         * so that the loop can finish correctly.
         */
        $matchCount = preg_match ( "/.*/is", $text, $matches, PREG_OFFSET_CAPTURE, $offset );
        $plainText = $matches[0][0];
        $fullTag = "";
        $tag = "";
        $isSelfClosingTag = false;
        $isClosingTag = false;
        //$offset = /* Don't care */
        $continue = false;
      }
      else
      {
        $plainText = $matches[1][0];
        $fullTag = $matches[2][0];
        $tag = JString::strtolower( $matches[4][0] );

        /* Determine whether the tag we found is an opening tag (e.g. <abc>), a closing tag (e.g. </abc>)
         * or a self-closing tag (e.g. <abc />).
         * If a closing slash is present, it is captured by the regular expression, either in index 3 (<abc />),
         * either in the last-but-one index (<abc />) - and the last-but-one index is always greater than 3.
         */
        $isSelfClosingTag = $matches[ count( $matches) - 2 ][0] == '/';
        $isClosingTag = $matches[3][0] == '/';

        /* Those pesky html4 tags are still lingering around. Be sure to
         * correctly determine a tag as self-closing, even when no closing
         * slash was present. e.g. <br> vs. <br/>
         */
        if ( !/*NOT*/ $isClosingTag )
        {
          if ( in_array( $tag, $this->_extraSelfClosingTags ) )
          {
            $isSelfClosingTag = true;
          }
        }

        /* Prepare the next loop: the value of $offset determines where the next search starts. */
        $offset = $matches[ count( $matches ) - 1 ][1] + 1;
        /* $continue remains true for now. May become false below. */
      }

      if ( $removeAllUntilEndOfTag )
      {
        /* We're inside a block of code of which nothing may be retained in the cut-off text.
         * Do not add the plaintext and tag strings.
         */
        if ( $isClosingTag )
        {
          $removeAllUntilEndOfTag--;
          if ( $removeAllUntilEndOfTag <= 0 )
          {
            $tagPattern = JString::str_ireplace( self::_tagReplacer, self::_anyTag, self::_tagPattern );
          }
        }
        else
        {
          $removeAllUntilEndOfTag++;
        }
      }
      else
      {
        /* Determine the length of the just extracted portion of $text.
         * Depending on the outcome, and the current value of $currentUnitIsOngoing
         * that may need to be tweaked a bit.
         * e.g. we need to count in paragraphs, the match contains no plaintext and a paragraph ending:
         *   the current ongoing paragraph is then closed and must be counted.
         * e.g. we need to count in words, the match equals 'def ghi?<b>':
         *   the returned value will be two, but we may only count one if '?' equals 'j' (two if it equals ' ').
         * Also update $currentUnitIsOngoing to reflect the state after the current portion has been added.
         */
        $end = true;
        $length = ReadLessTextHelper::DetermineLength( $plainText . $fullTag, $this->_lengthUnit, $end );
        if ( $currentUnitIsOngoing and $end )
        {
          if ( !/*NOT*/ $length )
          {
            $length = 1;
          }
        }
        if ( $length and !/*NOT*/ $end )
        {
          $length--;
        }
        if ( $currentUnitIsOngoing )
        {
          if ( $end )
          {
            $currentUnitIsOngoing = false;
          }
        }
        else
       {
         if ( $length and !/*NOT*/ $end )
         {
           $currentUnitIsOngoing = true;
         }
        }

        /* Add the new plaintext. */
        if ( $length >= $nrOfUnitsYetToRetain )
        {
          $plainText = ReadLessTextHelper::Substr( $plainText, $nrOfUnitsYetToRetain, $this->_lengthUnit, $this->_retainWholeWords );
          $shortened[] = $plainText;
          $this->_isShortened = true;
          //$nrOfUnitsYetToRetain = /* Don't care */
          $continue = false;
        }
        else
        {
          $shortened[] = $plainText;
          $nrOfUnitsYetToRetain -= $length;
          /* $continue remains true. */
        }

        /* Determine what to append to the just-added plain text.
         * Also:
         * - update the list of opened-and-not-yet-closed tags and
         * - prepare the next loop (if there is another one).
         */
        if ( in_array( $tag, $this->_tagsToRemoveWithContents ) )
        {
          /* We don't know what will be stripped away in the shortened text:
           * it could be markup, a title or a table.
           * For sure is that the author wants this tag with its contents in the
           * full article, and that it may not taken along in the shortened
           * version. Even when all the remainder of the article fits in the
           * shortened text, it is best to ensure a pre- and/or suffix is
           * appended when done shortening.
           */
          $this->_isShortened = true;

          /* Do not add the tag. */
          if ( $isClosingTag or $isSelfClosingTag )
          {
            /* Nothing more to do. */
          }
          else
          {
            $removeAllUntilEndOfTag++;
            $tagPattern = JString::str_ireplace( self::_tagReplacer, $tag, self::_tagPattern );
          }
        }
        else if ( in_array( $tag, $this->_tagsToRemove )
            or in_array( 'all', $this->_tagsToRemove ) )
        {
          /* Do not add the tag. */
        }
        else if ( $isSelfClosingTag )
        {
          $shortened[] = $fullTag;
        }
        else if ( $isClosingTag )
        {
          $shortened[] = $fullTag;
          /* For simplicity, just assume at this point the text only contains
           * valid HTML, i.e. that all opening tags are properly closed in the
           * correct order. That means we do not need to check whether some
           * pushed opening tag matches with this closing tag: it just has to
           * be.
           */
          unset( $openTags[ count( $openTags ) - 1 ] );
          $openTags = array_values( $openTags ); /* re-index */
        }
        else if ( $tag )
        {
          if ( $continue )
          {
            /* The tag found is a valid opening tag that must remain in the cut-off text. */
            $shortened[] = $fullTag;
            $openTags[] = $tag;
          }
          else
          {
            /* No need to open a tag just at the point where we will stop. */
          }
        }
      }
    } /* while ( $continue ) */

    /* Not all parts of $shortened will become part of 'the shortened text'.
     * All last portions that are either
     * - a tag,
     * - an empty string,
     * - a whitespace string
     * will be added to 'the closing tags'.
     * Plus - after the removal of these elements - the then last plaintext string is right trimmed.
     * All this to allow to 'glue' the inline suffix right after the last retained plaintext
     * character.
     */
    $continue = true;
    $i = count( $shortened ) - 1;
    while ( $continue and ( $i > 0 ) )
    {
      if ( ( $shortened[ $i ] === '' ) /* an empty string */
          or ( substr_compare( $shortened[ $i ], '<', 0, 1 ) == 0 ) /* a tag */
          or ( ctype_space( $shortened[ $i ] ) ) ) /* a whitespace string */
      {
        $closingTags = $shortened[ $i ] . $closingTags;
        $shortened[ $i ] = '';
        $i--;
      }
      else
      {
        $continue = false;
      }
    }
    if ( $i > 0 )
    {
      $shortened[ $i ] = ReadLessTextHelper::Rtrim( $shortened[ $i ] );
    }
    $shortened = implode( '', $shortened );

    /* All tags that were opened and not yet closed are now closed here
     * in the correct order: i.e. in reverse order.
     */
    if ( count( $openTags ) > 0 )
    {
      $openTags = array_reverse( $openTags );
      $closingTags .= '</' . implode( '></', $openTags ) . '>';
    }

    return array ( $shortened, $closingTags );
  }

  /* *********************************************************************** */

  /**
   * Various options needed while operating on the text.
   * May only be set in _PrepareArticleText or _GetParams.
   * Once set, it is to be considered RO.
   * @{
   */
  private $_cache = null; /* Set correctly in _PrepareArticleText(). */

  private $_addPrefix = 'no'; /**< Must be checked after shortening, (if applicable) in combination with _isShortened. */
  private $_addInlineSuffix = 'no'; /**< Must be checked after shortening, (if applicable) in combination with _isShortened. */
  private $_addSuffix = 'no'; /**< Must be checked after shortening, (if applicable) in combination with _isShortened. */
  private $_respectExistingReadmoreLink = true; /* Set correctly in _GetParams() */
  private $_applyFormatting = 'no'; /**< Must be checked after checking the article's length, (if applicable) in combination with _isShortened. */
  private $_createThumbnail = 'no'; /**< Must be checked after shortening, (if applicable) in combination with _isShortened. */
  private $_linkThumbnail = true; /* Set correctly in _GetParams() */
  private $_thumbnailTitle = ''; /* Set correctly in _GetParams() */
  private $_prefix = ''; /* Set correctly in _GetParams() */
  private $_inlineSuffix = ''; /* Set correctly in _GetParams() */
  private $_suffix = ''; /* Set correctly in _GetParams() */
  private $_articleUrl = '.';
  private $_retainWholeWords = false;
  private $_crop = array( 'horizontal_position' => 'no', 'vertical_position' => 'no' );

  private $_cacheTime = 2419200 /* 4 weeks */;
  private $_thumbWidth = 0;
  private $_thumbHeight = 0;
  private $_minimum = array( 'width' => 0, 'height' => 0, 'ratio' => 0.05 );

  private $_extraSelfClosingTags = array();
  private $_tagsToRemove = array();
  private $_tagsToRemoveWithContents = array();
  private $_squareTokensToRemove = array();
  private $_curlyTokensToRemove = array();
  private $_squareTokensToRemoveWithContents = array();
  private $_curlyTokensToRemoveWithContents = array();

  private $_htmltext = ''; /* Set correctly in _PrepareArticleText() */
  private $_plaintext = ''; /* Set correctly in _PrepareArticleText() */
  private $_lengthUnit = 'char'; /* Set correctly in _PrepareArticleText() */
  private $_wordCount = 0; /* Set correctly in _PrepareArticleText() */
  private $_hash = 0; /* Set correctly in _PrepareArticleText(). */

  private $_wrapperTag = array( 'open' => '', 'close' => '' ); /* Set correctly in _PrepareArticleText(). */
  /** @} */

  /**
   * Can be set to true, when an existing manually inserted read more token
   * is found; or later on, when the formatting options cause the removal of
   * parts of the article; or when the article is automatically shortened and
   * some remainder of the article is excluded.
   * Once set to true, the variable may not be set to false again.
   */
  private $_isShortened = false; /* Reset in _GetParams() */
  /** @} /*

  /* *********************************************************************** */

  /**
   * Used to find an image tag in a text.
   *
   * A match found using this regular expression will return at each index:
   * [0] The complete @c img tag, inclusive the brackets and the attributes
   * [1] The value of @src attribute, i.e. the URL where the image can be fetched.
   * [last] The closing bracket. Used to know the precise end byte
   *     offset of the matched tag. Especially needed for multi byte strings
   *     (some of the attributes inside the tag might very well be that),
   *     since JString::strlen returns the number characters, not the number
   *     of bytes. The offset given to preg_match needs to be a byte offset.
   *
   * @note: It is not possible (or: I could not get it to work) to include correct
   *   positions together with the found matches when using non-ASCII UTF8 strings
   *   when using this pattern with preg_match.
   *   The matches returned seem correct though, and strpos can be used to fetch
   *   the starting UTF8 character index.
   * @note This is a simplified version of _tagPattern. Potentially this can
   *   match a great portion of the text, crossing several html tags, _if_ an img
   *   tag is given _without_ a src attribute. If this happens, give them what they
   *   are asking for. Or, in other words: don't worry about that.
   */
  const _imgPattern = '/<img.+?src\s*=\s*["\']([^"\']+)["\'][^>]*(>)/muis';
  /*                                           1111111            -1    */
  /*                    00000000000000000000000000000000000000000000    */

  /**
   * Used to find an content gallery token in a text.
   *
   * A match found using this regular expression will return at each index:
   * [0] The complete @c content gallery token, inclusive the gallery data and the closing token.
   * [1] The gallery data, i.e. the relative URL where the gallery images can be fetched.
   * [last] The closing bracket. Used to know the precise end byte offset of the matched tag. Especially needed for
   *   multi byte strings since JString::strlen returns the number characters, not the number of bytes. The offset given
   *   to preg_match needs to be a byte offset.
   */
  const _galleryPattern = '/{(gallery|vsig|ppgallery|becssg)}\s*([^<]+)\s*{\/\1}/muis';
  /*                                                             11111        -1     */
  /*                        0000000000000000000000000000000000000000000000000000     */

  /**
   * Used to parse an html text by finding all the HTML tags.
   * Thanks to http://kev.coolcavemen.com/2007/03/ultimate-regular-expression-for-html-tag-parsing-with-php/
   * It is a bit modified, to catch the tag without attributes and brackets,
   * the closing tag character '/', and the last char in the match as well.
   * @note Before usage, the string @c _tagReplacer in @c _tagPattern must be replaced with the tag to search for,
   *   or with @c _anyTag
   *
   * A match found using this regular expression will return at each index:
   * [0] The full match; i.e. the concatenation of everything below
   * [1] The plaintext preceding the tag
   * [2] The complete tag, inclusive the brackets and the attributes
   * [3] Either empty, either '/' when the tag is a closing tag.
   * [4] The tag name
   * [5] The full attributes - possibly not present
   * [6] ...
   * [last but one] If the tag is self closing: '/'. Else, and if attributes
   *     are present: the last attribute. Else: the empty string.
   * [last] The closing bracket. Used to know the precise end byte
   *     offset of the matched tag. Especially needed for multi byte strings
   *     (some of the attributes inside the tag might very well be that),
   *     since JString::strlen returns the number characters, not the number
   *     of bytes. The offset given to preg_match needs to be a byte offset.
   *
   * @note the @c xxx part is to be replaced
   * - replace with @c _anyTag to catch any tag
   * - replace with 'abc' to catch tag abc
   *
   * @{
   */
  const _tagPattern = "/(.*?)(<(\/?)(xxx)((\s+(\w|\w[\w-]*\w)(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)(\/?)(>))/muis";
  /*                     111    333  444   --- one attribute --------------------------------------           -2   -1      */
  /*                                      --- all attributes from index 5 until index -3 ------------                      */
  /*                          222222222222222222222222222222222222222222222222222222222222222222222222222222222222222      */
  /*                    0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000     */
  const _tagReplacer = 'xxx';
  const _anyTag = '\w+';
  /** @} */

  /**
   * @li _tokenPattern Used to find third party token indications like
   *   {slider=MySlider}
   *   {gallery path/to/images}
   * @li _tokenPatternWithContents Used to find third party token indications like
   *   [pgn]...[/pgn]
   *   {slide}...{slide}...{slides}
   *
   * What can not be detected:
   * @li nested token codes
   * @li self closing token codes
   * @li escaped starts of token codes
   *
   * A match found using this regular expression will return at each index:
   * @li _tokenPattern
   *   [0] The complete token code, inclusive the opening and closing character.
   * @li _tokenPatternWithContents
   *   [0] The complete opening token, the complete closign token, and all text in between.
   *
   * @note the @c xxx, @c yyy and @c zzz parts are to be replaced
   * - replace @c xxx with [ or { or ... to catch the start of a token
   * - replace @c yyy with ] or } or ... to catch the end of a token
   *
   * @{
   */
  const _tokenPattern = "/xxx\s*.?\s*zzz.*?yyy/muis";
  const _tokenPatternWithContents = "/xxx\s*zzz.*?yyy.*?xxx\s*\/\s*zzzs?\s*yyy/muis";
  const _tokenOpeningReplacer = 'xxx';
  const _tokenClosingReplacer = 'yyy';
  const _tokenReplacer = 'zzz';
  /** @} */

//     private $profiler = null;
//     private $profiles = null;
}

?>
PK��#]D�c6ee*content/readlesstext/readlesstextcache.phpnu�[���<?php
/**
 * @package readlesstext
 * @copyright 2008-2014 Parvus
 * @license http://www.gnu.org/licenses/gpl-3.0.html
 * @link http://joomlacode.org/gf/project/cutoff/
 * @author Parvus
 *
 * readless is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * readless is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with readless. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version $Id$
 */

defined( '_JEXEC' ) or die;

class ReadLessTextCache
{
  /**
   * Constructor
   * @param string $rtable The table name where the item is stored.
   * @param uint $rid The item id in $rtable.
   * @param string $hash a fingerprint of the article. When the fingerprint doesn't match with the
   *   value stored in the database, the other fields are reset.
   */
  function __construct( $table, $rtable, $rid, $hash )
  {
    /* Must be set before calling _GetDataFromDb */
    $this->_table = $table;
    $this->_data[ 'rtable' ] = $rtable;
    $this->_data[ 'rid' ] = $rid;

    $this->_GetDataFromDb( $rtable, $rid );
    if ( array_key_exists( 'hash', $this->_data )
        and $this->_data[ 'hash' ]
        and ( $this->_data[ 'hash' ] == $hash ) )
    {
      /* Ok. Use the cached data. */
      $this->_dirty = false;
    }
    else
    {
      foreach ( array_keys( $this->_data ) as $key )
      {
        if ( $key != 'id' )
        {
          $this->_data[ $key ] = 0;
        }
      }
      $this->_data[ 'rtable' ] = $rtable;
      $this->_data[ 'rid' ] = $rid;
      $this->_data[ 'hash' ] = $hash;
      $this->_dirty = false; /* There is no need to store reset values. */
    }
  }

  /**
   * Retrieves the stored value for the given field.
   * @param string $field A field name, as stored in the database.
   * @note Possible fields are: 'char', 'word', 'sentence', 'paragraph', 'begin', 'end', 'url'.
   * @return @li 0 when the requested field or its field value could not be found. A valid value otherwise.
   */
  public function Get( $field )
  {
    $value = 0;
    if ( array_key_exists( $field, $this->_data ) )
    {
      $value = $this->_data[ $field ];
    }
    return $value;
  }

  /**
   * Sets or updates (a) value(s) for the given field(s).
   * @param mixed $field Either a field name, as stored in the database.
   *   Or an array of field names.
   * @param mixed value Either a fields value. It is assumed the values given can be converted to the stored database
   *   type.
   *   Or an array of field values.
   * @return void
   * @note The values are not yet stored in the database. Use @c Store() to make the changes permanent.
   * @see Store
   * @return void
   */
  public function Set( $field, $value )
  {
    if ( is_string( $field ) )
    {
      $set = array( $field => $value );
    }
    else
    {
      /* Assume is_array() */
      $set = array_combine( $field, $value );
    }
    foreach ( $set as $k => $v )
    {
      if ( isset( $this->_data[ $k ] ) and ( $this->_data[ $k ] == $v ) )
      {
        /* Nothing changed. No need to mark the data as changed. */
      }
      else
      {
        $this->_data[ $k ] = $v;
        $this->_dirty = true;
      }
    }
  }

  /**
   * Makes all changes permanent.
   */
  public function Store()
  {
    if ( $this->_dirty )
    {
      $this->_SetDataToDb();
      $this->_dirty = false;
    }
    else
    {
      /* Nothing changed. No need to write to the database. */
    }
  }

  /**
   * Fetches all known readlesstext data from the database of given article/item
   * @return void.
   * @post @c $this->_data will have been set to an associative array, with the
   *   field names as keys, and the field values as values, or to an empty array
   *   (when no stored data was found).
   */
  private function _GetDataFromDb()
  {
    $db = JFactory::getDBO();
    $query = 'SELECT *
        FROM ' . $this->_table . '
        WHERE rtable = ' . $db->Quote( $this->_data[ 'rtable' ] ) . '
        AND rid = ' . $db->Quote( $this->_data[ 'rid' ] );
    $db->setQuery( $query );
    $this->_data = $db->loadAssoc();
    if ( $this->_data )
    {
      unset( $this->_data[ 'last_update' ] );
    }
    else
    {
      $this->_data = array();
      /* rtable, rid, and hash will be filled in by the caller */
    }
  }

  /**
   * Writes all locally stored readlesstext data to the database of given article/item.
   * @note Both @c rtable and @c rid, given during construction, will be stored too.
   * @note If a record already exists, it will be updated; if not, a new one will be added.
   * @return void.
   */
  private function _SetDataToDb()
  {
    $db = JFactory::getDBO();

    $inserts = array();
    foreach ( $this->_data as $key => $value )
    {
      $inserts[ $db->quoteName( $key ) ] = $db->Quote( $value );
    }

    $updates = array();
    foreach ( $this->_data as $key => $value )
    {
      $updates[] = $db->quoteName( $key ) . '=' . $db->Quote( $value );
    }

    $query = 'INSERT INTO ' . $this->_table . ' (' . implode( ',', array_keys( $inserts ) ) . ')
        VALUES (' . implode( ',', $inserts ) . ')
        ON DUPLICATE KEY UPDATE ' . implode( ',', $updates );

    $db->setQuery( $query );
    $db->query();
  }

  private $_data = array(); /**< Local storage for all the readlesstext data. Keys correspond to the table fieldnames. */
  private $_dirty = false; /**< When @c False, no database write will be done. This eliminates needless writes. */
  private $_table = '#__readlesstext'; /**< The table name where readlesstext stores extra data about an article/item */
}
?>
PK��#]��%�%Jcontent/readlesstext/language/en-GB/en-GB.plg_content_readlesstext.sys.ininu�[���; site language file for read less text
; Copyright Copyright (C) 2010-2014 parvus
; license GNU/GPL_GPLv3 http://www.gnu.org/copyleft/gpl.html
;
; This file is part of the Joomla! extension plugin read less text.
;
; read less text is free software: you can redistribute it and/or modify it
; under the terms of the GNU_General Public License as published by the Free
; Software Foundation, either version 3 of the License, or (at your option)
; any later version.
;
; read less text is distributed in the hope that it will be useful, but
; WITHOUT_ANY_WARRANTY; without even the implied warranty of MERCHANTABILITY
; or FITNESS_FOR_A PARTICULAR_PURPOSE.  See the GNU_General Public License for
; more details.
;
; You should have received a copy of the GNU_General Public License along with
; read less text. If not, see <http://www.gnu.org/licenses/>.
;
; @version $Id: en-GB.plg_content_readlesstext.sys.ini 273 2014-11-26 20:43:05Z parvus $

PLG_CONTENT_READLESSTEXT_DESCRIPTION="<h2>v5.2 (r274)</h2><p><em>read less text</em> will control the article text: preview size, formatting and image placement can be adjusted to your liking, precisely on those pages and for those articles or items you want. <em>read less text</em> will not alter your article tables in any way. Only the display is controlled: uninstalling or disabling will bring back the original text.</p><p><em>It is advised to use the <code>Discover</code> mode should you want fine-grained control on when and where read less text is to be active. You can enable and disable the <code>Discover</code> mode in the section <code>When active</code>.</em></p><p>This version does not affect the article's titles. If you want to control the title length, prepend or append specific information, and adjust the casing of the title, you can install and use the separate extension <em><a href='http://extensions.joomla.org/extensions/style-a-design/titles/16619/'>read less title.</a></em></p><p>A companion plugin <em><a href='http://joomlacode.org/gf/project/cutoff/frs/'>read less text again</a></em> lets you define a second set of settings: whenever you want articles to be shortened or reformatted differently depending on the page they are shown, or depending on the location on the page they are shown, this companion plugin is made for you.</p><h2>Contexts - Quick</h2> <p>Check the table below to quickly configure the plugin: <table><tr><th><code>When Active</code> &gt; <code>Allowed</code></th> <th><em>only</em> active on</th></tr> <tr><td><code>frontpage</code></td> <td>the frontpage of your site</td></tr> <tr><td><code>category</code></td> <td>all the category blog pages</td></tr> <tr><td><br /><code>category=12</code></td> <td>the blog page of<br />the category with id 12</td></tr> <tr><td><code>135</code></td> <td>the article with id 135 <br /> on all blog and article pages</td></tr> </table></p> <ul><li>Most users will want to activate <em>read less text</em> for all the article blog pages. They can choose to select the quick configuration in which case the fields <code>Allowed</code> and <code>Disallowed</code> will be ignored.</li> <li><em>read less text</em> can not be active on a list layout of articles - this is a technical limitation.</li> <li>It is possible to be active on a list layout of other components - this entirely depends on the implementation of that component.</li></ul> <h2>Tokens</h2> <p><em>read less text</em> can add specific HTML both in front and at the end of each article. Both prefix and suffix may contain <em>token</em>s. A <em>token</em> is a special keyword that is surrounded by curly brackets. <ul>The following <em>tokens</em> are recognized: <li><code>{title}</code>, <code>{id}</code>, <code>{url}</code><br /><code>{author}</code>, <code>{author_id}</code><br /><code>{words}</code>, <code>{hits}</code><br /><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code><br /i><code>{category}</code>, <code>{category_id}</code><br /><code>{component}</code></li></ul></p> <p><em>Token</em>s are replaced for each article, using the article's specific information. Those tokens that are replaced with dates will be formatted according to the format you provide in the field <code>Date Format</code>. You can review the <a href='http://php.net/manual/en/function.date.php'>manual for the function <code>date</code></a> for a list of formatting characters and their explanation, and for a list of examples.<br/>The <code>{title}</code> token can be displayed shortened as well: if you use <a href='index.php?option=com_plugins&view=plugins&filter_search=read'><em>read less title</em></a>, and have ensured that the ordering number is lower than the ordering number of <em>read less text</em>, the shortened title will be used. This will work even if you selected not to display titles under <code><a href='index.php?option=com_content'>Article Manager</a> &gt; Options &gt; Articles</code> by setting the option <code>Show Title</code> to <code>Hide</code>.</p> <h2>Contexts - Slow</h2> <p> You can very precisely configure when this plugin may be active and when not. This is done by listing <em>contexts</em> in the <code>Allowed</code> and <code>Disallowed</code> fields. A <em>context</em> is simply a combination of a component name, the name of a view and an article id, separated by a single colon <code>:</code>.<ul><li>The component name may be omitted - in that case <code>com_content</code> is assumed.</li> <li>The view name may be omitted - in that case it is assumed all views are targeted.</li> <li>The article id may be omitted - in that case it is assumed all articles on the page are targeted.</li><li>The last part, where the article id can be given, has one special shortcut: <code>all-in-&lt;n&gt;</code>, where <code>&lt;n&gt;</code> is to be replaced with the id of a category. In that case all articles in the given category <code>&lt;n&gt;</code> are targeted.</li> </ul></p> <p>The table above already gave some examples. Should you want a very fine-grained control: you easily can.</p> <h2>Contexts - Discover</h2> <p>To know if it is possible for <em>read less text</em> to operate on a specific page, and to know the precise component name and view which is used on that page, you can enable the <code>Discover</code> mode. In <code>Discover</code> mode, <em>read less text</em> will replace the article's text or any component's <em>Item</em> text - if applicable - with the information you need to be able to fully verify and adjust your configuration.</p> <p>The <code>Discover</code> mode is only applied for users which have back-end access: you can thus safely activate the option and still be assured all your regular users continue to see your site as intended.</p> <h2>Contexts - Two more examples</h2> <p>Suppose you have as configuration:</p> <table><tr><th>Field</th> <th>Value</th></tr> <tr><td><code>Quick Configuration</code></td> <td><code>No, use the fields below</code></td></tr> <tr><td><code>Allowed</code></td> <td><code>frontpage, category, com_eventlist:venues</code></td></tr> <tr><td><code>Disallowed</code></td> <td><code>38, 245, 246, category=7, com_eventlist:venues:28</code></td></tr></table></p> <p> <ul>In this case <em>read less text</em> will:<li>Never be active on the text of the articles with id 38, 245 and 246, regardless where and on what kind of page the article is shown.</li> <li>Not be active when displaying the blog page of category 7.</li> <li>Be active on all articles on all other blog pages, including any category blog page within category 7.</li> <li>Be active on the articles on the frontpage except the articles with id 38, 245 and 246.</li> <li>Be active on all venues on all EventList's detailed venue list pages except for the specific venue with id 28</li></ul></p> <p>Suppose you have as configuration:</p> <table><tr><th>Field</th> <th>Value</th></tr> <tr><td><code>Restrict Access For Guests</code></td> <td><code>Yes</code></td></tr> <tr><td><code>Quick Configuration</code></td> <td><code>No, use the fields below</code></td></tr> <tr><td><code>Allowed</code></td> <td><code>blog, categories, category, featured</code></td></tr> <tr><td><code>Disallowed</code></td> <td><code>all-in-7</code></td></tr></table></p> <p> <ul>In this case <em>read less text</em> will:<li>Active on all content blog pages when a user is logged in,</li> <li>always be active on all content pages when a user is <em>not</em> logged in (i.e. is a guest),</li> <li><em>except</em> for all articles in category <code>7</code>, which <em>read less text</em> will never try to shorten - not even for guests, regardless the page on which they are shown.</li></ul></p><hr/><h2>Thank you!</h2><ul>You can show your appreciation - should there be any - by<li><em>helping yourself</em>. <a href='http://joomlacode.org/gf/project/cutoff/tracker/?action=TrackerItemBrowse&tracker_id=9352'>Report bugs</a> and <a href='http://joomlacode.org/gf/project/cutoff/tracker/?action=TrackerItemBrowse&tracker_id=9351'>request missing functionality</a>: everybody's time is limited, but most likely you won't get what you don't ask for.</li><li><em>helping other administrators</em>. <a href='http://extensions.joomla.org/extensions/news-display/article-elements/articles-summary/12432'>Rate my extension</a> and leave a correct review: the height of the rating and the tone of the reviews are important decision factors for potential new users.</li><li><em>helping me</em>. <a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=L9P4GMDWRKGUN'>Make a donation (PayPal)</a>: any gift is gratefully accepted, and you can be sure to have boosted my motivation!</li></ul>"
PK��#]�h��a�a�Fcontent/readlesstext/language/en-GB/en-GB.plg_content_readlesstext.ininu�[���; site language file for read less text
; Copyright Copyright (C) 2010-2014 parvus
; license GNU/GPL_GPLv3 http://www.gnu.org/copyleft/gpl.html
;
; This file is part of the Joomla! extension plugin read less text.
;
; read less text is free software: you can redistribute it and/or modify it
; under the terms of the GNU_General Public License as published by the Free
; Software Foundation, either version 3 of the License, or (at your option)
; any later version.
;
; read less text is distributed in the hope that it will be useful, but
; WITHOUT_ANY_WARRANTY; without even the implied warranty of MERCHANTABILITY
; or FITNESS_FOR_A PARTICULAR_PURPOSE.  See the GNU_General Public License for
; more details.
;
; You should have received a copy of the GNU_General Public License along with
; read less text. If not, see <http://www.gnu.org/licenses/>.
;
; @version $Id: en-GB.plg_content_readlesstext.ini 273 2014-11-26 20:43:05Z parvus $

; Sections
COM_PLUGINS_FORMATTING_FIELDSET_LABEL="Formatting"
COM_PLUGINS_INFO_FIELDSET_LABEL="Information"
COM_PLUGINS_LENGTH_FIELDSET_LABEL="Length"
COM_PLUGINS_PREFIX_FIELDSET_LABEL="Prefix"
COM_PLUGINS_SUFFIX_FIELDSET_LABEL="Read More (Suffix)"
COM_PLUGINS_THUMBNAIL_FIELDSET_LABEL="Thumbnail"
COM_PLUGINS_WHEN-ACTIVE_FIELDSET_LABEL="When Active"

; Options
PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX="Add Inline Suffix"
PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX_DESCRIPTION="Custom text can be added to the shortened (or not) article. The next fields below can be added <em>before</em> all tags have been <br/>closed. In practice this means the text you specify will look inline with the last part of the text: it will also have the same <br/>x formatting applied.<br />Choose here when the options that follow may be applied.<ul><li>Select <code>No</code> to not add any text.</li><li>Select <code>Always when read less text may be active</code> to apply all options when the constraints as set in the section <br/><em>When Active</em> are met. The options below will then be applied, regardless of the length of the article, and whether <br/>the article is shortened or not.</li><li>Select <code>Respect global option Show 'Read More'</code> to apply all options when <em>read less text</em> may be active, and when <br/>allowed by the aforementioned option in the <em>Article Manager</em>.</li><li>Select <code>Only when the article is shortened</code> to apply the options below when both the constraints as set in the <br/>section <em>When Active</em> are met, and the article is shortened (due to the <code>Shortened Text Length</code> or an existing <br/><em>Read More</em> which is to be respected as set in the <em>Length</em> section; or due to removed tags or tokens as set in the <br/><em>Formatting</em> section).</li></ul>"

PLG_CONTENT_READLESSTEXT_ADD_PREFIX="Add Prefix"
PLG_CONTENT_READLESSTEXT_ADD_PREFIX_DESCRIPTION="Choose here when the options in this section may be applied.<ul><li>Select <code>No</code> to disable all options in this <em>Prefix</em> section.</li><li>Select <code>Always when read less text may be active</code> to apply all options when the constraints as set in the section <br/><em>When Active</em> are met. The options below will then be applied, regardless of the length of the article, and whether the <br/>article is shortened or not.</li><li>Select <code>Only when the article is shortened</code> to apply the options below when both the constraints as set in the <br/>section <em>When Active</em> are met, and the article is shortened (due to the <code>Shortened Text Length</code> or an existing <br/><em>Read More</em> which is to be respected as set in the <em>Length</em> section; or due to removed tags or tokens as set in the <br/><em>Formatting</em> section).</li></ul>"

PLG_CONTENT_READLESSTEXT_ADD_SUFFIX="Add Read More (Suffix)"
PLG_CONTENT_READLESSTEXT_ADD_SUFFIX_DESCRIPTION="Custom text can be added to the shortened (or not) article, replacing the default <em>Read More</em> text. The next fields below can <br/>be added <em>after</em> all tags have been closed. In practice this means the text you specify will look as a separate paragraph <br/>appended below the text.<br />Choose here when the options that follow may be applied.<ul><li>Select <code>No</code> to not add any text.</li><li>Select <code>Always when read less text may be active</code> to apply all options when the constraints as set in the <br/>section <em>When Active</em> are met. The options below will then be applied, regardless of the length of the article, and whether <br/>the article is shortened or not.</li><li>Select <code>Respect global option Show 'Read More'</code> to apply all options when <em>read less text</em> may be active, and when <br/>allowed by the aforementioned option in the <em>Article Manager</em>.</li><li>Select <code>Only when the article is shortened</code> to apply the options below when both the constraints as set in the <br/>section <em>When Active</em> are met, and the article is shortened (due to the <code>Shortened Text Length</code> or an existing <br/><em>Read More</em> which is to be respected as set in the <em>Length</em> section; or due to removed tags or tokens as set in the <br/><em>Formatting</em> section).</li></ul>"

PLG_CONTENT_READLESSTEXT_ALLOWED="Allowed"
PLG_CONTENT_READLESSTEXT_ALLOWED_DESCRIPTION="Enter here a <em>comma</em> separated list of <em>contexts</em>. See the explanation aside for a full overview. If not empty, the plugin will <em>only</em> be active on articles or <em>items</em> in the given contexts. If empty, there is no restriction. <strong>When <code>Discover</code> mode is enabled, full context information for each article can be displayed.</strong>"

PLG_CONTENT_READLESSTEXT_ALWAYS_ACTIVE_FOR_GUESTS="Restrict Access<br />For Guests"
PLG_CONTENT_READLESSTEXT_ALWAYS_ACTIVE_FOR_GUESTS_DESCRIPTION="With this setting you can enforce all visitors of your site to log in before they can read the entire article's text.<br />When enabled, the setting <code>Allowed</code> is expanded with <code>, com_content</code> when a guest is requesting to view the page: <br/><em>read less text</em> will then always be active for all articles in <code>com_content</code>, except in the <em>context</em>s listed in <code>Disallowed</code>.<br/><strong>Note:</strong> If access is restricted, you will likely want to adapt the settings that may link to the full article: <br/><code>Prefix For Guests</code> under <code>Prefix</code> and/or <code>Suffix For Guests</code> under <code>Read More (Suffix)</code> - whichever has <br/>the option <code>... links to full article</code> set to <code>Yes</code>. There you can ensure your guests are redirected to a login page <br/>or a subscription page instead whenever they want to read the full article."

PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING="Apply Formatting<br />Options"
PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING_DESCRIPTION="<ul>Choose here when all options below in this section may be applied. <li>Select <code>No</code> to disable all options below in this <em>Formatting</em> section.</li><li>Select <code>Always when read less text may be active</code> to apply all options when the constraints as set in the section <em>When Active</em> are met. The options below will then be applied, regardless of the length of the article, and whether the article is shortened or not.</li><li>Select <code>Always when active and the article is long enough</code> to apply all options below when both the constraints as set in the section <em>When Active</em> are met, and the article is <em>long enough</em> (determined by the settings <code>Minimum Text Length</code> and <code>Respect Position Existing Read More</code>).</li></ul>"

PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SHORTEN_COUNT="# to shorten"
PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SHORTEN_COUNT_DESCRIPTION="Enter a number. For any given page, this indicates the number of articles that may be shortened, <strong>after</strong> skipping the above configured number of articles. All other articles that are prepared for display after this count has been reached will not be shortened. <br /><strong>Note:</strong> Enter 0 to shorten all articles or items (after skipping the above configured number)."

PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SKIP_COUNT="# to skip"
PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SKIP_COUNT_DESCRIPTION="Enter here a number. For any given page, this indicates the number of articles that must be skipped and may not be shortened.<br />Only after skipping this many articles or items, <em>read less text</em> will check the <em>Length</em> constraints and the other constraints set below, and possibly shorten the remainder of the articles or items.<br /><strong>Note:</strong> Enter 0 to not skip any article."

PLG_CONTENT_READLESSTEXT_COMPONENT_SCOPE="Within component scope"
PLG_CONTENT_READLESSTEXT_COMPONENT_SCOPE_DESCRIPTION="This option and the option below further restricts the usage of <em>read less text</em>. When a page is built, the output of any component - not just <code>com_content</code> - can contain article text. In most cases, this component allows plugins like <em>read less text</em> to intervene, to enhance the output (technical: the <code>onContentBeforeDisplay</code> event is fired). Some examples are <em>Eventlist</em> (<code>com_eventlist</code>) and <em>FJ Related Articles Blog and List Component</em> (<code>com_fjrelated</code>).<br />With this option you can choose if <em>read less text</em> must follow the context rules below, or may never be active on any component output. If the latter choice is made, the options <code>Quick Configuration?</code>, <code>Allowed</code> and <code>Disallowed</code> below are ignored for component output."

PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL="Create Thumbnail"
PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL_DESCRIPTION="<em>Read Less Text</em> can search for an image in the <em>full</em>text that meets the given criteria, and resize and move the first image <br/>as a thumbnail to the beginning of the article.<ul><li>Select <code>No</code> to disable all options in this <em>Thumbnail</em> section.</li><li>Select <code>Always when read less text may be active</code> to apply all options when the constraints as set in the section <br/><em>When Active</em> are met. The options below will then be applied, regardless of the length of the article, and <br/>whether the article is shortened or not.</li><li>Select <code>Only when the article is shortened</code> to apply the options below when both the constraints as set in <br/>the section <em>When Active</em> are met, and the article is shortened (due to the <code>Shortened Text Length</code> or an existing <br/><em>Read More</em> which is to be respected as set in the <em>Length</em> section; or due to removed tags or tokens as set in <br/>the <em>Formatting</em> section).</li></ul><strong>Note:</strong> All images not passing the criteria set here are ignored and left in place. <br/>If you want all images but one to be removed from the shortened text, you can add <code>img</code> to the setting <code>Tags To Remove</code>."

PLG_CONTENT_READLESSTEXT_CROP_HORIZONTAL_POSITION="Horizontal Crop"
PLG_CONTENT_READLESSTEXT_CROP_HORIZONTAL_POSITION_DESCRIPTION="When the ratio of the original image sizes and the ratio of the desired thumbnail sizes are not equal <em>(which is nearly always)</em>, we can crop in one direction, cutting of the extraneous portion of the image. The resulting resized image then has the exact desired thumbnail sizes. Here you can define which portion of the image may be cut off, if horizontal cropping needed.<br /><strong>Note:</strong> You can disable cropping in this direction: this may have as consequence that the resized </em>height will become less</em> than the configured thumbnail size."

PLG_CONTENT_READLESSTEXT_CROP_VERTICAL_POSITION="Vertical Crop"
PLG_CONTENT_READLESSTEXT_CROP_VERTICAL_POSITION_DESCRIPTION="When the ratio of the original image sizes and the ratio of the desired thumbnail sizes are not equal <em>(which is nearly always)</em>, we can crop in one direction, cutting of the extraneous portion of the image. The resulting resized image then has the exact desired thumbnail sizes. Here you can define which portion of the image may be cut off, if vertical cropping needed.<br /><strong>Note:</strong> You can disable cropping in this direction: this may have as consequence that the resized </em>width will become less</em> than the configured thumbnail size."

PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE="{tokens} To Remove"
PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_DESCRIPTION="Enter a list of <em>comma</em> separated words without { } markers, which must be removed in the text. <br /><strong>Note:</strong> When a token is removed due to this option, the article is considered to be shortened. According to the settings in the other sections, a thumbnail, a prefix, inline suffix and/or suffix may be added as a result. <br /><strong>Example:</strong> If you use the extension plugin <em>NoNumbers Slides</em>, you may have added something like <code>{slider somename}</code> to your content article, to transform portions of your content into slides. You can get rid of it in the shortened article by listing <code>slider</code> here."

PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_WITH_CONTENTS="{tokens} To Remove<br />With Contents"
PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION="Enter a list of <em>comma</em> separated words without { } markers, which must be removed in the text <strong>together with all the text that is present between the opening and the closing token</strong>.<br /><strong>Note:</strong> Self-closing tokens are not supported.<br /><strong>Note:</strong> When a token with its full contents is removed due to this option, the article is considered to be shortened. According to the settings in the other sections, a thumbnail, a prefix, inline suffix and/or suffix may be added as a result.<br /><strong>Example:</strong> If you use the extension plugin <em>Tabs & slides</em>, you may have added something like <code>{slide=somename}slide content{/slide}</code> to your content article. You can get rid of it in the shortened article by listing <code>slide</code> here."

PLG_CONTENT_READLESSTEXT_CUT_OFF_TEXT_LENGTH="Shortened Text Length"
PLG_CONTENT_READLESSTEXT_CUT_OFF_TEXT_LENGTH_DESCRIPTION="Enter a number. That number is expressed in the unit as selected below in <code>Length Unit</code>. When the article text is shortened, this many <em>units</em> will be retained. This number may be larger or smaller than the number above."

PLG_CONTENT_READLESSTEXT_DATE_FORMAT="Date Format"
PLG_CONTENT_READLESSTEXT_DATE_FORMAT_DESCRIPTION="Tags replaced with dates are formatted according this format. See the manual of the PHP function <code>date</code> for a list of formatting characters and their explanation, and for a list of examples. (A URL can be found in the help text aside.)<br /><strong>Example:</strong> <em>Monday, December 3</em> can be formatted as <code>l, F j</code><br /><strong>Example:</strong> <em>Mon 06:28</em> can be formatted as <code>D H:i</code><br /><strong>Example:</strong> <em>2012-07-28</em> can be formatted as <code>Y-m-d</code>"

PLG_CONTENT_READLESSTEXT_DEFAULT_THUMBNAIL_TEMPLATE="Default Thumbnail"
PLG_CONTENT_READLESSTEXT_DEFAULT_THUMBNAIL_TEMPLATE_DESCRIPTION="Enter the template of the path to the thumbnail to use when no suitable image has been found in the article. <br/>The path may be absolute, or relative to the root of your Joomla! installation. <br/>Tags in the given template will be expanded per article.<br /><em>read less text will resize, crop and cache the given thumbnail according to the setting made below, <br/>just like any image found within the article. The constraints however, are not checked.</em><br /><strong>Note:</strong> Leave this field empty to not insert a default thumbnail when no suitable image has been found.<ul>The following tokens are recognized and replaced for each article:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Note:</strong> If - after expanding the tags - the default thumbnail file can not be found, no thumbnail is inserted."

PLG_CONTENT_READLESSTEXT_DISALLOWED="Disallowed"
PLG_CONTENT_READLESSTEXT_DISALLOWED_DESCRIPTION="Enter here a <em>comma</em> separated list of <em>contexts</em>. See the help text aside for a quick overview on how these look like. If not empty, the plugin will <em>never</em> be active on articles or <em>Items</em> in the given contexts. If empty, there is no restriction. This list prevails over the list <code>Allowed</code> above. <strong>When <code>Discover</code> mode is enabled, full context information for each article can be displayed.</strong>"

PLG_CONTENT_READLESSTEXT_DISCOVER="<strong>Discover</strong>"
PLG_CONTENT_READLESSTEXT_DISCOVER_DESCRIPTION="Enabling this replaces the article's text with all information you need to configure the options in this section. <br/><strong>Only users that are allowed back-end access will see any effect: <br/>your normal users will continue to see the articles as intended.</strong> <br/>With this extra information, you can find out whether the plugin is active on each article, and what the precise <br/>context strings are for each article. Using the context strings, you can then fill in the <code>Allowed</code> &amp; <code>Disallowed</code> <br/>fields to have your unique configuration."

PLG_CONTENT_READLESSTEXT_EXTRA_SELF_CLOSING_TAGS="Non XHTML-compliant<br />&lt;tags&gt;"
PLG_CONTENT_READLESSTEXT_EXTRA_SELF_CLOSING_TAGS_DESCRIPTION="Enter a list of <em>comma</em> separated HTML tags without &lt; &gt; markers, for which the closing tag or the closing character <code>/</code> may be absent. As an example, consider the <code>br</code> tag. If not properly self-closed (i.e. if a trailing slash <code>/</code> is not added), this plugin might otherwise generate extra undesired whitespace by adding an additional closing tag.<br /><strong>A good choice seems <code>br, hr, img</code></strong>.<br /><strong>Note:</strong> This setting is applied regardless of the value of <code>Apply Formatting Options</code>."

PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX="Inline Suffix For Guests"
PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_DESCRIPTION="<strong>For guests only.</strong> Enter here the text to add right after the last character of the article, before closing all tags. <br/>You can provide HTML code here.<ul>The following tokens are recognized and replaced for each article:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Note:</strong> The default suffix just appends three dots. To reload the default value, just clear the <br/>text field and save the configuration.<br/><strong>Note:</strong> If the option <code>Enable Multi-language support?</code> is enabled, all text, including the HTML code, must be replaced with <br/>a placeholder; a placeholder is <strong>one</strong> word that must be used to define the real prefix - per language - under the <br/><em>Language Manager</em>.<br /><strong>Note:</strong> <code>url</code> will <em>always</em> point to the (SEO-optimized) url where the full article is to be found. If you have enabled the option <br/><code>Restrict Access For Guests</code> in the section <code>When active</code>, you likely don't want to use this token; replace it with <br/>the url to your login page, e.g. <code>index.php?option=com_users&amp;view=login&amp;Itemid=102</code>"

PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE="Guest inline suffix links to<br />full article"
PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="<strong>For guests only.</strong> If this option is enabled the suffix (text or HTML) will be wrapped and given as a link: when clicked, the guest is directed to the full article. If this option is disabled, you will have to provide another means for the guest to access the full article: by linking the title, by ensuring a thumbnail is generated, or by providing the desired HTML code yourself in the suffix. In the latter case, you can use the <code>{url}</code> token in combination with HTML tag <code>a</code>."

PLG_CONTENT_READLESSTEXT_GUEST_PREFIX="Prefix For Guests"
PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_DESCRIPTION="<strong>For guests only.</strong> Enter here the text to add before the article. <br/>You can provide HTML code here.<ul>The following tokens are recognized and replaced for each article:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><br /><strong>Note:</strong> Leave empty to not prepend the article.<br/><strong>Note:</strong> If the option <code>Enable Multi-language support?</code> is enabled, all text, including the HTML code, must be replaced <br/>with a placeholder; a placeholder is <strong>one</strong> word that must be used to define the real prefix - per language - under the <br/><em>Language Manager</em>.<br /><strong>Note:</strong> <code>url</code> will <em>always</em> point to the (SEO-optimized) url where the full article is to be found. If you have enabled the option <br/><code>Restrict Access For Guests</code> in the section <code>When active</code>, you likely don't want to use this token; replace it with the url to your login page, e.g. <code>index.php?option=com_users&amp;view=login&amp;Itemid=102</code>"

PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_LINKS_TO_FULL_ARTICLE="Guest prefix links to<br />full article"
PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="<strong>For guests only.</strong> If this option is enabled the prefix (text or HTML) will be wrapped and given as a link: when clicked, the guest is directed to the full article. If this option is disabled, you will have to provide another means for the guest to access the full article: by linking the title, by ensuring a thumbnail is generated, or by providing the desired HTML code yourself in the prefix. In the latter case, you can use the <code>{url}</code> token in combination with HTML tag <code>a</code>."

PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX="Suffix For Guests"
PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_DESCRIPTION="<strong>For guests only.</strong> Enter here the text to add after the article. This value replaces the default <em>Read More</em> text. <br/>You can provide HTML code here.<ul>The following tokens are recognized and replaced for each article:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Note:</strong> The default suffix mimics the standard <em>Read more</em> code Joomla! provides. To reload the default value, just clear the <br/>text field and save the configuration.<br/><strong>Note:</strong> If the option <code>Enable Multi-language support?</code> is enabled, all text, including the HTML code, must be replaced with <br/>a placeholder; a placeholder is <strong>one</strong> word that must be used to define the real prefix - per language - under the <br/><em>Language Manager</em>.<br /><strong>Note:</strong> <code>url</code> will <em>always</em> point to the (SEO-optimized) url where the full article is to be found. If you have enabled the option <br/><code>Restrict Access For Guests</code> in the section <code>When active</code>, you likely don't want to use this token; replace it with the url to <br/>your login page, e.g. <code>index.php?option=com_users&amp;view=login&amp;Itemid=102</code>"

PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_LINKS_TO_FULL_ARTICLE="Guest suffix links to<br />full article"
PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="<strong>For guests only.</strong> If this option is enabled the suffix (text or HTML) will be wrapped and given as a link: when clicked, the guest is directed to the full article. If this option is disabled, you will have to provide another means for the guest to access the full article: by linking the title, by ensuring a thumbnail is generated, or by providing the desired HTML code yourself in the suffix. In the latter case, you can use the <code>{url}</code> token in combination with HTML tag <code>a</code>. <br /><strong>Note:</strong> The default suffix mimics the standard <em>Read more</em> code Joomla! provides and already includes the <code>{url}</code> token in combination with the correct HTML tags: this option is best turned off in that case."

PLG_CONTENT_READLESSTEXT_LENGTH_UNIT="Length Unit"
PLG_CONTENT_READLESSTEXT_LENGTH_UNIT_DESCRIPTION="Select here the unit in which the two numbers above - both <code>Minimum Text Length</code> and <code>Shortened Text Length</code> - are expressed.<ul>Remarks and limitations:<li>A space or a tab is also counted as a <code>char</code>; however, subsequent whitespace is treated as one char.</li><li>Two <code>words</code> in the same paragraph must be separated by whitespace to be recognized as such.<br/>Two words with only a dot . in between (as in <em>this.that</em>) are counted as one word.</li><li>Two <code>sentences</code> are assumed to be separated by one of these characters: <code>. ? ! ¿</code> <br/>or by a paragraph ending, the end of a row in a table, a new bulleted or numbered item in a list. <br/>Subsequent sentence endings (for example, as in <code>What?!?!!</code>) are counted as one sentence ending. <br/>Two sentences with no whitespace in between (for example, as in <em>Been there.Done that</em>) are counted as two sentences.<br /><em>If your articles contain a lot of acronyms and/or versions (for example <code>R.E.M.</code>, <code>Joomla! 2.5.99</code>), <br/>the option <code>sentence</code> is less likely to give a satisfactory result.</em></li><li>A closing <code>p</code> tag is recognized as a <code>paragraph</code> ending (HTML code: <code>&lt;/p&gt;</code>), as is the end of a bulleted or numbered list. <br/>Title tags (such as <code>h1</code>, <code>h2</code>, etc.) are not counted. Empty paragraps are not counted.</li></ul>"

PLG_CONTENT_READLESSTEXT_LINK_THUMBNAIL="Create Link"
PLG_CONTENT_READLESSTEXT_LINK_THUMBNAIL_DESCRIPTION="Select <code>Yes</code> to create link of the thumbnail: when the user clicks on the thumbnail, the full article is shown."

PLG_CONTENT_READLESSTEXT_MAX_IMAGE_LOAD_TIME="Maximum Image<br />Load Time"
PLG_CONTENT_READLESSTEXT_MAX_IMAGE_LOAD_TIME_DESCRIPTION="Enter a number. <em>read less text</em> will abort the attempt to create a thumbnail from a remote image if this takes longer than this many seconds.<br />A very long loading time is usually caused by a not-responsive remote server; should this possibly occur, you can lower the loading time of your own pages to more acceptable levels by using a value of e.g. <code>2</code>. <br /><strong>Note:</strong> Enter <code>0</code> or leave blank to use the maximum time <em>read less text</em> is prepared to wait. This is currently set to <code>11</code> seconds."
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_HEIGHT="Minimum Height"
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_HEIGHT_DESCRIPTION="Enter a number. Only images which have a <strong>height</strong> in pixels greater than or equal to this number are considered as a potential thumbnail.<br />The first image that meets all conditions is resized and inserted in the shortened text.<br><strong>Note:</strong> All images not passing the criteria set here are ignored and left alone. If you want all images but one to be removed from the shortened text, you can add <code>img</code> to the setting <code>Tags To Remove</code>."
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_RATIO="Minimum Ratio"
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_RATIO_DESCRIPTION="Enter a number between 0 and 1. Only images which have a <strong>ratio</strong> in percentage greater than or equal to this number are considered as a potential thumbnail.<br /><strong>Examples</strong>: a square has a ratio of <code>1.00</code>; and a ratio of <code>0.25</code> means that either the width is four times larger than the height or the height is four times larger than the width.<br />The first image that meets all conditions is resized and inserted in the shortened text.<br><strong>Note:</strong> All images not passing the criteria set here are ignored and left alone. If you want all images but one to be removed from the shortened text, you can add <code>img</code> to the setting <code>Tags To Remove</code>."
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_WIDTH="Minimum Width"
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_WIDTH_DESCRIPTION="Enter a number. Only images which have a <strong>width</strong> in pixels greater than or equal to this number are considered as a potential thumbnail.<br />The first image that meets all conditions is resized and inserted in the shortened text.<br><strong>Note:</strong> All images not passing the criteria set below are ignored and left alone. If you want all images but one to be removed from the shortened text, you can add <code>img</code> to the setting <code>Tags To Remove</code>."
PLG_CONTENT_READLESSTEXT_MINIMUM_TEXT_LENGTH="Minimum Text Length"
PLG_CONTENT_READLESSTEXT_MINIMUM_TEXT_LENGTH_DESCRIPTION="Enter a number. That number is expressed in the unit as selected below in <code>Length Unit</code>. If the full length of the text in the selected unit is less than this number, this plugin will not shorten the text.<br/><strong>Note:</strong> Enter <code>0</code> to disable this restriction."
PLG_CONTENT_READLESSTEXT_MODULE_SCOPE="Within module scope"
PLG_CONTENT_READLESSTEXT_MODULE_SCOPE_DESCRIPTION="This option and the option above further restricts the usage of <em>read less text</em>. When a page is built, the output of one or more different modules can also contain artcile text. In some cases, these modules allow plugins like <em>read less text</em> to intervene, to enhance the output (technical: the <code>onContentBeforeDisplay</code> event is fired). An example is the standard Joomla! module <em>News Flash</em> (<code>mod_newsflash</code>). With this option you can choose if <em>read less text</em> must always be active on any module output, only active if the contexts below allow this, or never be active on any module output. If the first or the last choice is made, the options <code>Quick Configuration?</code>, <code>Allowed</code> and <code>Disallowed</code> below are ignored for module output."

PLG_CONTENT_READLESSTEXT_NOTES0="Notes"
PLG_CONTENT_READLESSTEXT_NOTES0_DESCRIPTION="This field is not used by <em>read less text</em>. You can use it to write down anything related to <em>read less text</em> and the use of contexts, e.g. why a specific context is added to one of the fields above - when reviewing the options again after several months, this can speed up the time needed to correctly reconfigure them."

PLG_CONTENT_READLESSTEXT_RESPECT_EXISTING_READMORE_LINK="Respect Position<br />Existing <em>Read More</em>"
PLG_CONTENT_READLESSTEXT_RESPECT_EXISTING_READMORE_LINK_DESCRIPTION="Choose what to do when an article already contains a manually inserted <em>Read More</em> link. <ul>You can choose to:<li><strong>Ignore it</strong>: select <code>No</code>.<br />The article will be shortened as if the <em>Read More</em> link was not present.</li><li><strong>Respect it</strong>: select <code>Yes</code>.<br />The text before the <em>Read More</em> link - the <em>intro text</em> - will be used as shortened text: the article will <em>not</em> be shortened using <br/>the length settings above, but at the position of the existing <em>Read More</em> link. The text will be considered shortened - this <br/>'property' is used when determining whether to add a thumbnail, prefix, inline suffix and suffix.</li><li><strong>Use it as an additional upper limit</strong>: select <code>Use it to respect 'Show Intro Text'</code>.<br />If you selected to hide the intro text when displaying an article in full under <code><a href='index.php?option=com_content'>Article Manager</a> &gt; Options &gt; Articles</code> by <br/>setting the option <code>Show Intro Text</code> to <code>Hide</code>, the shortening of the article will be based on the intro text <em>only</em>. <br/>The remainder of the article - the part after the read more token - will then never appear in the shortened text.<br />Normally, the option <code>Show Intro Text</code> will hide the intro text when displaying a single article on a page (provided <br/><em>read less text</em> is not allowed to run on that page). If you select this option, <em>read less text</em> uses the reverse meaning: <br/><em>only</em> the intro text will be considered on all pages where <em>read less text</em> is allowed to run.<br />The text will <em>not</em> be considered shortened if the full intro text is retained - but it will do so, should parts of the intro text be omitted.</li></ul><strong>Note:</strong> This choice does not affect other settings: e.g. the <em>Read More</em> text and styling as configured on this page are still applied, <br/>regardless of this setting.<br /><strong>Note:</strong> Searching for a thumbnail will always be done in the full article, regardless of this setting."
PLG_CONTENT_READLESSTEXT_RETAIN_WHOLE_WORDS="Whole words"
PLG_CONTENT_READLESSTEXT_RETAIN_WHOLE_WORDS_DESCRIPTION="Enable this to retain whole words only. The shortened text may become slightly smaller, to exclude the remainder characters of the word that would otherwise be cut in two. In any case, at least one word of the text will be retained.<br /><strong>Note:</strong> This option only has an effect when <code>character</code> is selected as <code>Length Unit</code>."

PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE="[tokens] To Remove"
PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_DESCRIPTION="Enter a list of <em>comma</em> separated words without [ ] markers, which must be removed in the text. <br /><strong>Note:</strong> When a token is removed due to this option, the article is considered to be shortened. According to the settings in the other sections, a thumbnail, a prefix, inline suffix and/or suffix may be added as a result."
PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_WITH_CONTENTS="[tokens] To Remove<br />With Contents"
PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION="Enter a list of <em>comma</em> separated words without [ ] markers, which must be removed in the text <strong>together with all the text that is present between the opening and the closing token</strong>.<br /><strong>Note:</strong> Self-closing tokens are not supported.<br /><strong>Note:</strong> When a token with its full contents is removed due to this option, the article is considered to be shortened. According to the settings in the other sections, a thumbnail, a prefix, inline suffix and/or suffix may be added as a result.<br /><strong>Example:</strong> If you use the extension plugin <em>EmbedChessboard</em>, you may have added something like <code>[pgn]chess moves[/pgn]</code> to your content article. You can get rid of it in the shortened article by listing <code>pgn</code> here."

PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE="&lt;tags&gt; To Remove"
PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_DESCRIPTION="Enter a list of <em>comma</em> separated HTML tags without &lt; &gt; markers, which must be removed in the text. Leave empty to retain all tags; enter <code>all</code> to remove all formatting.<br /><strong>Example:</strong> Enter <code>a, img</code>, so that links and images are only available when reading the full article.<br /><strong>Note:</strong> Even if <code>img</code> is added in this field, it is still possible to create and display the first valid image as thumbnail in the shortened article.<br /><strong>Note:</strong> The article is <em>not</em> considered to be shortened when a tag is removed due to this option."
PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_WITH_CONTENTS="&lt;tags&gt; To Remove<br />With Contents"
PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION="Enter a list of <em>comma</em> separated HTML tags without &lt; &gt; markers, which must be removed in the text <strong>together with all the html and plain text that is present between the opening and the closing tag</strong>.<br /><strong>Example:</strong> Enter the tag <code>table</code> to entirely remove all tables while displaying the cut-off article text. This is also handy to remove extra styling which you don't want applied in the shortened text.<br />A good choice seems <code>style, nav, menu, footer, script, head, form, noscript</code>.<br /><strong>Note:</strong> When a tag with its full contents is removed due to this option, the article is considered to be shortened. According to the settings in the other sections, a thumbnail, a prefix, inline suffix and/or suffix may be added as a result."
PLG_CONTENT_READLESSTEXT_THUMBNAIL_TITLE="Tooltip"
PLG_CONTENT_READLESSTEXT_THUMBNAIL_TITLE_DESCRIPTION="Select here what needs to be used for the thumbnail's title. The title of the thumbnail should be a small piece of text that will be displayed as a tooltip when the mouse is hovered over the image.<br /><strong>Note:</strong> It is not possible to display HTML formatted text in a tooltip. The text shown as tooltip will be unformatted, i.e. with all HTML tags removed."
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_COLOR="Border Color"
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_COLOR_DESCRIPTION="The color of the border around the moved and resized first image. You can enter a color here in any format CSS understands.<br /><strong>Note:</strong> Leave empty to restore the default value.<br /><strong>Note:</strong> Set <code>Border Width</code> to <code>-1</code> to not restyle the image in this respect."
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_STYLE="Border Style"
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_STYLE_DESCRIPTION="The style of the border around the moved and resized thumbnail. Choose <code>None</code> to not restyle the image in this respect."
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_WIDTH="Border Width"
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_WIDTH_DESCRIPTION="The width in pixels of the border around the moved and resized first image. Enter <code>-1</code> to not restyle the image in this respect."
PLG_CONTENT_READLESSTEXT_THUMB_CACHE_TIME="Cache Time"
PLG_CONTENT_READLESSTEXT_THUMB_CACHE_TIME_DESCRIPTION="Enter a number. This sets the caching time of any generated thumbnail to the given number, in seconds. You will still need to use the built-in functionality Joomla! provides to clear expired cached thumbnails (<code>Site &gt; Maintenance &gt; Purge Expired Cache</code>).<br /><strong>Note:</strong> Caching of thumbnails can not be disabled."
PLG_CONTENT_READLESSTEXT_THUMB_CLASS="Thumbnail Class"
PLG_CONTENT_READLESSTEXT_THUMB_CLASS_DESCRIPTION="Using the options above, some basic formatting can be applied. For full freedom and flexibility, you can also style the image with any CSS class.<br /><strong>Note:</strong> Choices made above prevail to the formatting that comes along the given CSS class."
PLG_CONTENT_READLESSTEXT_THUMB_HEIGHT="Thumbnail Height"
PLG_CONTENT_READLESSTEXT_THUMB_HEIGHT_DESCRIPTION="Enter a number. This will be the desired thumbnail height, expressed in pixels.<br />The first image that meets all conditions is resized while respecting the ratio of the original image, such that the thumbnail fits in the given width and height dimensions.<br /><strong>Note:</strong> Enter 0 to not impose a limit on the height."
PLG_CONTENT_READLESSTEXT_THUMB_MARGIN="Margin"
PLG_CONTENT_READLESSTEXT_THUMB_MARGIN_DESCRIPTION="<dl>The margin to set around the thumbnail. There are four ways to set the margin, and each way provides a different <br/>number of margins:<dt><strong>1 number</strong></dt><dd>The given margin is set all around the image.</dd><dt><strong>2 numbers</strong></dt><dd>The first number is used to set the margin above and below the image,<br />the second number is used to set the margin to the left and to the right of the image.</dd><dt><strong>3 numbers</strong></dt><dd>The first is used to set the margin above the image,<br />the second is used to the set the margin to the left and to the right of the image,<br />the third below the image.</dd><dt><strong>4 numbers</strong></dt><dd>The numbers are each used to set one margin of the image, going clockwise around the image, starting from above: <br/>above the image, to the right of, below and to the left of the image.</dd></dl><strong>Note:</strong> If no unit is given, the number is assumed to be expressed in pixels.<br /><strong>Note:</strong> Enter <code>-1</code> to not restyle the image in this respect.<br /><strong>Example:</strong> <code>6</code><br />sets a margin of 6 pixels all around the image.<br /><strong>Example:</strong> <code>0px 10px 10 0</code><br />seems suitable when the thumbnail is positioned in the upper left portion of the article, since there will be only a <br/>margin of 10 pixels below and to the right of the image.<br /><strong>Example:</strong> <code>4 4 1em</code><br />sets a margin of 4 pixels all around the image, except below, where a margin of 1 <em>em</em> is used."
PLG_CONTENT_READLESSTEXT_THUMB_PADDING="Padding"
PLG_CONTENT_READLESSTEXT_THUMB_PADDING_DESCRIPTION="The padding to set around the thumbnail.<br /><strong>Note:</strong> Enter <code>-1</code> to not restyle the image in this respect."
PLG_CONTENT_READLESSTEXT_THUMB_POSITION="Thumbnail Position"
PLG_CONTENT_READLESSTEXT_THUMB_POSITION_DESCRIPTION="The thumbnail will be placed on the given position, with the text flowing around the image."
PLG_CONTENT_READLESSTEXT_THUMB_WIDTH="Thumbnail Width"
PLG_CONTENT_READLESSTEXT_THUMB_WIDTH_DESCRIPTION="Enter a number. This will be the desired thumbnail width, expressed in pixels.<br />The first image that meets all conditions is resized while respecting the ratio of the original image, such that the thumbnail fits in the given width and height dimensions.<br /><strong>Note:</strong> Enter 0 to not impose a limit on the width."
PLG_CONTENT_READLESSTEXT_TRANSLATE_ADDITIONS="Enable Multi-language<br />support?"
PLG_CONTENT_READLESSTEXT_TRANSLATE_ADDITIONS_DESCRIPTION="Choose here whether multi-language support must be enabled. This means that all field values you can enter on this configuration page, and which can get displayed to your users, will automatically get translated to the language of your visitor.<ul>If you select <code>Yes</code> here, the affected fields are:<li><code>Prefix For Registered Users (and higher)</code></li><li><code>Prefix For Guests</code></li><li><code>Suffix For Registered Users (and higher)</code></li><li><code>Inline Suffix For Registered Users (and higher)</code></li><li><code>Suffix For Guests</code></li><li><code>Inline Suffix For Guests</code></li></ul> If this option is enabled, these fields <strong>must not</strong> contain the actual pre- or suffix text, but a placeholder, which <strong>must be</strong> written using  <em>only</em> capital letters and the underscore <code>_</code>. <strong>The full prefix or suffix including all HTML tags surrounding it must then be replaced with that placeholder word, and the entire field may only contain that one word.</strong> Examples of correct placeholders are <code>ABCDEFG</code>, <code>MY_PREFIX</code> or <code>MY_TO_BE_TRANSLATED_TEXT</code>.<br /><br />Then, you must use Joomla's language override feature to enter the proper translations <em>for each language your site supports</em>, and for each placeholder you entered for one of the affected fields. <ul>You can do that by going to <em>Extensions > Language Manager > Overrides</em>:<li>First select the language for which you want to add a new override using the dropdown box on the right,</li><li>then click <code>New</code>.</li><li>Use the placeholder as the value for <code>Language Constant</code>,</li><li>and for <code>Text</code> your translated, real pre- or suffix value, <em>together with all the HTML tags</em> that were originally present in the corresponding field on this configuration page. You can still provide all the available tokens, such as <code>{title}</code> and <code>{words}</code>.</li></ul><strong>Note:</strong> It is important to make the name long and distinctive enough to be unique among all translation strings on your entire site: if you decide to use a placeholder that is already in use on some other part of your site, that part will receive your new translation too.<br />As a trivial example: do not use <code>MOD_BREADCRUMBS_HERE</code> as a placeholder while configuring <em>read less text</em>."

PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX="Inline suffix For <br />Registered Users <br />(and higher)"
PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_DESCRIPTION="<strong>For registered users only.</strong> Enter here the text to add right after the last character of the article, before closing all tags. <br/>You can provide HTML code here.<ul>The following tokens are recognized and replaced for each article:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Note:</strong> The default suffix just appends three dots. To reload the default value, just clear the text field and save the configuration.<br/><strong>Note:</strong> If the option <code>Enable Multi-language support?</code> is enabled, all text, including the HTML code, must be replaced <br/>with a placeholder; a placeholder is <strong>one</strong> word that must be used to define the real prefix - per language - under the <br/><em>Language Manager</em>."
PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE="User inline suffix links to<br />full article"
PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="If this option is enabled the inline suffix (text or HTML) will be wrapped and given as a link: when clicked, the user is directed to the full article.<br />If this option is disabled, you will have to provide another means for the user to access the full article: by linking the title, by ensuring a thumbnail is generated, or by providing the desired HTML code yourself in the suffix. In the latter case, you can use the <code>{url}</code> token in combination with HTML tag <code>a</code>."
PLG_CONTENT_READLESSTEXT_USER_PREFIX="Prefix For Registered<br />Users (and higher)"
PLG_CONTENT_READLESSTEXT_USER_PREFIX_DESCRIPTION="<strong>For registered users only.</strong> Enter here the text to add before the article. <br/>You can provide HTML code here.<ul>The following tokens are recognized and replaced for each article:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><br /><strong>Note:</strong> Leave empty to not prepend the article.<br/><strong>Note:</strong> If the option <code>Enable Multi-language support?</code> is enabled, all text, including the HTML code, must be replaced <br/>with a placeholder; a placeholder is <strong>one</strong> word that must be used to define the real prefix - per language - under the <em>Language Manager</em>."
PLG_CONTENT_READLESSTEXT_USER_PREFIX_LINKS_TO_FULL_ARTICLE="User prefix links to<br />full article"
PLG_CONTENT_READLESSTEXT_USER_PREFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="If this option is enabled the prefix (text or HTML) will be wrapped and given as a link: when clicked, the user is directed to the full article.<br />If this option is disabled, you will have to provide another means for the user to access the full article: by linking the title, by ensuring a thumbnail is generated, or by providing the desired HTML code yourself in the suffix. In the latter case, you can use the <code>{url}</code> token in combination with HTML tag <code>a</code>."
PLG_CONTENT_READLESSTEXT_USER_SUFFIX="Suffix For <br />Registered Users <br />(and higher)"
PLG_CONTENT_READLESSTEXT_USER_SUFFIX_DESCRIPTION="<strong>For registered users only.</strong> Enter here the text to add after the article. This value replaces the default <em>Read More</em> text. <br/>You can provide HTML code here.<ul>The following tokens are recognized and replaced for each article:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Note:</strong> The default suffix mimics the standard <em>Read more</em> code Joomla! provides. To reload the default value, just clear <br/>the text field and save the configuration.<br/><strong>Note:</strong> If the option <code>Enable Multi-language support?</code> is enabled, all text, including the HTML code, must be replaced with <br/>a placeholder; a placeholder is <strong>one</strong> word that must be used to define the real prefix - per language - under the <br/><em>Language Manager</em>."
PLG_CONTENT_READLESSTEXT_USER_SUFFIX_LINKS_TO_FULL_ARTICLE="User suffix links to<br />full article"
PLG_CONTENT_READLESSTEXT_USER_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="If this option is enabled the suffix (text or HTML) will be wrapped and given as a link: when clicked, the user is directed to the full article.<br />If this option is disabled, you will have to provide another means for the user to access the full article: by linking the title, by ensuring a thumbnail is generated, or by providing the desired HTML code yourself in the suffix. In the latter case, you can use the <code>{url}</code> token in combination with HTML tag <code>a</code>. <br /><strong>Note:</strong> The default suffix mimics the standard <em>Read more</em> code Joomla! provides and already includes the <code>{url}</code> token in combination with the correct HTML tags: this option is best turned off in that case."

PLG_CONTENT_READLESSTEXT_WHEN="Quick Configuration?"
PLG_CONTENT_READLESSTEXT_WHEN_DESCRIPTION="Either use the quick configuration, which is assumed to suit most users, either decline it and use the full flexibility <em>read less text</em> offers."
PLG_CONTENT_READLESSTEXT_WRAPPER_CLASS="Wrapper Class"
PLG_CONTENT_READLESSTEXT_WRAPPER_CLASS_DESCRIPTION="Enter here one or more class names. These will be assigned to the selected wrapper tag."
PLG_CONTENT_READLESSTEXT_WRAPPER_TAG="Wrapper Tag"
PLG_CONTENT_READLESSTEXT_WRAPPER_TAG_DESCRIPTION="<br />Select the tag which must encapulate each shortened article. Using this tag and the corresponding <code>Wrapper Class</code> below, you have full flexibility in further enhancing the format of your articles.<br /><strong>Note:</strong> select <code>No</code> to disable this option.<br /><strong>Note:</strong> If a tag is selected, the article will be wrapped each time <em>read less text</em> may active."

; Option choices for
; - PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX,
; - PLG_CONTENT_READLESSTEXT_ADD_PREFIX,
; - PLG_CONTENT_READLESSTEXT_ADD_SUFFIX,
; - PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING and
; - PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL.
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE="Always when read less text may be active"
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_LONG_ENOUGH="Always when active and the article is long enough"
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_SHORTENED="Only when the article is shortened"
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_USE_ARTICLE_MANAGER_OPTION="Respect global option Show 'Read More'"

; Option choices for PLG_CONTENT_READLESSTEXT_COMPONENT_SCOPE
PLG_CONTENT_READLESSTEXT_SCOPE_ACCORDING_TO_CONTEXTS="Respecting options below"
PLG_CONTENT_READLESSTEXT_SCOPE_ALWAYS="Always, regardless options below"
PLG_CONTENT_READLESSTEXT_SCOPE_NEVER="Never, regardless options below"

; Option choices for
; - PLG_CONTENT_READLESSTEXT_CROP_HORIZONTAL_POSITION and/or
; - PLG_CONTENT_READLESSTEXT_CROP_VERTICAL_POSITION.
PLG_CONTENT_READLESSTEXT_CROP_BOTTOM="Retain the bottom, cut off the top"
PLG_CONTENT_READLESSTEXT_CROP_CENTER="Cut off evenly on both sides"
PLG_CONTENT_READLESSTEXT_CROP_FULL_HEIGHT="Do not crop. Retain the full height."
PLG_CONTENT_READLESSTEXT_CROP_FULL_WIDTH="Do not crop. Retain the full width."
PLG_CONTENT_READLESSTEXT_CROP_LEFT="Retain the left side, cut off on the right"
PLG_CONTENT_READLESSTEXT_CROP_RIGHT="Retain the right side, cut off on the left"
PLG_CONTENT_READLESSTEXT_CROP_TOP="Retain the top, cut off the bottom"

; Option choices for PLG_CONTENT_READLESSTEXT_LENGTH_UNIT
PLG_CONTENT_READLESSTEXT_CHAR="character"
PLG_CONTENT_READLESSTEXT_PARAGRAPH="paragraph"
PLG_CONTENT_READLESSTEXT_SENTENCE="sentence"
PLG_CONTENT_READLESSTEXT_WORD="word"

; Option choices for PLG_CONTENT_READLESSTEXT_RESPECT_EXISTING_READMORE_LINK
PLG_CONTENT_READLESSTEXT_RESPECT_SHOWINTRO="Use it to respect 'Show Intro Text'"

; Option choices for PLG_CONTENT_READLESSTEXT_THUMB_POSITION
PLG_CONTENT_READLESSTEXT_UPPER_LEFT="Upper Left"
PLG_CONTENT_READLESSTEXT_UPPER_RIGHT="Upper Right"

; Option choices for PLG_CONTENT_READLESSTEXT_THUMBNAIL_TITLE
PLG_CONTENT_READLESSTEXT_ARTICLE_TITLE_AS_THUMBNAIL_TITLE="Article title"
PLG_CONTENT_READLESSTEXT_INLINE_SUFFIX_AS_THUMBNAIL_TITLE="Article inline suffix"
PLG_CONTENT_READLESSTEXT_NO_THUMBNAIL_TITLE="None"
PLG_CONTENT_READLESSTEXT_PREFIX_AS_THUMBNAIL_TITLE="Article prefix"
PLG_CONTENT_READLESSTEXT_SUFFIX_AS_THUMBNAIL_TITLE="Article suffix"

; Option choices for PLG_CONTENT_READLESSTEXT_WHEN
PLG_CONTENT_READLESSTEXT_COMMON_USAGE="Yes, active on all content blog pages"
PLG_CONTENT_READLESSTEXT_SPECIFIC_USAGE="No, use the fields below"
PK��#]��T���Jcontent/readlesstext/language/nl-NL/nl-NL.plg_content_readlesstext.sys.ininu�[���; site language file for read less text
; Copyright Copyright (C) 2010-2013 parvus
; license GNU/GPL_GPLv3 http://www.gnu.org/copyleft/gpl.html
;
; This file is part of the Joomla! extension plugin read less text.
;
; read less text is free software: you can redistribute it and/or modify it
; under the terms of the GNU_General Public License as published by the Free
; Software Foundation, either version 3 of the License, or (at your option)
; any later version.
;
; read less text is distributed in the hope that it will be useful, but
; WITHOUT_ANY_WARRANTY; without even the implied warranty of MERCHANTABILITY
; or FITNESS_FOR_A PARTICULAR_PURPOSE.  See the GNU_General Public License for
; more details.
;
; You should have received a copy of the GNU_General Public License along with
; read less text. If not, see <http://www.gnu.org/licenses/>.
;
; @version $Id: nl-NL.plg_content_readlesstext.sys.ini 271 2014-11-25 19:55:07Z parvus $
PLG_CONTENT_READLESSTEXT_DESCRIPTION="<h2>v5.2 (r274)</h2><p><em>read less text</em> is een krachtiger alternatief voor de bestaande <em>Lees meer</em> functionaliteit. Automatisch afkorten, volledige controle over het selectief behoud van opmaak, en het automatisch aanmaken van het juiste pictogram die de begintekst in het oog doet springen; dit alles op precies die pagina's die u opgeeft. <em>read less text</em> maakt geen wijzigingen in de database en komt alleen tussenbeide bij de opbouw van de pagina: deïnstalleer de extensie of schakel hem uit om alle effecten ongedaan te maken.</p><p>De uitgebreide tooltips helpen u de uitgebreide instellingen naar uw hand te zetten om <a href='index.php?option=com_plugins&view=plugins&filter_search=read'><em>read less text</em></a> te laten integreren op uw site. Activeer de mode <em>Ontdekken</em> om de volledige flexibiliteit uit te buiten.</p><p>Deze versie laat de titels ongemoeid. Indien u ook te lange titels wil afkorten, specifieke informatie voor- of achteraan de titel wil toevoegen of het gebruik van hoofdletters wil onderdrukken, kan u terecht bij de afzonderlijke extensie <a href='http://extensions.joomla.org/extensions/style-a-design/titles/16619/'>read less title.</a></p>"
PK��#]܍4<��Fcontent/readlesstext/language/nl-NL/nl-NL.plg_content_readlesstext.ininu�[���; site language file for read less text
; Copyright Copyright (C) 2010-2014 parvus
; license GNU/GPL_GPLv3 http://www.gnu.org/copyleft/gpl.html
;
; This file is part of the Joomla! extension plugin read less text.
;
; read less text is free software: you can redistribute it and/or modify it
; under the terms of the GNU_General Public License as published by the Free
; Software Foundation, either version 3 of the License, or (at your option)
; any later version.
;
; read less text is distributed in the hope that it will be useful, but
; WITHOUT_ANY_WARRANTY; without even the implied warranty of MERCHANTABILITY
; or FITNESS_FOR_A PARTICULAR_PURPOSE.  See the GNU_General Public License for
; more details.
;
; You should have received a copy of the GNU_General Public License along with
; read less text. If not, see <http://www.gnu.org/licenses/>.
;
; @version $Id: nl-NL.plg_content_readlesstext.ini 213 2012-12-04 19:15:47Z parvus $

; Help
PLG_CONTENT_READLESSTEXT_DESCRIPTION="<h2>v5.2 (r274)</h2><p><em>read less text</em> is een krachtiger alternatief voor de bestaande <em>Lees meer</em> functionaliteit. Automatisch afkorten, volledige controle over het selectief behoud van opmaak, en het automatisch aanmaken van het juiste pictogram die de begintekst in het oog doet springen; dit alles op precies die pagina's die u opgeeft. <em>read less text</em> maakt geen wijzigingen in de artikel tabellen en komt alleen tussenbeide bij de opbouw van de pagina: deïnstalleer de extensie of schakel hem uit om alle effecten ongedaan te maken.</p><p><em>Het is ten zeerste aangeraden om de mode <code>Ontdekken</code> in te schakelen indien u een zeer specifieke configuratie wenst: hiermee kan u precies bepalen wanneer read less text tussenbeide mag komen. U kan deze mode in- en uitschakelen in de sectie <code>Wanneer Actief</code>.</em></p><p>Deze versie laat de titels ongemoeid. Indien u ook te lange titels wil afkorten, specifieke informatie voor- of achteraan de titel wil toevoegen of het gebruik van hoofdletters wil onderdrukken, kan u terecht bij de afzonderlijke extensie <a href='http://extensions.joomla.org/extensions/style-a-design/titles/16619/'>read less title.</a></p> <h2>Context - Snel</h2> <p>Een snelle configuratie kan u uit onderstaande tabel halen: <table><tr><th><code>Wanneer</code> &gt; <code>Actief</code></th> <th><em>alleen</em> actief op</th></tr> <tr><td><code>frontpage</code></td> <td>de voorpagina van deze site</td></tr> <tr><td><code>category</code></td> <td>alle artikel blog pagina's</td></tr> <tr><td><br /><code>category=12</code></td> <td>de blog pagina van<br />de categorie met id 12</td></tr> <tr><td><code>135</code></td> <td>Het artikel met id 135 <br /> op elke blog en artikel pagina</td></tr> </table></p> <ul><li>De meeste gebruikers zullen <em>read less text</em> willen activeren voor alle artikel blog pagina's. Zij kunnen kiezen voor de <code>Standaard Instelling</code>: de velden <code>Actief</code> en <code>Inactief</code> worden dan genegeerd.</li>  <li><em>read less text</em> kan niet geactiveerd worden op een lijst pagina - dit is een technische beperking.</li> <li><em>read less text</em> kan ook werkzaam zijn op <em>items</em> van andere componenten - dit hangt volledig af van de aard en implementatie van die component.</li></ul> <h2>Tokens</h2> <p><em>read less text</em> kan zowel vooraan als achteraan een opgegeven tekst toevoegen.</p> <p>Zowel de prefix als de suffix kunnen <em>tokens</em> bevatten. Een <em>token</em> is een speciaal codewoord, omringd door accolades. <ul>U kan de volgende codewoorden gebruiken: <li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul></p> <p>De opgegeven <em>tokens</em> worden telkens opnieuw vervangen voor elk artikel. Tokens die vervangen worden door een datum worden opgemaakt volgens de optie <code>Formaat Datums</code>. U kan de verschillende mogelijke codes and hun betekenis opzoeken in de PHP handleiding bij <a href='http://php.net/manual/en/function.date.php'>de functie <code>date</code></a>.</p> <h2>Context - Traag</h2> <p> <ul>U kan zeer precies aangeven voor welke pagina's deze plugin actief mag zijn en wanneer niet. U voegt hiervoor een zogenaamde <em>context</em> toe aan het veld <code>Actief</code> of <code>Inactief</code>. Een <em>context</em> is eenvoudigweg een combinatie van de naam van een component, de naam van een <em>view</em> en een artikel of <em>item</em> id, van elkaar gescheiden door een dubbele punt. <li>De component mag achterwege gelaten worden - in dat geval wordt verondersteld dat het over <code>com_content</code> gaat.</li> <li>De <em>view</em> mag achterwege gelaten worden - in dat geval wordt verondersteld dat elke <em>view</em> van de aangegeven component bedoeld wordt.</li> <li>Het artikel of <em>item</em> mag achterwege gelaten worden - in dat geval wordt verondersteld dat elk artikel of <em>item</em> op de aangegeven <em>view</em>s bedoeld wordt.</li> <li>Het laatste gedeelte, waar u een artikel id kan opgeven, bevat één speciaal codewoord: <code>all-in-&lt;n&gt;</code>, waarbij <code>&lt;n&gt;</code> vervangen dient te worden door het id van een categorie. Hiermee worden alle artikels in de opgegeven categorie <code>&lt;n&gt;</code> aangeduid.</li> </ul></p> <p>De bovenstaande tabel gaf al enkele eenvoudige voorbeelden. Een fijnere granulariteit is beschikbaar indien u deze nodig heeft.</p> <h2>Context - Ontdekken</h2> <p>Om te ontdekken of <em>read less text</em> actief kan zijn op een specifieke pagina, en hoe de configuratie dan gemaakt wordt, kan u de mode <code>Ontdekken</code> aanzetten. In deze mode zal <em>read less text</em> - waar mogelijk - de tekst van elk artikel of <em>item</em> vervangen door de informatie die u nodig heeft om de configuratie na te kijken en aan te passen naar uw wensen.</p> <p>De mode <code>Ontdekken</code> wordt alleen gebruikt voor gebruikers die zijn aangemeld en toegang hebben tot het back-end gedeelte van uw site. Deze optie kan u dus gerust activeren, zonder dat de bezoekers van uw site er iets van merken.</p> <h2>Contexts - Nog twee voorbeelden</h2> <p>Veronderstel de volgende configuratie:</p> <table><tr><th>Optie</th> <th>Waarde</th></tr> <tr><td><code>Standaard Instelling</code></td> <td><code>Nee, gebruik de velden hieronder</code></td></tr> <tr><td><code>Actief</code></td> <td><code>frontpage, category, com_eventlist:venues</code></td></tr> <tr><td><code>Inactief</code></td> <td><code>38, 245, 246, category=7, com_eventlist:venues:28</code></td></tr></table></p> <p> <ul>In dit geval zal <em>read less text</em>: <li>Nooit actief zijn voor de artikels met id 38, 245 and 246, ongeacht waar ze getoond worden.</li> <li>Niet actief zijn wanneer de artikels van de categorie 7 getoond worden in een blog pagina.</li> <li>Actief zijn voor alle andere artikels op alle andere blog pagina's, inclusief (alleen voor Joomla! 1.6) een categorie blog pagina binnen categorie 7.</li> <li>Actief zijn op de voorpagina, behalve voor de artikels met id 38, 245 en 246.</li> <li>Actief zijn op elke locatie lijst pagina's van EventList (<em>Categoryevents</em>), voor alle locaties behalve de locatie met id 28 </ul></p> <p>Veronderstel de volgende configuratie:</p> <table><tr><th>Optie</th> <th>Waarde</th></tr> <tr><td><code>Beperk Toegang Voor Gasten</code></td> <td><code>Ja</code></td></tr> <tr><td><code>Standaard Instelling</code></td> <td><code>Nee, gebruik de velden hieronder</code></td></tr> <tr><td><code>Actief</code></td> <td><code>blog, categories, category, featured</code></td></tr> <tr><td><code>Inactief</code></td> <td><code>all-in-7</code></td></tr></table></p> <p> <ul>In dit geval zal <em>read less text</em>:<li>Actief zijn op alle blog pagina's van <code>com_content</code> wanneer een gebruiker is aangemeld,</li> <li>altijd actief zijn voor alle artikels van <code>com_content</code> op alle pagina's wanneer een gebruiker <em>niet</em> is aangemeld (m.a.w. als een gast uw site bezoekt),</li> <li><em>behalve</em> voor de artikels die tot categorie <code>7</code> behoren, die <em>read less text</em> nooit zal proberen af te korten, ongeacht de pagina waar ze getoond worden.</li></ul></p> <hr/> <h2>Dank u wel!</h2> <ul>U kan uw eventuele waardering op verschillende manieren laten blijken: <li>Door <a href='http://joomlacode.org/gf/project/cutoff/tracker/?action=TrackerItemBrowse&tracker_id=9352'>fouten te rapporteren</a> of <a href='http://joomlacode.org/gf/project/cutoff/tracker/?action=TrackerItemBrowse&tracker_id=9351'>nieuwe functionaliteit aan te vragen</a>: zowel uw als mijn tijd zijn beperkt, en wat niet aangecraagd wordt, wordt waarschijnlijk ook niet opgelost of toegevoegd.</li><li>Door <a href='http://extensions.joomla.org/extensions/news-display/article-elements/articles-summary/12432'>een score te geven aan deze extensie</a> en een correcte gebruikerservaring toe te voegen: zowel de hoogte van de score en toon van de commentaren spelen in grote mate mee om nieuwe gebruikers te overtuigen deze extensie uit te proberen.</li><li>Door <a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=L9P4GMDWRKGUN'>een donatie over te maken (PayPal)</a>: elke gift is waardevol en wordt dankbaar aanvaard; het geeft een enorme motivatie!</li></ul>"

; Sections
COM_PLUGINS_FORMATTING_FIELDSET_LABEL="Opmaak"
COM_PLUGINS_INFO_FIELDSET_LABEL="Informatie"
COM_PLUGINS_LENGTH_FIELDSET_LABEL="Lengte"
COM_PLUGINS_PREFIX_FIELDSET_LABEL="Prefix"
COM_PLUGINS_SUFFIX_FIELDSET_LABEL="Lees Meer (Suffix)"
COM_PLUGINS_THUMBNAIL_FIELDSET_LABEL="Pictogram"
COM_PLUGINS_WHEN-ACTIVE_FIELDSET_LABEL="Wanneer Actief"

; Options
PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX="Voeg Aansluitende Suffix toe"
PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX_DESCRIPTION="Zelf gekozen tekst kan worden toegevoegd achter het (al dan niet) afgekorte artikel. De velden hieronder geven aan wat er toegevoegd moet worden <em>voordat</em> alle tags gesloten zijn. Dit betekent dat de tekst hieronder ingesteld tegen het laatste woord van het artikel wordt geplaatst, binnen dezelfde paragraaf, en met dezelfde opmaak.<br />Geef hier aan wanneer de hierna volgende opties toegepast mogen worden. <li>Kies <code>Nee</code> om de opties niet toe te passen.</li> <li>Kies <code>Altijd wanneer read less text actief mag zijn</code> om alle opties toe te passen wanneer de filters zoals ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten. De opties hieronder zullen dan worden toegepast, ongeacht de lengte van het artikel, en of het artikel nu afgekort wordt of niet.</li> <li><Kies <code>Respecteer de algemene optie 'Lees meer' Tonen</code> om alle opties toe te passen wanneer <em>read less text</em> actief mag zijn, én de voornoemde optie in <em>Artikelbeheer</em> dit toelaat.</li><li>Kies <code>Altijd wanneer actief en het artikel lang genoeg is</code> om alle opties hieronder toe te passen wanneer zowel de filters ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten; én het artikel werd afgekort, ofwel door de opties <code>Lengte Afgekorte Tekst</code> en <code>Behoud Positie Bestaande Lees Meer Link</code>, ofwel door het verwijderen van tags of tokens zoals ingesteld in de sectie <em>Opmaak</em>.</li></ul>"

PLG_CONTENT_READLESSTEXT_ADD_PREFIX="Voeg Prefix toe"
PLG_CONTENT_READLESSTEXT_ADD_PREFIX_DESCRIPTION="<ul>Geef hier aan wanneer alle opties hieronder in deze sectie toegepast mogen worden. <li>Kies <code>Nee</code> om de opties in deze <em>Voeg Prefix &amp; Suffix toe</em> sectie niet toe te passen.</li> <li>Kies <code>Altijd wanneer read less text actief mag zijn</code> om alle opties toe te passen wanneer de filters zoals ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten. De opties hieronder zullen dan worden toegepast, ongeacht de lengte van het artikel, en of het artikel nu afgekort wordt of niet.</li> <li>Kies <code>Altijd wanneer actief en het artikel lang genoeg is</code> om alle opties hieronder toe te passen wanneer zowel de filters ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten; én het artikel werd afgekort, ofwel door de opties <code>Lengte Afgekorte Tekst</code> en <code>Behoud Positie Bestaande Lees Meer Link</code>, ofwel door het verwijderen van tags of tokens zoals ingesteld in de sectie <em>Opmaak</em>.</li></ul>"

PLG_CONTENT_READLESSTEXT_ADD_SUFFIX="Voeg Lees Meer (Suffix) toe"
PLG_CONTENT_READLESSTEXT_ADD_SUFFIX_DESCRIPTION="<ul>Zelf gekozen tekst kan worden toegevoegd achter het (al dan niet) afgekorte artikel. De velden hieronder geven aan wat er toegevoegd moet worden <em>nadat</em> alle tags gesloten zijn. Dit betekent dat de tekst hieronder ingesteld onder het artikel wordt geplaatst, buiten de paragraaf.<br />Geef hier aan wanneer de hierna volgende opties toegepast mogen worden. <li>Kies <code>Nee</code> om de opties niet toe te passen.</li> <li>Kies <code>Altijd wanneer read less text actief mag zijn</code> om alle opties toe te passen wanneer de filters zoals ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten. De opties hieronder zullen dan worden toegepast, ongeacht de lengte van het artikel, en of het artikel nu afgekort wordt of niet.</li> <li><Kies <code>Respecteer de algemene optie 'Lees meer' Tonen</code> om alle opties toe te passen wanneer <em>read less text</em> actief mag zijn, én de voornoemde optie in <em>Artikelbeheer</em> dit toelaat.</li><li>Kies <code>Altijd wanneer actief en het artikel lang genoeg is</code> om alle opties hieronder toe te passen wanneer zowel de filters ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten; én het artikel werd afgekort, ofwel door de opties <code>Lengte Afgekorte Tekst</code> en <code>Behoud Positie Bestaande Lees Meer Link</code>, ofwel door het verwijderen van tags of tokens zoals ingesteld in de sectie <em>Opmaak</em>.</li></ul>"

PLG_CONTENT_READLESSTEXT_ALLOWED="Actief"
PLG_CONTENT_READLESSTEXT_ALLOWED_DESCRIPTION="Geef hier een lijst van <em>context</em>en, gescheiden door een <em>komma</em>. Kijk de uitleg hierlangs na voor een volledig overzicht. Indien dit veld niet leeg is, zal de plugin <em>alleen</em> actief zijn op artikels of <em>items</em> in de hier opgegeven contexten. Indien dit veld leeg is, wordt er geen beperking ingesteld. <strong>Met de mode <code>Ontdekken</code> actief, wordt de meest specifieke context voor elke artikel of <em>item</em> getoond.</strong>"

PLG_CONTENT_READLESSTEXT_ALWAYS_ACTIVE_FOR_GUESTS="Beperk Toegang<br />Voor Gasten"
PLG_CONTENT_READLESSTEXT_ALWAYS_ACTIVE_FOR_GUESTS_DESCRIPTION="Met deze instelling voorkomt u dat gasten de volledige tekst van het artikel of <em>Item</em> kunnen lezen: alleen bezoekers die zijn aangemeld krijgen de volledige tekst te zien. Indien deze optie actief is, wordt de optie <code>Actief</code> uitgebreid met <code>, com_content</code> indien een niet-aangemelde bezoeker een pagina opvraagt: <em>read less text</em> zal dan altijd actief zijn voor alle artikels in <code>com_content</code>, behalve voor de <em>context</em>en vermeld in <code>Inactief</code>.<br/><strong>Opmerking:</strong>Als de toegang beperkt wordt, kijk dan zeker ook de opties na die een link geven naar het volledige artikel: <code>Prefix Voor Gasten</code> onder <code>Prefix</code> en/of <code>Suffix Voor Gasten</code> onder <code>Lees Meer (Suffix)</code> - indien de bijhorende optie <code>Maak Link Van ...</code> is geactiveerd. Daar kan u er dan voor zorgen dat de gasten worden doorgestuurd naar een pagina waar ze kunnen aanmelden of zich kunnen inschrijven om het volledige artikel te lezen."

PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING="Verwijder niet gewenste<br /><em>tags</em> and <em>tokens</em>"
PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING_DESCRIPTION="<ul>Geef hier aan wanneer alle opties hieronder in deze sectie toegepast mogen worden. <li>Kies <code>Nee</code> om de opties in deze <em>Opmaak</em> sectie niet toe te passen.</li> <li>Kies <code>Altijd wanneer read less text actief mag zijn</code> om alle opties toe te passen wanneer de filters zoals ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten. De opties hieronder zullen dan worden toegepast, ongeacht de lengte van het artikel, en of het artikel nu afgekort wordt of niet.</li> <li>Kies <code>Altijd wanneer actief en het artikel lang genoeg is</code> om alle opties hieronder toe te passen wanneer zowel de filters ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten; én het artikel <em>lang genoeg</em> is, zoals bepaald door de opties <code>Minimum Lengte Tekst</code> en <code>Behoud Positie Bestaande Lees Meer Link</code>.</li></ul>"

PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SHORTEN_COUNT="Aantal af te korten artikels"
PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SHORTEN_COUNT_DESCRIPTION="Geef hier een getal in. <em>read less text</em> zal op elke webpagina alleen dit aantal artikels of <em>items</em> bekijken om af te korten, <em>na</em> het overslaan van het bovenstaande aantal artikels of items.<br />Geef hier <code>0</code> in om alle overblijvende artikels of items af te korten.<br/><strong>Opmerking:</strong> Zelfs wanneer an artikel niet overgeslagen mag worden, kan het gebeuren dat het artikel niet afgekort wordt. Dit indien het artikel of item niet lang genoeg is (kijk hiervoor de optie <code>Lengte</code> &gt; <code>Minimum Lengte Tekst</code> na) of door de <em>context</em> (kijk hiervoor de opties  <code>Standaard Instelling?</code>, <code>Actief</code> and <code>Inactief</code> hieronder na)."

PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SKIP_COUNT="Aantal over te slaan artikels"
PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SKIP_COUNT_DESCRIPTION="Geef hier een getal in. De eerste zoveel artikels of <em>Items</em> die op een pagina getoond gaan worden, zullen door <em>read less text</em> niet behandeld worden.<br/><strong>Opmerking:</strong> Zelfs als een artikel of <em>Item</em> niet overgeslagen mag worden, kan het zijn dat het artikel niet wordt afgekort: het kan zijn dat de tekst niet lang genmoeg is (zie hiervoor de optie <code>Lengte</code> &gt; <code>Minimum Lengte Tekst</code>), of dat de context hetr niet toeliet (zie hiervoor de opties <code>Standaard Instelling?</code>, <code>Actief</code> en <code>Inactief</code> hieronder).<br /><strong>Opmerking:</strong> Geef hier <code>0</code> in om geen artikels over te slaan."

PLG_CONTENT_READLESSTEXT_COMPONENT_SCOPE="In component scope"
PLG_CONTENT_READLESSTEXT_COMPONENT_SCOPE_DESCRIPTION="Met deze optie en de optie hieronder kan u het gebruik van <em>read less text</em> verder beperken. Tijdens de opbouw van een pagina kan een comnponent - niet alleen <code>com_content</code> - tekst van artikels tonen. In de meeste gevallen laat deze component ook de tussenkomst toe van <em>read less text</em> (technisch: het event <code>nContentBeforeDisplay</code> wordt gegenereerd). Voorbeelden zijn <em>Eventlist</em> (<code>com_eventlist</code>) en <em>FJ Related Articles Blog and List Component</em> (<code>com_fjrelated</code>).<br />Met deze optie kan u er voor kiezen of <em>read less text</em> de context regels moet volgen zoals hieronder ingesteld, of nooit actief mag zijn op de output van een conponent. Als de laatste keuze wordt gemaakt, worden de opties <code>Standaard Instelling?</code>, <code>Actief</code> en <code>Inactief</code> genegeerd voor alle output van elke component."

PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL="Genereer Pictogram"
PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL_DESCRIPTION="<ul><em>Read Less Text</em> kan in de tekst van het <em>volledige</em> artikel zoeken naar een afbeelding die voldoet aan alle opgelegde voorwaarden, deze herschalen en vooraan de afgekorte tekst als pictogram invoegen. <li>Kies <code>Nee</code> om de opties in deze <em>Genereer Pictogram</em> sectie niet toe te passen.</li> <li>Kies <code>Altijd wanneer read less text actief mag zijn</code> om alle opties toe te passen wanneer de filters zoals ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten. De opties hieronder zullen dan worden toegepast, ongeacht de lengte van het artikel, en of het artikel nu afgekort wordt of niet.</li> <li>Kies <code>Altijd wanneer actief en het artikel lang genoeg is</code> om alle opties hieronder toe te passen wanneer zowel de filters ingesteld in de sectie <em>Wanneer Actief</em> dit toelaten; én het artikel werd afgekort, ofwel door de opties <code>Minimum Lengte Tekst</code> en <code>Behoud Positie Bestaande Lees Meer Link</code>, ofwel door het verwijderen van tags of tokens zoals ingesteld in de sectie <em>Opmaak</em>.</li></ul><strong>Opmerking:</strong> Elke afbeelding die niet aan alle voorwaarden voldoet blijft in de tekst staan. Indien u in de afgekorte tekst geen enkele afbeelding wil zien behalve het uitgekozen pictogram, kan u <code>img</code> toevoegen aan de optie <code>Te Verwijderen Tags</code>."

PLG_CONTENT_READLESSTEXT_CROP_HORIZONTAL_POSITION="Horizontaal wegsnijden"
PLG_CONTENT_READLESSTEXT_CROP_HORIZONTAL_POSITION_DESCRIPTION="Geef hier aan welk gedeelte van de afbeelding mag weggesneden worden, indien na herschaling de afbeelding niet goed past in de opgegeven breedte van het pictogram. Door minimaal weg te snijden kan er voor gezorgd worden dat het pictogram precies de gewenste afmetingen heeft.<br /><strong>Opmerking:</strong> Indien wegsnijden uitgeschakeld wordt, kan het voorkomen dat de <em>hoogte van het pictogram kleiner</em> wordt dan de ingestelde waarde."

PLG_CONTENT_READLESSTEXT_CROP_VERTICAL_POSITION="Verticaal wegsnijden"
PLG_CONTENT_READLESSTEXT_CROP_VERTICAL_POSITION_DESCRIPTION="Geef hier aan welk gedeelte van de afbeelding mag weggesneden worden, indien na herschaling de afbeelding niet goed past in de opgegeven breedte van het pictogram. Door minimaal weg te snijden kan er voor gezorgd worden dat het pictogram precies de gewenste afmetingen heeft.<br /><strong>Opmerking:</strong> Indien wegsnijden uitgeschakeld wordt, kan het voorkomen dat de <em>breedte van het pictogram kleiner</em> wordt dan de ingestelde waarde."

PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_WITH_CONTENTS="Te Verwijderen {tokens}<br />Met Inhoud"
PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION="Geef hier een lijst van woorden zonder { } markeringen, gescheiden door een <strong>komma</strong>, die de plugin altijd moet verwijderen <strong>samen met alle tekst dat zich tussen de openende en sluitende token bevindt</strong>.<br /><strong>Opmerking:</strong> Op zichzelf staande tokens worden niet ondersteund.<br /><strong>Opmerking:</strong> Waneer een {token} hierdoor wordt verwijderd, wordt de tekst als afgekort beschouwd. Deze 'eigenschap' wordt gebruikt in de andere secties om te bepalen of een pictogram, prefix, inline suffix en/of suffix toegevoegd moet worden.<br /><strong>Voorbeeld:</strong> Voor de extensie <em>Tabs &amp; Slides</em> dient u een tekst gelijkaardig aan <code>{slide=mijntitel}zus en zo{/slide}</code> in te voegen in de tekst. U kan deze code verbergen in het afgekorte artikel door hier <code>slide</code> toe te voegen."

PLG_CONTENT_READLESSTEXT_CUT_OFF_TEXT_LENGTH="Lengte Afgekorte Tekst"
PLG_CONTENT_READLESSTEXT_CUT_OFF_TEXT_LENGTH_DESCRIPTION="Geef een getal in: dit getal is uitgedrukt in het aantal eenheden zoals ingesteld in de optie <code>Lengte Eenheid</code>. Wanneer het artikel wordt afgekort, worden het hier opgegeven aantal <em>eenheden</em> behouden. Dit getal mag groter of kleiner zijn dan het getal hierboven."

PLG_CONTENT_READLESSTEXT_DATE_FORMAT="Formaat Datums"
PLG_CONTENT_READLESSTEXT_DATE_FORMAT_DESCRIPTION="Geef hier het formaat op van elke datum die als pre- of suffix moet worden toegevoegd. Gebruik hiervoor de codes zoals beschreven bij de uitleg van de PHP functie <code>date</code>. (Een link vindt u in de uitleg hierlangs.)<br /><strong>Voorbeeld:</strong> <em>Maandag, 3 december</em> heeft als formaat <code>l, F j</code><br /><strong>Voorbeeld:</strong> <em>Din 06:28</em> heeft als formaat <code>D H:i</code><br /><strong>Voorbeeld:</strong> <em>2012-07-28</em> heeft als formaat <code>Y-m-d</code>"

PLG_CONTENT_READLESSTEXT_DEFAULT_THUMBNAIL_TEMPLATE="Standaard Pictogram"
PLG_CONTENT_READLESSTEXT_DEFAULT_THUMBNAIL_TEMPLATE_DESCRIPTION="Geef hier de locatie van het pictogram dat gebruikt moet worden indien er geen geschikte afbeelding werd gevonden in het artikel. Het opgegeven pad kan absoluut of relatief ten opzichte van de <em>root</em> van uw Joomla! installatie.<br /><em>Het standaard pictogram wordt herschaald en bijgehouden in de Joomla! cache door read less text, net als een afbeelding die in het artikel wordt gevonden. Alleen de minimum voorwaarden worden niet gecontroleerd.</em><br /><strong>Opmerking:</strong> Laat dit veld leeg om geen pictogram in te voegen indien er geen geschikte afbeelding werd gevonden in het artikel. <ul>Een aantal tags worden herkend en vervangen voor elk artikel:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Opmerking:</strong> Indien er - na het vervangen van de tags - op de opgegeven locatie geen bestand gevonden wordt, wordt geen pictogram ingevoegd."

PLG_CONTENT_READLESSTEXT_DISALLOWED="Inactief"
PLG_CONTENT_READLESSTEXT_DISALLOWED_DESCRIPTION="Geef hier een lijst van <em>context</em>en, gescheiden door een <em>komma</em>. Kijk de uitleg hierlangs na voor een volledig overzicht. Indien dit veld niet leeg is, zal de plugin <em>nooit</em> actief zijn op artikels of <em>items</em> in de opgegeven contexten. Indien dit veld leeg is, wordt er geen beperking ingesteld. <strong>Met de mode <code>Ontdekken</code> actief, wordt de meest specifieke context voor elke artikel of <em>item</em> getoond.</strong>"

PLG_CONTENT_READLESSTEXT_DISCOVER="<strong>Ontdekken</strong>"
PLG_CONTENT_READLESSTEXT_DISCOVER_DESCRIPTION="Indien deze mode actief is, wordt de tekst van elk artikel waar <em>read less text</em> actief <em>kan</em> zijn vervangen door alle informatie die u nodig heeft om de opties in deze sectie precies in te stellen of na te kijken. <strong>Alleen gebruikers die toegang hebben tot het back-end gedeelte van deze site zullen deze informatie te zien krijgen: gewone bezoekers blijven de artikels zien zoals voorheen.</strong> Met deze extra informatie kan u gemakkelijk uitzoeken of en waarom deze plugin actief is op elk artikel, en welke context hier van toepassing is. De gewenste contexten kan u invullen in de opties <code>Actief</code> en <code>Inactief</code>."

PLG_CONTENT_READLESSTEXT_EXTRA_SELF_CLOSING_TAGS="XHTML Afwijkende &lt;tags&gt;"
PLG_CONTENT_READLESSTEXT_EXTRA_SELF_CLOSING_TAGS_DESCRIPTION="Geef hier een lijst van HTML tags zonder &lt; &gt; markeringen, gescheiden door een <strong>komma</strong>, die de plugin moet beschouwen als een op zichzelf staande tag, waar geen bijhorende sluitende tag bij moet horen. Je kan hier bijvoorbeeld de HTML tag <code>p</code> opgeven, indien in de tekst de paragrafen niet (altijd) gesloten worden met <code>/p</code>; of de HTML tag <code>br</code>, indien dit in de HTML code niet altijd gevolgd wordt door het sluitende teken <code>/</code>. Deze plugin zou anders door behoud van opmaak te verzekeren extra witruimte genereren.<br /><strong>Een goede keuze lijkt <code>br, hr, img</code></strong>."

PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX="Aansluitende Suffix<br />Voor Gasten"
PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_DESCRIPTION="<strong>Alleen voor gasten.</strong> Geef hier de tekst in die toegevoegd moet worden na de afgekorte tekst, maar vooraleer de nog epenstaande tags gesloten zijn. U kan hier HTML code plaatsen.<ul>Een aantal tags worden herkend en vervangen voor elk artikel:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Opmerking:</strong> De standaard waarde imiteert de (Engelse) standaard <em>Lees meer</em> code waar Joomla! in voorziet. Als u het veld leeg maakt, wordt de standaard waarde terug ingesteld.<br /><strong>Opmerking:</strong> Indien u hier geen suffix wenst, maar ook niet de hele sectie wil uitschakelen, kan u hier een spatie opgeven.<br /><strong>Opmerking:</strong> Indien bij de optie <code>Schakel extra vertaalslag in</code> voor <em>Ja</em> is gekozen, moet hier een codewoord staan; de werkelijke suffix dient u dan in te geven bij <em>Taalbeheer</em>.<br /><strong>Opmerking:</strong> <code>url</code> zal <em>altijd</em> verwijzen naar de (SEO geoptimaliseerde) url waar het volledige artikel kan gelezen worden. Indien u de optie <code>Beperk Toegang Voor Gasten</code> in de sectie <code>Wanneer Actief</code> gebruikt, is het waarschijnlijk beter om dit token niet te gebruiken: gebruik in plaats daarvan de url van uw login pagina, e.g. <code>index.php?option=com_users&amp;view=login&amp;Itemid=102</code>"

PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE="Maak Link Van Aansluitende Suffix Voor Gasten"
PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="<strong>Alleen voor gasten.</strong> Kies <em>Ja</em> om automatisch de opgegeven suffix (tekst of HTML) om te vormen tot een link, die leidt naar het volledige artikel."

PLG_CONTENT_READLESSTEXT_GUEST_PREFIX="Prefix Voor Gasten"
PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_DESCRIPTION="<strong>Alleen voor gasten.</strong> Geef hier de tekst in die voor elke tekst toegevoegd moet worden, of hij nu afgekort wordt of niet. U kan hier HTML code plaatsen.<ul>Een aantal tags worden herkend en vervangen voor elk artikel:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Opmerking:</strong> Laat dit veld leeg om vooraan niets toe te voegen.<br /><strong>Opmerking:</strong> Indien bij de optie <code>Schakel extra vertaalslag in</code> voor <em>Ja</em> is gekozen, moet hier een codewoord staan; de werkelijke prefix dient u dan in te geven bij <em>Taalbeheer</em>.<br /><strong>Opmerking:</strong> <code>url</code> zal <em>altijd</em> verwijzen naar de (SEO geoptimaliseerde) url waar het volledige artikel kan gelezen worden. Indien u de optie <code>Beperk Toegang Voor Gasten</code> in de sectie <code>Wanneer Actief</code> gebruikt, is het waarschijnlijk beter om dit token niet te gebruiken: gebruik in plaats daarvan de url van uw login pagina, e.g. <code>index.php?option=com_users&amp;view=login&amp;Itemid=102</code>"

PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_LINKS_TO_FULL_ARTICLE="Maak Link Van Prefix<br />Voor Gasten"
PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="<strong>Alleen voor gasten.</strong> Kies <em>Ja</em> om automatisch de opgegeven prefix (tekst of HTML) om te vormen tot een link, die leidt naar het volledige artikel. Indien u hier <em>Nee</em> kiest, dient u er zelf voor te zorgen dat de gebruiker op een andere manier het volledige artikel kan bereiken: door de titel als link te gebruiken, of door er voor te zorgen dat er altijd een pictogram gegenereerd wordt, of door zelf de HTML code te voorzien in de suffix. In het laatste geval kan u de token <code>{url}</code> gebruiken in combinatie met de HTML tag <code>a</code>."

PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX="Suffix Voor Gasten"
PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_DESCRIPTION="<strong>Alleen voor gasten.</strong> Geef hier de tekst in die na elke <em>afgekorte</em> tekst toegevoegd moet worden. Deze waarde vervangt de standaard <em>Lees Meer</em> aanduiding. U kan hier HTML code plaatsen.<ul>Een aantal tags worden herkend en vervangen voor elk artikel:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Opmerking:</strong> De standaard waarde imiteert de (Engelse) standaard <em>Lees meer</em> code waar Joomla! in voorziet. Als u het veld leeg maakt, wordt de standaard waarde terug ingesteld.<br /><strong>Opmerking:</strong> Indien u hier geen suffix wenst, maar ook niet de hele sectie wil uitschakelen, kan u hier een spatie opgeven.<br /><strong>Opmerking:</strong> Indien bij de optie <code>Schakel extra vertaalslag in</code> voor <em>Ja</em> is gekozen, moet hier een codewoord staan; de werkelijke suffix dient u dan in te geven bij <em>Taalbeheer</em>.<br /><strong>Opmerking:</strong> <code>url</code> zal <em>altijd</em> verwijzen naar de (SEO geoptimaliseerde) url waar het volledige artikel kan gelezen worden. Indien u de optie <code>Beperk Toegang Voor Gasten</code> in de sectie <code>Wanneer Actief</code> gebruikt, is het waarschijnlijk beter om dit token niet te gebruiken: gebruik in plaats daarvan de url van uw login pagina, e.g. <code>index.php?option=com_users&amp;view=login&amp;Itemid=102</code>"

PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_LINKS_TO_FULL_ARTICLE="Maak Link Van Suffix<br />Voor Gasten"
PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="<strong>Alleen voor gasten.</strong> Kies <em>Ja</em> om automatisch de opgegeven suffix (tekst of HTML) om te vormen tot een link, die leidt naar het volledige artikel. Indien u hier <em>Nee</em> kiest, dient u er zelf voor te zorgen dat de gebruiker op een andere manier het volledige artikel kan bereiken: door de titel als link te gebruiken, of door er voor te zorgen dat er altijd een pictogram gegenereerd wordt, of door zelf de HTML code te voorzien in de suffix. In het laatste geval kan u de token <code>{url}</code> gebruiken in combinatie met de HTML tag <code>a</code>.<br /><strong>Opmerking:</strong> De standaard waarde imiteert de (Engelse) standaard <em>Lees meer</em> code waar Joomla! in voorziet, en deze bevat al de juiste HTML code om een link naar het volledige artikel weer te geven. In dat geval kan u deze optie best uitschakelen."

PLG_CONTENT_READLESSTEXT_INLINE_SUFFIX_AS_THUMBNAIL_TITLE="Artikel inline suffix"

PLG_CONTENT_READLESSTEXT_LENGTH_UNIT="Lengte Eenheid"
PLG_CONTENT_READLESSTEXT_LENGTH_UNIT_DESCRIPTION="Kies hier de eenheid waarin de twee getallen hierboven - zowel <code>Minimum Lengte Tekst</code> and <code>Lengte Afgekorte Tekst</code> - zijn uitgedrukt.<ul>Opmerkingen en beperkingen:<li>Een spatie of een tab wordt ook geteld als een <code>karakter</code>, maar opeenvolgende witruimte wordt samengenomen en geteld als één karakter.</li><li>Tussen twee <code>woorden</code> in eenzelfde paragraaf moet er witruimte zijn, om ze ook als twee woorden te kunnen herkennen. Twee woorden met daartussen alleen een punt . (zoals bijvoorbeeld <em>hier.daar</em>) worden als één woord geteld.</li><li>Twee <code>zinnen</code> worden als zodanig herkend wanneer ze gescheiden worden door een van de volgende leestekens: <code>. ? ! ¿</code>, of door een paragraaf-einde, het einde van een rij in een tabel, of het einde van een item in een opsommingslijst. Opeenvolgende leestekens of code die een zin beëindigen (Bijvoorbeeld <code>Wat?!?!!</code>) worden samengenomen en geteld als één zinseinde. Twee zinnen zonder witruimte daartussen (bijvoorbeeld <em>Doe dit.Doe dat</em>) worden als twee zinnen geteld.<br /><em>Indien uw artikels veel afkortingen of versienummers bevatten (bijvoorbeeld <code>R.E.M.</code> en <code>Joomla! 2.5.99</code>), geeft de optie <code>zin</code> waarschijnlijk geen goed resultaat.</em></li><li>De HTML tag <code>p</code> wordt herkend als het einde van een <code>paragraaf</code> (HTML code: <code>&lt;/p&gt;</code>); ook het einde van een opsommingslijst verhoogt de paragraaf-teller. Titels gemarkeerd met tags als <code>h1</code>, <code>h2</code>, enz. worden niet geteld als een paragraaf. Lege paragrafen worden niet meegeteld.</li></ul>"

PLG_CONTENT_READLESSTEXT_LINK_THUMBNAIL="Maak Link"
PLG_CONTENT_READLESSTEXT_LINK_THUMBNAIL_DESCRIPTION="Kies <code>Ja</code> om een link te maken van het pictogram: de gebruiker kan dan met een klik op het pictogram het volledige artikel zien."

PLG_CONTENT_READLESSTEXT_MAX_IMAGE_LOAD_TIME="Maximale laadtijd"
PLG_CONTENT_READLESSTEXT_MAX_IMAGE_LOAD_TIME_DESCRIPTION="Geef hier een getal in. Dit is de maximale laadtijd in seconden die gespendeerd mag worden door <em>read less text</em> bij het aanmaken van een pictogram van een afbeelding die op een andere server staat.<br />Een lange laadtijd kan optreden wanneer de andere server (tijdelijk) slecht toegankelijk is. In dit geval kan de laadtijd van uw eigen pagina's verbeterd worden door hier een lage waarde in te geven, bijvoorbeeld <code>2</code>. <br /><strong>Opmerking:</strong> Geef hier <code>0</code> in om de maximale waarde te gebruiken dat <em>read less text</em> bereid is te wachten - de huidige waarde is <code>11</code> seconden."
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_HEIGHT="Minimum Hoogte"
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_HEIGHT_DESCRIPTION="Geef een getal in. Alleen afbeeldingen waarvan de <strong>hoogte</strong> in pixels gelijk is aan of groter is dan dit getal komen in aanmerking om als pictogram gebruikt te worden.<br />De eerste afbeelding die aan alle hieronder opgelegde voorwaarden voldoet wordt herschaald en vooraan de afgekorte tekst ingevoegd.<br><strong>Opmerking:</strong> Elke afbeelding die niet aan alle voorwaarden voldoet blijft in de tekst staan. Indien u in de afgekorte tekst geen enkele afbeelding wil zien behalve het uitgekozen pictogram, kan u <code>img</code> toevoegen aan de optie <code>Te Verwijderen Tags</code>."
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_RATIO="Minimum Verhouding"
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_RATIO_DESCRIPTION="Geef een kommagetal tussen 0 en 1 in (met een punt als scheidingsteken). Alleen afbeeldingen waarvan de <strong>verhouding</strong> in procent gelijk is aan of groter is dan dit getal komen in aanmerking om als pictogram gebruikt te worden.<br /><strong>Voorbeelden</strong>: een vierkant heeft een verhouding gelijk aan <code>1.00</code>; en de verhouding <code>0.25</code> geeft aan dat de afbeelding ofwel vier keer zo hoog is als breed, ofwel vier keer zo breed is dan hoog.<br />De eerste afbeelding die aan alle hier opgelegde voorwaarden voldoet wordt herschaald en vooraan de afgekorte tekst ingevoegd.<br><strong>Opmerking:</strong> Elke afbeelding die niet aan alle voorwaarden voldoet blijft in de tekst staan. Indien u in de afgekorte tekst geen enkele afbeelding wil zien behalve het uitgekozen pictogram, kan u <code>img</code> toevoegen aan de optie <code>Te Verwijderen Tags</code>."
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_WIDTH="Minimum Breedte"
PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_WIDTH_DESCRIPTION="Geef een getal in. Alleen afbeeldingen waarvan de <strong>breedte</strong> in pixels gelijk is aan of groter is dan dit getal komen in aanmerking om als pictogram gebruikt te worden.<br />De eerste afbeelding die aan alle hier opgelegde voorwaarden voldoet wordt herschaald en vooraan de afgekorte tekst ingevoegd.<br><strong>Opmerking:</strong> Elke afbeelding die niet aan alle voorwaarden voldoet blijft in de tekst staan. Indien u in de afgekorte tekst geen enkele afbeelding wil zien behalve het uitgekozen pictogram, kan u <code>img</code> toevoegen aan de optie <code>Te Verwijderen Tags</code>."
PLG_CONTENT_READLESSTEXT_MINIMUM_TEXT_LENGTH="Minimum Lengte Tekst"
PLG_CONTENT_READLESSTEXT_MINIMUM_TEXT_LENGTH_DESCRIPTION="Geef hier een lengte op, uitgedrukt in de eenheid zoals gekozen in de optie <code>Lengte Eenheid</code>. Indien de tekst in de opgegeven eenheid langer is dan dit getal, zal de plugin actief zijn en het artikel afkorten. Indien niet, zal de plugin geen enkele aanpassing aan het artikel maken. <br /><strong>Opmerking:</strong> Geef hier 0 in om deze beperking uit te schakelen."
PLG_CONTENT_READLESSTEXT_MODULE_SCOPE="In module scope"
PLG_CONTENT_READLESSTEXT_MODULE_SCOPE_DESCRIPTION="Met deze optie en de optie hierboven kan u het gebruik van <em>read less text</em> verder beperken. Tijdens de opbouw van een pagina kunnen modules tekst van artikels tonen. In een aantal gevallen laat een module ook de tussenkomst toe van <em>read less text</em> (technisch: het event <code>nContentBeforeDisplay</code> wordt gegenereerd). Een voorbeeld is de standard Joomla! module <em>News Flash</em> (<code>mod_newsflash</code>)<br /><ul>Met deze optie kan u er voor kiezen of <em>read less text</em>, op de output van een module,<li>altijd actief moet zijn op de output van een module</li><li>de context regels moet volgen zoals hieronder ingesteld, of</li><li>nooit actief mag zijn op de output van een module</li></ul>. Als de laatste keuze wordt gemaakt, worden de opties <code>Standaard Instelling?</code>, <code>Actief</code> en <code>Inactief</code> genegeerd voor alle output van elke component."

PLG_CONTENT_READLESSTEXT_NOTES0="Notities"
PLG_CONTENT_READLESSTEXT_NOTES0_DESCRIPTION="Dit veld wordt niet gebruikt door <em>read less text</em>. U kan dit veld gebruiken om eender welke informatie te bewaren dat gerelateerd is aan <em>read less text</em> en het specifiek gebruik van bovenstaande contexten, bijvoorbeeld de reden(en) waarom een context werd toegevoegd - indien u na verloop van tijd bovenstaande velden wilt bewerken, kan dit er voor zorgen dat u gemakkelijker en sneller de wijzigingen kunt aanbrengen."
PLG_CONTENT_READLESSTEXT_NO_THUMBNAIL_TITLE="Geen"

PLG_CONTENT_READLESSTEXT_PARAGRAPH="paragraaf"
PLG_CONTENT_READLESSTEXT_PREFIX_AS_THUMBNAIL_TITLE="Artikel prefix"

PLG_CONTENT_READLESSTEXT_RESPECT_EXISTING_READMORE_LINK="Behoud Positie Bestaande<br/><em>Lees Meer</em> Link"
PLG_CONTENT_READLESSTEXT_RESPECT_EXISTING_READMORE_LINK_DESCRIPTION="Duid het gewenste gedrag aan indien een tekst reeds een bestaande <em>Lees Meer</em> link bevat, die werd toegevoegd met behulp van de standaard <em>Lees Meer</em> knop. <ul>U kan er voor kiezen: <li><strong>om deze in zijn geheel te negeren</strong>: kies dan <code>Nee</code>.<br />De tekst wordt dan afgekort net alsof er nog geen <em>Lees Meer</em> link was ingevoegd.</li><li><strong>om deze in zijn geheel te respecteren</strong>: kies dan <code>Ja</code>.<br />De tekst vóór de <em>Lees Meer</em> link - de <em>intro tekst</em> wordt dan als afgekorte tekst genomen. De opties hierboven worden dan genegeerd; alle andere opties blijven wel nog geldig. De intro tekst wordt als 'afgekort' beschouwd. - deze 'eigenschap' wordt gebruikt om te bepalen of er een pictogram, prefix, inline suffix of suffix toegevoegd moet worden.</li><li><strong>om het te gebruiken als een bijkomende limiet op de te gebruiken tekst</strong>: kies dan <code>Gedeeltelijk</code>.<br />Er wordt dan geen tekst weergegeven in de afgekorte tekst dat ná het bestaande <em>Lees Meer</em> link staat. Indien de introtekst langer is dan de hierboven opgegeven criteria, wordt de introtekst afgekort; anders wordt de volledige introtekst behouden. <br />De optie <code>Toon Intro Tekst</code> wordt normaal gebruikt om de intro tekst te verbergen wanneer één enkel artikel wordt getoond op een pagina (en indien <em>read less text</em> niet actief is op die pagina). Met deze derde optie past <em>read less text</em> dit ook omgelkeerd toe: <em>alleen</em> de intro tekst wordt dan weerhouden op alle pagina's waar <em>read less text</em> actief mag zijn.<br />De tekst wordt <em>niet</em> als afgekort beschouwd <em>indien</em> if de volledige intro tekst getoond wordt.</li></ul><strong>Opmerking:</strong> deze instelling beïnvloedt andere instellingen niet: bijvooorbeeld de <em>Lees Meer</em> tekst zoals onder ingesteld wordt nog altijd gebruikt.<br /><strong>Opmerking:</strong> Bij het zoeken naar een geschikt pictogram wortdt altijd het volledige artikel gebruikt, ongeacht de waarde van deze instelling."
PLG_CONTENT_READLESSTEXT_RESPECT_SHOWINTRO="Alleen in combinatie met <code>Toon Intro</code>"
PLG_CONTENT_READLESSTEXT_RETAIN_WHOLE_WORDS="Hele Woorden"
PLG_CONTENT_READLESSTEXT_RETAIN_WHOLE_WORDS_DESCRIPTION="Kies <em>Ja</em> om alleen af te breken tussen twee woorden in. De afgekorte tekst kan dan lichtjes korter worden. In elk geval wordt altijd minstens 1 woord weerhouden.<br /><strong>Opmerking:</strong> Deze optie heeft alleen een effect indien <code>karakter</code> als <code>Lengte Eenheid</code> is gekozen."

PLG_CONTENT_READLESSTEXT_SCOPE_ACCORDING_TO_CONTEXTS="Volgens de opties hieronder"
PLG_CONTENT_READLESSTEXT_SCOPE_ALWAYS="Altijd, ongeacht de opties hieronder"
PLG_CONTENT_READLESSTEXT_SCOPE_NEVER="Nooit, ongeacht de opties hieronder"
PLG_CONTENT_READLESSTEXT_SENTENCE="zin"
PLG_CONTENT_READLESSTEXT_SPECIFIC_USAGE="Nee, gebruik de velden hieronder"
PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_WITH_CONTENTS="Te Verwijderen [tokens]<br />Met Inhoud"
PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION="Geef hier een lijst van woorden zonder [ ] markeringen, gescheiden door een <strong>komma</strong>, die de plugin altijd moet verwijderen <strong>samen met alle tekst dat zich tussen de openende en sluitende token bevindt</strong>.<br /><strong>Opmerkingen:</strong> Op zichzelf staande tokens worden niet ondersteund.<br /><strong>Opmerking:</strong> Waneer een {token} hierdoor wordt verwijderd, wordt de tekst als afgekort beschouwd. Deze 'eigenschap' wordt gebruikt in de andere secties om te bepalen of een pictogram, prefix, inline suffix en/of suffix toegevoegd moet worden.<br /><strong>Voorbeeld:</strong> Voor de extensie <em>EmbedChessboard</em> dient u een tekst gelijkaardig aan <code>[pgn]schaakzetten[/pgn]</code> in te voegen in de tekst. U kan deze code verbergen in het afgekorte artikel door hier <code>pgn</code> toe te voegen."
PLG_CONTENT_READLESSTEXT_SUFFIX_AS_THUMBNAIL_TITLE="Artikel suffix"

PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE="Te Verwijderen &lt;tags&gt;"
PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_DESCRIPTION="Geef hier een lijst van HTML tags zonder &lt; &gt; markeringen, gescheiden door een <strong>komma</strong>, die de plugin altijd moet verwijderen. Je kan hier bijvoorbeeld <code>a, img</code> inpgeven, zodat links en foto's alleen beschikbaar zijn indien het volledige artikel wordt geladen. Laat dit veld leeg om geen tags te verwijderen; geef hier <code>all</code> in om alle tags en dus ook opmaak te verwijderen.<br /><strong>Opmerking:</strong> Zelfs met <code>img</code> hier toegevoegd, is het mogelijk om de eerste foto of tekening te gebruiken als pictogram in het afgekorte artikel.<br /><strong>Opmerking:</strong> De tekst wordt <em>niet</em> beschouwd als afgekort wanneer door het verwijderen van een een tag door deze optie."
PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_WITH_CONTENTS="Te Verwijderen &lt;tags&gt;<br />Met Inhoud"
PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION="Geef hier een lijst van HTML tags zonder &lt; &gt; markeringen, gescheiden door een <strong>komma</strong>, die de plugin altijd moet verwijderen <strong>samen met alle HTML tags en tekst dat zich tussen de openende en sluitende tag bevindt</strong>. U kan hier bijvoorbeeld de HTML tag <code>table</code> opgeven, indien u in de afgekorte tekst geen tabellen wil tonen. Deze optie kan u ook gebruiken om extra opmaak regels te verwijderen in de afgekorte tekst waardoor uw pagina uniformer wordt.<br /><strong>Een goede keuze lijkt <code>style, nav, menu, footer, script, head, form, noscript</code></strong>.<br /><strong>Opmerking:</strong> Waneer een {token} hierdoor wordt verwijderd, wordt de tekst als afgekort beschouwd. Deze 'eigenschap' wordt gebruikt in de andere secties om te bepalen of een pictogram, prefix, inline suffix en/of suffix toegevoegd moet worden."
PLG_CONTENT_READLESSTEXT_THUMBNAIL_TITLE="Tooltip"
PLG_CONTENT_READLESSTEXT_THUMBNAIL_TITLE_DESCRIPTION="kies hier welke tekst gekozen moet worden als titel van het pictogram. Deze test zal worden gebruikt als tooltip wanneer de gebruiker met mus over het pictogram beweegd.<br /><strong>Opmerking:</strong> Het is niet mogelijk om opmaak toe te voegen in een tooltip. De tekst zal daartom getoond worden zonder de HTML tags die eventueel vorokomen in de geselecteerde tekst."
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_COLOR="Randkleur"
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_COLOR_DESCRIPTION="De kleur van de rand rondom de verplaatste en herschaalde afbeelding. U kan hier een kleur opgeven in elk formaat dat CSS begrijpt. <br /><strong>Opmerking:</strong> Laat dit veld leeg om hiervoor geen specifieke opmaak toe te voegen.<br /><strong>Opmerking:</strong> Geef <code>-1</code> in bij <code>Randbreedte</code> om hiervoor geen specifieke opmaak toe te voegen."
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_STYLE="Randstijl"
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_STYLE_DESCRIPTION="Deze keuze bepaalt het type van de rand rondom het pictogram. Kies <code>None</code> om hiervoor geen specifieke opmaak toe te voegen."
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_WIDTH="Randbreedte"
PLG_CONTENT_READLESSTEXT_THUMB_BORDER_WIDTH_DESCRIPTION="De dikte in aantal pixels van de rand rondom het pictogram.<br /><strong>Opmerking:</strong> Geef hier <code>-1</code> in om hiervoor geen specifieke opmaak toe te voegen."
PLG_CONTENT_READLESSTEXT_THUMB_CACHE_TIME="Cache Tijd"
PLG_CONTENT_READLESSTEXT_THUMB_CACHE_TIME_DESCRIPTION="Geef een getal in. Dit bepaalt hoelang elke aangemaakte pictogram geldig blijft, uitgedrukt in seconden. Gebruik de standaard Joomla! functionaliteit om de verlopen cache te verwijderen <code>Site &gt; Maintenance &gt; Purge Expired Cache</code>).<br /><strong>Opmerking:</strong> Deze cache kan niet uitgeschakeld worden."
PLG_CONTENT_READLESSTEXT_THUMB_CLASS="Class"
PLG_CONTENT_READLESSTEXT_THUMB_CLASS_DESCRIPTION="Voor een precieze en volledige opmaak van het pictogram, kan u hier de naam van een <em>CSS class</em> opgeven.<br /><strong>Opmerking:</strong> de andere keuzes die hierboven werden gemaakt krijgen voorrang op opmaak die aan de opgegeven <em>CSS class</em> gekoppeld wordt."
PLG_CONTENT_READLESSTEXT_THUMB_HEIGHT="Pictogram Hoogte"
PLG_CONTENT_READLESSTEXT_THUMB_HEIGHT_DESCRIPTION="Geef een getal in. Dit wordt de gewenste hoogte van het pictogram, uitgedrukt in pixels. De afbeelding die voldoet aan alle voorwaarden wordt herschaald tot zowel hoogte als breedte passen in de opgegeven dimensies. <br /><strong>Opmerking:</strong> Geef hier 0 in indien u geen beperking in de hoogte wenst. De verhouding van hoogte en breedte van de originele afbeelding blijft in elk geval behouden."
PLG_CONTENT_READLESSTEXT_THUMB_MARGIN="Marge"
PLG_CONTENT_READLESSTEXT_THUMB_MARGIN_DESCRIPTION="<dl>De in te stellen witruimte rondom het pictogram. U kan op 4 verschillende manieren de witruimte bepalen, door telkens een verschillend aantal getallen in te geven:<dt><strong>1 getal</strong></dt><dd>Deze waarde wordt gebruikt rondom het hele pictogram.</dd><dt><strong>2 getallen</strong></dt><dd>De eerste waarde wordt gebruikt om de witruimte in te stellen boven- en onderaan het pictogram,<br />de tweede waarde stelt de witruimte in aan de linker- en rechterkant.</dd><dt><strong>3 getallen</strong></dt><dd>De eerste waarde bepaalt de witruimte boven het pictogram,<br />de tweede waarde wordt gebruikt aan de linker- en rechterkant,<br />de derde waarde onderaan het pictogram.</dd><dt><strong>4 getallen</strong></dt><dd>Elk getal wordt gebruikt voor één zijde, waarbij kloksgewijs rond het pictogram wordt gegaan, bovenaan te beginnen: bovenkant, rechterkant, onderkant, linkerkant.</dd></dl><strong>Opmerking:</strong> Indien er geen eenheid is opgegeven, wordt verondersteld dat de waarden in pixels zijn uitgedrukt.<br /><strong>Opmerking:</strong> Geef hier <code>-1</code> in om hiervoor geen specifieke opmaak toe te voegen.<br /><strong>Opmerking:</strong> Laat dit veld leeg om geen expliciete keuze te maken (zodat de opgegeven CSS class de opmaak bepaalt).<br /><strong>Voorbeeld:</strong> <code>6</code><br />zorgt voor een witruimte van 6 pixels rondom het pictogram.<br /><strong>Voorbeeld:</strong> <code>0px 10px 10 0</code><br />lijkt goed geschikt wanneer het pictogram bovenaan links wordt geplaatst; er is dan alleen maar een witruimte van 10 pixels aan de rechter- en onderkant.<br /><strong>Voorbeeld:</strong> <code>4 4 1em</code><br />stelt een witruimte van 4 pixels in aan drie zijden, en een witruimte van 1 <em>em</em> onderaan het pictogram."
PLG_CONTENT_READLESSTEXT_THUMB_PADDING="Padding"
PLG_CONTENT_READLESSTEXT_THUMB_PADDING_DESCRIPTION="De padding waarde in aantal pixels rondom het pictogram.<br /><strong>Opmerking:</strong> Geef hier <code>-1</code> in om hiervoor geen specifieke opmaak toe te voegen."
PLG_CONTENT_READLESSTEXT_THUMB_POSITION="Pictogram Positie"
PLG_CONTENT_READLESSTEXT_THUMB_POSITION_DESCRIPTION="Het pictogram wordt in de opgegeven positie ingevoegd."
PLG_CONTENT_READLESSTEXT_THUMB_WIDTH="Pictogram Breedte"
PLG_CONTENT_READLESSTEXT_THUMB_WIDTH_DESCRIPTION="Geef een getal in. Dit wordt de gewenste breedte van het pictogram, uitgedrukt in pixels. De afbeelding die voldoet aan alle voorwaarden wordt herschaald tot zowel hoogte als breedte passen in de opgegeven dimensies. <br /><strong>Opmerking:</strong> Geef hier 0 indien u geen beperking in de breedte wenst. De verhouding van hoogte en breedte van de originele afbeelding blijft in elk geval behouden."
PLG_CONTENT_READLESSTEXT_TRANSLATE_ADDITIONS="Schakel extra vertaalslag in"
PLG_CONTENT_READLESSTEXT_TRANSLATE_ADDITIONS_DESCRIPTION="Duid hier aan of u meerdere talen tegelijk wilt aanbieden. Indien u hier <em>Ja</em> kiest, kunnen alle velden hier op deze configuratiepagina waarvan de velden zichtbaar kunnen worden voor de gebruiker, vertaald worden in de taal van die gebruiker.<ul>De voor de gebruiker zichtbare velden zijn:<li><code>Prefix Voor Aangemelde Bezoekers</code></li><li><code>Prefix Voor Gasten</code></li><li><code>Suffix Voor Aangemelde Bezoekers</code></li><li><code>Suffix Voor Gasten</code></li></ul> Indien ingeschakeld, dienen deze velden <strong>niet</strong> de werkelijke pre- of suffix bevatten, maar een codewoord, waarbij alleen gebruik gemaakt mag worden van hoofdletters en het liggend streepje <code>_</code>. De <strong>volledige HTML pre- of suffix</strong> dient dan vervangen te worden, en het veld mag dan <strong>alleen nog maar dat ene codewoord</strong> bevatten. Bijvoorbeeld <code>MY_PREFIX</code> of <code>MY_TO_BE_TRANSLATED_TEXT</code>.<br /><br />Daarna maakt u gebruik van Joomla's language override functionaliteit om de gewenste vertalingen in iedere taal voor elk codewoord dat u heeft opgegeven. <ul>Hiervoor gaat u naar <em>Extensies > Taalbeheer > Overrides</em>:<li>Selecteer eerst een taal gebruik makend van de uitklappend elijst aan de rechterkant,</li><li>Klik daarna op <code>Nieuw</code>.</li><li>Vul het codewoord in bij <code>Language Constant</code>,</li><li>en uw vertaalde werkelijke pre- of suffix bij <code>Text</code>, volledig <strong>met alle HTML opmaak</strong> die u oorspronkelijk in een configuratieveld bij <em>read less text</em> had geplaatst. Ook blijft het mogelijk om de tokens gekend bij <em>read less text</em> te gebruiken bij <code>Text</code>.</li></ul><strong>Opmerking:</strong> Let er op dat de naam lang en specifiek genoeg is om uniek te zijn. Alle stukken tekst die vertaald kunnen worden op uw site hebben een overeenkomstig codewoord, en indien een codewoord wordt gekozen dat al in gebruik is op uw site, zal uw opgegeven vertaling ook daar gebruikt worden.<br />Gebruik bijvoorbeeld zeker niet <code>MOD_BREADCRUMBS_HERE</code> als codewoord om <em>read less text</em> te configureren."

PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX="Aansluitende Suffix<br />Aangemelde Bezoekers"
PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_DESCRIPTION="<strong>Alleen voor aangemelde bezoekers.</strong> Geef hier de tekst in die toegevoegd moet worden na de afgekorte tekst, maar vooraleer de nog epenstaande tags gesloten zijn. U kan hier HTML code plaatsen.<ul>Een aantal tags worden herkend en vervangen voor elk artikel:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Opmerking:</strong> De standaard waarde imiteert de (Engelse) standaard <em>Lees meer</em> code waar Joomla! in voorziet. Als u het veld leeg maakt, wordt de standaard waarde terug ingesteld.<br /><strong>Opmerking:</strong> Indien u hier geen suffix wenst, maar ook niet de hele sectie wil uitschakelen, kan u hier een spatie opgeven.<br /><strong>Opmerking:</strong> Indien bij de optie <code>Schakel extra vertaalslag in</code> voor <em>Ja</em> is gekozen, moet hier een codewoord staan; de werkelijke suffix dient u dan in te geven bij <em>Taalbeheer</em>."
PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE="Maak Link Van Aansluitende Suffix Voor Aangemelde Bezoekers"
PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="<strong>Alleen voor gasten.</strong> Kies <em>Ja</em> om automatisch de opgegeven suffix (tekst of HTML) om te vormen tot een link, die leidt naar het volledige artikel."
PLG_CONTENT_READLESSTEXT_USER_PREFIX="Prefix Voor<br />Aangemelde Bezoekers"
PLG_CONTENT_READLESSTEXT_USER_PREFIX_DESCRIPTION="<strong>Alleen voor aangemelde bezoekers.</strong> Geef hier de tekst in die voor elke tekst toegevoegd moet worden, of hij nu afgekort wordt of niet. U kan hier HTML code plaatsen.<ul>Een aantal tags worden herkend en vervangen voor elk artikel:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Opmerking:</strong> Laat dit veld leeg om vooraan niets toe te voegen.<br /><strong>Opmerking:</strong> Indien bij de optie <code>Schakel extra vertaalslag in</code> voor <em>Ja</em> is gekozen, moet hier een codewoord staan; de werkelijke prefix dient u dan in te geven bij <em>Taalbeheer</em>."
PLG_CONTENT_READLESSTEXT_USER_PREFIX_LINKS_TO_FULL_ARTICLE="Maak Link Van Suffix<br />Voor Aangemelde Bezoekers"
PLG_CONTENT_READLESSTEXT_USER_PREFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="Kies <em>Ja</em> om automatisch de opgegeven suffix (tekst of HTML) om te vormen tot een link, die leidt naar het volledige artikel. Indien u hier <em>Nee</em> kiest, dient u er zelf voor te zorgen dat de gebruiker op een andere manier het volledige artikel kan bereiken: door de titel als link te gebruiken, of door er voor te zorgen dat er altijd een pictogram gegenereerd wordt, of door zelf de HTML code te voorzien in de suffix. In het laatste geval kan u de token <code>{url}</code> gebruiken in combinatie met de HTML tag <code>a</code>."
PLG_CONTENT_READLESSTEXT_USER_SUFFIX="Suffix Voor<br />Aangemelde Bezoekers"
PLG_CONTENT_READLESSTEXT_USER_SUFFIX_DESCRIPTION="<strong>Alleen voor aangemelde bezoekers.</strong> Geef hier de tekst in die na elke <em>afgekorte</em> tekst toegevoegd moet worden. Deze waarde vervangt de standaard <em>Lees Meer</em> aanduiding. U kan hier HTML code plaatsen.<ul>Een aantal tags worden herkend en vervangen voor elk artikel:<li><code>{title}</code>, <code>{id}</code>, <code>{url}</code></li><li><code>{author}</code>, <code>{author_id}</code></li><li><code>{words}</code>, <code>{hits}</code></li><li><code>{created}</code>, <code>{modified}</code>, <code>{publish_up}</code></li><li><code>{category}</code>, <code>{category_id}</code></li><li><code>{component}</code></li></ul><strong>Opmerking:</strong> De standaard waarde imiteert de (Engelse) standaard <em>Lees meer</em> code waar Joomla! in voorziet. Als u het veld leeg maakt, wordt de standaard waarde terug ingesteld.<br /><strong>Opmerking:</strong> Indien u hier geen suffix wenst, maar ook niet de hele sectie wil uitschakelen, kan u hier een spatie opgeven.<br /><strong>Opmerking:</strong> Indien bij de optie <code>Schakel extra vertaalslag in</code> voor <em>Ja</em> is gekozen, moet hier een codewoord staan; de werkelijke suffix dient u dan in te geven bij <em>Taalbeheer</em>."
PLG_CONTENT_READLESSTEXT_USER_SUFFIX_LINKS_TO_FULL_ARTICLE="Maak Link Van Suffix<br />Voor Aangemelde Bezoekers"
PLG_CONTENT_READLESSTEXT_USER_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION="Kies <em>Ja</em> om automatisch de opgegeven suffix (tekst of HTML) om te vormen tot een link, die leidt naar het volledige artikel. Indien u hier <em>Nee</em> kiest, dient u er zelf voor te zorgen dat de gebruiker op een andere manier het volledige artikel kan bereiken: door de titel als link te gebruiken, of door er voor te zorgen dat er altijd een pictogram gegenereerd wordt, of door zelf de HTML code te voorzien in de suffix. In het laatste geval kan u de token <code>{url}</code> gebruiken in combinatie met de HTML tag <code>a</code>.<br /><strong>Opmerking:</strong> De standaard waarde imiteert de (Engelse) standaard <em>Lees meer</em> code waar Joomla! in voorziet, en deze bevat al de juiste HTML code om een link naar het volledige artikel weer te geven. In dat geval kan u deze optie best uitschakelen."

PLG_CONTENT_READLESSTEXT_WHEN="Standaard Instelling?"
PLG_CONTENT_READLESSTEXT_WHEN_DESCRIPTION="De standaard instelling is verondersteld tegemoet te komen aan de noden van de meeste gebruikers. U kan de standaard instelling ook weigeren en de velden eronder gebruiken om zo de volledige flexibiliteit te benutten die <em>read less text</em> u geeft."
PLG_CONTENT_READLESSTEXT_WRAPPER_CLASS="Wrapper Class"
PLG_CONTENT_READLESSTEXT_WRAPPER_CLASS_DESCRIPTION="Feef hier de gewenste <em>class</em> naam of namen in. Deze zullen worden toegekend aan de <code>Wrapper Tag</code>."
PLG_CONTENT_READLESSTEXT_WRAPPER_TAG="Wrapper Tag"
PLG_CONTENT_READLESSTEXT_WRAPPER_TAG_DESCRIPTION="<br />Kies hier de tag die u wilt gebruiken die rond uw artikel of <em>Item</em> geplaatst moet worden. Deze tag samen met de onderstaande optie <code>Wrapper Class</code> geeft u volledige flexibiliteit om de opmaak van uw artikels verder aan te passen.<br /><strong>Opmerking:</code> kies <code>Nee</code> om de optie niet toe te passen.<br /><strong>Opmerking:</strong> de tag - indien er een geselecteer is - zal worden gebruikt telkens <em>read less text</em> actief mag zijn."

; Option choices for
; - PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX,
; - PLG_CONTENT_READLESSTEXT_ADD_PREFIX,
; - PLG_CONTENT_READLESSTEXT_ADD_SUFFIX,
; - PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING and
; - PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL.
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE="Altijd wanneer read less text actief mag zijn"
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_LONG_ENOUGH="Altijd wanneer actief en het artikel lang genoeg is"
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_SHORTENED="Alleen wanneer het artikel wordt afgekort"
PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_USE_ARTICLE_MANAGER_OPTION="Respecteer de algemene optie 'Lees meer' Tonen"

PLG_CONTENT_READLESSTEXT_WORD="woord"

PLG_CONTENT_READLESSTEXT_UPPER_LEFT="Bovenaan links"
PLG_CONTENT_READLESSTEXT_UPPER_RIGHT="Bovenaan rechts"

PLG_CONTENT_READLESSTEXT_ARTICLE_TITLE_AS_THUMBNAIL_TITLE="Artikel titel"
PLG_CONTENT_READLESSTEXT_CHAR="letter"
PLG_CONTENT_READLESSTEXT_COMMON_USAGE="Ja, actief op alle artikel blog pagina's"

PLG_CONTENT_READLESSTEXT_CROP_BOTTOM="Toon de onderkant, snijd weg bovenaan"
PLG_CONTENT_READLESSTEXT_CROP_CENTER="Snijd evenveel weg aan beide kanten"
PLG_CONTENT_READLESSTEXT_CROP_FULL_HEIGHT="Niet verticaal wegsnijden: herschaal de volledige hoogte."
PLG_CONTENT_READLESSTEXT_CROP_FULL_WIDTH="Niet horizontaal wegsnijden: herschaal de volledige breedte."

PLG_CONTENT_READLESSTEXT_CROP_LEFT="Toon de linkerkant, snijd weg aan de rechterkant"
PLG_CONTENT_READLESSTEXT_CROP_RIGHT="Toon de rechterkant, snijd weg aan de linkerkant"
PLG_CONTENT_READLESSTEXT_CROP_TOP="Toon de bovenkant, snijd weg onderaan"
PK��#])�O
�
�
%content/readlesstext/readlesstext.phpnu�[���<?php
/**
 * @package readlesstext
 * @copyright 2008-2014 Parvus
 * @license http://www.gnu.org/licenses/gpl-3.0.html
 * @link http://joomlacode.org/gf/project/cutoff/
 * @author Parvus
 *
 * readless is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * readless is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with readless. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version $Id: readlesstext.php 270 2014-11-24 21:43:01Z parvus $
 */

defined( '_JEXEC' ) or die;
require_once 'readlesstextmain.php';

class plgContentReadLessText extends JPlugin
{
  /**
   * Constructor
   * @param object &$subject The object to observe
   * @param array $config An optional associative array of configuration settings.
   */
  public function __construct( &$subject, $config = array() )
  {
    parent::__construct( $subject, $config );
    $this->loadLanguage();
    $this->_main = new ReadLessTextMain( $subject, $config );
  }

//  This function can not be used reliably.
//  It can be that another plugin altered the text as stored in the database before this plugin get execution time.
//  read less must then work on the altered text, not on the text as stored in the database.
//   /**
//    * Entry function. Will be called each time some article text has been
//    * saved. The article's lengths will be calculated and stored or updated
//    * in the database.
//    * @param string $context ignored
//    * @param JTableContent $article The item/article being prepared for display.
//    * @param bool $isNew If the content has just been created
//    * @note Article is passed by reference, but after the save, so no changes
//    *   will be saved.
//    * @return true
//    */
//   public function onContentAfterSave( $context, &$article, $isNew )
//   {
//     return true;
//   }

  /**
   * Entry function. Will be called each time some article text is to be
   * prepared for display.
   * @param string $context ignored
   * @param JTableContent $article The item/article being prepared for display.
   * @param $params ignored
   * @param integer $limitstart ignored
   * @return void
   */
  function onContentBeforeDisplay( $context, &$article, &$params, $limitstart = 0 )
  {
    $app = JFactory::getApplication();
    $scope = $app->scope;
    if ( !/*NOT*/key_exists( $scope, self::$_callCount ) )
    {
      self::$_callCount[ $scope ] = 0;
    }

    $this->_main->ReadLessText( $article, self::$_callCount[ $scope ], 'plg_content_readlesstext' );
  }
//   onContentPrepare is not used: the call is too limited.
//   $article only contains a text field, not the id and other needed fields.
//   function onContentPrepare( $context, &$article, &$params, $limitstart = 0 )
//   {
//     $app = JFactory::getApplication();
//     $scope = $app->scope;
//     if ( !/*NOT*/in_array( $scope, self::$_callCount ) )
//     {
//       self::$_callCount[ $scope ] = 0;
//     }
//     $this->ReadLessText( $article, self::$_callCount );
//   }

    private $_main = null;
    private static $_callCount = array();
}

?>
PK��#]��N�
`
`%content/readlesstext/readlesstext.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>

<extension type="plugin" group="content" version="2.5" method="upgrade">
  <name>Content - Read Less - Text</name>
  <version>v5.2 (r274)</version>
  <license>GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
    http://www.gnu.org/licenses/gpl.html
  </license>
  <author>parvus</author>
  <authorEmail>1500@engineer.com</authorEmail>
  <authorUrl>http://joomlacode.org/gf/project/cutoff/</authorUrl>
  <copyright>Copyright (C) 2010-2014. All rights reserved.</copyright>
  <creationDate>November 2014</creationDate>

<!--  <updateservers>
    <server type="extension" priority="2" name="Read Less - Text - Updates">http://joomlacode.org/gf/project/cutoff/</server>
 </updateservers>
 --> 
  <config>
    <fields name="params">
      <fieldset name="info">
        <field name="readlesstextDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_DESCRIPTION" />
      </fieldset>
      <fieldset name="length">
        <field name="minimumTextLength" type="text" default="70" filter="integer" label="PLG_CONTENT_READLESSTEXT_MINIMUM_TEXT_LENGTH" description="PLG_CONTENT_READLESSTEXT_MINIMUM_TEXT_LENGTH_DESCRIPTION"></field>
        <field name="cutOffTextLength" type="text" default="50" filter="integer" label="PLG_CONTENT_READLESSTEXT_CUT_OFF_TEXT_LENGTH" description="PLG_CONTENT_READLESSTEXT_CUT_OFF_TEXT_LENGTH_DESCRIPTION"></field>
        <field name="" type="spacer" hr="true" />
        <field name="lengthUnit" type="list" default="char" filter="word" label="PLG_CONTENT_READLESSTEXT_LENGTH_UNIT">
          <option value="char">PLG_CONTENT_READLESSTEXT_CHAR</option>
          <option value="word">PLG_CONTENT_READLESSTEXT_WORD</option>
          <option value="sentence">PLG_CONTENT_READLESSTEXT_SENTENCE</option>
          <option value="paragraph">PLG_CONTENT_READLESSTEXT_PARAGRAPH</option>
        </field>
        <field name="lengthUnitDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_LENGTH_UNIT_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="retainWholeWords" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_RETAIN_WHOLE_WORDS" description="PLG_CONTENT_READLESSTEXT_RETAIN_WHOLE_WORDS_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="respectExistingReadmoreLink" type="list" default="1" filter="string" label="PLG_CONTENT_READLESSTEXT_RESPECT_EXISTING_READMORE_LINK" description="">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
          <option value="respectShowIntro">PLG_CONTENT_READLESSTEXT_RESPECT_SHOWINTRO</option>
        </field>
        <field name="respectExistingReadmoreLinkDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_RESPECT_EXISTING_READMORE_LINK_DESCRIPTION" />
      </fieldset>
      
      <fieldset name="when-active">
        <field name="articleNumberSkipCount" type="text" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SKIP_COUNT" description="PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SKIP_COUNT_DESCRIPTION"></field>
        <field name="articleNumberShortenCount" type="text" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SHORTEN_COUNT" description="PLG_CONTENT_READLESSTEXT_ARTICLE_NUMBER_SHORTEN_COUNT_DESCRIPTION"></field>
        <field name="" type="spacer" hr="true" />
        <field name="alwaysActiveForGuests" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_ALWAYS_ACTIVE_FOR_GUESTS">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="alwaysActiveForGuestsDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_ALWAYS_ACTIVE_FOR_GUESTS_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="componentScope" type="list" default="accordingToContexts" filter="word" label="PLG_CONTENT_READLESSTEXT_COMPONENT_SCOPE" description="PLG_CONTENT_READLESSTEXT_COMPONENT_SCOPE_DESCRIPTION">
<!--          <option value="always">PLG_CONTENT_READLESSTEXT_SCOPE_ALWAYS</option> -->
          <option value="accordingToContexts">PLG_CONTENT_READLESSTEXT_SCOPE_ACCORDING_TO_CONTEXTS</option>
          <option value="never">PLG_CONTENT_READLESSTEXT_SCOPE_NEVER</option>
        </field>        
        <field name="moduleScope" type="list" default="accordingToContexts" filter="word" label="PLG_CONTENT_READLESSTEXT_MODULE_SCOPE" description="PLG_CONTENT_READLESSTEXT_MODULE_SCOPE_DESCRIPTION">
          <option value="always">PLG_CONTENT_READLESSTEXT_SCOPE_ALWAYS</option>
          <option value="accordingToContexts">PLG_CONTENT_READLESSTEXT_SCOPE_ACCORDING_TO_CONTEXTS</option>
          <option value="never">PLG_CONTENT_READLESSTEXT_SCOPE_NEVER</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="when" type="list" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_WHEN" description="PLG_CONTENT_READLESSTEXT_WHEN_DESCRIPTION">
          <option value="0">PLG_CONTENT_READLESSTEXT_COMMON_USAGE</option>
          <option value="1">PLG_CONTENT_READLESSTEXT_SPECIFIC_USAGE</option>
        </field>
        <field name="allowed" type="textarea" cols="30" rows="6" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_ALLOWED" description="PLG_CONTENT_READLESSTEXT_ALLOWED_DESCRIPTION"></field>
        <field name="disallowed" type="textarea" cols="30" rows="6" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_DISALLOWED" description="PLG_CONTENT_READLESSTEXT_DISALLOWED_DESCRIPTION"></field>
        <field name="notes0" type="textarea" cols="30" rows="6" default="" filter="raw" label="PLG_CONTENT_READLESSTEXT_NOTES0" description="PLG_CONTENT_READLESSTEXT_NOTES0_DESCRIPTION"></field>
        <field name="" type="spacer" hr="true" />
        <field name="discover" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_DISCOVER">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="discoverDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_DISCOVER_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
      </fieldset>

      <fieldset name="thumbnail">
        <field name="createThumbnail" type="list" default="when_shortened" filter="word" label="PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL">
          <option value="no">JNO</option>
          <option value="when_active">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE</option>
          <option value="when_shortened">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_SHORTENED</option>
        </field>
        <field name="createThumbnailDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_CREATE_THUMBNAIL_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="linkThumbnail" type="radio" default="1" filter="integer" label="PLG_CONTENT_READLESSTEXT_LINK_THUMBNAIL" description="PLG_CONTENT_READLESSTEXT_LINK_THUMBNAIL_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="thumbnailTitle" type="list" default="articleTitle" filter="word" label="PLG_CONTENT_READLESSTEXT_THUMBNAIL_TITLE" description="PLG_CONTENT_READLESSTEXT_THUMBNAIL_TITLE_DESCRIPTION">
          <option value="0">PLG_CONTENT_READLESSTEXT_NO_THUMBNAIL_TITLE</option>
          <option value="articleTitle">PLG_CONTENT_READLESSTEXT_ARTICLE_TITLE_AS_THUMBNAIL_TITLE</option>
          <option value="prefix">PLG_CONTENT_READLESSTEXT_PREFIX_AS_THUMBNAIL_TITLE</option>
          <option value="inlineSuffix">PLG_CONTENT_READLESSTEXT_INLINE_SUFFIX_AS_THUMBNAIL_TITLE</option>
          <option value="suffix">PLG_CONTENT_READLESSTEXT_SUFFIX_AS_THUMBNAIL_TITLE</option>
        </field>
        <field name="thumbPosition" type="list" default="left" filter="word" label="PLG_CONTENT_READLESSTEXT_THUMB_POSITION" description="PLG_CONTENT_READLESSTEXT_THUMB_POSITION_DESCRIPTION">
          <option value="left">PLG_CONTENT_READLESSTEXT_UPPER_LEFT</option>
          <option value="right">PLG_CONTENT_READLESSTEXT_UPPER_RIGHT</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="defaultThumbnailTemplate" type="text" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_DEFAULT_THUMBNAIL_TEMPLATE"></field>
        <field name="defaultThumbnailTemplateDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_DEFAULT_THUMBNAIL_TEMPLATE_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="minimumImageWidth" type="text" default="32" filter="integer" label="PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_WIDTH" description="PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_WIDTH_DESCRIPTION"></field>
        <field name="minimumImageHeight" type="text" default="32" filter="integer" label="PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_HEIGHT" description="PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_HEIGHT_DESCRIPTION"></field>
        <field name="minimumImageRatio" type="text" default="0.10" filter="integer" label="PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_RATIO" description="PLG_CONTENT_READLESSTEXT_MINIMUM_IMAGE_RATIO_DESCRIPTION"></field>
        <field name="" type="spacer" hr="true" />
        <field name="thumbWidth" type="text" default="123" filter="integer" label="PLG_CONTENT_READLESSTEXT_THUMB_WIDTH" description="PLG_CONTENT_READLESSTEXT_THUMB_WIDTH_DESCRIPTION"></field>
        <field name="thumbHeight" type="text" default="123" filter="integer" label="PLG_CONTENT_READLESSTEXT_THUMB_HEIGHT" description="PLG_CONTENT_READLESSTEXT_THUMB_HEIGHT_DESCRIPTION"></field>
        <field name="cropHorizontalPosition" type="list" default="left" filter="word" label="PLG_CONTENT_READLESSTEXT_CROP_HORIZONTAL_POSITION" description="PLG_CONTENT_READLESSTEXT_CROP_HORIZONTAL_POSITION_DESCRIPTION">
          <option value="left">PLG_CONTENT_READLESSTEXT_CROP_LEFT</option>
          <option value="center">PLG_CONTENT_READLESSTEXT_CROP_CENTER</option>
          <option value="right">PLG_CONTENT_READLESSTEXT_CROP_RIGHT</option>
          <option value="no">PLG_CONTENT_READLESSTEXT_CROP_FULL_WIDTH</option>
        </field>
        <field name="cropVerticalPosition" type="list" default="top" filter="word" label="PLG_CONTENT_READLESSTEXT_CROP_VERTICAL_POSITION" description="PLG_CONTENT_READLESSTEXT_CROP_VERTICAL_POSITION_DESCRIPTION">
          <option value="top">PLG_CONTENT_READLESSTEXT_CROP_TOP</option>
          <option value="center">PLG_CONTENT_READLESSTEXT_CROP_CENTER</option>
          <option value="bottom">PLG_CONTENT_READLESSTEXT_CROP_BOTTOM</option>
          <option value="no">PLG_CONTENT_READLESSTEXT_CROP_FULL_HEIGHT</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="thumbMargin" type="text" default="3" filter="words" label="PLG_CONTENT_READLESSTEXT_THUMB_MARGIN"></field>
        <field name="thumbMarginDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_THUMB_MARGIN_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="thumbPadding" type="text" default="-1" filter="integer" label="PLG_CONTENT_READLESSTEXT_THUMB_PADDING" description="PLG_CONTENT_READLESSTEXT_THUMB_PADDING_DESCRIPTION"></field>
        <field name="thumbBorderWidth" type="text" default="1" filter="integer" label="PLG_CONTENT_READLESSTEXT_THUMB_BORDER_WIDTH" description="PLG_CONTENT_READLESSTEXT_THUMB_BORDER_WIDTH_DESCRIPTION"></field>
        <field name="thumbBorderColor" type="text" default="#cccccc" filter="string" label="PLG_CONTENT_READLESSTEXT_THUMB_BORDER_COLOR" description="PLG_CONTENT_READLESSTEXT_THUMB_BORDER_COLOR_DESCRIPTION"></field>
        <field name="thumbBorderStyle" type="list" default="solid" filter="word" label="PLG_CONTENT_READLESSTEXT_THUMB_BORDER_STYLE" description="PLG_CONTENT_READLESSTEXT_THUMB_BORDER_STYLE_DESCRIPTION">
          <option value="dotted">Dotted</option>
          <option value="dashed">Dashed</option>
          <option value="solid">Solid</option>
          <option value="double">Double</option>
          <option value="groove">Groove</option>
          <option value="ridge">Ridge</option>
          <option value="inset">Inset</option>
          <option value="outset">Outset</option>
          <option value="none">None</option>
        </field>
        <field name="thumbClass" type="text" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_THUMB_CLASS" description="PLG_CONTENT_READLESSTEXT_THUMB_CLASS_DESCRIPTION"></field>
        <field name="" type="spacer" hr="true" />
        <field name="thumbCacheTime" type="text" default="2419200" filter="integer" label="PLG_CONTENT_READLESSTEXT_THUMB_CACHE_TIME" description="PLG_CONTENT_READLESSTEXT_THUMB_CACHE_TIME_DESCRIPTION"></field>
        <field name="maxImageLoadTime" type="text" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_MAX_IMAGE_LOAD_TIME" description="PLG_CONTENT_READLESSTEXT_MAX_IMAGE_LOAD_TIME_DESCRIPTION"></field>
      </fieldset>      
      
      <fieldset name="prefix">
        <field name="addPrefix" type="list" default="when_active" filter="word" label="PLG_CONTENT_READLESSTEXT_ADD_PREFIX">
          <option value="no">JNO</option>
          <option value="when_active">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE</option>
          <option value="when_shortened">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_SHORTENED</option>
        </field>
        <field name="addPrefixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_ADD_PREFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="userPrefix" type="textarea" cols="30" rows="6" default="" filter="raw" label="PLG_CONTENT_READLESSTEXT_USER_PREFIX"></field>
        <field name="userPrefixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_USER_PREFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="userPrefixLinksToFullArticle" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_USER_PREFIX_LINKS_TO_FULL_ARTICLE" description="PLG_CONTENT_READLESSTEXT_USER_PREFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="guestPrefix" type="textarea" cols="30" rows="6" default="" filter="raw" label="PLG_CONTENT_READLESSTEXT_GUEST_PREFIX"></field>
        <field name="guestPrefixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="guestPrefixLinksToFullArticle" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_LINKS_TO_FULL_ARTICLE" description="PLG_CONTENT_READLESSTEXT_GUEST_PREFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="prefixDateFormat" type="text" default="[M, jS]" filter="raw" label="PLG_CONTENT_READLESSTEXT_DATE_FORMAT" description="PLG_CONTENT_READLESSTEXT_DATE_FORMAT_DESCRIPTION"></field>
      </fieldset>

      <fieldset name="suffix">
        <field name="addInlineSuffix" type="list" default="when_shortened" filter="word" label="PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX">
          <option value="no">JNO</option>
          <option value="when_active">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE</option>
          <option value="when_active_use_article_manager_option">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_USE_ARTICLE_MANAGER_OPTION</option>
          <option value="when_shortened">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_SHORTENED</option>
        </field>
        <field name="addInlineSuffixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_ADD_INLINE_SUFFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="userInlineSuffix" type="textarea" cols="30" rows="6" default="&amp;hellip;" filter="raw" label="PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX"></field>
        <field name="userInlineSuffixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="userInlineSuffixLinksToFullArticle" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE" description="PLG_CONTENT_READLESSTEXT_USER_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="guestInlineSuffix" type="textarea" cols="30" rows="6" default="&amp;hellip;" filter="raw" label="PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX"></field>
        <field name="guestInlineSuffixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="guestInlineSuffixLinksToFullArticle" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE" description="PLG_CONTENT_READLESSTEXT_GUEST_INLINE_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="" type="spacer" hr="true" />
        <field name="addSuffix" type="list" default="when_active_use_article_manager_option" filter="word" label="PLG_CONTENT_READLESSTEXT_ADD_SUFFIX">
          <option value="no">JNO</option>
          <option value="when_active">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE</option>
          <option value="when_active_use_article_manager_option">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_USE_ARTICLE_MANAGER_OPTION</option>
          <option value="when_shortened">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_SHORTENED</option>
        </field>
        <field name="addSuffixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_ADD_SUFFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="userSuffix" type="textarea" cols="30" rows="6" default="&lt;p class='readmore'&gt;&lt;a href='{url}'&gt;Read more: {title}&lt;/a>&lt;/p&gt;" filter="raw" label="PLG_CONTENT_READLESSTEXT_USER_SUFFIX"></field>
        <field name="userSuffixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_USER_SUFFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="userSuffixLinksToFullArticle" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_USER_SUFFIX_LINKS_TO_FULL_ARTICLE" description="PLG_CONTENT_READLESSTEXT_USER_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="guestSuffix" type="textarea" cols="30" rows="6" default="&lt;p class='readmore'&gt;&lt;a href='{url}'&gt;Read more: {title}&lt;/a>&lt;/p&gt;" filter="raw" label="PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX"></field>
        <field name="guestSuffixDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="guestSuffixLinksToFullArticle" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_LINKS_TO_FULL_ARTICLE" description="PLG_CONTENT_READLESSTEXT_GUEST_SUFFIX_LINKS_TO_FULL_ARTICLE_DESCRIPTION">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="" type="spacer" hr="true" />
        <field name="suffixDateFormat" type="text" default="[M, jS]" filter="raw" label="PLG_CONTENT_READLESSTEXT_DATE_FORMAT" description="PLG_CONTENT_READLESSTEXT_DATE_FORMAT_DESCRIPTION"></field>
      </fieldset>      

      <fieldset name="formatting">
        <field name="wrapperTag" type="list" default="0" filter="word" label="PLG_CONTENT_READLESSTEXT_WRAPPER_TAG" description="PLG_CONTENT_READLESSTEXT_WRAPPER_TAG_DESCRIPTION">
          <option value="0">JNO</option>
          <option value="article">article</option>
          <option value="div">div</option>
          <option value="section">section</option>
          <option value="span">span</option>
        </field>
        <field name="wrapperClass" type="text" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_WRAPPER_CLASS" description="PLG_CONTENT_READLESSTEXT_WRAPPER_CLASS_DESCRIPTION"></field>
        <field name="" type="spacer" hr="true" />
        <field name="translateAdditions" type="radio" default="0" filter="integer" label="PLG_CONTENT_READLESSTEXT_TRANSLATE_ADDITIONS">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
        <field name="translateAdditionsDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_TRANSLATE_ADDITIONS_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />      
        <field name="extraSelfClosingTags" type="text" default="br, hr, img" filter="string" label="PLG_CONTENT_READLESSTEXT_EXTRA_SELF_CLOSING_TAGS" description="PLG_CONTENT_READLESSTEXT_EXTRA_SELF_CLOSING_TAGS_DESCRIPTION"></field>
        <field name="" type="spacer" hr="true" />
        <field name="applyFormatting" type="list" default="when_active" filter="word" label="PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING">
          <option value="when_active">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE</option>
          <option value="when_long_enough">PLG_CONTENT_READLESSTEXT_ALLOWED_WHEN_ACTIVE_AND_LONG_ENOUGH</option>
        </field>
        <field name="applyFormattingDescription" type="spacer" label="PLG_CONTENT_READLESSTEXT_APPLY_FORMATTING_DESCRIPTION" />
        <field name="" type="spacer" hr="true" />
        <field name="tagsToRemove" type="text" default="img" filter="string" label="PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE" description="PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_DESCRIPTION"></field>
        <field name="tagsToRemoveWithContents" type="text" default="style, nav, menu, footer, script, head, form, noscript" filter="string" label="PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_WITH_CONTENTS" description="PLG_CONTENT_READLESSTEXT_TAGS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION"></field>
        <field name="squareTokensToRemove" type="text" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE" description="PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_DESCRIPTION"></field>
        <field name="squareTokensToRemoveWithContents" type="text" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_WITH_CONTENTS" description="PLG_CONTENT_READLESSTEXT_SQUARE_TOKENS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION"></field>
        <field name="curlyTokensToRemove" type="text" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE" description="PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_DESCRIPTION"></field>
        <field name="curlyTokensToRemoveWithContents" type="text" default="" filter="string" label="PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_WITH_CONTENTS" description="PLG_CONTENT_READLESSTEXT_CURLY_TOKENS_TO_REMOVE_WITH_CONTENTS_DESCRIPTION"></field>
      </fieldset>
    </fields>
  </config>

  <files>
    <filename plugin="readlesstext">readlesstext.php</filename>
    <filename plugin="readlesstext">readlesstextcache.php</filename>
    <filename plugin="readlesstext">readlesstextexpand.php</filename>
    <filename plugin="readlesstext">readlesstexthelper.php</filename>
    <filename plugin="readlesstext">readlesstextmain.php</filename>
    <filename plugin="readlesstext">readlesstextthumb.php</filename>
    <folder>language</folder>
  </files>
  
  <scriptfile>script.php</scriptfile>

  <languages folder="language">
    <language tag="en-GB">en-GB/en-GB.plg_content_readlesstext.sys.ini</language>
    <language tag="en-GB">en-GB/en-GB.plg_content_readlesstext.ini</language>
    <language tag="nl-NL">nl-NL/nl-NL.plg_content_readlesstext.sys.ini</language>
    <language tag="nl-NL">nl-NL/nl-NL.plg_content_readlesstext.ini</language>
  </languages>

</extension>
PK��#]ʹ���+content/readlesstext/readlesstextexpand.phpnu�[���<?php
/**
 * @package readlesstext
 * @copyright 2008-2014 Parvus
 * @license http://www.gnu.org/licenses/gpl-3.0.html
 * @link http://joomlacode.org/gf/project/cutoff/
 * @author Parvus
 *
 * readless is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * readless is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with readless. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version $Id$
 */

defined( '_JEXEC' ) or die;
jimport( 'joomla.utilities.date' );
require_once 'readlesstexthelper.php';

class ReadLessTextExpand
{
  function __construct()
  {
    $this->_expandables[ '{author_id}' ] = 0;
    $this->_expandables[ '{author}' ] = '';
    $this->_expandables[ '{created}' ] = '';
    $this->_expandables[ '{modified}' ] = '';
    $this->_expandables[ '{publish_up}' ] = '';
    $this->_expandables[ '{hits}' ] = '';
    $this->_expandables[ '{title}' ] = '';
    $this->_expandables[ '{words}' ] = '';
  }

  /**
   * Prepares a future call to Expand(). Based on the given arguments, the
   * expandables are set. Existing exandables are overwritten.
   * @param JTableContent $article RO. The item/article being prepared for display. May be Null.
   * @param string $plaintext RO. The plain text version of the full,
   *   unshortened article. May be Null.
   * @param string $dateFormat Determines the format for the date fields to expand
   *   in the pre- and suffixes. May be Null.
   * @param $overrides Overrides information deduced from $article with given
   *   values. Keys are one of {author}, {author_id}, {words}, {created},
   *   {modified}, {publish_up}, {hits}, {category}, {category_id}, {id},
   *   {component}, {title}, {url}. May be Null.
   * @note {words} can only be expanded correctly if it is set via @c $overrides
   */
  public function SetExpandables( $article, $plaintext, $dateFormat, $overrides )
  {
    if ( $article )
    {
      /* {id} */
      $this->_expandables[ '{id}' ] = ReadLessTextHelper::GetArticleId( $article );

      /* {component} */
      $this->_expandables[ '{component}' ] = JRequest::getWord( 'option' );

      /* {category_id} */
      $this->_expandables[ '{category_id}' ] = ReadLessTextHelper::GetCategoryId( $article );

      /* {category} */
      if ( isset( $article->category_title ) )
      {
        $this->_expandables[ '{category}' ] = $article->category_title;
      }

      /* {author_id} */
      if ( isset( $article->created_by ) )
      {
        $this->_expandables[ '{author_id}' ] = $article->created_by;
      }

      /* {author} */
      if ( isset( $article->created_by_alias ) and $article->created_by_alias )
      {
        $this->_expandables[ '{author}' ] = $article->created_by_alias;
      }
      else if ( isset( $article->author ) and $article->author )
      {
        $this->_expandables[ '{author}' ] = $article->author;
      }

      /* {created} */
      if ( isset( $article->created ) )
      {
        $this->_created = new JDate( $article->created );
      }

      /* {modified} */
      if ( isset( $article->modified ) and ( $article->modified != '0000-00-00 00:00:00' ) )
      {
        $this->_modified = new JDate( $article->modified );
      }
      else
     {
        $this->_modified = $this->_created;
      }

      /* {publish_up} */
      if ( isset( $article->publish_up ) )
      {
        $this->_publishUp = new JDate( $article->publish_up );
      }

      /* {hits} */
      if ( isset( $article->hits ) )
      {
        $this->_expandables[ '{hits}' ] = $article->hits;
      }

      /* {title} */
      if ( isset( $article->title ) )
      {
        $this->_expandables[ '{title}' ] = $article->title;
      }
    }

    if ( $dateFormat )
    {
      if ( $this->_created )
      {
        $this->_expandables[ '{created}' ] = $this->_created->Format( $dateFormat );
      }
      if ( $this->_modified )
      {
        $this->_expandables[ '{modified}' ] = $this->_modified->Format( $dateFormat );
      }
      if ( $this->_publishUp )
      {
        $this->_expandables[ '{publish_up}' ] = $this->_publishUp->Format( $dateFormat );
      }
    }

    /* {words} must be set via $overrides */

    if ( $overrides )
    {
      $this->_expandables = array_merge( $this->_expandables, $overrides );
    }
  }

  /**
   * Expands the string according to the expandables, set in a previous call to SetExpandables
   * @param string $string
   */
  public function Expand( $string )
  {
    return JString::str_ireplace( array_keys( $this->_expandables ), array_values( $this->_expandables ), $string );
  }

  private $_expandables = array();
}
?>
PK��#]��`�jjcontent/vote/vote.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.vote
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Vote plugin.
 *
 * @since  1.5
 */
class PlgContentVote extends JPlugin
{
	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.7.0
	 */
	protected $app;

	/**
	 * The position the voting data is displayed in relative to the article.
	 *
	 * @var    string
	 * @since  3.7.0
	 */
	protected $votingPosition;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   3.7.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$this->votingPosition = $this->params->get('position', 'top');
	}

	/**
	 * Displays the voting area when viewing an article and the voting section is displayed before the article
	 *
	 * @param   string   $context  The context of the content being passed to the plugin
	 * @param   object   &$row     The article object
	 * @param   object   &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  string|boolean  HTML string containing code for the votes if in com_content else boolean false
	 *
	 * @since   1.6
	 */
	public function onContentBeforeDisplay($context, &$row, &$params, $page = 0)
	{
		if ($this->votingPosition !== 'top')
		{
			return '';
		}

		return $this->displayVotingData($context, $row, $params, $page);
	}

	/**
	 * Displays the voting area when viewing an article and the voting section is displayed after the article
	 *
	 * @param   string   $context  The context of the content being passed to the plugin
	 * @param   object   &$row     The article object
	 * @param   object   &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  string|boolean  HTML string containing code for the votes if in com_content else boolean false
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterDisplay($context, &$row, &$params, $page = 0)
	{
		if ($this->votingPosition !== 'bottom')
		{
			return '';
		}

		return $this->displayVotingData($context, $row, $params, $page);
	}

	/**
	 * Displays the voting area
	 *
	 * @param   string   $context  The context of the content being passed to the plugin
	 * @param   object   &$row     The article object
	 * @param   object   &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  string|boolean  HTML string containing code for the votes if in com_content else boolean false
	 *
	 * @since   3.7.0
	 */
	private function displayVotingData($context, &$row, &$params, $page)
	{
		$parts = explode('.', $context);

		if ($parts[0] !== 'com_content')
		{
			return false;
		}

		if (empty($params) || !$params->get('show_vote', null))
		{
			return '';
		}

		// Load plugin language files only when needed (ex: they are not needed if show_vote is not active).
		$this->loadLanguage();

		// Get the path for the rating summary layout file
		$path = JPluginHelper::getLayoutPath('content', 'vote', 'rating');

		// Render the layout
		ob_start();
		include $path;
		$html = ob_get_clean();

		if ($this->app->input->getString('view', '') === 'article' && $row->state == 1)
		{
			// Get the path for the voting form layout file
			$path = JPluginHelper::getLayoutPath('content', 'vote', 'vote');

			// Render the layout
			ob_start();
			include $path;
			$html .= ob_get_clean();
		}

		return $html;
	}
}
PK��#]m*�~~content/vote/vote.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="content" method="upgrade">
	<name>plg_content_vote</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_VOTE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="vote">vote.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_vote.ini</language>
		<language tag="en-GB">en-GB.plg_content_vote.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="position"
					type="list"
					label="PLG_VOTE_POSITION_LABEL"
					description="PLG_VOTE_POSITION_DESC"
					default="top"
					>
					<option value="top">PLG_VOTE_TOP</option>
					<option value="bottom">PLG_VOTE_BOTTOM</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]^�y��content/vote/tmpl/vote.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.vote
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Layout variables
 * -----------------
 * @var   string   $context  The context of the content being passed to the plugin
 * @var   object   &$row     The article object
 * @var   object   &$params  The article params
 * @var   integer  $page     The 'page' number
 * @var   array    $parts    The context segments
 * @var   string   $path     Path to this file
 */

$uri = clone JUri::getInstance();
$uri->setVar('hitcount', '0');

// Create option list for voting select box
$options = array();

for ($i = 1; $i < 6; $i++)
{
	$options[] = JHtml::_('select.option', $i, JText::sprintf('PLG_VOTE_VOTE', $i));
}

?>
<form method="post" action="<?php echo htmlspecialchars($uri->toString(), ENT_COMPAT, 'UTF-8'); ?>" class="form-inline">
	<span class="content_vote">
		<label class="unseen element-invisible" for="content_vote_<?php echo (int) $row->id; ?>"><?php echo JText::_('PLG_VOTE_LABEL'); ?></label>
		<?php echo JHtml::_('select.genericlist', $options, 'user_rating', null, 'value', 'text', '5', 'content_vote_' . (int) $row->id); ?>
		&#160;<input class="btn btn-mini" type="submit" name="submit_vote" value="<?php echo JText::_('PLG_VOTE_RATE'); ?>" />
		<input type="hidden" name="task" value="article.vote" />
		<input type="hidden" name="hitcount" value="0" />
		<input type="hidden" name="url" value="<?php echo htmlspecialchars($uri->toString(), ENT_COMPAT, 'UTF-8'); ?>" />
		<?php echo JHtml::_('form.token'); ?>
	</span>
</form>
PK��#]'��wwcontent/vote/tmpl/rating.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.vote
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Layout variables
 * -----------------
 * @var   string   $context  The context of the content being passed to the plugin
 * @var   object   &$row     The article object
 * @var   object   &$params  The article params
 * @var   integer  $page     The 'page' number
 * @var   array    $parts    The context segments
 * @var   string   $path     Path to this file
 */

if ($context == 'com_content.categories')
{
	return;
}

$rating = (int) $row->rating;
$rcount = (int) $row->rating_count;

// Look for images in template if available
$starImageOn  = JHtml::_('image', 'system/rating_star.png', JText::_('PLG_VOTE_STAR_ACTIVE'), null, true);
$starImageOff = JHtml::_('image', 'system/rating_star_blank.png', JText::_('PLG_VOTE_STAR_INACTIVE'), null, true);

$img = '';

for ($i = 0; $i < $rating; $i++)
{
	$img .= $starImageOn;
}

for ($i = $rating; $i < 5; $i++)
{
	$img .= $starImageOff;
}

?>
<div class="content_rating">
	<?php if ($rcount) : ?>
		<p class="unseen element-invisible" itemprop="aggregateRating" itemscope itemtype="https://schema.org/AggregateRating">
			<?php echo JText::sprintf('PLG_VOTE_USER_RATING', '<span itemprop="ratingValue">' . $rating . '</span>', '<span itemprop="bestRating">5</span>'); ?>
			<meta itemprop="ratingCount" content="<?php echo $rcount; ?>" />
			<meta itemprop="worstRating" content="1" />
		</p>
	<?php endif; ?>
	<?php echo $img; ?>
</div>
PK��#]�)��content/vote/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��content/emailcloak/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#](q���!content/emailcloak/emailcloak.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="content" method="upgrade">
	<name>plg_content_emailcloak</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_EMAILCLOAK_XML_DESCRIPTION</description>
	<files>
		<filename plugin="emailcloak">emailcloak.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_emailcloak.ini</language>
		<language tag="en-GB">en-GB.plg_content_emailcloak.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="mode"
					type="list"
					label="PLG_CONTENT_EMAILCLOAK_MODE_LABEL"
					description="PLG_CONTENT_EMAILCLOAK_MODE_DESC"
					default="1"
					filter="integer"
					>
					<option value="0">PLG_CONTENT_EMAILCLOAK_NONLINKABLE</option>
					<option value="1">PLG_CONTENT_EMAILCLOAK_LINKABLE</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]tKh��D�D!content/emailcloak/emailcloak.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.emailcloak
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\String\StringHelper;

/**
 * Email cloack plugin class.
 *
 * @since  1.5
 */
class PlgContentEmailcloak extends JPlugin
{
	/**
	 * Plugin that cloaks all emails in content from spambots via Javascript.
	 *
	 * @param   string   $context  The context of the content being passed to the plugin.
	 * @param   mixed    &$row     An object with a "text" property or the string to be cloaked.
	 * @param   mixed    &$params  Additional parameters. See {@see PlgContentEmailcloak()}.
	 * @param   integer  $page     Optional page number. Unused. Defaults to zero.
	 *
	 * @return  boolean	True on success.
	 */
	public function onContentPrepare($context, &$row, &$params, $page = 0)
	{
		// Don't run this plugin when the content is being indexed
		if ($context === 'com_finder.indexer')
		{
			return true;
		}

		if (is_object($row))
		{
			return $this->_cloak($row->text, $params);
		}

		return $this->_cloak($row, $params);
	}

	/**
	 * Generate a search pattern based on link and text.
	 *
	 * @param   string  $link  The target of an email link.
	 * @param   string  $text  The text enclosed by the link.
	 *
	 * @return  string	A regular expression that matches a link containing the parameters.
	 */
	protected function _getPattern ($link, $text)
	{
		$pattern = '~(?:<a ([^>]*)href\s*=\s*"mailto:' . $link . '"([^>]*))>' . $text . '</a>~i';

		return $pattern;
	}

	/**
	 * Adds an attributes to the js cloaked email.
	 *
	 * @param   string  $jsEmail  Js cloaked email.
	 * @param   string  $before   Attributes before email.
	 * @param   string  $after    Attributes after email.
	 *
	 * @return string Js cloaked email with attributes.
	 */
	protected function _addAttributesToEmail($jsEmail, $before, $after)
	{
		if ($before !== '')
		{
			$before = str_replace("'", "\'", $before);
			$jsEmail = str_replace(".innerHTML += '<a '", ".innerHTML += '<a {$before}'", $jsEmail);
		}

		if ($after !== '')
		{
			$after = str_replace("'", "\'", $after);
			$jsEmail = str_replace("'\'>'", "'\'{$after}>'", $jsEmail);
		}

		return $jsEmail;
	}

	/**
	 * Cloak all emails in text from spambots via Javascript.
	 *
	 * @param   string  &$text    The string to be cloaked.
	 * @param   mixed   &$params  Additional parameters. Parameter "mode" (integer, default 1)
	 *                             replaces addresses with "mailto:" links if nonzero.
	 *
	 * @return  boolean  True on success.
	 */
	protected function _cloak(&$text, &$params)
	{
		/*
		 * Check for presence of {emailcloak=off} which is explicits disables this
		 * bot for the item.
		 */
		if (StringHelper::strpos($text, '{emailcloak=off}') !== false)
		{
			$text = StringHelper::str_ireplace('{emailcloak=off}', '', $text);

			return true;
		}

		// Simple performance check to determine whether bot should process further.
		if (StringHelper::strpos($text, '@') === false)
		{
			return true;
		}

		$mode = $this->params->def('mode', 1);

		// Example: any@example.org
		$searchEmail = '([\w\.\'\-\+]+\@(?:[a-z0-9\.\-]+\.)+(?:[a-zA-Z0-9\-]{2,24}))';

		// Example: any@example.org?subject=anyText
		$searchEmailLink = $searchEmail . '([?&][\x20-\x7f][^"<>]+)';

		// Any Text
		$searchText = '((?:[\x20-\x7f]|[\xA1-\xFF]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF4][\x80-\xBF]{3})[^<>]+)';

		// Any Image link
		$searchImage = '(<img[^>]+>)';

		// Any Text with <span or <strong
		$searchTextSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)' . $searchText . '(</span>|</strong>|</span></strong>)';

		// Any address with <span or <strong
		$searchEmailSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)' . $searchEmail . '(</span>|</strong>|</span></strong>)';

		/*
		 * Search and fix derivatives of link code <a href="http://mce_host/ourdirectory/email@example.org"
		 * >email@example.org</a>. This happens when inserting an email in TinyMCE, cancelling its suggestion to add
		 * the mailto: prefix...
		 */
		$pattern = $this->_getPattern($searchEmail, $searchEmail);
		$pattern = str_replace('"mailto:', '"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[3][0];
			$mailText = $regs[5][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search and fix derivatives of link code <a href="http://mce_host/ourdirectory/email@example.org"
		 * >anytext</a>. This happens when inserting an email in TinyMCE, cancelling its suggestion to add
		 * the mailto: prefix...
		 */
		$pattern = $this->_getPattern($searchEmail, $searchText);
		$pattern = str_replace('"mailto:', '"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[3][0];
			$mailText = $regs[5][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@example.org"
		 * >email@example.org</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@amail.com"
		 * ><anyspan >email@amail.com</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchEmailSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@amail.com">
		 * <anyspan >anytext</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchTextSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . addslashes($regs[5][0]) . $regs[6][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@example.org">
		 * anytext</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = addslashes($regs[4][0]);

			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@example.org">
		 * <img anything></a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchImage);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@example.org">
		 * <img anything>email@example.org</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchImage . $searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . $regs[5][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@example.org">
		 * <img anything>any text</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchImage . $searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . addslashes($regs[5][0]);

			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@example.org?
		 * subject=Text">email@example.org</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0];

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@example.org?
		 * subject=Text">anytext</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = addslashes($regs[5][0]);

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@amail.com?subject= Text"
		 * ><anyspan >email@amail.com</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchEmailSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0] . $regs[6][0] . $regs[7][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a href="mailto:email@amail.com?subject= Text">
		 * <anyspan >anytext</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchTextSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0] . addslashes($regs[6][0]) . $regs[7][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code
		 * <a href="mailto:email@amail.com?subject=Text"><img anything></a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchImage);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0];

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code
		 * <a href="mailto:email@amail.com?subject=Text"><img anything>email@amail.com</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchImage . $searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
			$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code
		 * <a href="mailto:email@amail.com?subject=Text"><img anything>any text</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchImage . $searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
			$mailText = $regs[4][0] . $regs[5][0] . addslashes($regs[6][0]);

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode, $mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = html_entity_decode($this->_addAttributesToEmail($replacement, $regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1], strlen($regs[0][0]));
		}

		/*
		 * Search for plain text email addresses, such as email@example.org but not within HTML tags:
		 * <img src="..." title="email@example.org"> or <input type="text" placeholder="email@example.org">
		 * The '<[^<]*>(*SKIP)(*F)|' trick is used to exclude this kind of occurrences
		 */
		$pattern = '~<[^<]*>(*SKIP)(*F)|' . $searchEmail . '~i';

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0];
			$replacement = JHtml::_('email.cloak', $mail, $mode);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[1][1], strlen($mail));
		}

		return true;
	}
}
PK��#]�)��content/finder/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]c|���content/finder/finder.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.finder
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Smart Search Content Plugin
 *
 * @since  2.5
 */
class PlgContentFinder extends JPlugin
{
	/**
	 * Smart Search after save content method.
	 * Content is passed by reference, but after the save, so no changes will be saved.
	 * Method is called right after the content is saved.
	 *
	 * @param   string  $context  The context of the content passed to the plugin (added in 1.6)
	 * @param   object  $article  A JTableContent object
	 * @param   bool    $isNew    If the content has just been created
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentAfterSave($context, $article, $isNew)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderAfterSave event.
		$dispatcher->trigger('onFinderAfterSave', array($context, $article, $isNew));
	}

	/**
	 * Smart Search before save content method.
	 * Content is passed by reference. Method is called before the content is saved.
	 *
	 * @param   string  $context  The context of the content passed to the plugin (added in 1.6).
	 * @param   object  $article  A JTableContent object.
	 * @param   bool    $isNew    If the content is just about to be created.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentBeforeSave($context, $article, $isNew)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderBeforeSave event.
		$dispatcher->trigger('onFinderBeforeSave', array($context, $article, $isNew));
	}

	/**
	 * Smart Search after delete content method.
	 * Content is passed by reference, but after the deletion.
	 *
	 * @param   string  $context  The context of the content passed to the plugin (added in 1.6).
	 * @param   object  $article  A JTableContent object.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentAfterDelete($context, $article)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderAfterDelete event.
		$dispatcher->trigger('onFinderAfterDelete', array($context, $article));
	}

	/**
	 * Smart Search content state change method.
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the plugin.
	 * @param   array    $pks      A list of primary key ids of the content that has changed state.
	 * @param   integer  $value    The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentChangeState($context, $pks, $value)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderChangeState event.
		$dispatcher->trigger('onFinderChangeState', array($context, $pks, $value));
	}

	/**
	 * Smart Search change category state content method.
	 * Method is called when the state of the category to which the
	 * content item belongs is changed.
	 *
	 * @param   string   $extension  The extension whose category has been updated.
	 * @param   array    $pks        A list of primary key ids of the content that has changed state.
	 * @param   integer  $value      The value of the state that the content has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onCategoryChangeState($extension, $pks, $value)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderCategoryChangeState event.
		$dispatcher->trigger('onFinderCategoryChangeState', array($extension, $pks, $value));
	}
}
PK��#]4M�FFcontent/finder/finder.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="content" method="upgrade">
	<name>plg_content_finder</name>
	<author>Joomla! Project</author>
	<creationDate>December 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_FINDER_XML_DESCRIPTION</description>

	<files>
		<filename plugin="finder">finder.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_finder.ini</language>
		<language tag="en-GB">en-GB.plg_content_finder.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
		</fields>
	</config>
</extension>
PK��#]�)�� content/confirmconsent/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�5�77)content/confirmconsent/confirmconsent.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="content" method="upgrade">
	<name>plg_content_confirmconsent</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_CONTENT_CONFIRMCONSENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="confirmconsent">confirmconsent.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_confirmconsent.ini</language>
		<language tag="en-GB">en-GB.plg_content_confirmconsent.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic" addfieldpath="/administrator/components/com_content/models/fields">
				<field
					name="consentbox_text"
					type="textarea"
					label="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_LABEL"
					description="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DESC"
					hint="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DEFAULT"
					class="span12"
					rows="7"
					cols="20"
					filter="html"
				/>

				<field
					name="privacy_article"
					type="modal_article"
					label="PLG_CONTENT_CONFIRMCONSENT_FIELD_ARTICLE_LABEL"
					description="PLG_CONTENT_CONFIRMCONSENT_FIELD_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�p�|��)content/confirmconsent/confirmconsent.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.confirmconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;

/**
 * The Joomla Core confirm consent plugin
 *
 * @since  3.9.0
 */
class PlgContentConfirmConsent extends CMSPlugin
{
	/**
	 * The Application object
	 *
	 * @var    JApplicationSite
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * The supported form contexts
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $supportedContext = array(
		'com_contact.contact',
		'com_mailto.mailto',
		'com_privacy.request',
	);

	/**
	 * Add additional fields to the supported forms
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm(JForm $form, $data)
	{
		if ($this->app->isClient('administrator') || !in_array($form->getName(), $this->supportedContext))
		{
			return true;
		}

		// Get the consent box Text & the selected privacyarticle
		$consentboxText  = (string) $this->params->get('consentbox_text', Text::_('PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DEFAULT'));
		$privacyArticle  = $this->params->get('privacy_article', false);

		$form->load('
			<form>
				<fieldset name="default" addfieldpath="/plugins/content/confirmconsent/fields">
					<field
						name="consentbox"
						type="consentbox"
						articleid="' . $privacyArticle . '"
						label="PLG_CONTENT_CONFIRMCONSENT_CONSENTBOX_LABEL"
						required="true"
						>
						<option value="0">' . htmlspecialchars($consentboxText, ENT_COMPAT, 'UTF-8') . '</option>
					</field>
				</fieldset>
			</form>'
		);

		return true;
	}
}
PK��#]P�Ltt,content/confirmconsent/fields/consentbox.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.confirmconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

JFormHelper::loadFieldClass('Checkboxes');

/**
 * Consentbox Field class for the Confirm Consent Plugin.
 *
 * @since  3.9.1
 */
class JFormFieldConsentBox extends JFormFieldCheckboxes
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.1
	 */
	protected $type = 'ConsentBox';

	/**
	 * Flag to tell the field to always be in multiple values mode.
	 *
	 * @var    boolean
	 * @since  3.9.1
	 */
	protected $forceMultiple = false;

	/**
	 * The article ID.
	 *
	 * @var    integer
	 * @since  3.9.1
	 */
	protected $articleid;

	/**
	 * Method to set certain otherwise inaccessible properties of the form field object.
	 *
	 * @param   string  $name   The property name for which to set the value.
	 * @param   mixed   $value  The value of the property.
	 *
	 * @return  void
	 *
	 * @since   3.9.1
	 */
	public function __set($name, $value)
	{
		switch ($name)
		{
			case 'articleid':
				$this->articleid = (int) $value;
				break;

			default:
				parent::__set($name, $value);
		}
	}

	/**
	 * Method to get certain otherwise inaccessible properties from the form field object.
	 *
	 * @param   string  $name  The property name for which to get the value.
	 *
	 * @return  mixed  The property value or null.
	 *
	 * @since   3.9.1
	 */
	public function __get($name)
	{
		switch ($name)
		{
			case 'articleid':
				return $this->$name;
		}

		return parent::__get($name);
	}

	/**
	 * Method to attach a JForm object to the field.
	 *
	 * @param   SimpleXMLElement  $element  The SimpleXMLElement object representing the `<field>` tag for the form field object.
	 * @param   mixed             $value    The form field value to validate.
	 * @param   string            $group    The field name group control value. This acts as an array container for the field.
	 *                                      For example if the field has name="foo" and the group value is set to "bar" then the
	 *                                      full field name would end up being "bar[foo]".
	 *
	 * @return  boolean  True on success.
	 *
	 * @see     JFormField::setup()
	 * @since   3.9.1
	 */
	public function setup(SimpleXMLElement $element, $value, $group = null)
	{
		$return = parent::setup($element, $value, $group);

		if ($return)
		{
			$this->articleid = (int) $this->element['articleid'];
		}

		return $return;
	}

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.9.1
	 */
	protected function getLabel()
	{
		if ($this->hidden)
		{
			return '';
		}

		$data = $this->getLayoutData();

		// Forcing the Alias field to display the tip below
		$position = $this->element['name'] == 'alias' ? ' data-placement="bottom" ' : '';

		// When we have an article let's add the modal and make the title clickable
		if ($data['articleid'])
		{
			$attribs['data-toggle'] = 'modal';

			$data['label'] = HTMLHelper::_(
				'link',
				'#modal-' . $this->id,
				$data['label'],
				$attribs
			);
		}

		// Here mainly for B/C with old layouts. This can be done in the layouts directly
		$extraData = array(
			'text'     => $data['label'],
			'for'      => $this->id,
			'classes'  => explode(' ', $data['labelclass']),
			'position' => $position,
		);

		return $this->getRenderer($this->renderLabelLayout)->render(array_merge($data, $extraData));
	}

	/**
	 * Method to get the field input markup.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   3.9.2
	 */
	protected function getInput()
	{
		$modalHtml  = '';
		$layoutData = $this->getLayoutData();

		if ($this->articleid)
		{
			$modalParams['title']  = $layoutData['label'];
			$modalParams['url']    = $this->getAssignedArticleUrl();
			$modalParams['height'] = 800;
			$modalParams['width']  = '100%';
			$modalHtml = HTMLHelper::_('bootstrap.renderModal', 'modal-' . $this->id, $modalParams);
		}

		return $modalHtml . parent::getInput();
	}

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.9.1
	 */
	protected function getLayoutData()
	{
		$data = parent::getLayoutData();

		$extraData = array(
			'articleid' => (integer) $this->articleid,
		);

		return array_merge($data, $extraData);
	}

	/**
	 * Return the url of the assigned article based on the current user language
	 *
	 * @return  string  Returns the link to the article
	 *
	 * @since   3.9.1
	 */
	private function getAssignedArticleUrl()
	{
		$db = Factory::getDbo();

		// Get the info from the article
		$query = $db->getQuery(true)
			->select($db->quoteName(array('id', 'catid', 'language')))
			->from($db->quoteName('#__content'))
			->where($db->quoteName('id') . ' = ' . (int) $this->articleid);
		$db->setQuery($query);

		try
		{
			$article = $db->loadObject();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			// Something at the database layer went wrong
			return Route::_(
				'index.php?option=com_content&view=article&id='
				. $this->articleid . '&tmpl=component'
			);
		}

		if (!is_object($article))
		{
			// We have not found the article object lets show a 404 to the user
			return Route::_(
				'index.php?option=com_content&view=article&id='
				. $this->articleid . '&tmpl=component'
			);
		}

		// Register ContentHelperRoute
		JLoader::register('ContentHelperRoute', JPATH_BASE . '/components/com_content/helpers/route.php');

		if (!Associations::isEnabled())
		{
			return Route::_(
				ContentHelperRoute::getArticleRoute(
					$article->id,
					$article->catid,
					$article->language
				) . '&tmpl=component'
			);
		}

		$associatedArticles = Associations::getAssociations('com_content', '#__content', 'com_content.item', $article->id);
		$currentLang        = Factory::getLanguage()->getTag();

		if (isset($associatedArticles) && $currentLang !== $article->language && array_key_exists($currentLang, $associatedArticles))
		{
			return Route::_(
				ContentHelperRoute::getArticleRoute(
					$associatedArticles[$currentLang]->id,
					$associatedArticles[$currentLang]->catid,
					$associatedArticles[$currentLang]->language
				) . '&tmpl=component'
			);
		}

		// Association is enabled but this article is not associated
		return Route::_(
			'index.php?option=com_content&view=article&id='
				. $article->id . '&catid=' . $article->catid
				. '&tmpl=component&lang=' . $article->language
		);
	}
}
PK��#]�)��content/rsform/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�#o,,content/rsform/index.htmlnu�[���<html><body bgcolor="#FFFFFF"></body></html>PK��#]�5JJcontent/rsform/script.phpnu�[���<?php
/**
* @package RSForm! Pro
* @copyright (C) 2007-2015 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

defined('_JEXEC') or die('Restricted access');

class plgContentRsformInstallerScript
{
	protected static $minJoomla = '3.7.0';
	protected static $minComponent = '3.0.0';
	
	public function preflight($type, $parent)
	{
		if ($type == 'uninstall')
		{
			return true;
		}

		try
		{
			$jversion = new JVersion();

			if (!$jversion->isCompatible(static::$minJoomla))
			{
				throw new Exception('Please upgrade to at least Joomla! ' . static::$minJoomla . ' before continuing!');
			}

			if (!file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/rsform.php'))
			{
				throw new Exception('Please install the RSForm! Pro component before continuing.');
			}

			if (!file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/assets.php') || !file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/version.php'))
			{
				throw new Exception('Please upgrade RSForm! Pro to at least version ' . static::$minComponent . ' before continuing!');
			}

			require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/version.php';

			if (!class_exists('RSFormProVersion') || version_compare((string) new RSFormProVersion, static::$minComponent, '<'))
			{
				throw new Exception('Please upgrade RSForm! Pro to at least version ' . static::$minComponent . ' before continuing!');
			}
		}
		catch (Exception $e)
		{
			JFactory::getApplication()->enqueueMessage($e->getMessage(), 'error');
			return false;
		}

		return true;
	}
	
	public function postflight($type, $parent) {
		if ($type == 'uninstall') {
			return true;
		}
		
		$db = JFactory::getDbo();
		$query = $db->getQuery(true);
		$query->select('extension_id')
			  ->from($db->qn('#__extensions'))
			  ->where($db->qn('type').' = '.$db->q('plugin'))
			  ->where($db->qn('folder').' = '.$db->q('content'))
			  ->where($db->qn('element').' = '.$db->q('rsform'));
		$pluginId = $db->setQuery($query)->loadResult();
		?>
		<style type="text/css">
		.version-history {
			margin: 0 0 2em 0;
			padding: 0;
			list-style-type: none;
		}
		.version-history > li {
			margin: 0 0 0.5em 0;
			padding: 0 0 0 4em;
			text-align:left;
			font-weight:normal;
		}
		.version-new,
		.version-fixed,
		.version-upgraded {
			float: left;
			font-size: 0.8em;
			margin-left: -4.9em;
			width: 4.5em;
			color: white;
			text-align: center;
			font-weight: bold;
			text-transform: uppercase;
			-webkit-border-radius: 4px;
			-moz-border-radius: 4px;
			border-radius: 4px;
		}

		.version-new {
			background: #7dc35b;
		}
		.version-fixed {
			background: #e9a130;
		}
		.version-upgraded {
			background: #61b3de;
		}
		</style>

		<h3>RSForm! Pro Content Plugin v3.0.0 Changelog</h3>
		<ul class="version-history">
			<li><span class="version-upgraded">Upg</span> Joomla! 4.0 and RSForm! Pro 3.0 compatibility.</li>
		</ul>
		<?php if ($pluginId) { ?>
		<a class="btn btn-primary btn-large" href="<?php echo JRoute::_('index.php?option=com_plugins&task=plugin.edit&extension_id='.$pluginId); ?>">Start using the RSForm! Pro Content Plugin.</a>
		<?php } ?>
		<a class="btn" href="https://www.rsjoomla.com/support/documentation/rsform-pro/plugins-and-modules/content-plugin-plgcontent-display-the-form-in-an-article.html" target="_blank">Read the documentation</a>
		<a class="btn btn-secondary" href="https://www.rsjoomla.com/support.html" target="_blank">Get Support!</a>
		<div style="clear: both;"></div>
		<?php
	}
}PK��#]�S@##content/rsform/rsform.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="content" method="upgrade">
	<name>Content - RSForm! Pro</name>
	<author>RSJoomla!</author>
	<creationDate>June 2015</creationDate>
	<copyright>(C) 2007-2017 www.rsjoomla.com</copyright>
	<license>GNU General Public License</license>
	<authorEmail>support@rsjoomla.com</authorEmail>
	<authorUrl>www.rsjoomla.com</authorUrl>
	<version>3.0.0</version>
	<scriptfile>script.php</scriptfile>
	
	<updateservers>
        <server type="extension" priority="1" name="RSForm! Pro - Content Plugin">https://www.rsjoomla.com/updates/com_rsform/Plugins/plg_content.xml</server>
    </updateservers>
	
	<description><![CDATA[PLG_CONTENT_RSFORM_DESC]]></description>
	<files>
		<filename plugin="rsform">rsform.php</filename>
		<filename>index.html</filename>
	</files>
	<languages folder="language/en-GB">
		<language tag="en-GB">en-GB.plg_content_rsform.ini</language>
		<language tag="en-GB">en-GB.plg_content_rsform.sys.ini</language>
	</languages>
</extension>PK��#]��}r

content/rsform/rsform.phpnu�[���<?php
/**
* @package RSForm! Pro
* @copyright (C) 2007-2015 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

defined('_JEXEC') or die('Restricted access');

class plgContentRsform extends JPlugin
{
	// Joomla! Triggers - onContentPrepare()
	public function onContentPrepare($context, &$row, &$params, $page = 0)
	{
		// Don't run this plugin when the content is being indexed
		if ($context == 'com_finder.indexer')
		{
			return true;
		}

		if (is_object($row) && isset($row->text))
		{
			$this->_addForm($row->text);
		}
		elseif (is_string($row))
		{
			$this->_addForm($row);
		}
	}
	
	// Syntax replacement function
	private function _addForm(&$text)
	{
		// Performance check
		if (strpos($text, '{rsform ') === false)
		{
			return false;
		}

		if (!class_exists('RSFormProHelper'))
		{
			$helper = JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsform.php';
			if (!file_exists($helper))
			{
				return false;
			}

			require_once $helper;
		}

		// Expression to search for
		$pattern = '#\{rsform ([0-9]+)(.*?)?\}#i';
		// Found matches
		if (preg_match_all($pattern, $text, $matches))
		{
			// No replacement when we're not dealing with HTML
			if (JFactory::getDocument()->getType() != 'html')
			{
				$text = preg_replace($pattern, '', $text);
				return true;
			}

			// Load language
			JFactory::getLanguage()->load('com_rsform', JPATH_SITE);

			// Disable caching
			JFactory::getCache('com_content')->setCaching(false);

			foreach ($matches[0] as $i => $fullMatch)
			{
				$attributes = trim($matches[2][$i]);
				if (strlen($attributes) && preg_match_all('#[a-z0-9_\-]+=".*?"#i', $attributes, $attributesMatches))
				{
					$data = array();

					foreach ($attributesMatches[0] as $pair)
					{
						list($attribute, $value) = explode('=', $pair, 2);

						$attribute  = trim(html_entity_decode($attribute));
						$value 		= html_entity_decode(trim($value, '"'));

						if (isset($data[$attribute]))
						{
							if (!is_array($data[$attribute]))
							{
								$data[$attribute] = (array) $data[$attribute];
							}

							$data[$attribute][] = $value;
						}
						else
						{
							$data[$attribute] = $value;
						}
					}

					if ($data)
					{
						JFactory::getApplication()->input->get->set('form', $data);
					}
				}

				$formId = $matches[1][$i];
				$text = str_replace($fullMatch, RSFormProHelper::displayForm($formId, true), $text);
			}
		}

		return true;
	}
}PK��#]'/�"�"content/joomla/joomla.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.joomla
 *
 * @copyright   (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Example Content Plugin
 *
 * @since  1.6
 */
class PlgContentJoomla extends JPlugin
{
	/**
	 * Example after save content method
	 * Article is passed by reference, but after the save, so no changes will be saved.
	 * Method is called right after the content is saved
	 *
	 * @param   string   $context  The context of the content passed to the plugin (added in 1.6)
	 * @param   object   $article  A JTableContent object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  boolean   true if function not enabled, is in frontend or is new. Else true or
	 *                    false depending on success of save function.
	 *
	 * @since   1.6
	 */
	public function onContentAfterSave($context, $article, $isNew)
	{
		// Check we are handling the frontend edit form.
		if ($context !== 'com_content.form')
		{
			return true;
		}

		// Check if this function is enabled.
		if (!$this->params->def('email_new_fe', 1))
		{
			return true;
		}

		// Check this is a new article.
		if (!$isNew)
		{
			return true;
		}

		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName('id'))
			->from($db->quoteName('#__users'))
			->where($db->quoteName('sendEmail') . ' = 1')
			->where($db->quoteName('block') . ' = 0');
		$db->setQuery($query);
		$users = (array) $db->loadColumn();

		if (empty($users))
		{
			return true;
		}

		$user = JFactory::getUser();

		// Messaging for new items
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/models', 'MessagesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/tables');

		$default_language = JComponentHelper::getParams('com_languages')->get('administrator');
		$debug = JFactory::getConfig()->get('debug_lang');
		$result = true;

		foreach ($users as $user_id)
		{
			if ($user_id != $user->id)
			{
				// Load language for messaging
				$receiver = JUser::getInstance($user_id);
				$lang = JLanguage::getInstance($receiver->getParam('admin_language', $default_language), $debug);
				$lang->load('com_content');
				$message = array(
					'user_id_to' => $user_id,
					'subject' => $lang->_('COM_CONTENT_NEW_ARTICLE'),
					'message' => sprintf($lang->_('COM_CONTENT_ON_NEW_CONTENT'), $user->get('name'), $article->title)
				);
				$model_message = JModelLegacy::getInstance('Message', 'MessagesModel');
				$result = $model_message->save($message);
			}
		}

		return $result;
	}

	/**
	 * Don't allow categories to be deleted if they contain items or subcategories with items
	 *
	 * @param   string  $context  The context for the content passed to the plugin.
	 * @param   object  $data     The data relating to the content that was deleted.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onContentBeforeDelete($context, $data)
	{
		// Skip plugin if we are deleting something other than categories
		if ($context !== 'com_categories.category')
		{
			return true;
		}

		// Check if this function is enabled.
		if (!$this->params->def('check_categories', 1))
		{
			return true;
		}

		$extension = JFactory::getApplication()->input->getString('extension');

		// Default to true if not a core extension
		$result = true;

		$tableInfo = array(
			'com_banners' => array('table_name' => '#__banners'),
			'com_contact' => array('table_name' => '#__contact_details'),
			'com_content' => array('table_name' => '#__content'),
			'com_newsfeeds' => array('table_name' => '#__newsfeeds'),
			'com_weblinks' => array('table_name' => '#__weblinks')
		);

		// Now check to see if this is a known core extension
		if (isset($tableInfo[$extension]))
		{
			// Get table name for known core extensions
			$table = $tableInfo[$extension]['table_name'];

			// See if this category has any content items
			$count = $this->_countItemsInCategory($table, $data->get('id'));

			// Return false if db error
			if ($count === false)
			{
				$result = false;
			}
			else
			{
				// Show error if items are found in the category
				if ($count > 0)
				{
					$msg = JText::sprintf('COM_CATEGORIES_DELETE_NOT_ALLOWED', $data->get('title'))
						. JText::plural('COM_CATEGORIES_N_ITEMS_ASSIGNED', $count);
					JError::raiseWarning(403, $msg);
					$result = false;
				}

				// Check for items in any child categories (if it is a leaf, there are no child categories)
				if (!$data->isLeaf())
				{
					$count = $this->_countItemsInChildren($table, $data->get('id'), $data);

					if ($count === false)
					{
						$result = false;
					}
					elseif ($count > 0)
					{
						$msg = JText::sprintf('COM_CATEGORIES_DELETE_NOT_ALLOWED', $data->get('title'))
							. JText::plural('COM_CATEGORIES_HAS_SUBCATEGORY_ITEMS', $count);
						JError::raiseWarning(403, $msg);
						$result = false;
					}
				}
			}

			return $result;
		}
	}

	/**
	 * Get count of items in a category
	 *
	 * @param   string   $table  table name of component table (column is catid)
	 * @param   integer  $catid  id of the category to check
	 *
	 * @return  mixed  count of items found or false if db error
	 *
	 * @since   1.6
	 */
	private function _countItemsInCategory($table, $catid)
	{
		$db = JFactory::getDbo();
		$query = $db->getQuery(true);

		// Count the items in this category
		$query->select('COUNT(id)')
			->from($table)
			->where('catid = ' . $catid);
		$db->setQuery($query);

		try
		{
			$count = $db->loadResult();
		}
		catch (RuntimeException $e)
		{
			JError::raiseWarning(500, $e->getMessage());

			return false;
		}

		return $count;
	}

	/**
	 * Get count of items in a category's child categories
	 *
	 * @param   string   $table  table name of component table (column is catid)
	 * @param   integer  $catid  id of the category to check
	 * @param   object   $data   The data relating to the content that was deleted.
	 *
	 * @return  mixed  count of items found or false if db error
	 *
	 * @since   1.6
	 */
	private function _countItemsInChildren($table, $catid, $data)
	{
		$db = JFactory::getDbo();

		// Create subquery for list of child categories
		$childCategoryTree = $data->getTree();

		// First element in tree is the current category, so we can skip that one
		unset($childCategoryTree[0]);
		$childCategoryIds = array();

		foreach ($childCategoryTree as $node)
		{
			$childCategoryIds[] = $node->id;
		}

		// Make sure we only do the query if we have some categories to look in
		if (count($childCategoryIds))
		{
			// Count the items in this category
			$query = $db->getQuery(true)
				->select('COUNT(id)')
				->from($table)
				->where('catid IN (' . implode(',', $childCategoryIds) . ')');
			$db->setQuery($query);

			try
			{
				$count = $db->loadResult();
			}
			catch (RuntimeException $e)
			{
				JError::raiseWarning(500, $e->getMessage());

				return false;
			}

			return $count;
		}
		else
			// If we didn't have any categories to check, return 0
		{
			return 0;
		}
	}

	/**
	 * Change the state in core_content if the state in a table is changed
	 *
	 * @param   string   $context  The context for the content passed to the plugin.
	 * @param   array    $pks      A list of primary key ids of the content that has changed state.
	 * @param   integer  $value    The value of the state that the content has been changed to.
	 *
	 * @return  boolean
	 *
	 * @since   3.1
	 */
	public function onContentChangeState($context, $pks, $value)
	{
		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName('core_content_id'))
			->from($db->quoteName('#__ucm_content'))
			->where($db->quoteName('core_type_alias') . ' = ' . $db->quote($context))
			->where($db->quoteName('core_content_item_id') . ' IN (' . $pksImploded = implode(',', $pks) . ')');
		$db->setQuery($query);
		$ccIds = $db->loadColumn();

		$cctable = new JTableCorecontent($db);
		$cctable->publish($ccIds, $value);

		return true;
	}

	/**
	* The save event.
	*
	* @param   string   $context  The context
	* @param   object   $table    The item
	* @param   boolean  $isNew    Is new item
	*
	* @return  void
	*
	* @since   3.9.12
	*/
	public function onContentBeforeSave($context, $table, $isNew)
	{
		// Check we are handling the frontend edit form.
		if ($context !== 'com_menus.item')
		{
			return true;
		}

		// Special case for Create article menu item
		if ($table->link !== 'index.php?option=com_content&view=form&layout=edit')
		{
			return true;
		}

		// Display error if catid is not set when enable_category is enabled
		$params = json_decode($table->params, true);

		if ($params['enable_category'] == 1 && empty($params['catid']))
		{
			$table->setError(JText::_('COM_CONTENT_CREATE_ARTICLE_ERROR'));

			return false;
		}
	}
}
PK��#]�|f..content/joomla/joomla.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="content" method="upgrade">
	<name>plg_content_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>November 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_joomla.ini</language>
		<language tag="en-GB">en-GB.plg_content_joomla.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="check_categories"
					type="radio"
					label="PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_LABEL"
					description="PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field 
					name="email_new_fe"
					type="radio"
					label="PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_FE_LABEL"
					description="PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_FE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>

</extension>
PK��#]�)��content/joomla/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��content/fields/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��ig``content/fields/fields.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.Fields
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die();

/**
 * Plug-in to show a custom field in eg an article
 * This uses the {fields ID} syntax
 *
 * @since  3.7.0
 */
class PlgContentFields extends JPlugin
{
	/**
	 * Plugin that shows a custom field
	 *
	 * @param   string  $context  The context of the content being passed to the plugin.
	 * @param   object  &$item    The item object.  Note $article->text is also available
	 * @param   object  &$params  The article params
	 * @param   int     $page     The 'page' number
	 *
	 * @return void
	 *
	 * @since  3.7.0
	 */
	public function onContentPrepare($context, &$item, &$params, $page = 0)
	{
		// If the item has a context, overwrite the existing one
		if ($context == 'com_finder.indexer' && !empty($item->context))
		{
			$context = $item->context;
		}
		elseif ($context == 'com_finder.indexer')
		{
			// Don't run this plugin when the content is being indexed and we have no real context
			return;
		}

		// Don't run if there is no text property (in case of bad calls) or it is empty
		if (empty($item->text))
		{
			return;
		}

		// Simple performance check to determine whether bot should process further
		if (strpos($item->text, 'field') === false)
		{
			return;
		}

		// Register FieldsHelper
		JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');

		// Prepare the text
		if (isset($item->text))
		{
			$item->text = $this->prepare($item->text, $context, $item);
		}

		// Prepare the intro text
		if (isset($item->introtext))
		{
			$item->introtext = $this->prepare($item->introtext, $context, $item);
		}
	}

	/**
	 * Prepares the given string by parsing {field} and {fieldgroup} groups and replacing them.
	 *
	 * @param   string  $string   The text to prepare
	 * @param   string  $context  The context of the content
	 * @param   object  $item     The item object
	 *
	 * @return string
	 *
	 * @since  3.8.1
	 */
	private function prepare($string, $context, $item)
	{
		// Search for {field ID} or {fieldgroup ID} tags and put the results into $matches.
		$regex = '/{(field|fieldgroup)\s+(.*?)}/i';
		preg_match_all($regex, $string, $matches, PREG_SET_ORDER);

		if (!$matches)
		{
			return $string;
		}

		$parts = FieldsHelper::extract($context);

		if (count($parts) < 2)
		{
			return $string;
		}

		$context    = $parts[0] . '.' . $parts[1];
		$fields     = FieldsHelper::getFields($context, $item, true);
		$fieldsById = array();
		$groups     = array();

		// Rearranging fields in arrays for easier lookup later.
		foreach ($fields as $field)
		{
			$fieldsById[$field->id]     = $field;
			$groups[$field->group_id][] = $field;
		}

		foreach ($matches as $i => $match)
		{
			// $match[0] is the full pattern match, $match[1] is the type (field or fieldgroup) and $match[2] the ID and optional the layout
			$explode = explode(',', $match[2]);
			$id      = (int) $explode[0];
			$output  = '';

			if ($match[1] == 'field' && $id)
			{
				if (isset($fieldsById[$id]))
				{
					$layout = !empty($explode[1]) ? trim($explode[1]) : $fieldsById[$id]->params->get('layout', 'render');
					$output = FieldsHelper::render(
						$context,
						'field.' . $layout,
						array(
							'item'    => $item,
							'context' => $context,
							'field'   => $fieldsById[$id]
						)
					);
				}
			}
			else
			{
				if ($match[2] === '*')
				{
					$match[0]     = str_replace('*', '\*', $match[0]);
					$renderFields = $fields;
				}
				else
				{
					$renderFields = isset($groups[$id]) ? $groups[$id] : '';
				}

				if ($renderFields)
				{
					$layout = !empty($explode[1]) ? trim($explode[1]) : 'render';
					$output = FieldsHelper::render(
						$context,
						'fields.' . $layout,
						array(
							'item'    => $item,
							'context' => $context,
							'fields'  => $renderFields
						)
					);
				}
			}

			$string = preg_replace("|$match[0]|", addcslashes($output, '\\$'), $string, 1);
		}

		return $string;
	}
}
PK��#]���qqcontent/fields/fields.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7.0" type="plugin" group="content" method="upgrade">
	<name>plg_content_fields</name>
	<author>Joomla! Project</author>
	<creationDate>February 2017</creationDate>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_CONTENT_FIELDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="fields">fields.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_fields.ini</language>
		<language tag="en-GB">en-GB.plg_content_fields.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)�� content/pagenavigation/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]@4'content/pagenavigation/tmpl/default.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagenavigation
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');

$lang = JFactory::getLanguage();

?>
<ul class="pager pagenav">
<?php if ($row->prev) :
	$direction = $lang->isRtl() ? 'right' : 'left'; ?>
	<li class="previous">
		<a class="hasTooltip" title="<?php echo htmlspecialchars($rows[$location-1]->title); ?>" aria-label="<?php echo JText::sprintf('JPREVIOUS_TITLE', htmlspecialchars($rows[$location-1]->title)); ?>" href="<?php echo $row->prev; ?>" rel="prev">
			<?php echo '<span class="icon-chevron-' . $direction . '" aria-hidden="true"></span> <span aria-hidden="true">' . $row->prev_label . '</span>'; ?>
		</a>
	</li>
<?php endif; ?>
<?php if ($row->next) :
	$direction = $lang->isRtl() ? 'left' : 'right'; ?>
	<li class="next">
		<a class="hasTooltip" title="<?php echo htmlspecialchars($rows[$location+1]->title); ?>" aria-label="<?php echo JText::sprintf('JNEXT_TITLE', htmlspecialchars($rows[$location+1]->title)); ?>" href="<?php echo $row->next; ?>" rel="next">
			<?php echo '<span aria-hidden="true">' . $row->next_label . '</span> <span class="icon-chevron-' . $direction . '" aria-hidden="true"></span>'; ?>
		</a>
	</li>
<?php endif; ?>
</ul>
PK��#]f�;��)content/pagenavigation/pagenavigation.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="content" method="upgrade">
	<name>plg_content_pagenavigation</name>
	<author>Joomla! Project</author>
	<creationDate>January 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_PAGENAVIGATION_XML_DESCRIPTION</description>
	<files>
		<filename plugin="pagenavigation">pagenavigation.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_content_pagenavigation.ini</language>
		<language tag="en-GB">en-GB.plg_content_pagenavigation.sys.ini</language>
	</languages>
	<config>
		<fields name="params">

			<fieldset name="basic">
				<field
					name="position"
					type="list"
					label="PLG_PAGENAVIGATION_FIELD_POSITION_LABEL"
					description="PLG_PAGENAVIGATION_FIELD_POSITION_DESC"
					default="1"
					filter="integer"
					>
					<option value="1">PLG_PAGENAVIGATION_FIELD_VALUE_BELOW</option>
					<option value="0">PLG_PAGENAVIGATION_FIELD_VALUE_ABOVE</option>
				</field>

				<field
					name="relative"
					type="list"
					label="PLG_PAGENAVIGATION_FIELD_RELATIVE_LABEL"
					description="PLG_PAGENAVIGATION_FIELD_RELATIVE_DESC"
					default="1"
					filter="integer"
					>
					<option value="1">PLG_PAGENAVIGATION_FIELD_VALUE_ARTICLE</option>
					<option value="0">PLG_PAGENAVIGATION_FIELD_VALUE_TEXT</option>
				</field>

				<field
					name="display"
					type="list"
					label="PLG_PAGENAVIGATION_FIELD_DISPLAY_LABEL"
					description="PLG_PAGENAVIGATION_FIELD_DISPLAY_DESC"
					default="0"
					filter="integer"
					>
					<option value="0">PLG_PAGENAVIGATION_FIELD_VALUE_NEXTPREV</option>
					<option value="1">PLG_PAGENAVIGATION_FIELD_VALUE_TITLE</option>
				</field>

			</fieldset>
		</fields>
	</config>
</extension>
PK��#]:k��)content/pagenavigation/pagenavigation.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagenavigation
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php');

/**
 * Pagenavigation plugin class.
 *
 * @since  1.5
 */
class PlgContentPagenavigation extends JPlugin
{
	/**
	 * If in the article view and the parameter is enabled shows the page navigation
	 *
	 * @param   string   $context  The context of the content being passed to the plugin
	 * @param   object   &$row     The article object
	 * @param   mixed    &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  mixed  void or true
	 *
	 * @since   1.6
	 */
	public function onContentBeforeDisplay($context, &$row, &$params, $page = 0)
	{
		$app   = JFactory::getApplication();
		$view  = $app->input->get('view');
		$print = $app->input->getBool('print');

		if ($print)
		{
			return false;
		}

		if ($context === 'com_content.article' && $view === 'article' && $params->get('show_item_navigation'))
		{
			$db       = JFactory::getDbo();
			$user     = JFactory::getUser();
			$lang     = JFactory::getLanguage();
			$nullDate = $db->getNullDate();

			$date = JFactory::getDate();
			$now  = $date->toSql();

			$uid        = $row->id;
			$option     = 'com_content';
			$canPublish = $user->authorise('core.edit.state', $option . '.article.' . $row->id);

			/**
			 * The following is needed as different menu items types utilise a different param to control ordering.
			 * For Blogs the `orderby_sec` param is the order controlling param.
			 * For Table and List views it is the `orderby` param.
			**/
			$params_list = $params->toArray();

			if (array_key_exists('orderby_sec', $params_list))
			{
				$order_method = $params->get('orderby_sec', '');
			}
			else
			{
				$order_method = $params->get('orderby', '');
			}

			// Additional check for invalid sort ordering.
			if ($order_method === 'front')
			{
				$order_method = '';
			}

			// Get the order code
			$orderDate = $params->get('order_date');
			$queryDate = $this->getQueryDate($orderDate);

			// Determine sort order.
			switch ($order_method)
			{
				case 'date' :
					$orderby = $queryDate;
					break;
				case 'rdate' :
					$orderby = $queryDate . ' DESC ';
					break;
				case 'alpha' :
					$orderby = 'a.title';
					break;
				case 'ralpha' :
					$orderby = 'a.title DESC';
					break;
				case 'hits' :
					$orderby = 'a.hits';
					break;
				case 'rhits' :
					$orderby = 'a.hits DESC';
					break;
				case 'order' :
					$orderby = 'a.ordering';
					break;
				case 'author' :
					$orderby = 'a.created_by_alias, u.name';
					break;
				case 'rauthor' :
					$orderby = 'a.created_by_alias DESC, u.name DESC';
					break;
				case 'front' :
					$orderby = 'f.ordering';
					break;
				default :
					$orderby = 'a.ordering';
					break;
			}

			$xwhere = ' AND (a.state = 1 OR a.state = -1)'
				. ' AND (publish_up = ' . $db->quote($nullDate) . ' OR publish_up <= ' . $db->quote($now) . ')'
				. ' AND (publish_down = ' . $db->quote($nullDate) . ' OR publish_down >= ' . $db->quote($now) . ')';

			// Array of articles in same category correctly ordered.
			$query = $db->getQuery(true);

			// Sqlsrv changes
			$case_when = ' CASE WHEN ' . $query->charLength('a.alias', '!=', '0');
			$a_id = $query->castAsChar('a.id');
			$case_when .= ' THEN ' . $query->concatenate(array($a_id, 'a.alias'), ':');
			$case_when .= ' ELSE ' . $a_id . ' END as slug';

			$case_when1 = ' CASE WHEN ' . $query->charLength('cc.alias', '!=', '0');
			$c_id = $query->castAsChar('cc.id');
			$case_when1 .= ' THEN ' . $query->concatenate(array($c_id, 'cc.alias'), ':');
			$case_when1 .= ' ELSE ' . $c_id . ' END as catslug';
			$query->select('a.id, a.title, a.catid, a.language,' . $case_when . ',' . $case_when1)
				->from('#__content AS a')
				->join('LEFT', '#__categories AS cc ON cc.id = a.catid');

			if ($order_method === 'author' || $order_method === 'rauthor')
			{
				$query->select('a.created_by, u.name');
				$query->join('LEFT', '#__users AS u ON u.id = a.created_by');
			}

			$query->where(
					'a.catid = ' . (int) $row->catid . ' AND a.state = ' . (int) $row->state
						. ($canPublish ? '' : ' AND a.access IN (' . implode(',', JAccess::getAuthorisedViewLevels($user->id)) . ') ') . $xwhere
				);
			$query->order($orderby);

			if ($app->isClient('site') && $app->getLanguageFilter())
			{
				$query->where('a.language in (' . $db->quote($lang->getTag()) . ',' . $db->quote('*') . ')');
			}

			$db->setQuery($query);
			$list = $db->loadObjectList('id');

			// This check needed if incorrect Itemid is given resulting in an incorrect result.
			if (!is_array($list))
			{
				$list = array();
			}

			reset($list);

			// Location of current content item in array list.
			$location = array_search($uid, array_keys($list));
			$rows     = array_values($list);

			$row->prev = null;
			$row->next = null;

			if ($location - 1 >= 0)
			{
				// The previous content item cannot be in the array position -1.
				$row->prev = $rows[$location - 1];
			}

			if (($location + 1) < count($rows))
			{
				// The next content item cannot be in an array position greater than the number of array postions.
				$row->next = $rows[$location + 1];
			}

			if ($row->prev)
			{
				$row->prev_label = ($this->params->get('display', 0) == 0) ? JText::_('JPREV') : $row->prev->title;
				$row->prev = JRoute::_(ContentHelperRoute::getArticleRoute($row->prev->slug, $row->prev->catid, $row->prev->language));
			}
			else
			{
				$row->prev_label = '';
				$row->prev = '';
			}

			if ($row->next)
			{
				$row->next_label = ($this->params->get('display', 0) == 0) ? JText::_('JNEXT') : $row->next->title;
				$row->next = JRoute::_(ContentHelperRoute::getArticleRoute($row->next->slug, $row->next->catid, $row->next->language));
			}
			else
			{
				$row->next_label = '';
				$row->next = '';
			}

			// Output.
			if ($row->prev || $row->next)
			{
				// Get the path for the layout file
				$path = JPluginHelper::getLayoutPath('content', 'pagenavigation');

				// Render the pagenav
				ob_start();
				include $path;
				$row->pagination = ob_get_clean();

				$row->paginationposition = $this->params->get('position', 1);

				// This will default to the 1.5 and 1.6-1.7 behavior.
				$row->paginationrelative = $this->params->get('relative', 0);
			}
		}
	}

	/**
	 * Translate an order code to a field for primary ordering.
	 *
	 * @param   string  $orderDate  The ordering code.
	 *
	 * @return  string  The SQL field(s) to order by.
	 *
	 * @since   3.3
	 */
	private static function getQueryDate($orderDate)
	{
		$db = JFactory::getDbo();

		switch ($orderDate)
		{
			// Use created if modified is not set
			case 'modified' :
				$queryDate = ' CASE WHEN a.modified = ' . $db->quote($db->getNullDate()) . ' THEN a.created ELSE a.modified END';
				break;

			// Use created if publish_up is not set
			case 'published' :
				$queryDate = ' CASE WHEN a.publish_up = ' . $db->quote($db->getNullDate()) . ' THEN a.created ELSE a.publish_up END ';
				break;

			// Use created as default
			case 'created' :
			default :
				$queryDate = ' a.created ';
				break;
		}

		return $queryDate;
	}
}
PK��#]1���MM(system/privacyconsent/privacyconsent.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.privacyconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\Utilities\ArrayHelper;

/**
 * An example custom privacyconsent plugin.
 *
 * @since  3.9.0
 */
class PlgSystemPrivacyconsent extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * Constructor
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An array that holds the plugin configuration
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		JFormHelper::addFieldPath(__DIR__ . '/field');
	}

	/**
	 * Adds additional fields to the user editing form
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm($form, $data)
	{
		if (!($form instanceof JForm))
		{
			$this->_subject->setError('JERROR_NOT_A_FORM');

			return false;
		}

		// Check we are manipulating a valid form - we only display this on user registration form and user profile form.
		$name = $form->getName();

		if (!in_array($name, array('com_users.profile', 'com_users.registration')))
		{
			return true;
		}

		// We only display this if user has not consented before
		if (is_object($data))
		{
			$userId = isset($data->id) ? $data->id : 0;

			if ($userId > 0 && $this->isUserConsented($userId))
			{
				return true;
			}
		}

		// Add the privacy policy fields to the form.
		JForm::addFormPath(__DIR__ . '/privacyconsent');
		$form->loadFile('privacyconsent');

		$privacyArticleId = $this->getPrivacyArticleId();
		$privacynote      = $this->params->get('privacy_note');

		// Push the privacy article ID into the privacy field.
		$form->setFieldAttribute('privacy', 'article', $privacyArticleId, 'privacyconsent');
		$form->setFieldAttribute('privacy', 'note', $privacynote, 'privacyconsent');
	}

	/**
	 * Method is called before user data is stored in the database
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isNew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 * @throws  InvalidArgumentException on missing required data.
	 */
	public function onUserBeforeSave($user, $isNew, $data)
	{
		// // Only check for front-end user creation/update profile
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0, 'int');

		// User already consented before, no need to check it further
		if ($userId > 0 && $this->isUserConsented($userId))
		{
			return true;
		}

		// Check that the privacy is checked if required ie only in registration from frontend.
		$option = $this->app->input->getCmd('option');
		$task   = $this->app->input->get->getCmd('task');
		$form   = $this->app->input->post->get('jform', array(), 'array');

		if ($option == 'com_users' && in_array($task, array('registration.register', 'profile.save'))
			&& empty($form['privacyconsent']['privacy']))
		{
			throw new InvalidArgumentException(Text::_('PLG_SYSTEM_PRIVACYCONSENT_FIELD_ERROR'));
		}

		return true;
	}

	/**
	 * Saves user privacy confirmation
	 *
	 * @param   array    $data    entered user data
	 * @param   boolean  $isNew   true if this is a new user
	 * @param   boolean  $result  true if saving the user worked
	 * @param   string   $error   error message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($data, $isNew, $result, $error)
	{
		// Only create an entry on front-end user creation/update profile
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		// Get the user's ID
		$userId = ArrayHelper::getValue($data, 'id', 0, 'int');

		// If user already consented before, no need to check it further
		if ($userId > 0 && $this->isUserConsented($userId))
		{
			return true;
		}

		$option = $this->app->input->getCmd('option');
		$task   = $this->app->input->get->getCmd('task');
		$form   = $this->app->input->post->get('jform', array(), 'array');

		if ($option == 'com_users'
			&&in_array($task, array('registration.register', 'profile.save'))
			&& !empty($form['privacyconsent']['privacy']))
		{
			$userId = ArrayHelper::getValue($data, 'id', 0, 'int');

			// Get the user's IP address
			$ip = $this->app->input->server->get('REMOTE_ADDR', '', 'string');

			// Get the user agent string
			$userAgent = $this->app->input->server->get('HTTP_USER_AGENT', '', 'string');

			// Create the user note
			$userNote = (object) array(
				'user_id' => $userId,
				'subject' => 'PLG_SYSTEM_PRIVACYCONSENT_SUBJECT',
				'body'    => Text::sprintf('PLG_SYSTEM_PRIVACYCONSENT_BODY', $ip, $userAgent),
				'created' => Factory::getDate()->toSql(),
			);

			try
			{
				$this->db->insertObject('#__privacy_consents', $userNote);
			}
			catch (Exception $e)
			{
				// Do nothing if the save fails
			}

			$userId = ArrayHelper::getValue($data, 'id', 0, 'int');

			$message = array(
				'action'      => 'consent',
				'id'          => $userId,
				'title'       => $data['name'],
				'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $userId,
				'userid'      => $userId,
				'username'    => $data['username'],
				'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $userId,
			);

			JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

			/* @var ActionlogsModelActionlog $model */
			$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
			$model->addLog(array($message), 'PLG_SYSTEM_PRIVACYCONSENT_CONSENT', 'plg_system_privacyconsent', $userId);
		}

		return true;
	}

	/**
	 * Remove all user privacy consent information for the given user ID
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0, 'int');

		if ($userId)
		{
			// Remove user's consent
			try
			{
				$query = $this->db->getQuery(true)
					->delete($this->db->quoteName('#__privacy_consents'))
					->where($this->db->quoteName('user_id') . ' = ' . (int) $userId);
				$this->db->setQuery($query);
				$this->db->execute();
			}
			catch (Exception $e)
			{
				$this->_subject->setError($e->getMessage());

				return false;
			}
		}

		return true;
	}

	/**
	 * If logged in users haven't agreed to privacy consent, redirect them to profile edit page, ask them to agree to
	 * privacy consent before allowing access to any other pages
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRoute()
	{
		// Run this in frontend only
		if ($this->app->isClient('administrator'))
		{
			return;
		}

		$userId = Factory::getUser()->id;

		// Check to see whether user already consented, if not, redirect to user profile page
		if ($userId > 0)
		{
			// If user consented before, no need to check it further
			if ($this->isUserConsented($userId))
			{
				return;
			}

			$option = $this->app->input->getCmd('option');
			$task   = $this->app->input->get('task');
			$view   = $this->app->input->getString('view', '');
			$layout = $this->app->input->getString('layout', '');
			$id     = $this->app->input->getInt('id');

			$privacyArticleId = $this->getPrivacyArticleId();

			/*
			 * If user is already on edit profile screen or view privacy article
			 * or press update/apply button, or logout, do nothing to avoid infinite redirect
			 */
			if ($option == 'com_users' && in_array($task, array('profile.save', 'profile.apply', 'user.logout', 'user.menulogout'))
				|| ($option == 'com_content' && $view == 'article' && $id == $privacyArticleId)
				|| ($option == 'com_users' && $view == 'profile' && $layout == 'edit'))
			{
				return;
			}

			// Redirect to com_users profile edit
			$this->app->enqueueMessage($this->getRedirectMessage(), 'notice');
			$link = 'index.php?option=com_users&view=profile&layout=edit';
			$this->app->redirect(\JRoute::_($link, false));
		}
	}

	/**
	 * Event to specify whether a privacy policy has been published.
	 *
	 * @param   array  &$policy  The privacy policy status data, passed by reference, with keys "published", "editLink" and "articlePublished".
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCheckPrivacyPolicyPublished(&$policy)
	{
		// If another plugin has already indicated a policy is published, we won't change anything here
		if ($policy['published'])
		{
			return;
		}

		$articleId = $this->params->get('privacy_article');

		if (!$articleId)
		{
			return;
		}

		// Check if the article exists in database and is published
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('id', 'state')))
			->from($this->db->quoteName('#__content'))
			->where($this->db->quoteName('id') . ' = ' . (int) $articleId);
		$this->db->setQuery($query);

		$article = $this->db->loadObject();

		// Check if the article exists
		if (!$article)
		{
			return;
		}

		// Check if the article is published
		if ($article->state == 1)
		{
			$policy['articlePublished'] = true;
		}

		$policy['published'] = true;
		$policy['editLink']  = JRoute::_('index.php?option=com_content&task=article.edit&id=' . $articleId);
	}

	/**
	 * Returns the configured redirect message and falls back to the default version.
	 *
	 * @return  string  redirect message
	 *
	 * @since   3.9.0
	 */
	private function getRedirectMessage()
	{
		$messageOnRedirect = trim($this->params->get('messageOnRedirect', ''));

		if (empty($messageOnRedirect))
		{
			return Text::_('PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DEFAULT');
		}

		return $messageOnRedirect;
	}

	/**
	 * Method to check if the given user has consented yet
	 *
	 * @param   integer  $userId  ID of uer to check
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	private function isUserConsented($userId)
	{
		$query = $this->db->getQuery(true);
		$query->select('COUNT(*)')
			->from('#__privacy_consents')
			->where('user_id = ' . (int) $userId)
			->where('subject = ' . $this->db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
			->where('state = 1');
		$this->db->setQuery($query);

		return (int) $this->db->loadResult() > 0;
	}

	/**
	 * Get privacy article ID. If the site is a multilingual website and there is associated article for the
	 * current language, ID of the associated article will be returned
	 *
	 * @return  integer
	 *
	 * @since   3.9.0
	 */
	private function getPrivacyArticleId()
	{
		$privacyArticleId = $this->params->get('privacy_article');

		if ($privacyArticleId > 0 && JLanguageAssociations::isEnabled())
		{
			$privacyAssociated = JLanguageAssociations::getAssociations('com_content', '#__content', 'com_content.item', $privacyArticleId);
			$currentLang = JFactory::getLanguage()->getTag();

			if (isset($privacyAssociated[$currentLang]))
			{
				$privacyArticleId = $privacyAssociated[$currentLang]->id;
			}
		}

		return $privacyArticleId;
	}

	/**
	 * The privacy consent expiration check code is triggered after the page has fully rendered.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRender()
	{
		if (!$this->params->get('enabled', 0))
		{
			return;
		}

		$cacheTimeout = (int) $this->params->get('cachetimeout', 30);
		$cacheTimeout = 24 * 3600 * $cacheTimeout;

		// Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if ((abs($now - $last) < $cacheTimeout))
		{
			return;
		}

		// Update last run status
		$this->params->set('lastrun', $now);
		$db    = $this->db;
		$query = $db->getQuery(true)
			->update($db->quoteName('#__extensions'))
			->set($db->quoteName('params') . ' = ' . $db->quote($this->params->toString('JSON')))
			->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
			->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
			->where($db->quoteName('element') . ' = ' . $db->quote('privacyconsent'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();
			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		// Delete the expired privacy consents
		$this->invalidateExpiredConsents();

		// Remind for privacy consents near to expire
		$this->remindExpiringConsents();

	}

	/**
	 * Method to send the remind for privacy consents renew
	 *
	 * @return  integer
	 *
	 * @since   3.9.0
	 */
	private function remindExpiringConsents()
	{
		// Load the parameters.
		$expire = (int) $this->params->get('consentexpiration', 365);
		$remind = (int) $this->params->get('remind', 30);
		$now    = JFactory::getDate()->toSql();
		$period = '-' . ($expire - $remind);

		$db    = $this->db;
		$query = $db->getQuery(true)
			->select($db->quoteName(array('r.id', 'r.user_id', 'u.email')))
			->from($db->quoteName('#__privacy_consents', 'r'))
			->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = r.user_id')
			->where($db->quoteName('subject') . ' = ' . $db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
			->where($db->quoteName('remind') . ' = 0');
		$query->where($query->dateAdd($db->quote($now), $period, 'DAY') . ' > ' . $db->quoteName('created'));

		try
		{
			$users = $db->setQuery($query)->loadObjectList();
		}
		catch (JDatabaseException $exception)
		{
			return false;
		}

		$app      = JFactory::getApplication();
		$linkMode = $app->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;

		foreach ($users as $user)
		{
			$token       = JApplicationHelper::getHash(JUserHelper::genRandomPassword());
			$hashedToken = JUserHelper::hashPassword($token);

			// The mail
			try
			{
				$substitutions = array(
					'[SITENAME]' => $app->get('sitename'),
					'[URL]'      => JUri::root(),
					'[TOKENURL]' => JRoute::link('site', 'index.php?option=com_privacy&view=remind&remind_token=' . $token, false, $linkMode, true),
					'[FORMURL]'  => JRoute::link('site', 'index.php?option=com_privacy&view=remind', false, $linkMode, true),
					'[TOKEN]'    => $token,
					'\\n'        => "\n",
				);

				$emailSubject = JText::_('PLG_SYSTEM_PRIVACYCONSENT_EMAIL_REMIND_SUBJECT');
				$emailBody = JText::_('PLG_SYSTEM_PRIVACYCONSENT_EMAIL_REMIND_BODY');

				foreach ($substitutions as $k => $v)
				{
					$emailSubject = str_replace($k, $v, $emailSubject);
					$emailBody    = str_replace($k, $v, $emailBody);
				}

				$mailer = JFactory::getMailer();
				$mailer->setSubject($emailSubject);
				$mailer->setBody($emailBody);
				$mailer->addRecipient($user->email);

				$mailResult = $mailer->Send();

				if ($mailResult instanceof JException)
				{
					return false;
				}
				elseif ($mailResult === false)
				{
					return false;
				}

				// Update the privacy_consents item to not send the reminder again
				$query->clear()
					->update($db->quoteName('#__privacy_consents'))
					->set($db->quoteName('remind') . ' = 1 ')
					->set($db->quoteName('token') . ' = ' . $db->quote($hashedToken))
					->where($db->quoteName('id') . ' = ' . (int) $user->id);
				$db->setQuery($query);

				try
				{
					$db->execute();
				}
				catch (RuntimeException $e)
				{
					return false;
				}
			}
			catch (phpmailerException $exception)
			{
				return false;
			}
		}
	}

	/**
	 * Method to delete the expired privacy consents
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	private function invalidateExpiredConsents()
	{
		// Load the parameters.
		$expire = (int) $this->params->get('consentexpiration', 365);
		$now    = JFactory::getDate()->toSql();
		$period = '-' . $expire;

		$db    = $this->db;
		$query = $db->getQuery(true);
		$query->select($db->quoteName(array('id', 'user_id')))
			->from($db->quoteName('#__privacy_consents'))
			->where($query->dateAdd($db->quote($now), $period, 'DAY') . ' > ' . $db->quoteName('created'))
			->where($db->quoteName('subject') . ' = ' . $db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
			->where($db->quoteName('state') . ' = 1');
		$db->setQuery($query);

		try
		{
			$users = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		// Do not process further if no expired consents found
		if (empty($users))
		{
			return true;
		}

		// Push a notification to the site's super users
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/models', 'MessagesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/tables');
		/** @var MessagesModelMessage $messageModel */
		$messageModel = JModelLegacy::getInstance('Message', 'MessagesModel');

		foreach ($users as $user)
		{
			$query = $db->getQuery(true)
				->update($db->quoteName('#__privacy_consents'))
				->set('state = 0')
				->where($db->quoteName('id') . ' = ' . (int) $user->id);
			$db->setQuery($query);

			try
			{
				$db->execute();
			}
			catch (RuntimeException $e)
			{
				return false;
			}

			$messageModel->notifySuperUsers(
				JText::_('PLG_SYSTEM_PRIVACYCONSENT_NOTIFICATION_USER_PRIVACY_EXPIRED_SUBJECT'),
				JText::sprintf('PLG_SYSTEM_PRIVACYCONSENT_NOTIFICATION_USER_PRIVACY_EXPIRED_MESSAGE', JFactory::getUser($user->user_id)->username)
			);
		}

		return true;
	}
	/**
	 * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since    3.9.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1))
	{
		$conf = JFactory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR . '/cache' :
							$conf->get('cache_path', JPATH_SITE . '/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
PK��#]�UqGJ
J
(system/privacyconsent/privacyconsent.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="system" method="upgrade">
	<name>plg_system_privacyconsent</name>
	<author>Joomla! Project</author>
	<creationDate>April 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_SYSTEM_PRIVACYCONSENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="privacyconsent">privacyconsent.php</filename>
		<folder>privacyconsent</folder>
		<folder>field</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_privacyconsent.ini</language>
		<language tag="en-GB">en-GB.plg_system_privacyconsent.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic" addfieldpath="/administrator/components/com_content/models/fields">
				<field
					name="privacy_note"
					type="textarea"
					label="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DESC"
					hint="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DEFAULT"
					class="span12"
					rows="7"
					cols="20"
					filter="html"
				/>
				<field
					name="privacy_article"
					type="modal_article"
					label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ARTICLE_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>
				<field
					name="messageOnRedirect"
					type="textarea"
					label="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DESC"
					hint="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DEFAULT"
					class="span12"
					rows="7"
					cols="20"
					filter="html"
				/>
			</fieldset>
			<fieldset
				name="expiration"
				label="PLG_SYSTEM_PRIVACYCONSENT_EXPIRATION_FIELDSET_LABEL"
			>
				<field
					name="enabled"
					type="radio"
					label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ENABLED_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ENABLED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
				<field
					name="cachetimeout"
					type="integer"
					label="PLG_SYSTEM_PRIVACYCONSENT_CACHETIMEOUT_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_CACHETIMEOUT_DESC"
					first="0"
					last="120"
					step="1"
					default="30"
					filter="int"
					validate="number"
				/>
				<field
					name="consentexpiration"
					type="integer"
					label="PLG_SYSTEM_PRIVACYCONSENT_CONSENTEXPIRATION_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_CONSENTEXPIRATION_DESC"
					first="180"
					last="720"
					step="30"
					default="360"
					filter="int"
					validate="number"
				/>
				<field
					name="remind"
					type="integer"
					label="PLG_SYSTEM_PRIVACYCONSENT_REMINDBEFORE_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_REMINDBEFORE_DESC"
					first="0"
					last="120"
					step="1"
					default="30"
					filter="int"
					validate="number"
				/>
				<field
					name="lastrun"
					type="hidden"
					default="0"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]��ɢ�
�
'system/privacyconsent/field/privacy.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.privacyconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;

JFormHelper::loadFieldClass('radio');

/**
 * Provides input for privacy
 *
 * @since  3.9.0
 */
class JFormFieldprivacy extends JFormFieldRadio
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $type = 'privacy';

	/**
	 * Method to get the field input markup.
	 *
	 * @return  string   The field input markup.
	 *
	 * @since   3.9.0
	 */
	protected function getInput()
	{
		// Display the message before the field
		echo $this->getRenderer('plugins.system.privacyconsent.message')->render($this->getLayoutData());

		return parent::getInput();
	}

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.9.0
	 */
	protected function getLabel()
	{
		if ($this->hidden)
		{
			return '';
		}

		return $this->getRenderer('plugins.system.privacyconsent.label')->render($this->getLayoutData());

	}

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.9.4
	 */
	protected function getLayoutData()
	{
		$data = parent::getLayoutData();

		$article = false;
		$privacyArticle = $this->element['article'] > 0 ? (int) $this->element['article'] : 0;

		if ($privacyArticle && Factory::getApplication()->isClient('site'))
		{
			$db    = Factory::getDbo();
			$query = $db->getQuery(true)
				->select($db->quoteName(array('id', 'alias', 'catid', 'language')))
				->from($db->quoteName('#__content'))
				->where($db->quoteName('id') . ' = ' . (int) $privacyArticle);
			$db->setQuery($query);
			$article = $db->loadObject();

			JLoader::register('ContentHelperRoute', JPATH_BASE . '/components/com_content/helpers/route.php');

			$slug = $article->alias ? ($article->id . ':' . $article->alias) : $article->id;
			$article->link  = ContentHelperRoute::getArticleRoute($slug, $article->catid, $article->language);
		}

		$extraData = array(
			'privacynote' => !empty($this->element['note']) ? $this->element['note'] : Text::_('PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DEFAULT'),
			'options' => $this->getOptions(),
			'value'   => (string) $this->value,
			'translateLabel' => $this->translateLabel,
			'translateDescription' => $this->translateDescription,
			'translateHint' => $this->translateHint,
			'privacyArticle' => $privacyArticle,
			'article' => $article,
		);

		return array_merge($data, $extraData);
	}
}
PK��#]�)��system/privacyconsent/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�h=::7system/privacyconsent/privacyconsent/privacyconsent.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="privacyconsent">
		<fieldset
			name="privacyconsent"
			label="PLG_SYSTEM_PRIVACYCONSENT_LABEL"
		>
			<field
				name="privacy"
				type="privacy"
				label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_LABEL"
				description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_DESC"
				default="0"
				filter="integer"
				required="true"
				>
				<option value="1">PLG_SYSTEM_PRIVACYCONSENT_OPTION_AGREE</option>
				<option value="0">PLG_SYSTEM_PRIVACYCONSENT_OPTION_DO_NOT_AGREE</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]��&�V-V-0system/updatenotification/updatenotification.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.updatenotification
 *
 * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

// Uncomment the following line to enable debug mode (update notification email sent every single time)
// define('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG', 1);

/**
 * Joomla! Update Notification plugin
 *
 * Sends out an email to all Super Users or a predefined email address when a new Joomla! version is available.
 *
 * This plugin is a direct adaptation of the corresponding plugin in Akeeba Ltd's Admin Tools. The author has
 * consented to relicensing their plugin's code under GPLv2 or later (the original version was licensed under
 * GPLv3 or later) to allow its inclusion in the Joomla! CMS.
 *
 * @since  3.5
 */
class PlgSystemUpdatenotification extends JPlugin
{
	/**
	 * Load plugin language files automatically
	 *
	 * @var    boolean
	 * @since  3.6.3
	 */
	protected $autoloadLanguage = true;

	/**
	 * The update check and notification email code is triggered after the page has fully rendered.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	public function onAfterRender()
	{
		// Get the timeout for Joomla! updates, as configured in com_installer's component parameters
		$component = JComponentHelper::getComponent('com_installer');

		/** @var \Joomla\Registry\Registry $params */
		$params        = $component->params;
		$cache_timeout = (int) $params->get('cachetimeout', 6);
		$cache_timeout = 3600 * $cache_timeout;

		// Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if (!defined('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG') && (abs($now - $last) < $cache_timeout))
		{
			return;
		}

		// Update last run status
		// If I have the time of the last run, I can update, otherwise insert
		$this->params->set('lastrun', $now);

		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
					->update($db->qn('#__extensions'))
					->set($db->qn('params') . ' = ' . $db->q($this->params->toString('JSON')))
					->where($db->qn('type') . ' = ' . $db->q('plugin'))
					->where($db->qn('folder') . ' = ' . $db->q('system'))
					->where($db->qn('element') . ' = ' . $db->q('updatenotification'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		// This is the extension ID for Joomla! itself
		$eid = 700;

		// Get any available updates
		$updater = JUpdater::getInstance();
		$results = $updater->findUpdates(array($eid), $cache_timeout);

		// If there are no updates our job is done. We need BOTH this check AND the one below.
		if (!$results)
		{
			return;
		}

		// Unfortunately Joomla! MVC doesn't allow us to autoload classes
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_installer/models', 'InstallerModel');

		// Get the update model and retrieve the Joomla! core updates
		$model = JModelLegacy::getInstance('Update', 'InstallerModel');
		$model->setState('filter.extension_id', $eid);
		$updates = $model->getItems();

		// If there are no updates we don't have to notify anyone about anything. This is NOT a duplicate check.
		if (empty($updates))
		{
			return;
		}

		// Get the available update
		$update = array_pop($updates);

		// Check the available version. If it's the same or less than the installed version we have no updates to notify about.
		if (version_compare($update->version, JVERSION, 'le'))
		{
			return;
		}

		// If we're here, we have updates. First, get a link to the Joomla! Update component.
		$baseURL  = JUri::base();
		$baseURL  = rtrim($baseURL, '/');
		$baseURL .= (substr($baseURL, -13) !== 'administrator') ? '/administrator/' : '/';
		$baseURL .= 'index.php?option=com_joomlaupdate';
		$uri      = new JUri($baseURL);

		/**
		 * Some third party security solutions require a secret query parameter to allow log in to the administrator
		 * backend of the site. The link generated above will be invalid and could probably block the user out of their
		 * site, confusing them (they can't understand the third party security solution is not part of Joomla! proper).
		 * So, we're calling the onBuildAdministratorLoginURL system plugin event to let these third party solutions
		 * add any necessary secret query parameters to the URL. The plugins are supposed to have a method with the
		 * signature:
		 *
		 * public function onBuildAdministratorLoginURL(JUri &$uri);
		 *
		 * The plugins should modify the $uri object directly and return null.
		 */

		JEventDispatcher::getInstance()->trigger('onBuildAdministratorLoginURL', array(&$uri));

		// Let's find out the email addresses to notify
		$superUsers    = array();
		$specificEmail = $this->params->get('email', '');

		if (!empty($specificEmail))
		{
			$superUsers = $this->getSuperUsers($specificEmail);
		}

		if (empty($superUsers))
		{
			$superUsers = $this->getSuperUsers();
		}

		if (empty($superUsers))
		{
			return;
		}

		/*
		 * Load the appropriate language. We try to load English (UK), the current user's language and the forced
		 * language preference, in this order. This ensures that we'll never end up with untranslated strings in the
		 * update email which would make Joomla! seem bad. So, please, if you don't fully understand what the
		 * following code does DO NOT TOUCH IT. It makes the difference between a hobbyist CMS and a professional
		 * solution! 
		 */
		$jLanguage = JFactory::getLanguage();
		$jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, 'en-GB', true, true);
		$jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, null, true, false);

		// Then try loading the preferred (forced) language
		$forcedLanguage = $this->params->get('language_override', '');

		if (!empty($forcedLanguage))
		{
			$jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, $forcedLanguage, true, false);
		}

		// Set up the email subject and body

		$email_subject = JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT');
		$email_body    = JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY');

		// Replace merge codes with their values
		$newVersion = $update->version;

		$jVersion       = new JVersion;
		$currentVersion = $jVersion->getShortVersion();

		$jConfig  = JFactory::getConfig();
		$sitename = $jConfig->get('sitename');
		$mailFrom = $jConfig->get('mailfrom');
		$fromName = $jConfig->get('fromname');

		$substitutions = array(
			'[NEWVERSION]'  => $newVersion,
			'[CURVERSION]'  => $currentVersion,
			'[SITENAME]'    => $sitename,
			'[URL]'         => JUri::base(),
			'[LINK]'        => $uri->toString(),
			'[RELEASENEWS]' => 'https://www.joomla.org/announcements/release-news/',
			'\\n'           => "\n",
		);

		foreach ($substitutions as $k => $v)
		{
			$email_subject = str_replace($k, $v, $email_subject);
			$email_body    = str_replace($k, $v, $email_body);
		}

		// Send the emails to the Super Users
		foreach ($superUsers as $superUser)
		{
			$mailer = JFactory::getMailer();
			$mailer->setSender(array($mailFrom, $fromName));
			$mailer->addRecipient($superUser->email);
			$mailer->setSubject($email_subject);
			$mailer->setBody($email_body);
			$mailer->Send();
		}
	}

	/**
	 * Returns the Super Users email information. If you provide a comma separated $email list
	 * we will check that these emails do belong to Super Users and that they have not blocked
	 * system emails.
	 *
	 * @param   null|string  $email  A list of Super Users to email
	 *
	 * @return  array  The list of Super User emails
	 *
	 * @since   3.5
	 */
	private function getSuperUsers($email = null)
	{
		// Get a reference to the database object
		$db = JFactory::getDbo();

		// Convert the email list to an array
		if (!empty($email))
		{
			$temp   = explode(',', $email);
			$emails = array();

			foreach ($temp as $entry)
			{
				$entry    = trim($entry);
				$emails[] = $db->q($entry);
			}

			$emails = array_unique($emails);
		}
		else
		{
			$emails = array();
		}

		// Get a list of groups which have Super User privileges
		$ret = array();

		try
		{
			$rootId    = JTable::getInstance('Asset', 'JTable')->getRootId();
			$rules     = JAccess::getAssetRules($rootId)->getData();
			$rawGroups = $rules['core.admin']->getData();
			$groups    = array();

			if (empty($rawGroups))
			{
				return $ret;
			}

			foreach ($rawGroups as $g => $enabled)
			{
				if ($enabled)
				{
					$groups[] = $db->q($g);
				}
			}

			if (empty($groups))
			{
				return $ret;
			}
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		// Get the user IDs of users belonging to the SA groups
		try
		{
			$query = $db->getQuery(true)
						->select($db->qn('user_id'))
						->from($db->qn('#__user_usergroup_map'))
						->where($db->qn('group_id') . ' IN(' . implode(',', $groups) . ')');
			$db->setQuery($query);
			$rawUserIDs = $db->loadColumn(0);

			if (empty($rawUserIDs))
			{
				return $ret;
			}

			$userIDs = array();

			foreach ($rawUserIDs as $id)
			{
				$userIDs[] = $db->q($id);
			}
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		// Get the user information for the Super Administrator users
		try
		{
			$query = $db->getQuery(true)
						->select(
							array(
								$db->qn('id'),
								$db->qn('username'),
								$db->qn('email'),
							)
						)->from($db->qn('#__users'))
						->where($db->qn('id') . ' IN(' . implode(',', $userIDs) . ')')
						->where($db->qn('block') . ' = 0')
						->where($db->qn('sendEmail') . ' = ' . $db->q('1'));

			if (!empty($emails))
			{
				$query->where('LOWER(' . $db->qn('email') . ') IN(' . implode(',', array_map('strtolower', $emails)) . ')');
			}

			$db->setQuery($query);
			$ret = $db->loadObjectList();
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		return $ret;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1))
	{
		$conf = JFactory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR . '/cache' :
							$conf->get('cache_path', JPATH_SITE . '/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
PK��#]�Z::0system/updatenotification/updatenotification.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin" group="system" method="upgrade">
	<name>plg_system_updatenotification</name>
	<author>Joomla! Project</author>
	<creationDate>May 2015</creationDate>
	<copyright>(C) 2015 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.5.0</version>
	<description>PLG_SYSTEM_UPDATENOTIFICATION_XML_DESCRIPTION</description>
	<files>
		<filename plugin="updatenotification">updatenotification.php</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB.plg_system_updatenotification.ini</language>
		<language tag="en-GB">en-GB.plg_system_updatenotification.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="email"
					type="text"
					label="PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_LBL"
					description="PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_DESC"
					default=""
					size="40"
				/>

				<field
					name="language_override"
					type="language"
					label="PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_LBL"
					description="PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_DESC"
					default=""
					client="administrator"
					>
					<option value="">PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_NONE</option>
				</field>

				<field
					name="lastrun"
					type="hidden"
					default="0"
					size="15"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�����9system/updatenotification/postinstall/updatecachetime.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.updatenotification
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

/**
 * Checks if the com_installer config for the cache Hours are eq 0 and the updatenotification Plugin is enabled
 *
 * @return  boolean
 *
 * @since   3.6.3
 */
function updatecachetime_postinstall_condition()
{
	$cacheTimeout = (int) JComponentHelper::getComponent('com_installer')->params->get('cachetimeout', 6);

	// Check if cachetimeout is eq zero
	if ($cacheTimeout === 0 && JPluginHelper::isEnabled('system', 'updatenotification'))
	{
		return true;
	}

	return false;
}

/**
 * Sets the cachetimeout back to the default (6 hours)
 *
 * @return  void
 *
 * @since   3.6.3
 */
function updatecachetime_postinstall_action()
{
	$installer = JComponentHelper::getComponent('com_installer');

	// Sets the cachetimeout back to the default (6 hours)
	$installer->params->set('cachetimeout', 6);

	// Save the new parameters back to com_installer
	$table = JTable::getInstance('extension');
	$table->load($installer->id);
	$table->bind(array('params' => $installer->params->toString()));

	// Store the changes
	if (!$table->store())
	{
		// If there is an error show it to the admin
		JFactory::getApplication()->enqueueMessage($table->getError(), 'error');
	}
}
PK��#]�)��#system/updatenotification/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��system/redirect/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]1�r��!system/redirect/form/excludes.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset>
		<field
			name="term"
			type="text"
			label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_TERM_LABEL"
			description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_TERM_DESC"
			required="true"
		/>
		<field
			name="regexp"
			type="checkbox"
			label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_REGEXP_LABEL"
			description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_REGEXP_DESC"
			filter="integer"
		/>
	</fieldset>
</form>
PK��#]-LS�TTsystem/redirect/redirect.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_redirect</name>
	<author>Joomla! Project</author>
	<creationDate>April 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_REDIRECT_XML_DESCRIPTION</description>
	<files>
		<folder>form</folder>
		<filename plugin="redirect">redirect.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_redirect.ini</language>
		<language tag="en-GB">en-GB.plg_system_redirect.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="collect_urls"
					type="radio"
					label="PLG_SYSTEM_REDIRECT_FIELD_COLLECT_URLS_LABEL"
					description="PLG_SYSTEM_REDIRECT_FIELD_COLLECT_URLS_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JENABLED</option>
					<option value="0">JDISABLED</option>
				</field>
				<field
					name="includeUrl"
					type="radio"
					label="PLG_SYSTEM_REDIRECT_FIELD_STORE_FULL_URL_LABEL"
					description="PLG_SYSTEM_REDIRECT_FIELD_STORE_FULL_URL_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
				<field
					name="exclude_urls"
					type="subform"
					label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_LABEL"
					description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_DESC"
					multiple="true"
					formsource="plugins/system/redirect/form/excludes.xml"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�6j�%&%&system/redirect/redirect.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.redirect
 *
 * @copyright   (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;
use Joomla\String\StringHelper;

/**
 * Plugin class for redirect handling.
 *
 * @since  1.6
 */
class PlgSystemRedirect extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded automatically.
	 *
	 * @var    boolean
	 * @since  3.4
	 */
	protected $autoloadLanguage = false;

	/**
	 * The global exception handler registered before the plugin was instantiated
	 *
	 * @var    callable
	 * @since  3.6
	 */
	private static $previousExceptionHandler;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   1.6
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// Set the JError handler for E_ERROR to be the class' handleError method.
		JError::setErrorHandling(E_ERROR, 'callback', array('PlgSystemRedirect', 'handleError'));

		// Register the previously defined exception handler so we can forward errors to it
		self::$previousExceptionHandler = set_exception_handler(array('PlgSystemRedirect', 'handleException'));
	}

	/**
	 * Method to handle an error condition from JError.
	 *
	 * @param   JException  $error  The JException object to be handled.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public static function handleError(JException $error)
	{
		self::doErrorHandling($error);
	}

	/**
	 * Method to handle an uncaught exception.
	 *
	 * @param   Exception|Throwable  $exception  The Exception or Throwable object to be handled.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 * @throws  InvalidArgumentException
	 */
	public static function handleException($exception)
	{
		// If this isn't a Throwable then bail out
		if (!($exception instanceof Throwable) && !($exception instanceof Exception))
		{
			throw new InvalidArgumentException(
				sprintf('The error handler requires an Exception or Throwable object, a "%s" object was given instead.', get_class($exception))
			);
		}

		self::doErrorHandling($exception);
	}

	/**
	 * Internal processor for all error handlers
	 *
	 * @param   Exception|Throwable  $error  The Exception or Throwable object to be handled.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	private static function doErrorHandling($error)
	{
		$app = JFactory::getApplication();

		if ($app->isClient('administrator') || ((int) $error->getCode() !== 404))
		{
			// Proxy to the previous exception handler if available, otherwise just render the error page
			if (self::$previousExceptionHandler)
			{
				call_user_func_array(self::$previousExceptionHandler, array($error));
			}
			else
			{
				JErrorPage::render($error);
			}
		}

		$uri = JUri::getInstance();

		// These are the original URLs
		$orgurl                = rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'query', 'fragment')));
		$orgurlRel             = rawurldecode($uri->toString(array('path', 'query', 'fragment')));

		// The above doesn't work for sub directories, so do this
		$orgurlRootRel         = str_replace(JUri::root(), '', $orgurl);

		// For when users have added / to the url
		$orgurlRootRelSlash    = str_replace(JUri::root(), '/', $orgurl);
		$orgurlWithoutQuery    = rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'fragment')));
		$orgurlRelWithoutQuery = rawurldecode($uri->toString(array('path', 'fragment')));

		// These are the URLs we save and use
		$url                = StringHelper::strtolower(rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'query', 'fragment'))));
		$urlRel             = StringHelper::strtolower(rawurldecode($uri->toString(array('path', 'query', 'fragment'))));

		// The above doesn't work for sub directories, so do this
		$urlRootRel         = str_replace(JUri::root(), '', $url);

		// For when users have added / to the url
		$urlRootRelSlash    = str_replace(JUri::root(), '/', $url);
		$urlWithoutQuery    = StringHelper::strtolower(rawurldecode($uri->toString(array('scheme', 'host', 'port', 'path', 'fragment'))));
		$urlRelWithoutQuery = StringHelper::strtolower(rawurldecode($uri->toString(array('path', 'fragment'))));

		$plugin = JPluginHelper::getPlugin('system', 'redirect');

		$params = new Registry($plugin->params);

		$excludes = (array) $params->get('exclude_urls');

		$skipUrl = false;

		foreach ($excludes as $exclude)
		{
			if (empty($exclude->term))
			{
				continue;
			}

			if (!empty($exclude->regexp))
			{
				// Only check $url, because it includes all other sub urls
				if (preg_match('/' . $exclude->term . '/i', $orgurlRel))
				{
					$skipUrl = true;
					break;
				}
			}
			else
			{
				if (StringHelper::strpos($orgurlRel, $exclude->term) !== false)
				{
					$skipUrl = true;
					break;
				}
			}
		}

		// Why is this (still) here?
		if ($skipUrl || (strpos($url, 'mosConfig_') !== false) || (strpos($url, '=http://') !== false))
		{
			JErrorPage::render($error);
		}

		$db = JFactory::getDbo();

		$query = $db->getQuery(true);

		$query->select('*')
			->from($db->quoteName('#__redirect_links'))
			->where(
				'('
				. $db->quoteName('old_url') . ' = ' . $db->quote($url)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($urlRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($urlRootRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($urlRootRelSlash)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($urlWithoutQuery)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($urlRelWithoutQuery)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($orgurl)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($orgurlRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($orgurlRootRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($orgurlRootRelSlash)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($orgurlWithoutQuery)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' . $db->quote($orgurlRelWithoutQuery)
				. ')'
			);

		$db->setQuery($query);

		$redirect = null;

		try
		{
			$redirects = $db->loadAssocList();
		}
		catch (Exception $e)
		{
			JErrorPage::render(new Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e));
		}

		$possibleMatches = array_unique(
			array(
				$url,
				$urlRel,
				$urlRootRel,
				$urlRootRelSlash,
				$urlWithoutQuery,
				$urlRelWithoutQuery,
				$orgurl,
				$orgurlRel,
				$orgurlRootRel,
				$orgurlRootRelSlash,
				$orgurlWithoutQuery,
				$orgurlRelWithoutQuery,
			)
		);

		foreach ($possibleMatches as $match)
		{
			if (($index = array_search($match, array_column($redirects, 'old_url'))) !== false)
			{
				$redirect = (object) $redirects[$index];

				if ((int) $redirect->published === 1)
				{
					break;
				}
			}
		}

		// A redirect object was found and, if published, will be used
		if ($redirect !== null && ((int) $redirect->published === 1))
		{
			if (!$redirect->header || (bool) JComponentHelper::getParams('com_redirect')->get('mode', false) === false)
			{
				$redirect->header = 301;
			}

			if ($redirect->header < 400 && $redirect->header >= 300)
			{
				$urlQuery = $uri->getQuery();

				$oldUrlParts = parse_url($redirect->old_url);

				$newUrl = $redirect->new_url;

				if ($urlQuery !== '' && empty($oldUrlParts['query']))
				{
					$newUrl .= '?' . $urlQuery;
				}

				$dest = JUri::isInternal($newUrl) || strpos($newUrl, 'http') === false ?
					JRoute::_($newUrl) : $newUrl;

				// In case the url contains double // lets remove it
				$destination = str_replace(JUri::root() . '/', JUri::root(), $dest);

				// Always count redirect hits
				$redirect->hits++;

				try
				{
					$db->updateObject('#__redirect_links', $redirect, 'id');
				}
				catch (Exception $e)
				{
					// We don't log issues for now
				}

				$app->redirect($destination, (int) $redirect->header);
			}

			JErrorPage::render(new RuntimeException($error->getMessage(), $redirect->header, $error));
		}
		// No redirect object was found so we create an entry in the redirect table
		elseif ($redirect === null)
		{
			$params = new Registry(JPluginHelper::getPlugin('system', 'redirect')->params);

			if ((bool) $params->get('collect_urls', 1))
			{
				if (!$params->get('includeUrl', 1))
				{
					$url = $urlRel;
				}

				$data = (object) array(
					'id' => 0,
					'old_url' => $url,
					'referer' => $app->input->server->getString('HTTP_REFERER', ''),
					'hits' => 1,
					'published' => 0,
					'created_date' => JFactory::getDate()->toSql()
				);

				try
				{
					$db->insertObject('#__redirect_links', $data, 'id');
				}
				catch (Exception $e)
				{
					JErrorPage::render(new Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e));
				}
			}
		}
		// We have an unpublished redirect object, increment the hit counter
		else
		{
			$redirect->hits++;

			try
			{
				$db->updateObject('#__redirect_links', $redirect, 'id');
			}
			catch (Exception $e)
			{
				JErrorPage::render(new Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'), 500, $e));
			}
		}

		// Proxy to the previous exception handler if available, otherwise just render the error page
		if (self::$previousExceptionHandler)
		{
			call_user_func_array(self::$previousExceptionHandler, array($error));
		}
		else
		{
			JErrorPage::render($error);
		}
	}
}
PK��#]�)��system/logout/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#][�G%�
�
system/logout/logout.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.logout
 *
 * @copyright   (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plugin class for logout redirect handling.
 *
 * @since  1.6
 */
class PlgSystemLogout extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.7.3
	 */
	protected $app;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe -- event dispatcher.
	 * @param   object  $config    An optional associative array of configuration settings.
	 *
	 * @since   1.6
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// If we are on admin don't process.
		if (!$this->app->isClient('site'))
		{
			return;
		}

		$hash  = JApplicationHelper::getHash('PlgSystemLogout');

		if ($this->app->input->cookie->getString($hash))
		{
			// Destroy the cookie.
			$this->app->input->cookie->set($hash, '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));

			// Set the error handler for E_ALL to be the class handleError method.
			JError::setErrorHandling(E_ALL, 'callback', array('PlgSystemLogout', 'handleError'));
		}
	}

	/**
	 * Method to handle any logout logic and report back to the subject.
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (client, ...).
	 *
	 * @return  boolean  Always returns true.
	 *
	 * @since   1.6
	 */
	public function onUserLogout($user, $options = array())
	{
		if ($this->app->isClient('site'))
		{
			// Create the cookie.
			$this->app->input->cookie->set(
				JApplicationHelper::getHash('PlgSystemLogout'),
				true,
				time() + 86400,
				$this->app->get('cookie_path', '/'),
				$this->app->get('cookie_domain', ''),
				$this->app->isHttpsForced(),
				true
			);
		}

		return true;
	}

	/**
	 * Method to handle an error condition.
	 *
	 * @param   Exception  &$error  The Exception object to be handled.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public static function handleError(&$error)
	{
		// Get the application object.
		$app = JFactory::getApplication();

		// Make sure the error is a 403 and we are in the frontend.
		if ($error->getCode() == 403 && $app->isClient('site'))
		{
			// Redirect to the home page.
			$app->enqueueMessage(JText::_('PLG_SYSTEM_LOGOUT_REDIRECT'));
			$app->redirect('index.php');
		}
		else
		{
			// Render the custom error page.
			JError::customErrorPage($error);
		}
	}
}
PK��#]��C�system/logout/logout.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_logout</name>
	<author>Joomla! Project</author>
	<creationDate>April 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_LOGOUT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="logout">logout.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_logout.ini</language>
		<language tag="en-GB">en-GB.plg_system_logout.sys.ini</language>
	</languages>
</extension>
PK��#]�)��system/p3p/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�!$$system/p3p/p3p.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_p3p</name>
	<author>Joomla! Project</author>
	<creationDate>September 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_P3P_XML_DESCRIPTION</description>
	<files>
		<filename plugin="p3p">p3p.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_p3p.ini</language>
		<language tag="en-GB">en-GB.plg_system_p3p.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="header"
					type="text"
					label="PLG_P3P_HEADER_LABEL"
					description="PLG_P3P_HEADER_DESCRIPTION"
					default="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
					size="37"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�g��system/p3p/p3p.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.p3p
 *
 * @copyright   (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! P3P Header Plugin.
 *
 * @since  1.6
 * @deprecate  4.0  Obsolete
 */
class PlgSystemP3p extends JPlugin
{
	/**
	 * After initialise.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 * @deprecate  4.0  Obsolete
	 */
	public function onAfterInitialise()
	{
		// Get the header.
		$header = $this->params->get('header', 'NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM');
		$header = trim($header);

		// Bail out on empty header (why would anyone do that?!).
		if (empty($header))
		{
			return;
		}

		// Replace any existing P3P headers in the response.
		JFactory::getApplication()->setHeader('P3P', 'CP="' . $header . '"', true);
	}
}
PK��#]~��[{
{
!system/rsfprecaptchav2/script.phpnu�[���<?php
/**
* @package RSForm!Pro
* @copyright (C) 2007-2017 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

class plgSystemRsfprecaptchav2InstallerScript
{
	protected static $minJoomla = '3.9.0';
	protected static $minComponent = '3.1.0';

	public function preflight($type, $parent)
	{
		if ($type == 'uninstall')
		{
			return true;
		}

		try
		{
			$source = $parent->getParent()->getPath('source');

			$jversion = new JVersion();
			if (!$jversion->isCompatible(static::$minJoomla))
			{
				throw new Exception(sprintf('Please upgrade to at least Joomla! %s before continuing!', static::$minJoomla));
			}

			if (!file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/rsform.php'))
			{
				throw new Exception('Please install the RSForm! Pro component before continuing.');
			}

			if (!file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/assets.php') || !file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/version.php'))
			{
				throw new Exception(sprintf('Please upgrade RSForm! Pro to at least version %s before continuing!', static::$minComponent));
			}

			// Check version matches
			require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/version.php';

			if (!class_exists('RSFormProVersion') || version_compare((string) new RSFormProVersion, static::$minComponent, '<'))
			{
				throw new Exception(sprintf('Please upgrade RSForm! Pro to at least version %s before continuing!', static::$minComponent));
			}

			// All good.
			// Copy needed files
			$this->copyFiles($source);
			
			// Update? Run our SQL file
			if ($type == 'update')
			{
				$this->runSQL($source, 'install');
			}
		}
		catch (Exception $e)
		{
			JFactory::getApplication()->enqueueMessage($e->getMessage(), 'error');
			return false;
		}
		
		return true;
	}
	
	protected function copyFiles($source)
	{
		// Copy /admin files
		$src	= $source.'/admin';
		$dest 	= JPATH_ADMINISTRATOR.'/components/com_rsform';
		if (!JFolder::copy($src, $dest, '', true))
		{
			throw new Exception('Could not copy to '.str_replace(JPATH_ADMINISTRATOR, '', $dest).', please make sure destination is writable!');
		}
	}

	protected function runSQL($source, $file)
	{
		$db = JFactory::getDbo();
		$sqlfile = $source . '/sql/mysql/' . $file . '.sql';

		if (file_exists($sqlfile))
		{
			$buffer = file_get_contents($sqlfile);
			if ($buffer !== false)
			{
				$queries = $db->splitSql($buffer);
				foreach ($queries as $query)
				{
					$query = trim($query);
					if ($query != '')
					{
						$db->setQuery($query)->execute();
					}
				}
			}
		}
	}
}PK��#]�)�� system/rsfprecaptchav2/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]
J���.system/rsfprecaptchav2/forms/configuration.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="params">
		<field name="recaptchav2.site.key" type="text" label="RSFP_RECAPTCHAV2_SITE_KEY" size="100" />
		<field name="recaptchav2.secret.key" type="text" label="RSFP_RECAPTCHAV2_SECRET_KEY" size="100" />
		<field name="recaptchav2.language" type="list" label="RSFP_RECAPTCHAV2_LANGUAGE">
			<option value="auto">RSFP_RECAPTCHAV2_LANGUAGE_AUTO</option>
			<option value="site">RSFP_RECAPTCHAV2_LANGUAGE_SITE</option>
		</field>
		<field name="recaptchav2.noscript" type="radio" class="btn-group btn-group-yesno" label="RSFP_RECAPTCHAV2_NOSCRIPT" description="RSFP_RECAPTCHAV2_NOSCRIPT_DESC">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>
		<field name="recaptchav2.asyncdefer" type="radio" class="btn-group btn-group-yesno" label="RSFP_RECAPTCHAV2_ASYNC_DEFER" description="RSFP_RECAPTCHAV2_ASYNC_DEFER_DESC">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>
		<field name="recaptchav2.domain" type="list" label="PLG_SYSTEM_RSFPRECAPTCHAV2_DOMAIN" description="PLG_SYSTEM_RSFPRECAPTCHAV2_DOMAIN_DESC">
			<option value="google.com">google.com</option>
			<option value="recaptcha.net">recaptcha.net</option>
		</field>
	</fieldset>
</form>PK��#]�#o,,!system/rsfprecaptchav2/index.htmlnu�[���<html><body bgcolor="#FFFFFF"></body></html>PK��#]�#o,,+system/rsfprecaptchav2/sql/mysql/index.htmlnu�[���<html><body bgcolor="#FFFFFF"></body></html>PK��#]m�kk.system/rsfprecaptchav2/sql/mysql/uninstall.sqlnu�[���DELETE FROM #__rsform_component_types WHERE ComponentTypeId = 2424;
DELETE FROM #__rsform_component_type_fields WHERE ComponentTypeId = 2424;

DELETE FROM #__rsform_config WHERE SettingName = 'recaptchav2.site.key';
DELETE FROM #__rsform_config WHERE SettingName = 'recaptchav2.secret.key';
DELETE FROM #__rsform_config WHERE SettingName = 'recaptchav2.language';PK��#]���dd,system/rsfprecaptchav2/sql/mysql/install.sqlnu�[���DELETE FROM `#__rsform_component_types` WHERE `ComponentTypeId` IN (2424);

INSERT IGNORE INTO `#__rsform_component_types` (`ComponentTypeId`, `ComponentTypeName`, `CanBeDuplicated`) VALUES
(2424, 'recaptchav2', 0);

INSERT IGNORE INTO `#__rsform_config` (`SettingName`, `SettingValue`) VALUES
('recaptchav2.site.key', ''),
('recaptchav2.secret.key', ''),
('recaptchav2.language', 'auto'),
('recaptchav2.noscript', '1'),
('recaptchav2.asyncdefer', '0'),
('recaptchav2.domain', 'google.com');

DELETE FROM `#__rsform_component_type_fields` WHERE ComponentTypeId = 2424;

INSERT IGNORE INTO `#__rsform_component_type_fields` (`ComponentTypeId`, `FieldName`, `FieldType`, `FieldValues`, `Properties`, `Ordering`) VALUES
(2424, 'NAME', 'textbox', '', '', 0),
(2424, 'CAPTION', 'textbox', '', '', 1),
(2424, 'ADDITIONALATTRIBUTES', 'textarea', '', '', 2),
(2424, 'DESCRIPTION', 'textarea', '', '', 3),
(2424, 'VALIDATIONMESSAGE', 'textarea', 'INVALIDINPUT', '', 4),
(2424, 'THEME', 'select', 'LIGHT\r\nDARK', '', 5),
(2424, 'TYPE', 'select', 'IMAGE\r\nAUDIO', '', 6),
(2424, 'SIZE', 'select', 'NORMAL\r\nCOMPACT\r\nINVISIBLE', '{"case":{"INVISIBLE":{"show":["BADGE"],"hide":[]},"NORMAL":{"show":[],"hide":["BADGE"]},"COMPACT":{"show":[],"hide":["BADGE"]}}}', 7),
(2424, 'BADGE', 'select', 'INLINE\r\nBOTTOMRIGHT\r\nBOTTOMLEFT', '', 8),
(2424, 'COMPONENTTYPE', 'hidden', '2424', '', 8);PK��#]�#o,,%system/rsfprecaptchav2/sql/index.htmlnu�[���<html><body bgcolor="#FFFFFF"></body></html>PK��#]m�L��*system/rsfprecaptchav2/rsfprecaptchav2.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="system" method="upgrade">
	<name>System - RSForm! Pro reCAPTCHA v2</name>
	<author>RSJoomla!</author>
	<creationDate>December 2019</creationDate>
	<copyright>(C) 2014-2022 www.rsjoomla.com</copyright>
	<license>GNU General Public License</license>
	<authorEmail>support@rsjoomla.com</authorEmail>
	<authorUrl>www.rsjoomla.com</authorUrl>
	<version>3.1.1</version>
	<description><![CDATA[PLG_SYSTEM_RSFPRECAPTCHAV2_DESC]]></description>
	<scriptfile>script.php</scriptfile>
	
	<updateservers>
        <server type="extension" priority="1" name="RSForm! Pro - reCAPTCHA v2 Plugin">https://www.rsjoomla.com/updates/com_rsform/Plugins/plg_recaptchav2.xml</server>
    </updateservers>
	
	<install>
		<sql>
			<file driver="mysql" charset="utf8">sql/mysql/install.sql</file>
		</sql>
	</install>
	<uninstall>
		<sql>
			<file driver="mysql" charset="utf8">sql/mysql/uninstall.sql</file>
		</sql>
	</uninstall>

	<files>
		<folder>forms</folder>
		<folder>sql</folder>
		<filename plugin="rsfprecaptchav2">rsfprecaptchav2.php</filename>
		<filename>index.html</filename>
	</files>
	
	<media destination="plg_system_rsfprecaptchav2" folder="media">
		<folder>images</folder>
		<folder>js</folder>
	</media>
	
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_system_rsfprecaptchav2.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_system_rsfprecaptchav2.sys.ini</language>
	</languages>
</extension>PK��#]eo���
�
*system/rsfprecaptchav2/rsfprecaptchav2.phpnu�[���<?php
/**
* @package RSform!Pro
* @copyright (C) 2014 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

defined('_JEXEC') or die;

define('RSFORM_FIELD_RECAPTCHAV2', 2424);

class plgSystemRsfprecaptchav2 extends JPlugin
{
	protected $autoloadLanguage = true;

	public function onRsformBackendAfterCreateFieldGroups(&$fieldGroups, $self)
	{
		$formId = JFactory::getApplication()->input->getInt('formId');
		$exists = RSFormProHelper::componentExists($formId, RSFORM_FIELD_RECAPTCHAV2);

		$fieldGroups['captcha']->fields[] = (object) array(
			'id' 	=> RSFORM_FIELD_RECAPTCHAV2,
			'name' 	=> JText::_('RSFP_RECAPTCHAV2_LABEL'),
			'icon'  => 'rsficon rsficon-spinner9',
			'exists' => $exists ? $exists[0] : false
		);
	}

	// Show the Configuration tab
	public function onRsformBackendAfterShowConfigurationTabs($tabs)
	{
		$tabs->addTitle(JText::_('RSFP_RECAPTCHAV2_LABEL'), 'page-recaptchav2');
		$tabs->addContent($this->showConfigurationScreen());
	}
	
	protected function showConfigurationScreen()
	{
		ob_start();

		JForm::addFormPath(__DIR__ . '/forms');

		$form = JForm::getInstance( 'plg_system_rsfprecaptchav2.configuration', 'configuration', array('control' => 'rsformConfig'), false, false );
		$form->bind($this->loadFormData());

		?>
		<div id="page-recaptchav2" class="form-horizontal">
			<p><a href="https://www.google.com/recaptcha/" target="_blank"><?php echo JText::_('RSFP_RECAPTCHAV2_GET_RECAPTCHA_HERE'); ?></a></p>
			<?php
			foreach ($form->getFieldsets() as $fieldset)
			{
				if ($fields = $form->getFieldset($fieldset->name))
				{
					foreach ($fields as $field)
					{
						echo $field->renderField();
					}
				}
			}
			?>
		</div>
		<?php

		$contents = ob_get_contents();
		ob_end_clean();

		return $contents;
	}

	private function loadFormData()
	{
		$data 	= array();
		$db 	= JFactory::getDbo();

		$query = $db->getQuery(true)
			->select('*')
			->from($db->qn('#__rsform_config'))
			->where($db->qn('SettingName') . ' LIKE ' . $db->q('recaptchav2.%', false));
		if ($results = $db->setQuery($query)->loadObjectList())
		{
			foreach ($results as $result)
			{
				$data[$result->SettingName] = $result->SettingValue;
			}
		}

		return $data;
	}
	
	public function onRsformFrontendAJAXScriptCreate($args)
	{
		$script =& $args['script'];
		$formId = $args['formId'];
		
		if ($componentId = RSFormProHelper::componentExists($formId, RSFORM_FIELD_RECAPTCHAV2))
		{
			$form = RSFormProHelper::getForm($formId);

			$logged	= $form->RemoveCaptchaLogged ? JFactory::getUser()->id : false;

			$data = RSFormProHelper::getComponentProperties($componentId[0]);
			
			if (!empty($data['SIZE']) && $data['SIZE'] == 'INVISIBLE' && !$logged)
			{
				$script .= 'ajaxValidationRecaptchaV2(task, formId, data, '.$componentId[0].');'."\n";
			}
		}
	}
	
	public function onRsformFrontendAfterFormProcess($args)
	{
		$formId = $args['formId'];
		
		if (RSFormProHelper::componentExists($formId, RSFORM_FIELD_RECAPTCHAV2)) {
			JFactory::getSession()->clear('com_rsform.recaptchav2Token'.$formId);
		}
	}

	public function onRsformFrontendInitFormDisplay($args)
	{
		if ($componentIds = RSFormProHelper::componentExists($args['formId'], RSFORM_FIELD_RECAPTCHAV2))
		{
			$all_data = RSFormProHelper::getComponentProperties($componentIds);

			if ($all_data)
			{
				foreach ($all_data as $componentId => $data)
				{
					$args['formLayout'] = preg_replace('/<label (.*?) for="' . preg_quote($data['NAME'], '/') .'"/', '<label $1', $args['formLayout']);
				}
			}
		}
	}
}PK��#]�)��system/remember/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]q!����=system/remember/plugin_googlemap2/plugin_googlemap2_proxy.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2_proxy.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2011 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

// No protection of Joomla because this php program may be called directly to deliver content
// defined( '_JEXEC' ) or die( 'Restricted access' );

$debug = urldecode($_GET['debug']);
if ($debug!="1")
	@ob_start();
	
header('content-type:text/xml;');

if (!isset($HTTP_RAW_POST_DATA)){
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
}
$post_data = $HTTP_RAW_POST_DATA;
$header[] = "Content-type: text/xml";
$header[] = "Content-length: ".strlen($post_data);

$url = urldecode($_GET['url']);
$url = "http://".$url;
	
$ok = false;

if (ini_get('allow_url_fopen'))
	if (($response = file_get_contents($url)))
		$ok = true;

if (!$ok) {
	$ch = curl_init( $url );

	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	if( !ini_get('safe_mode')&&!ini_get('open_basedir') )
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		
	curl_setopt($ch, CURLOPT_TIMEOUT, 80);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
	curl_setopt($ch, CURLOPT_FAILONERROR, 0);
	curl_setopt($ch, CURLOPT_VERBOSE, 1);

	if ( strlen($post_data)>0 ){
		curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
	}
	
	$response = curl_exec($ch);    
	if (curl_errno($ch)) {
		print curl_error($ch);
	} else {
		curl_close($ch);
		$ok = true;
	}
}

if (!$ok) {
	$url = urldecode($_GET['url']);

    // Do it the safe mode way for local files
	$pattern = "/(www.)?".$_SERVER["HTTP_HOST"]."/i";
	if (preg_match($pattern, $url)!=0) {
		$url = $_SERVER["DOCUMENT_ROOT"].preg_replace($pattern, "", $url);
	
		if (ini_get('allow_url_fopen'))
			if (($response = file_get_contents($url)))
				$ok = true;
		
		if (!$ok) {
			$ch = curl_init( $url );
		
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
			curl_setopt($ch, CURLOPT_TIMEOUT, 80);
			curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
			curl_setopt($ch, CURLOPT_FAILONERROR, 0);
			curl_setopt($ch, CURLOPT_VERBOSE, 1);
			curl_setopt($ch, CURLOPT_COOKIEFILE, 1);
			
			if ( strlen($post_data)>0 ){
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
			}
			
			$response = curl_exec($ch);    
			if (curl_errno($ch)) {
				print curl_error($ch);
			} else {
				curl_close($ch);
				$ok = true;
			}
		}
	}
}

if ($ok) {
	while (@ob_end_clean());
}

print $response;

?> PK��#]|�wfK�K�)system/remember/plugin_googlemap2/gpl.txtnu�[���                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
PK��#]�F�=h=h>system/remember/plugin_googlemap2/plugin_googlemap2_helper.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2_helper.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2011 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

defined( '_JEXEC' ) or die( 'Restricted access' );

if (!defined('_CMN_JAVASCRIPT')) define('_CMN_JAVASCRIPT', "<b>JavaScript must be enabled in order for you to use Google Maps.</b> <br/>However, it seems JavaScript is either disabled or not supported by your browser. <br/>To view Google Maps, enable JavaScript by changing your browser options, and then try again.");

class plgSystemPlugin_googlemap2_helper
{
	var $jversion;
	var $params;
	var $regex;
	var $document;
	var $brackets;
	var $debug_plugin;
	var $debug_text;
	var $protocol;
	var $googlewebsite;
	var $urlsetting;
	var $googlekey;
	var $language;
	var $langtype;
	var $iso;
	var $no_javascript;
	var $pagebreak;
	var	$google_API_version;
	var $mapcss;
	var	$timeinterval;
	var	$googleindexing;
	var	$langanim;
	var	$first_google;
	var	$first_googlemaps;
	var	$first_mootools;
	var	$first_modalbox;
	var	$first_localsearch;
	var $first_googleearth;
	var	$first_kmlrenderer;
	var	$first_kmlelabel;
	var	$first_svcontrol;
	var	$first_animdir;
	var	$first_arcgis;
	var	$first_panoramiolayer;
	var $initparams;
	var $clientgeotype;
	var $event;
	var $_text;
	var	$_langanim;
	var	$_client_geo;
	var $_inline_coords;
	var $_inline_tocoords;
	var $_kmlsbwidthorig;
	var $_lbxwidthorig;
	
	/**
	 * Constructor
	 *
	 * @access      protected
	 * @since       1.0
	 */
	 // Can we use _construct or should we use init?
	 //	function init() {
	public function __construct($jversion, $params, $regex, $document, $brackets)
	{
		// The params of the plugin
		$this->jversion = $jversion;
		$this->params = $params;
		$this->regex = $regex;
		$this->document = $document;
		$this->brackets = $brackets;
		// Set debug
		$this->debug_plugin = $this->params->get( 'debug', '0' );
		$this->debug_text = '';
		// Get ID
		$this->id = intval( JRequest::getVar('id', null) );	
		$this->id = explode(":", $this->id);
		$this->id = $this->id[0];
		// What is the url of website without / at the end
		$this->url = preg_replace('/\/$/', '', JURI::base());
		$this->_debug_log("url base(): ".$this->url);			
		$this->base = JURI::base(true);
		$this->_debug_log("url base(true): ".$this->base);			
		// Protocol not working with maps.google.com only with enterprise account
		if ($_SERVER['SERVER_PORT'] == 443)
			$this->protocol = "https://";
		else
			$this->protocol = "http://";
		$this->_debug_log("Protocol: ".$this->protocol);
		// Get language
		$this->langtype = $this->params->get( 'langtype', '' );
		$this->lang = JFactory::getLanguage();
		// Load the language files for Joomla 1.5. In Joomla 1.6 it is done in the construct of the plugin
		if (substr($this->jversion,0,3)=="1.5")
			$this->lang->load("plg_system_plugin_googlemap2", JPATH_SITE."/administrator", $this->lang->getTag(), true);
		$this->language = $this->_getlang();
		$this->no_javascript = JText::_( 'CMN_JAVASCRIPT', _CMN_JAVASCRIPT);
		// Get region
		$this->region = $this->params->get( 'region', '' );
		// Define encoding
		$this->iso = "utf-8";
		// Get params
		$this->googlewebsite = $this->params->get( 'googlewebsite', 'maps.google.com' );
		$this->_debug_log("googlewebsite: ".$this->googlewebsite);
		$this->urlsetting = $this->params->get( 'urlsetting', 'http_host' );
		$this->_debug_log("urlsetting: ".$this->urlsetting);
		if ($this->urlsetting=='mosconfig')
			$this->urlsetting = $this->url;
		else 
			$this->urlsetting = $_SERVER['HTTP_HOST'];
		$this->google_API_version = $this->params->get( 'Google_API_version', '2.x' );
		$this->googleindexing = $this->params->get( 'googleindexing', '1' );
		$this->mapcss = $this->params->get( 'mapcss', '' );
		$this->timeinterval = $this->params->get( 'timeinterval', '500' );
		$this->clientgeotype = $this->params->get( 'clientgeotype', '0' );
		$this->langanim = $this->params->get( 'langanim', 'en;The requested panorama could not be displayed|Could not generate a route for the current start and end addresses|Street View coverage is not available for this route|You have reached your destination|miles|miles|ft|kilometers|kilometer|meters|In|You will reach your destination|Stop|Drive|Press Drive to follow your route|Route|Speed|Fast|Medium|Slow' );
		// Get key
		$this->googlekey = $this->_get_API_key();
		// Pagebreak regular expression
		$this->pagebreak = '/<hr\s(title=".*"\s)?class="system-pagebreak"(\stitle=".*")?\s\/>/si';
		// load scripts once
		$this->first_google=true;
		$this->first_googlemaps=true;
		$this->first_mootools=true;
		$this->first_modalbox=true;
		$this->first_localsearch=true;
		$this->first_googleearth=true;
		$this->first_kmlrenderer=true;
		$this->first_kmlelabel=true;
		$this->first_svcontrol=true;
		$this->first_animdir= true;
		$this->first_arcgis=true;
		$this->first_panoramiolayer = true;
		$this->_debug_log("brackets: ".$this->brackets);
		// Get params
		$this->initparams = (object) null;
		$this->_getInitialParams();
	}	
	
	function process($match, $params, &$text, $counter, $event) {
		$startmem = round($this->_memory_get_usage()/1024);
		$this->_debug_log("Memory Usage Start (_process): " . $startmem . " KB");
		$this->_text = &$text;
		$this->event = $event;
		
		// Parameters can get the default from the plugin if not empty or from the administrator part of the plugin
		$this->_mp = clone $this->initparams;

		// Language initial value
		$this->_mp->lang = $this->language;
		
		// Next parameters can be set as default out of the administrtor module or stay empty and the plugin-code decides the default. 
		$this->_mp->zoomtype = $this->params->get( 'zoomType', '' );
		$this->_mp->mapType = strtolower($this->params->get( 'mapType', '' )); 

		// Default global process parameters
		$this->_client_geo = 0;
		//track if coordinates different from config
		$this->_inline_coords = 0;
		$this->_inline_tocoords = 0;
		$this->_mp->geocoded = 0;

		// default empty and should be filled as a parameter with the plugin out of the content item
		$this->_mp->tolat='';
		$this->_mp->tolon='';
		$this->_mp->toaddress='';
		$this->_mp->description='';
		$this->_mp->tooltip='';
		$this->_mp->kml = array();
		$this->_mp->kmlsb = array();
		$this->_mp->layer = array();
		$this->_mp->lookat = array();
		$this->_mp->camera = array();
		$this->_mp->msid='';
		$this->_mp->searchtext='';
		$this->_mp->latitude='';
		$this->_mp->longitude='';
		$this->_mp->waypoints = array();

		// Give the map a random name so it won't interfere with another map
		$this->_mp->mapnm = $this->id."_".$this->_randomkeys(5)."_".$counter;
		
		// Match the field details to build the html
		$fields = explode("|", $params);

		foreach($fields as $value) {
			$value = trim($value, " \xC2\xA0\n\t\r\0\x0B");
			$values = explode("=",$value, 2);
			$values[0] = trim(strtolower($values[0]), " \xC2\xA0\n\t\r\0\x0B");
			$values[0] = preg_replace(array('/\r/','/\n/','/\<.*?\b[^>]*>/si'), '', $values[0]);
			$values=preg_replace("/^'/", '', $values);
			$values=preg_replace("/'$/", '', $values);
			$values=preg_replace("/^&#0{0,2}39;/",'',$values);
			$values=preg_replace("/&#0{0,2}39;$/",'',$values);
//			echo "<br/>".$values[0]." = ".$values[1];
				
			if (count($values)>1) {
				$values[1] = trim($values[1], " \xC2\xA0\n\t\r\0\x0B");

				if($values[0]=='debug'){
					$this->debug_plugin=$values[1];
				}else if($values[0]=='gmv'){
					$this->google_API_version = $values[1];
				}else if($values[0]=='lat'&&$values[1]!=''){
					$this->_mp->latitude=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='lon'&&$values[1]!=''){
					$this->_mp->longitude=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='centerlat'){
					$this->_mp->centerlat=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='centerlon'){
					$this->_mp->centerlon=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='tolat'){
					$this->_mp->tolat=$this->_remove_html_tags($values[1]);
					$this->_inline_tocoords = 1;
				}else if($values[0]=='tolon'){
					$this->_mp->tolon=$this->_remove_html_tags($values[1]);
					$this->_inline_tocoords = 1;
				}else if($values[0]=='text'){
					$this->_mp->description=html_entity_decode(html_entity_decode(trim($values[1])));
					if(!$this->_is_utf8($this->_mp->description)) 
						$this->_mp->description = utf8_encode($this->_mp->description);
					if (substr($this->google_API_version,0,1)=='2')
						$this->_mp->description=str_replace("\"","\\\"", $this->_mp->description);
					$this->_mp->description=str_replace("&#0{0,2}39;","'", $this->_mp->description);
				}else if($values[0]=='tooltip'){
					$this->_mp->tooltip=html_entity_decode(html_entity_decode(trim($values[1])));
					$this->_mp->tooltip=str_replace("&amp;","&", $this->_mp->tooltip);
					if(!$this->_is_utf8($this->_mp->tooltip)) 
						$this->_mp->tooltip= utf8_encode($this->_mp->tooltip);
				}else if($values[0]=='maptype'){
					$this->_mp->mapType=strtolower($values[1]);
				}else if ($values[0]=='waypoint'){
					$this->_mp->waypoints[0] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/waypoint\([0-9]+\)/", $values[0])){
					$this->_mp->waypoints[$this->_get_index($values[0], '(')] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/waypoint\[[0-9]+\]/", $values[0])){
					$this->_mp->waypoints[$this->_get_index($values[0], '[')] = $values[1];
				}else if($values[0]=='kml'){
					$this->_mp->kml[0]=$this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/kml\([0-9]+\)/", $values[0])){
					$this->_mp->kml[$this->_get_index($values[0], '(')] = $this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/kml\[[0-9]+\]/", $values[0])){
					$this->_mp->kml[$this->_get_index($values[0], '[')] = $this->_remove_html_tags($values[1]);
				}else if($values[0]=='kmlsb'){
					$this->_mp->kmlsb[0]=$this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/kmlsb\([0-9]+\)/", $values[0])){
					$this->_mp->kmlsb[$this->_get_index($values[0], '(')] = $this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/kmlsb\[[0-9]+\]/", $values[0])){
					$this->_mp->kmlsb[$this->_get_index($values[0], '[')] = $this->_remove_html_tags($values[1]);
				}else if($values[0]=='layer'){
					$this->_mp->layer[0]=$this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/layer\([0-9]+\)/", $values[0])){
					$this->_mp->layer[$this->_get_index($values[0], '(')] = $this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/layer\[[0-9]+\]/", $values[0])){
					$this->_mp->layer[$this->_get_index($values[0], '[')] = $this->_remove_html_tags($values[1]);
				}else if($values[0]=='lookat'){
					$this->_mp->lookat[0]=$values[1];
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/lookat\([0-9]+\)/", $values[0])){
					$this->_mp->lookat[$this->_get_index($values[0], '(')] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/lookat\[[0-9]+\]/", $values[0])){
					$this->_mp->lookat[$this->_get_index($values[0], '[')] = $values[1];
				}else if($values[0]=='camera'){
					$this->_mp->camera[0]=$values[1];
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/camera\([0-9]+\)/", $values[0])){
					$this->_mp->camera[$this->_get_index($values[0], '(')] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/camera\[[0-9]+\]/", $values[0])){
					$this->_mp->camera[$this->_get_index($values[0], '[')] = $values[1];
				}else if($values[0]=='tilelayer'){
					$this->_mp->tilelayer=$this->_remove_html_tags($values[1]);
				}else {
					// other parameters
					if ($values[0]!='')
						$this->_mp->$values[0]=$values[1];
				}
			}
		}
		
		// Search for geo parameters inside the text
		//$this->_findgeoparam();
		
		//Translate parameters
		$this->_mp->erraddr = $this->_translate($this->_mp->erraddr, $this->_mp->lang);
		$this->_mp->txtaddr = $this->_translate($this->_mp->txtaddr, $this->_mp->lang);
		$this->_mp->txtaddr = str_replace(array("\r\n", "\r", "\n"), '', $this->_mp->txtaddr );
		$this->_mp->txtgetdir = $this->_translate($this->_mp->txtgetdir, $this->_mp->lang);
		$this->_mp->txtfrom = $this->_translate($this->_mp->txtfrom, $this->_mp->lang);
		$this->_mp->txtto = $this->_translate($this->_mp->txtto, $this->_mp->lang);
		$this->_mp->txtdiraddr = $this->_translate($this->_mp->txtdiraddr, $this->_mp->lang);
		$this->_mp->txtdir = $this->_translate($this->_mp->txtdir, $this->_mp->lang);
		$this->_mp->txtlightbox = $this->_translate(html_entity_decode($this->_mp->txtlightbox), $this->_mp->lang);
		$this->_mp->txt_driving = $this->_translate($this->_mp->txt_driving, $this->_mp->lang);
		$this->_mp->txt_avhighways = $this->_translate($this->_mp->txt_avhighways, $this->_mp->lang);
		$this->_mp->txt_walking = $this->_translate($this->_mp->txt_walking, $this->_mp->lang);
		$this->_mp->txt_optimize = $this->_translate($this->_mp->txt_optimize, $this->_mp->lang);
		$this->_mp->txt_alternatives = $this->_translate($this->_mp->txt_alternatives, $this->_mp->lang);
		$this->_langanim = $this->_translate($this->langanim, $this->_mp->lang);
		$this->_langanim = explode("|", $this->_langanim);

		$this->_debug_log("clientgeotype: ".$this->clientgeotype);
		
		// Latitude only when no coordinates are specified and no address
		if(!empty($this->_mp->latitudeid)) {
			// Get information
			$url = "http://www.google.de/latitude/apps/badge/api?user=".$this->_mp->latitudeid."&type=kml";
			unset($this->_mp->latitudeid);
			$getpage = $this->_getURL($url);
			if ($getpage!='') {
				$expr = '/xmlns/';
				$getpage = preg_replace($expr, 'id', $getpage);
				$xml = new SimpleXMLElement($getpage);
				$coords = "";
				foreach($xml->xpath('//coordinates') as $coordinates) {
					$coords = $coordinates;
					break;
				}
				if ($coords!='') {
					$this->_debug_log("Coordinates: ".join(", ", explode(",", $coords)));
					list ($this->_mp->longitude, $this->_mp->latitude) = explode(",", $coords);
					$this->_inline_coords = 1;
					
					if ($this->_mp->centerlat==''&&$this->_mp->centerlon=='') {
						$this->_mp->zoom = 19 + $this->_mp->corzoom;
					}
					
					// Get icon
					if ($this->_mp->icon=='') {
						foreach($xml->xpath('//Icon/href') as $href) {
							$this->_mp->icon = (string) $href;
							break;
						}
						if ($this->_mp->icon!=""&&$this->_mp->iconwidth==""&&$this->_mp->iconheight=="") {
							$this->_mp->iconwidth = "32";
							$this->_mp->iconheight = "32";
						}
						if ($this->_mp->icon!=""&&$this->_mp->iconanchorx==""&&$this->_mp->iconanchory=="") {
							$this->_mp->iconanchorx = "16";
							$this->_mp->iconanchory = "32";
						}
					}
					// show description -> add to text
					if ($this->_mp->latitudedesc=="1") {
						foreach($xml->xpath('//description') as $descr) {
							$desc = $descr;
							break;
						}
						$desc=html_entity_decode(html_entity_decode(trim($desc)));
						$desc=str_replace("\"","\\\"", $desc);
						$desc=str_replace("&#0{0,2}39;","'", $desc);
						
						$this->_mp->description .= "<p class='latitude'>".str_replace(' http://www.google.com/latitude/apps/badge', '', $desc)."</p>";
					}
					// show coordinates -> add to text
					if ($this->_mp->latitudecoord=="1") {
						$this->_mp->description .= "<table class=latitudetable><tr><td>Latitude</td><td>".$this->_mp->latitude."</td></tr><tr><td>Longitude</td><td>".$this->_mp->longitude."</td></tr></table>";
					}
				} else
					$this->_debug_log("Latitude coordinates: null");
			} else
				$this->_debug_log("Latitude totally wrong!");
			unset($url, $getpage, $expr, $xml, $coord, $coordinates, $descr, $desc);
		}

		if ($this->_mp->twittername!="") {
			$url = $this->base."/plugins/system/plugin_googlemap2_twitter_kml.php?";
			$url .= "twittername=".urlencode($this->_mp->twittername);
			$url .= "&twittertweets=".urlencode($this->_mp->twittertweets);
			$url .= "&twittericon=".urlencode($this->_mp->twittericon);
			$url .= "&twitterline=".urlencode($this->_mp->twitterline);
			$url .= "&twitterlinewidth=".urlencode($this->_mp->twitterlinewidth);
			$url .= "&twitterstartloc=".urlencode($this->_mp->twitterstartloc);
			
			$this->_mp->kml[] = $url;
			unset($url, $this->_mp->twittername, $this->_mp->twittertweets, $this->_mp->twittericon, $this->_mp->twitterline, $this->_mp->twitterlinewidth, $this->_mp->twitterstartloc);
		}

		if($this->_inline_coords == 0 && !empty($this->_mp->address))	{
			if ($this->clientgeotype=="local")
				$coord = "";
			else
				$coord = $this->get_geo($this->_mp->address);
				
			if ($coord=='') {
				$this->_client_geo = 1;
			} else {
				list ($this->_mp->longitude, $this->_mp->latitude, $altitude) = explode(",", $coord);
				$this->_inline_coords = 1;
				$this->_mp->geocoded = 1;
			}
		}

		if($this->_inline_tocoords == 0 && !empty($this->_mp->toaddress))	{
			if ($this->clientgeotype=="local")
				$tocoord = "";
			else
				$tocoord = $this->get_geo($this->_mp->toaddress);
			if ($tocoord=='') {
				$client_togeo = 1;
			} else {
				list ($this->_mp->tolon, $this->_mp->tolat, $altitude) = explode(",", $tocoord);
				$this->_inline_tocoords = 1;
			}
		}

		if (is_numeric($this->_mp->svwidth)) 
			$this->_mp->svwidth .= "px";
			
		if (is_numeric($this->_mp->svheight))
			$this->_mp->svheight.= "px";

		if (is_numeric($this->_mp->kmlsbwidth)) {
			$this->_kmlsbwidthorig = $this->_mp->kmlsbwidth;
			$this->_mp->kmlsbwidth .= "px";
		} else 
			$this->_kmlsbwidthorig = 0;
			
		$this->_lbxwidthorig = $this->_mp->lbxwidth;
		
		if (is_numeric($this->_mp->lbxwidth))
			$this->_mp->lbxwidth .= "px";
		
		if (is_numeric($this->_mp->lbxheight))
			$this->_mp->lbxheight .= "px";
			
		if (is_numeric($this->_mp->width))
			$this->_mp->width .= "px";
			
		if (is_numeric($this->_mp->height))
			$this->_mp->height .= "px";

		if (!is_numeric($this->_mp->panomax))
			$this->_mp->panomax= "50";
			
		if ($this->_mp->msid!=''&&count($this->_mp->kml)==0) {
			$this->_mp->kml[0]=$this->protocol.$this->googlewebsite.'/maps/ms?';
			if ($this->_mp->lang!='')
				$this->_mp->kml[0] .= "hl=".$this->_mp->lang."&amp;";
			$this->_mp->kml[0].='ie='.$this->iso.'&amp;msa=0&amp;msid='.$this->_mp->msid.'&amp;output=kml';
			$this->_debug_log("- msid: ".$this->_mp->kml[0]);
		}

		// Get the code to be added to the text
		if (substr($this->google_API_version,0,1)=='2')
			list ($code, $lbcode) = $this->_processMapv2();
		else
			list ($code, $lbcode) = $this->_processMapv3();
		
		// Get memory before adding code to text
		$endmem = round($this->_memory_get_usage()/1024);
		$diffmem = $endmem-$startmem;
		$this->_debug_log("Memory Usage End: " . $endmem . " KB (".$diffmem." KB)");

		// Add code to text
		$code = "\n<!-- Plugin Google Maps version 2.18 by Mike Reumer ".(($this->debug_text!='')?$this->debug_text."\n":"")."-->".$code;

		// Clean up debug text for next _process
		$this->debug_text = '';
		
		// Depending of show place the code at end of page or on the {mosmap} position		
		if ($this->_mp->show==0) {
			$offset = strpos($this->_text, $match);
			$this->_text = preg_replace($this->regex, $lbcode, $this->_text, 1);
			// If pagebreak add code before pagebreak
			preg_match($this->pagebreak, $this->_text, $m, PREG_OFFSET_CAPTURE, $offset);
			if (count($m)>0)
				$offsetpagebreak = $m[0][1];
			else
				$offsetpagebreak = 0;
			if ($offsetpagebreak!=0) 
				$this->_text = substr($this->_text, 0, $offsetpagebreak).$code.substr($this->_text, $offsetpagebreak);
			else
				$this->_text .= $code;
		} else
			$this->_text = preg_replace($this->regex, $code, $this->_text, 1);

		// Clean up generated variables
		unset($startmem, $endmem, $diffmem, $offset, $lbcode, $m, $offsetpagebreak, $code);
		
		return true;
	}
	
	function _processMapv2() {
		// Variables of process
		$code='';
		$lbcode='';
		
		if ($this->_mp->googlebar=='1'||$this->_mp->localsearch=='1') {
			$searchoption = array();

			switch ($this->_mp->searchlist) {
			case "suppress":
				$searchoption[] ="resultList : G_GOOGLEBAR_RESULT_LIST_SUPPRESS";
				break;
			
			case "inline":
				$searchoption[] ="resultList : G_GOOGLEBAR_RESULT_LIST_INLINE";
				break;

			case "div":
				$searchoption[] ="resultList : document.getElementById('searchresult".$this->_mp->mapnm."')";
				break;

			default:
				if(empty($this->_mp->searchlist))
					$searchoption[] ="resultList : G_GOOGLEBAR_RESULT_LIST_INLINE";
				else {
					$searchoption[] ="resultList : document.getElementById('".$this->_mp->searchlist."')";
					$extsearchresult= true;
				}
				break;
			}
			
			switch ($this->_mp->searchtarget) {
			case "_self":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_SELF";
				break;
			
			case "_blank":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_BLANK";
				break;

			case "_top":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_TOP";
				break;

			case "_parent":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_PARENT";
				break;

			default:
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_BLANK";
				break;
			}
			
			if ($this->_mp->searchzoompan=="1")
				$searchoption[] ="suppressInitialResultSelection : false
								  , suppressZoomToBounds : false";
			else

				$searchoption[] ="suppressInitialResultSelection : true
								  , suppressZoomToBounds : true";
								  
			$searchoptions = implode(', ', $searchoption);
		} else 
			$searchoptions = "";

		if ($this->_mp->icon!='') {
			$code .= "\n<img src='".$this->_mp->icon."' style='display:none' alt='icon' />";
			if ($this->_mp->iconshadow!='')
				$code .= "\n<img src='".$this->_mp->iconshadow."' style='display:none' alt='icon shadow' />";
			if ($this->_mp->icontransparent!='')
				$code .= "\n<img src='".$this->_mp->icontransparent."' style='display:none' alt='icon transparent' />";
		} 
		
		if ($this->_mp->sv!='none'&&$this->_mp->animdir=='0') {
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-0.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-1.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-2.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-3.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-4.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-5.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-6.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-7.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-8.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-9.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-10.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-11.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-12.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-13.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-14.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-15.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man-pick.png' style='display:none' alt='streetview icon' />";
		}
		// Generate the map position prior to any Google Scripts so that these can parse the code
		$code.= "<!-- fail nicely if the browser has no Javascript -->
				<noscript><blockquote class='warning'><p>".$this->no_javascript."</p></blockquote></noscript>";			

		if ($this->_mp->align!='none')
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none; text-align:".$this->_mp->align."\">";
		else
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none;\">";

		if ($this->_mp->lightbox=='1') {
			$lboptions = array();
			if ($this->_mp->lbxzoom!="")
				$lboptions[] = "zoom : ".$this->_mp->lbxzoom;
			if ($this->_mp->lbxcenterlat!=""&&$this->_mp->lbxcenterlon!="")
				$lboptions[] = "mapcenter : \"".$this->_mp->lbxcenterlat." ".$this->_mp->lbxcenterlon."\"";
				
			$this->_lbxwidthorig = (is_numeric($this->_lbxwidthorig)?(($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right")?$this->_lbxwidthorig+$this->_kmlsbwidthorig+5:$this->_lbxwidthorig)."px":$this->_lbxwidthorig);
			$lbname = (($this->_mp->gotoaddr=='1'||(($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))||$this->_mp->animdir!='0'||$this->_mp->sv=='top'||$this->_mp->sv=='bottom'||$this->_mp->searchlist=='div'||$this->_mp->dir=='5'||($this->_mp->formaddress==1&&$this->_mp->animdir==0))?"lightbox":"googlemap");
			
			if ($this->_mp->show==1) {
				$code.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", map".$this->_mp->mapnm.", {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."'>";
			} else {
				$lbcode.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", map".$this->_mp->mapnm.", {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."' style='display:none'>";
			}
		}

		if ($this->_mp->gotoaddr=='1')	{
			$code.="<form name=\"gotoaddress".$this->_mp->mapnm."\" class=\"gotoaddress\" onSubmit=\"javascript:gotoAddress".$this->_mp->mapnm."();return false;\">";
			$code.="	<input id=\"txtAddress".$this->_mp->mapnm."\" name=\"txtAddress".$this->_mp->mapnm."\" type=\"text\" size=\"25\" value=\"\">";
			$code.="	<input name=\"goto\" type=\"button\" class=\"button\" onClick=\"gotoAddress".$this->_mp->mapnm."();return false;\" value=\"Goto\">";
			$code.="</form>";
		}
		
		if ($this->_mp->formaddress==1&&$this->_mp->animdir==0) {
			$code.="<form id='directionform".$this->_mp->mapnm."' action='".$this->protocol.$this->googlewebsite."/maps' method='get' target='_blank' onsubmit='DirectionMarkersubmit".$this->_mp->mapnm."(this);return false;' class='mapdirform'>";
			$code.=$this->_mp->txtdir;
			$code.=(($this->_mp->txtfrom=='')?"":"<br />").$this->_mp->txtfrom."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='saddr' id='saddr' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."' />";
			$code.=(($this->_mp->txtto=='')?"":"<br />").$this->_mp->txtto."<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='daddr' id='daddr' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."' />";

			if ($this->_mp->txt_driving!=''||$this->_mp->dirtype=="D")
				$code.="<br/><input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"");
			if ($this->_mp->txt_avhighways!=''||$this->_mp->dirtype=="1")
				$code.="<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"");
			if ($this->_mp->txt_transit!=''||$this->_mp->dirtype=="R")
				$code.="<input ".(($this->_mp->txt_transit=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='r' ".(($this->_mp->dirtype=="R")?"checked='checked'":"")." />".$this->_mp->txt_transit.(($this->_mp->txt_transit!='')?"&nbsp;":"");
			if ($this->_mp->txt_bicycle!=''||$this->_mp->dirtype=="B")
				$code.="<input ".(($this->_mp->txt_bicycle=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='b' ".(($this->_mp->dirtype=="B")?"checked='checked'":"")." />".$this->_mp->txt_bicycle.(($this->_mp->txt_bicycle!='')?"&nbsp;":"");
			if ($this->_mp->txt_walking!=''||$this->_mp->dirtype=="W")
				$code.="<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"");
			$code.="<input value='".$this->_mp->txtgetdir."' class='button' type='submit' style='margin-top: 2px;'>";

			if ($this->_mp->dir=='2')
				$code.= "<input type='hidden' name='pw' value='2'/>";

			if ($this->_mp->lang!='') 
				$code.= "<input type='hidden' name='hl' value='".$this->_mp->lang."'/>";
			$code.="</form>";
		}
		
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<table style=\"width:100%;border-spacing:0px;\">
					<tr>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="left")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\" class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<td>";
			
		if ($this->_mp->sv=='top'||($this->_mp->animdir!='0'&&$this->_mp->animdir!='3')) {
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";

			if ($this->_mp->animdir!='0') {
				$code.="<div id='status".$this->_mp->mapnm."' class='status' style='top: -".floor($this->_mp->svheight/2)."px'><b>Loading</b></div><div id='instruction".$this->_mp->mapnm."' class='instruction'></div></div><div id='progressBorder".$this->_mp->mapnm."' class='progressBorder'><div id='progressBar".$this->_mp->mapnm."' class='progressBar'></div></div>";
				$code.= "<div class='animforms'>";
				$code.= "<div class='animbuttonforms'><input type='button' value='Drive' id='stopgo".$this->_mp->mapnm."'  onclick='route".$this->_mp->mapnm.".startDriving()'  disabled='disabled' /></div>";

				if ($this->_mp->formspeed==1)
					$code.= "<div class='animformspeed'>
								<div class='animlabel'>".((array_key_exists(16, $this->_langanim))?$this->_langanim[16]:"Drive")."</div>
								<select id='speed".$this->_mp->mapnm."' onchange='route".$this->_mp->mapnm.".setSpeed()'>
									<option value='0'>".((array_key_exists(17, $this->_langanim))?$this->_langanim[17]:"Fast")."</option>
									<option value='1' selected='selected'>".((array_key_exists(18, $this->_langanim))?$this->_langanim[18]:"Normal")."</option>
									<option value='2'>".((array_key_exists(19, $this->_langanim))?$this->_langanim[19]:"Slow")."</option>
								</select>
							</div>";

				if ($this->_mp->formdirtype==1)
					$code.= "<div class='animformdirtype'>
								<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"")."<br />
							</div>";

				if ($this->_mp->formaddress==1)
					$code.= "<div class='animformaddress'>
								".(($this->_mp->txtfrom=='')?"":"<div class='animlabel'>".$this->_mp->txtfrom."</div>")."
								<div class='animinput'><input id='from".$this->_mp->mapnm."' ".(($this->_mp->txtfrom=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."'/></div>
								<div style='clear: both;'></div>
								".(($this->_mp->txtto=='')?"":"<div class='animlabel'>".$this->_mp->txtto."</div>")."
								<div class='animinput'><input id='to".$this->_mp->mapnm."' ".(($this->_mp->txtto=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."'/></div>
							</div>
							<div class='animbuttons'>
								<input type='button' value='".((array_key_exists(15, $this->_langanim))?$this->_langanim[15]:"Route")."' class='animroute' onclick='route".$this->_mp->mapnm.".generateRoute()' />
							</div>
							";
			}
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
		}

		if (($this->_mp->animdir=='2'||$this->_mp->animdir=='3')&&$this->_mp->showdir!='0') {
			$code.="<table style=\"width:".$this->_mp->width.";\"><tr>";
			$code.="<td style='width:50%;'><div id=\"googlemap".$this->_mp->mapnm."\" ".((!empty($this->_mp->mapclass))?"class=\"".$this->_mp->mapclass."\"" :"class=\"map\"")." style=\"" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:100%; height:".$this->_mp->height.";".(($this->_mp->show==0&&$this->_mp->lightbox==0)?"display:none;":"").(((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&$this->_mp->kmlsidebar=="right")||$this->_mp->animdir=='2')?"float:left;":"")."\"></div></td>";
			$code.= "<td style='width:50%;'><div id=\"dirsidebar".$this->_mp->mapnm."\" class='directions' style='float:left;width:100%;height: ".$this->_mp->height.";overflow:auto; '></div></td>";				
			$code.="</tr></table>";
		} else {
			$code.="<div id=\"googlemap".$this->_mp->mapnm."\" ".((!empty($this->_mp->mapclass))?"class=\"".$this->_mp->mapclass."\"" :"class=\"map\"")." style=\"" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->width."; height:".$this->_mp->height.";".(($this->_mp->show==0&&$this->_mp->lightbox==0)?"display:none;":"").(((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&$this->_mp->kmlsidebar=="right")||$this->_mp->animdir=='2')?"float:left;":"")."\"></div>";
		}
					
		if ($this->_mp->sv=='bottom'||$this->_mp->animdir=="3") {
			if ($this->_mp->animdir=='3') {
				$code.="<div id='progressBorder".$this->_mp->mapnm."' class='progressBorder'><div id='progressBar".$this->_mp->mapnm."' class='progressBar'></div></div>";
				$code.= "<div class='animforms'>";
				$code.= "<div class='animbuttonforms'><input type='button' value='Drive' id='stopgo".$this->_mp->mapnm."'  onclick='route".$this->_mp->mapnm.".startDriving()'  disabled='disabled' /></div>";


				if ($this->_mp->formspeed==1)
					$code.= "<div class='animformspeed'>
								<div class='animlabel'>".((array_key_exists(16, $this->_langanim))?$this->_langanim[16]:"Drive")."</div>
								<select id='speed".$this->_mp->mapnm."' onchange='route".$this->_mp->mapnm.".setSpeed()'>
									<option value='0'>".((array_key_exists(17, $this->_langanim))?$this->_langanim[17]:"Fast")."</option>
									<option value='1' selected='selected'>".((array_key_exists(18, $this->_langanim))?$this->_langanim[18]:"Normal")."</option>
									<option value='2'>".((array_key_exists(19, $this->_langanim))?$this->_langanim[19]:"Slow")."</option>
								</select>
							</div>";

				if ($this->_mp->formdirtype==1)
					$code.= "<div class='animformdirtype'>
								<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"")."<br />
							</div>";

				if ($this->_mp->formaddress==1)
					$code.= "<div class='animformaddress'>
								".(($this->_mp->txtfrom=='')?"":"<div class='animlabel'>".$this->_mp->txtfrom."</div>")."
								<div class='animinput'><input id='from".$this->_mp->mapnm."' ".(($this->_mp->txtfrom=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."'/></div>
								<div style='clear: both;'></div>
								".(($this->_mp->txtto=='')?"":"<div class='animlabel'>".$this->_mp->txtto."</div>")."
								<div class='animinput'><input id='to".$this->_mp->mapnm."' ".(($this->_mp->txtto=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."'/></div>
							</div>
							<div class='animbuttons'>
								<input type='button' value='".((array_key_exists(15, $this->_langanim))?$this->_langanim[15]:"Route")."' class='animroute' onclick='route".$this->_mp->mapnm.".generateRoute()' />
							</div>
							";
			}
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";
			if ($this->_mp->animdir!='0')
				$code.="<div id='status".$this->_mp->mapnm."' class='status' style='top: -".floor($this->_mp->svheight/2)."px'><b>Loading</b></div><div id='instruction".$this->_mp->mapnm."' class='instruction'></div></div>";
		}

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</td>";
		
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="right")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\"  class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";
			
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</tr>
					</table>";

		if ($this->_mp->searchlist=='div')
			$code.="<div id=\"searchresult".$this->_mp->mapnm."\"></div>";

		if ($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right")
			$code.="<div style=\"clear: both;\"></div>";
		
		if (((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->address)||($this->_mp->dir=='5'))&&($this->_mp->animdir!='2'||($this->_mp->animdir=='2'&&$this->_mp->showdir=='0')))
			$code.= "<div id=\"dirsidebar".$this->_mp->mapnm."\" class='directions' ".(($this->_mp->showdir=='0')?"style='display:none'":"")."></div>";

		if ($this->_mp->lightbox=='1')
			$code .= "</div>";

		// Close of mapbody div
		$code.="</div>";

		// Only add the scripts and css once
		if($this->first_google) {
			$url = $this->protocol.$this->googlewebsite."/maps?file=api&amp;v=".$this->google_API_version."&amp;oe=".$this->iso;				
			if ($this->_mp->lang!='') 
				$url .= "&amp;hl=".$this->_mp->lang;

			$url .= "&amp;key=".$this->googlekey;
			$url .= "&amp;sensor=false";
			$url .= "&amp;indexing=".(($this->googleindexing)?"true":"false");
			
			$this->_addscript($url);
			if ($this->mapcss!='') {
				$url = $this->base."/media/plugin_googlemap2/site/googlemaps/googlemaps.css.php";
				$this->_addstylesheet($url);
			}
			$this->first_google=false;
		}

		if (($this->_mp->loadmootools=="1"||$this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->effect!="none"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_mootools) {
			if ($this->event!='onAfterRender') {
				if (substr($this->jversion,0,3)=='1.5')
					JHTML::_('behavior.mootools');
				else
					JHtml::_('behavior.framework',false);				
			} else {
				if (substr($this->jversion,0,3)=='1.5')
					$url = $this->base."/plugins/system/mtupgrade/mootools.js";
				else {
					$mooconfig = JFactory::getConfig();
		            $moodebug = $mooconfig->get('debug');
			        $moouncompressed   = $moodebug ? '-uncompressed' : '';
					$url = $this->base."/media/system/js/mootools-core".$moouncompressed.".js";
					unset($mooconfig, $moodebug, $moouncompressed);
				}
				$this->_addscript($url);
			}
			$this->first_mootools = false;
		}

		if (($this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_modalbox)	{
			if (substr($this->jversion,0,3)=='1.5')
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/modalbox1.2hack.js");
			else
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/moodalbox1.3hack.js");
			
			$this->_addstylesheet($this->base."/media/plugin_googlemap2/site/moodalbox/css/moodalbox.css");
			$this->first_modalbox = false;
		}

		if (($this->_mp->localsearch=="1"||$this->_client_geo==1)&&$this->first_localsearch) {
			$this->_addscript($this->protocol."www.google.com/uds/api?file=uds.js&amp;v=1.0&amp;key=".$this->googlekey);
			$this->_addscript($this->protocol."www.google.com/uds/solutions/localsearch/gmlocalsearch.js".((!empty($this->_mp->adsense))?"?adsense=".$this->_mp->adsense:"").((!empty($this->_mp->channel)&&!empty($this->_mp->adsense))?"&amp;channel=".$this->_mp->channel:""));
			$style = "@import url('".$this->protocol."www.google.com/uds/css/gsearch.css');\n@import url('".$this->protocol."www.google.com/uds/solutions/localsearch/gmlocalsearch.css');";
			$this->_addstyledeclaration($style);
			$this->first_localsearch = false;
		}
		
		if ($this->first_kmlelabel&&(($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")||($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!=""))) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/elabel/elabel.js");
			$this->first_kmlelabel = false;
		}
		
		if (($this->_mp->kmlrenderer=='geoxml'||count($this->_mp->kmlsb)!=0)&&$this->first_kmlrenderer) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/geoxml/geoxml.js");
			$this->first_kmlrenderer = false;
		}
		
		if ($this->_mp->zoomtype=='3D-largeSV'&&$this->first_svcontrol) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/StreetViewControl/StreetViewControl.js");
			$this->first_svcontrol = false;
		}

		if ($this->_mp->animdir!='0'&&$this->first_animdir) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/directions/directions.js");
			$this->_addstylesheet($this->base."/media/plugin_googlemap2/site/directions/directions.css");
			$this->first_animdir = false;
		}
		
		if ($this->_mp->kmlrenderer=='arcgis'&&$this->first_arcgis) {
			$this->_addscript($this->protocol."serverapi.arcgisonline.com/jsapi/gmaps/?v=1.4");
			$this->first_arcgis = false;
		}

		if ($this->_mp->panotype!='none'&&$this->first_panoramiolayer) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/panoramiolayer/panoramiolayer.js");
			$this->first_panoramiolayer = false;
		}

		$code.="<script type='text/javascript'>/*<![CDATA[*/\n";
		if ($this->debug_plugin=="1")
			$code.="function VersionControl(opt_no_style){
					  this.noStyle = opt_no_style;
					};
					VersionControl.prototype = new GControl();
					VersionControl.prototype.initialize = function(map) {
					  var display = document.createElement('div');
					  map.getContainer().appendChild(display);
					  display.innerHTML = '2.'+G_API_VERSION;
					  display.className = 'api-version-display';
					  if(!this.noStyle){
						display.style.fontFamily = 'Arial, sans-serif';
						display.style.fontSize = '11px';
					  }
					  this.htmlElement = display;
					  return display;
					};
					VersionControl.prototype.getDefaultPosition = function() {
					  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(3, 38));
					};
				";

		// Globale map variable linked to the div
		$code.="var tst".$this->_mp->mapnm."=document.getElementById('googlemap".$this->_mp->mapnm."');
		var tstint".$this->_mp->mapnm.";
		var map".$this->_mp->mapnm.";
		var mySlidemap".$this->_mp->mapnm.";
		var overviewmap".$this->_mp->mapnm.";
		var overmap".$this->_mp->mapnm.";
		var xml".$this->_mp->mapnm.";
		var imageovl".$this->_mp->mapnm.";
		var directions".$this->_mp->mapnm.";
		";
		
		if ($this->_mp->proxy=="1") {
			if (substr($this->jversion,0,3)=="1.5")
				$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2_proxy.php?';";
			else
				$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2/plugin_googlemap2_proxy.php?';";
		}

		if ($this->_mp->traffic=='1') 
			$code.="\nvar trafficInfo".$this->_mp->mapnm.";";
		if ($this->_mp->localsearch=='1') 
			$code.="\nvar localsearch".$this->_mp->mapnm.";";
		if ($this->_mp->adsmanager=='1') 
			$code.="\nvar adsmanager".$this->_mp->mapnm.";";
		if ($this->_mp->kmlrenderer=='geoxml'||count($this->_mp->kmlsb)!=0) {
			$code.="\nvar exml".$this->_mp->mapnm.";";

			$code.="\ntop.publishdirectory = '".$this->base."/media/plugin_googlemap2/site/geoxml/';";
		}
		if (count($this->_mp->lookat)>0||count($this->_mp->camera)>0||$this->_mp->tilelayer!=''||$this->_mp->mapType=='earth'||$this->_mp->showearthmaptype=="1")
			$code.="\nvar geplugin".$this->_mp->mapnm.";";

		if ($this->_mp->panotype!='none')
			$code.="\nvar panoLayer".$this->_mp->mapnm.";";

		if ($this->_mp->icon!='') {
			$code.="\nmarkericon".$this->_mp->mapnm." = new GIcon(G_DEFAULT_ICON);";
			$code.="\nmarkericon".$this->_mp->mapnm.".image = '".$this->_mp->icon."';";
			if ($this->_mp->iconwidth!=''&&$this->_mp->iconheight!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".iconSize = new GSize(".$this->_mp->iconwidth.", ".$this->_mp->iconheight.");";
			if ($this->_mp->iconshadow !='') {
				$code.="\nmarkericon".$this->_mp->mapnm.".shadow = '".$this->_mp->iconshadow."';";

				if ($this->_mp->iconshadowwidth!=''&&$this->_mp->iconshadowheight!='') 
					$code.="\nmarkericon".$this->_mp->mapnm.".shadowSize = new GSize(".$this->_mp->iconshadowwidth.", ".$this->_mp->iconshadowheight.");";
			}
			if ($this->_mp->iconanchorx!=''&&$this->_mp->iconanchory!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".iconAnchor = new GPoint(".$this->_mp->iconanchorx.", ".$this->_mp->iconanchory.");";
			if ($this->_mp->iconinfoanchorx!=''&&$this->_mp->iconinfoanchory!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".infoWindowAnchor = new GPoint(".$this->_mp->iconinfoanchorx.", ".$this->_mp->iconinfoanchory.");";
			if ($this->_mp->icontransparent!='') 			
				$code.="\nmarkericon".$this->_mp->mapnm.".transparent = '".$this->_mp->icontransparent."';";
			if ($this->_mp->iconimagemap!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".imageMap = [".$this->_mp->iconimagemap."];";
		}
		
		if ($this->_mp->sv!='none'||$this->_mp->animdir!='0') {
			$code.="\nvar svclient".$this->_mp->mapnm.";
					var svmarker".$this->_mp->mapnm.";
					var svlastpoint".$this->_mp->mapnm.";
					var svpanorama".$this->_mp->mapnm.";
					";
			if ($this->_mp->svautorotate=="1")
				$code.="\nvar timer".$this->_mp->mapnm." = null;
						var svfocus".$this->_mp->mapnm." = false;
						var panobj".$this->_mp->mapnm.";
					";
		}

		if ($this->_mp->animdir!='0')				
			$code.="\nvar route".$this->_mp->mapnm.";
					";
		
		if ($this->_mp->sv!='none'&&$this->_mp->animdir=='0') {
			$code.="\nvar guyIcon".$this->_mp->mapnm." = new GIcon(G_DEFAULT_ICON);
					guyIcon".$this->_mp->mapnm.".image = '".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-0.png';
					guyIcon".$this->_mp->mapnm.".transparent = '".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man-pick.png';
					guyIcon".$this->_mp->mapnm.".imageMap = [26,13, 30,14, 32,28, 27,28, 28,36, 18,35, 18,27, 16,26, 16,20, 16,14, 19,13, 22,8];
					guyIcon".$this->_mp->mapnm.".iconSize = new GSize(49, 52);
					guyIcon".$this->_mp->mapnm.".iconAnchor = new GPoint(25, 35);
					guyIcon".$this->_mp->mapnm.".infoWindowAnchor = new GPoint(25, 5);
					";
		}
		if ($this->_mp->tilelayer!="") {
			$code.="\nvar tilelayer".$this->_mp->mapnm.";
					var mercator".$this->_mp->mapnm.";
					var copyright".$this->_mp->mapnm.";
					";
		}

		if ( array_key_exists('HTTP_USER_AGENT',$_SERVER) && strpos(" ".$_SERVER['HTTP_USER_AGENT'], 'Opera') ) {
			$code.="var _mSvgForced = true;
					var _mSvgEnabled = true; ";
		}

		if($this->_mp->zoomwheel=='1') {
			$code.="function CancelEvent".$this->_mp->mapnm."(event) { 
						var e = event; 
						if (typeof e.preventDefault == 'function') e.preventDefault(); 
							if (typeof e.stopPropagation == 'function') e.stopPropagation(); 

						if (window.event) { 
							window.event.cancelBubble = true; // for IE 
							window.event.returnValue = false; // for IE 
						} 
					}
				";
		}
		
		$code.="\nfunction resetposition".$this->_mp->mapnm."() {
			map".$this->_mp->mapnm.".returnToSavedPosition();
		}";

		if ($this->_mp->gotoaddr=='1') {
			$code.="function gotoAddress".$this->_mp->mapnm."() {
						var address = document.getElementById('txtAddress".$this->_mp->mapnm."').value;

						if (address.length > 0) {
							var geocoder = new GClientGeocoder();
							geocoder.setViewport(map".$this->_mp->mapnm.".getBounds());

							geocoder.getLatLng(address,
							function(point) {
								if (!point) {
									var erraddr = '{$this->_mp->erraddr}';
									erraddr = erraddr.replace(/##/, address);
								  alert(erraddr);
								} else {
								  var txtaddr = '{$this->_mp->txtaddr}';
								  txtaddr = txtaddr.replace(/##/, address);
								  map".$this->_mp->mapnm.".setCenter(point".(($this->_mp->gotoaddrzoom!=0)?",".$this->_mp->gotoaddrzoom:"").");
								  map".$this->_mp->mapnm.".openInfoWindowHtml(point,txtaddr);
								  setTimeout('map".$this->_mp->mapnm.".closeInfoWindow();', 5000);
								}
							  });
						  }
						  return false;
						  
					}";
		}
		
		if (($this->_mp->dir!='0')||((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->toaddress))&&$this->_mp->animdir=='0') {
			$code .="function handleErrors".$this->_mp->mapnm."(){
						var dirsidebar".$this->_mp->mapnm." = document.getElementById('dirsidebar".$this->_mp->mapnm."');
						var newelem = document.createElement('p');
						if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_UNKNOWN_ADDRESS)
							newelem.innerHTML = 'No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_SERVER_ERROR)
							newelem.innerHTML = 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_MISSING_QUERY)
							 newelem.innerHTML = 'The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						//   else if (directions".$this->_mp->mapnm.".getStatus().code == G_UNAVAILABLE_ADDRESS)  <--- Doc bug... this is either not defined, or Doc is wrong
						//     newelem.innerHTML = 'The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						   else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_BAD_KEY)
							 newelem.innerHTML = 'The given key is either invalid or does not match the domain for which it was given.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						
						   else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_BAD_REQUEST)
							 newelem.innerHTML = 'A directions request could not be successfully parsed.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						   else newelem.innerHTML = 'An unknown error occurred.';
						dirsidebar".$this->_mp->mapnm.".appendChild(newelem); 
					}
						";
			}
			
		if ($this->_mp->dir!='0'&&$this->_mp->animdir=='0') {
			$code.="\nDirectionMarkersubmit".$this->_mp->mapnm." = function( formObj ){
						if(formObj.dir&&formObj.dir[1].checked ){
							tmp = formObj.daddr.value;
							formObj.daddr.value = formObj.saddr.value;
							formObj.saddr.value = tmp;
						}";
			if ($this->_mp->dir=='1')
				$code.="\nformObj.submit();";
			elseif ($this->_mp->dir=='2')
				$code.="\nformObj.submit();";
			elseif ($this->_mp->dir=='3')
				$code.="\nfor (var i=0; i < formObj.dirflg.length; i++) {
						   if (formObj.dirflg[i].checked) {
							  var dirflg= formObj.dirflg[i].value;
							  break;
						   }
						}
						MOOdalBox.open('".$this->protocol.$this->googlewebsite."/maps?dir=to&dirflg='+dirflg+'&saddr='+formObj.saddr.value+'&hl=en&daddr='+formObj.daddr.value+'".(($this->_mp->lang!='')?"&amp;hl=".$this->_mp->lang:"")."&pw=2', '".$this->_mp->lbxcaption."', '".$this->_mp->lbxwidth." ".$this->_mp->lbxheight."', null, 16);";
			elseif ($this->_mp->dir=='5') 
					$code .= "\nfor (var i=0; i < formObj.dirflg.length; i++) {
								   if (formObj.dirflg[i].checked) {
									  var dirflg= formObj.dirflg[i].value;
									  break;
								   }
								}
								var dirsidebar".$this->_mp->mapnm." = document.getElementById('dirsidebar".$this->_mp->mapnm."');
								if (directions".$this->_mp->mapnm.") {
									directions".$this->_mp->mapnm.".clear();
									if ( dirsidebar".$this->_mp->mapnm.".hasChildNodes() )
										{
											while ( dirsidebar".$this->_mp->mapnm.".childNodes.length >= 1 )
											{
												dirsidebar".$this->_mp->mapnm.".removeChild( dirsidebar".$this->_mp->mapnm.".firstChild );       
											} 
										}
								} else {
									directions".$this->_mp->mapnm." = new GDirections(map".$this->_mp->mapnm.", dirsidebar".$this->_mp->mapnm.");
									GEvent.addListener(directions".$this->_mp->mapnm.", 'error', handleErrors".$this->_mp->mapnm.");
								}
								options = Array();
								if (dirflg=='w')
									options.travelMode = G_TRAVEL_MODE_WALKING;
								if (dirflg=='h')
									options.avoidHighways = true;
								directions".$this->_mp->mapnm.".load('from: '+formObj.saddr.value+' to: '+formObj.daddr.value, options);
							";
			else
				$code.="\nfor (var i=0; i < formObj.dirflg.length; i++) {
						   if (formObj.dirflg[i].checked) {
							  var dirflg= formObj.dirflg[i].value;
							  break;
						   }
						}
						MOOdalBox.open('".$this->protocol.$this->googlewebsite."/maps?dir=to&dirflg='+dirflg+'&saddr='+formObj.saddr.value+'&hl=en&daddr='+formObj.daddr.value+'".(($this->_mp->lang!='')?"&amp;hl=".$this->_mp->lang:"")."', '".$this->_mp->lbxcaption."', '".$this->_mp->lbxwidth." ".$this->_mp->lbxheight."', null, 16);";
				
			$code.="\nif(formObj.dir&&formObj.dir[1].checked )
						setTimeout('DirectionRevert".$this->_mp->mapnm."()',100);
					};";
			
			$code.="\nDirectionRevert".$this->_mp->mapnm." = function(){
						formObj = document.getElementById('directionform".$this->_mp->mapnm."');
						tmp = formObj.daddr.value;
						formObj.daddr.value = formObj.saddr.value;
						formObj.saddr.value = tmp;
					};";
		}
		
		// Function for overview
		if(!$this->_mp->overview==0) {
			$code.="\nfunction checkOverview".$this->_mp->mapnm."() {
						for (var i in overviewmap".$this->_mp->mapnm.") {
							if (overviewmap".$this->_mp->mapnm."[i].setMapType) {
								overmap".$this->_mp->mapnm." = overviewmap".$this->_mp->mapnm."[i];
								break;
							}
						}						
						if (overmap".$this->_mp->mapnm.") {
					";
						  
			if($this->_mp->overview==2)

			{
				$code.="\n		overviewmap".$this->_mp->mapnm.".hide(true);";
			}

			switch ($this->_mp->mapType) {
			case "satellite":
			
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_SATELLITE_MAP);";
				break;
			
			case "hybrid":
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_HYBRID_MAP);";
				break;

			case "terrain":
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_PHYSICAL_MAP);";
				break;
			
			case "earth":
				break;

			default:
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_NORMAL_MAP);";
				break;
			}
			
			if ($this->_mp->ovzoom!="") {
				$code.="\n		setTimeout('overmap".$this->_mp->mapnm.".setCenter(map".$this->_mp->mapnm.".getCenter(), map".$this->_mp->mapnm.".getZoom()+".$this->_mp->ovzoom.")', 100);";
				$code.="\n		GEvent.addListener(map".$this->_mp->mapnm.",'move',function() {
var c = Math.min(Math.max(0, map".$this->_mp->mapnm.".getZoom()+".$this->_mp->ovzoom."), 19);
overmap".$this->_mp->mapnm.".setCenter(map".$this->_mp->mapnm.".getCenter(), c);
});";
				$code.="\n		GEvent.addListener(map".$this->_mp->mapnm.",'moveend',function() {
var c = Math.min(Math.max(0, map".$this->_mp->mapnm.".getZoom()+".$this->_mp->ovzoom."), 19);
overmap".$this->_mp->mapnm.".setCenter(map".$this->_mp->mapnm.".getCenter(), c);

});";
			}
			$code.= "\n	} else {
						  setTimeout('checkOverview".$this->_mp->mapnm."()',100);
						}
					  }";
		}
		
		$code.="\nfunction initearth".$this->_mp->mapnm."(geplugin) {
			if (!geplugin".$this->_mp->mapnm.")
				geplugin".$this->_mp->mapnm." = geplugin;
			if (geplugin".$this->_mp->mapnm."&&map".$this->_mp->mapnm.".getCurrentMapType() == G_SATELLITE_3D_MAP) {";

		// Add layers
		if ($this->_mp->earthborders=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_BORDERS, true);";
		if ($this->_mp->earthbuildings=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_BUILDINGS, true);";
		else
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_BUILDINGS, false);";
		if ($this->_mp->earthroads=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_ROADS, true);";
		if ($this->_mp->earthterrain=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_TERRAIN, true);";
		else
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_TERRAIN, false);";
			
		if ($this->_mp->tilelayer) {
			$code.="\n	var url = '".$this->_mp->tilelayer."';
			var newurl = url+'/doc.kml';
			var link = geplugin".$this->_mp->mapnm.".createLink('');
			link.setHref(newurl);
			var networkLink = geplugin".$this->_mp->mapnm.".createNetworkLink('');
			networkLink.set(link, false, false);
			geplugin".$this->_mp->mapnm.".getFeatures().appendChild(networkLink);";
		}
		
		if (count($this->_mp->lookat)>0||count($this->_mp->camera)>0)
			$code.="\n	setTimeout('setearth".$this->_mp->mapnm."()', ".$this->_mp->earthtimeout.");";
			
		$code.="\n}
				}";
				
		if (count($this->_mp->lookat)>0||count($this->_mp->camera)>0) {
			$la = false;
			$cam = false;
			$code.="\nfunction setearth".$this->_mp->mapnm."() {
						var lookat = geplugin".$this->_mp->mapnm.".getView().copyAsLookAt(geplugin".$this->_mp->mapnm.".ALTITUDE_RELATIVE_TO_GROUND);
						var camera = geplugin".$this->_mp->mapnm.".getView().copyAsCamera(geplugin".$this->_mp->mapnm.".ALTITUDE_RELATIVE_TO_GROUND);";
			if (count($this->_mp->lookat)>0) {
				$values = explode(',', $this->_mp->lookat[0]);
				if (count($values)>0&&$values[0]!='') { // Latitude
					$code.="\nlookat.setLatitude(".$values[0].");";
					$la = true;
				}
				if (count($values)>1&&$values[1]!='') { // Longitude
					$code.="\nlookat.setLongitude(".$values[1].");";
					$la = true;
				}
				if (count($values)>2&&$values[2]!='') { // Range
					$code.="\nlookat.setRange(".$values[2].");";
					$la = true;
				}
				if (count($values)>3&&$values[3]!='') { // tilt
					$code.="\nlookat.setTilt(".$values[3].");";
					$la = true;
				}
				if (count($values)>4&&$values[4]!='') { // setHeading
					$code.="\nlookat.setHeading(".$values[4].");";
					$la = true;
				}
				if (count($values)>5&&$values[5]!='') { // altitude
					$code.="\nlookat.setAltitude(".$values[5].");";
					$la = true;
				}
				if (count($values)>6&&$values[6]!='') {// flyspeed
					if ($values[6]=='teleport')
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(geplugin".$this->_mp->mapnm.".SPEED_TELEPORT);";
					else
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(".$values[6].");";
				}
			}
			
			if (count($this->_mp->camera)>0) {
				$values = explode(',', $this->_mp->camera[0]);
				if (count($values)>0&&$values[0]!='') { // Latitude
					$code.="\ncamera.setLatitude(".$values[0].");";
					$cam = true;

				}
				if (count($values)>1&&$values[1]!='') { // Longitude
					$code.="\ncamera.setLongitude(".$values[1].");";
					$cam = true;
				}
				if (count($values)>2&&$values[2]!='') { // tilt
					$code.="\ncamera.setTilt(".$values[2].");";
					$cam = true;
				}
				if (count($values)>3&&$values[3]!='') { // heading
					$code.="\ncamera.setHeading(".$values[3].");";
					$cam = true;
				}
				if (count($values)>4&&$values[4]!='') { // altitude
					$code.="\ncamera.setAltitude(".$values[4].");";
					$cam = true;
				}
				if (count($values)>5&&$values[5]!='') { // roll
					$code.="\ncamera.setRoll(".$values[5].");";
					$cam = true;
				}
				if (count($values)>6&&$values[6]!='') {// flyspeed
					if ($values[6]=='teleport')
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(geplugin".$this->_mp->mapnm.".SPEED_TELEPORT);";
					else
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(".$values[6].");";
				}
			}
					
			if ($la)
				$code.="\n	geplugin".$this->_mp->mapnm.".getView().setAbstractView(lookat);";
			if ($cam)
				$code.="\n	geplugin".$this->_mp->mapnm.".getView().setAbstractView(camera);";
				
			$code.="\n}";
		}

		if ($this->_mp->kmlrenderer=='arcgis') {
			$code .="\nfunction dynmapcallback".$this->_mp->mapnm."(mapservicelayer) {
						  map".$this->_mp->mapnm.".addOverlay(mapservicelayer);
							}";	
		}
		
		if ($this->_mp->kmlrenderer=='google') {
			$code .= "\nfunction savePositionKML".$this->_mp->mapnm."() {
							ok = true;
							for (x=0;x<xml".$this->_mp->mapnm.".length;x++) {
								if (!xml".$this->_mp->mapnm."[x].hasLoaded())
									ok = false;
							}
							if (ok)
								map".$this->_mp->mapnm.".savePosition();
							else
								setTimeout('savePositionKML".$this->_mp->mapnm."()',100);
						}
					";
		}
		
			
		// Functions to watch if the map has changed
		$code.="\nfunction checkMap".$this->_mp->mapnm."()
		{
			if (tst".$this->_mp->mapnm.") {
			";
			
		if ($this->_mp->show!=0)
			$code.="\n			if (tst".$this->_mp->mapnm.".offsetWidth != tst".$this->_mp->mapnm.".getAttribute(\"oldValue\"))
					{
						tst".$this->_mp->mapnm.".setAttribute(\"oldValue\",tst".$this->_mp->mapnm.".offsetWidth);
						if (tst".$this->_mp->mapnm.".offsetWidth > 0) {
					";

		$code.="\n				if (tst".$this->_mp->mapnm.".getAttribute(\"refreshMap\")==0)

							clearInterval(tstint".$this->_mp->mapnm.");";
		if ($this->_mp->effect !='none') 
			$code .="\n					mySlidemap".$this->_mp->mapnm." = new Fx.Slide('googlemap".$this->_mp->mapnm."',{duration: 1500, mode: '".$this->_mp->effect."'});
							mySlidemap".$this->_mp->mapnm.".hide();
							mySlidemap".$this->_mp->mapnm.".slideIn();";

		$code .="\n					getMap".$this->_mp->mapnm."();
							tst".$this->_mp->mapnm.".setAttribute(\"refreshMap\", 1);";
		if ($this->_mp->show!=0)
			$code .="\n				} 
					}";
		$code .="\n	}
		}
		";

		if ($this->_mp->sv!="none"&&$this->_mp->animdir=='0') {
			$code .="\nfunction onYawChange".$this->_mp->mapnm."(newYaw) {
						var GUY_NUM_ICONS = 16;
						var GUY_ANGULAR_RES = 360/GUY_NUM_ICONS;
						if (newYaw < 0) {
							newYaw += 360;
						}
						var guyImageNum = Math.round(newYaw/GUY_ANGULAR_RES) % GUY_NUM_ICONS;
						var guyImageUrl = '".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-' + guyImageNum + '.png';
						svmarker".$this->_mp->mapnm.".setImage(guyImageUrl);
					}

					function onNewLocation".$this->_mp->mapnm."(point) {
						// Get the original x + y coordinates
						svmarker".$this->_mp->mapnm.".setLatLng(point.latlng);
						map".$this->_mp->mapnm.".panTo(point.latlng);
						svlastpoint".$this->_mp->mapnm." = point.latlng;";
			if ($this->_mp->svautorotate=="1")		
				$code .="\nspiralstart".$this->_mp->mapnm."();
";
						
			$code .="\n}

					function onDragEnd".$this->_mp->mapnm."() {
						var latlng = svmarker".$this->_mp->mapnm.".getLatLng();
						if (svpanorama".$this->_mp->mapnm.") {
							svclient".$this->_mp->mapnm.".getNearestPanorama(latlng, svonResponse".$this->_mp->mapnm.");
						}
					}

					function svonResponse".$this->_mp->mapnm."(response) {
						if (response.code != 200) {
							svmarker".$this->_mp->mapnm.".setLatLng(svlastpoint".$this->_mp->mapnm.");
							map".$this->_mp->mapnm.".setCenter(svlastpoint".$this->_mp->mapnm.");
						} else {
							var latlng = new GLatLng(response.Location.lat, response.Location.lng);

							svmarker".$this->_mp->mapnm.".setLatLng(latlng);
							svlastpoint".$this->_mp->mapnm." = latlng;
							svpanorama".$this->_mp->mapnm.".setLocationAndPOV(latlng, null);
						}
					}
					";

			if ($this->_mp->svautorotate=="1")		
				$code .="\nfunction spiral".$this->_mp->mapnm."() {
							var pov=svpanorama".$this->_mp->mapnm.".getPOV();
							svpanorama".$this->_mp->mapnm.".panTo({yaw:pov.yaw+2, pitch:pov.pitch, zoom:pov.zoom});
						}
						function svmouseover".$this->_mp->mapnm." () {
							svfocus".$this->_mp->mapnm." = true;
							spiralstop".$this->_mp->mapnm."();
						}
						function svmouseout".$this->_mp->mapnm." () {
							svfocus".$this->_mp->mapnm." = false;
							spiralstart".$this->_mp->mapnm."();
						}
						function spiralstop".$this->_mp->mapnm."() {
							if (timer".$this->_mp->mapnm.") {
								clearInterval(timer".$this->_mp->mapnm.");
								timer".$this->_mp->mapnm." = null;
							}
						}
						function spiralstart".$this->_mp->mapnm."() {
							if (!svfocus".$this->_mp->mapnm.") {
								if (timer".$this->_mp->mapnm.")
									spiralstop".$this->_mp->mapnm."();
								timer".$this->_mp->mapnm." = window.setInterval(spiral".$this->_mp->mapnm.", 200);
							}
						}
				";
		}

		// Function for displaying the map and marker
		$code.="\nfunction getMap".$this->_mp->mapnm."(){";
	
		if ($this->_mp->show!=0)
			$code.="\n	if (tst".$this->_mp->mapnm.".offsetWidth > 0) {";
		
		$code.="\n	map".$this->_mp->mapnm." = new GMap2(document.getElementById('googlemap".$this->_mp->mapnm."')".(($this->_mp->googlebar=='1'&&!empty($searchoptions))?", { googleBarOptions: {".$searchoptions." } }":"").");
				map".$this->_mp->mapnm.".getContainer().style.overflow='hidden';
				";
		
		if ($this->_mp->sv!="none"||$this->_mp->animdir!='0')
			$code.="\nsvclient".$this->_mp->mapnm." = new GStreetviewClient();";
			
		if($this->_mp->keyboard=='1'&&$this->_mp->controltype=='user')
		{
			$code.="\nnew GKeyboardHandler(map".$this->_mp->mapnm.");
			";
		} 
		if($this->_mp->dragging=="0")
			$code.="\nmap".$this->_mp->mapnm.".disableDragging();";
	
		if ($this->_mp->shownormalmaptype=="0")
			$code.="\nmap".$this->_mp->mapnm.".removeMapType(G_NORMAL_MAP);";
		if ($this->_mp->showsatellitemaptype=="0")
			$code.="\nmap".$this->_mp->mapnm.".removeMapType(G_SATELLITE_MAP);";
		if ($this->_mp->showhybridmaptype=="0")
			$code.="\nmap".$this->_mp->mapnm.".removeMapType(G_HYBRID_MAP);";
		if ($this->_mp->showterrainmaptype=="1")
			$code.="\nmap".$this->_mp->mapnm.".addMapType(G_PHYSICAL_MAP);";
		if ($this->_mp->showearthmaptype=="1") {
			$code.="\nmap".$this->_mp->mapnm.".addMapType(G_SATELLITE_3D_MAP);";
			$code.="\nGEvent.addListener(map".$this->_mp->mapnm.", 'maptypechanged', function() {
										if (map".$this->_mp->mapnm.".getCurrentMapType() == G_SATELLITE_3D_MAP)
											setTimeout('map".$this->_mp->mapnm.".getEarthInstance(initearth".$this->_mp->mapnm.")',100);
						 });
						";			
		}
	
		if(!$this->_mp->overview==0)
		{
			$code.="\noverviewmap".$this->_mp->mapnm." = new GOverviewMapControl();";

			$code.="\nmap".$this->_mp->mapnm.".addControl(overviewmap".$this->_mp->mapnm.", new GControlPosition(G_ANCHOR_BOTTOM_RIGHT));";
			$code.="setTimeout('checkOverview".$this->_mp->mapnm."()',100);";
	
		} elseif (!$this->_mp->overview==0) {
			$code.="\noverviewmap".$this->_mp->mapnm." = new GOverviewMapControl();";
			$code.="\nmap".$this->_mp->mapnm.".addControl(overviewmap".$this->_mp->mapnm.", new GControlPosition(G_ANCHOR_BOTTOM_RIGHT));";
			
			if($this->_mp->overview==2)
			{
				$code.="\noverviewmap".$this->_mp->mapnm.".hide(true);";
			}
		}
	
		if($this->_mp->navlabel == 1)
			$code.="\nmap".$this->_mp->mapnm.".addControl(new GNavLabelControl(), new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(7, 30)));";
	
		if($this->_client_geo == 1) {
			if ($this->clientgeotype=="local") {
				$code.="\nvar localSearch = new GlocalSearch();";
				$replace = array("\n", "\r", "&lt;br/&gt;", "&lt;br /&gt;", "&lt;br&gt;");
				$addr = str_replace($replace, '', $this->_mp->address);
	
				$code.="\nvar address = \"".$addr."\";";
				$code.="\nlocalSearch.setSearchCompleteCallback(null,	function() {
						if (localSearch.results[0]) {
							var resultLat = localSearch.results[0].lat;
							var resultLng = localSearch.results[0].lng;
							var point = new GLatLng(resultLat,resultLng);
						} else 
						";
				if ($this->_mp->latitude !=''&&$this->_mp->longitude!='')
					$code.="var point = new GLatLng( {$this->_mp->latitude}, {$this->_mp->longitude});";
				else
					$code.="var point = new GLatLng( {$this->_mp->deflatitude}, {$this->_mp->deflongitude});";
			} else {
				$code.="var geocoder = new GClientGeocoder();";
				$replace = array("\n", "\r", "&lt;br/&gt;", "&lt;br /&gt;", "&lt;br&gt;");
				$addr = str_replace($replace, '', $this->_mp->address);
	
				$code.="var address = \"".$addr."\";";
				$code.="geocoder.getLatLng(address, function(point) {
							if (!point)";
							
				if ($this->_mp->latitude !=''&&$this->_mp->longitude!='')
					$code.="var point = new GLatLng( {$this->_mp->latitude}, {$this->_mp->longitude});";
				else
					$code.="var point = new GLatLng( {$this->_mp->deflatitude}, {$this->_mp->deflongitude});";
			}
		} else { 
			if ($this->_mp->latitude !=''&&$this->_mp->longitude!='')
				$code.="\nvar point = new GLatLng( {$this->_mp->latitude}, {$this->_mp->longitude});";
			else
				$code.="\nvar point = new GLatLng( {$this->_mp->deflatitude}, {$this->_mp->deflongitude});";
		}
		if (!empty($this->_mp->centerlat)&&!empty($this->_mp->centerlon))
			$code.="\nvar centerpoint = new GLatLng( {$this->_mp->centerlat}, {$this->_mp->centerlon});";
		else
			$code.="\nvar centerpoint = point;";
	
		if ($this->_inline_coords == 0 && count($this->_mp->kml)>0)
			$code.="map".$this->_mp->mapnm.".setCenter(new GLatLng(0, 0), 0);
			";					
		else
			$code.="map".$this->_mp->mapnm.".setCenter(centerpoint, ".$this->_mp->zoom.");
			";					
			
		if ($this->_mp->controltype=='user') {
			switch ($this->_mp->zoomtype) {
				case "Large":
					$code.="map".$this->_mp->mapnm.".addControl(new GLargeMapControl());";

					break;
				case "Small":
					$code.="map".$this->_mp->mapnm.".addControl(new GSmallMapControl());";
					break;
				case "3D-large":
					$code.="map".$this->_mp->mapnm.".addControl(new GLargeMapControl3D());";
					if ($this->_mp->rotation)
						$code.="map".$this->_mp->mapnm.".enableRotation();";
					break;
				case "3D-largeSV":
					$code.="map".$this->_mp->mapnm.".addControl(new StreetViewControl());";
					if ($this->_mp->rotation)
						$code.="map".$this->_mp->mapnm.".enableRotation();";
					break;
				case "3D-small":
					$code.="map".$this->_mp->mapnm.".addControl(new GSmallZoomControl3D());";
					if ($this->_mp->rotation)
						$code.="map".$this->_mp->mapnm.".enableRotation();";
					break;
				default:
					break;
			}
			
			switch ($this->_mp->showmaptype) {
				case "0":
					break;
				case "1":
					$code.="map".$this->_mp->mapnm.".addControl(new GMapTypeControl());";
					break;
				case "2":
					$code.="map".$this->_mp->mapnm.".addControl(new GHierarchicalMapTypeControl());";
					break;
				case "3":
					$code.="map".$this->_mp->mapnm.".addControl(new GMenuMapTypeControl());";
					break;
			} 
	
			if ($this->_mp->showscale==1)
				$code.="map".$this->_mp->mapnm.".addControl(new GScaleControl());";
		} else {
			$code.="map".$this->_mp->mapnm.".setUIToDefault();";
			if ($this->_mp->rotation)
				$code.="map".$this->_mp->mapnm.".enableRotation();";
		}
			
		if (count($this->_mp->kml)>0) {
			if ($this->_mp->kmlrenderer=="google") {
				$code .= "xml".$this->_mp->mapnm." = [];";
				$kmz= false;
				foreach ($this->_mp->kml as $idx => $val) {
					$code .= "var kmlurl = '".$this->_make_absolute($this->_mp->kml[$idx])."';";
					$code .= "kmlurl = kmlurl.replace(/&amp;/g, String.fromCharCode(38));";
					$code .= "\nxml".$this->_mp->mapnm."[".$idx."] = new GGeoXml(kmlurl);";
					$code .= "\nmap".$this->_mp->mapnm.".addOverlay(xml".$this->_mp->mapnm."[".$idx."]);";
					if (strpos($this->_mp->kml[$idx], '.kmz')!=0)
						$kmz = true;
				}
				if ($kmz) {
					$code .= "\n   GEvent.addListener(map".$this->_mp->mapnm.", 'infowindowopen', function() {
						var divs = map".$this->_mp->mapnm.".getContainer().getElementsByTagName('div');
						for (var n = 0 ; n < divs.length ; ++n) {
							if (divs[n].id == 'iw_kml') {
								var imgs = divs[n].getElementsByTagName('img');
								for (var j = 0 ; j < imgs.length ; ++j) {
									var index = imgs[j].src.indexOf('/mapsatt');
									if (index != -1)
										imgs[j].src = 'http://maps.google.com' + imgs[j].src.substr(index);
								}
							}
						}
					}
					);";
				}
				if ($this->_inline_coords==0) {
					
					$code .= "\nGEvent.addListener(xml".$this->_mp->mapnm."[0], 'load', function() {
								if (xml".$this->_mp->mapnm."[0].loadedCorrectly()) {";
					$code .= "\nxml".$this->_mp->mapnm."[0].gotoDefaultViewport(map".$this->_mp->mapnm.");";
					if ($this->_mp->corzoom!='0')
						$code .= "\nmap".$this->_mp->mapnm.".setZoom(map".$this->_mp->mapnm.".getZoom()+".$this->_mp->corzoom.");";
					$code .= "\nsavePositionKML".$this->_mp->mapnm."();"; 
					$code .= "\n}
							});";
				}
				if (count($this->_mp->kmlsb)!=0) {
					$this->_mp->kmlrenderer = 'geoxml';
					$this->_mp->kml=$this->_mp->kmlsb;
				}
			}
			
			if ($this->_mp->kmlrenderer=="arcgis") {
				$code .= "var xml = [];";
				foreach ($this->_mp->kml as $idx => $val) {
					$code .= "var kmlurl = '".$this->_make_absolute($this->_mp->kml[$idx])."';";
					$code .= "\nkmlurl = kmlurl.replace(/&amp;/g, String.fromCharCode(38));";
					$code .= "\nxml[".$idx."] = new esri.arcgis.gmaps.DynamicMapServiceLayer(kmlurl, null, 0.75, dynmapcallback".$this->_mp->mapnm.");";
				}
			}
			
			if ($this->_mp->kmlrenderer=="geoxml") {
				$code .= "\nvar kml".$this->_mp->mapnm." = [];";
				foreach ($this->_mp->kml as $idx => $val) {
					$code .= "\nvar kmlurl = '".(($this->_mp->proxy=='1')?$this->_make_absolute($this->_mp->kml[$idx]):$this->_mp->kml[$idx])."';";
					$code .= "\nkmlurl = escape(kmlurl.replace(/&amp;/g, String.fromCharCode(38)));";
					$code .= "\nkml".$this->_mp->mapnm.".push(kmlurl);";
				}
				$xmloptions = array();
				if ($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right") {
					$xmloptions[] = "sidebarid: 'kmlsidebar".$this->_mp->mapnm."'";
				} else {
					if ($this->_mp->kmlsidebar!="none")
						$xmloptions[] = "sidebarid: '".$this->_mp->kmlsidebar."'";
				}
				if ($this->_mp->kmlmessshow=='1')
					$xmloptions[] = "messshow: true";
				
				if ($this->_inline_coords==1)
					$xmloptions[] = "nozoom: true";
	
				if ($this->_mp->dir!='0')
					$xmloptions[] = "directions: true";
					
				if ($this->_mp->kmlfoldersopen!='0')
					$xmloptions[] = "allfoldersopen: true";
					
				if ($this->_mp->kmlhide!='0')
					$xmloptions[] = "hideall: true";

				if ($this->_mp->kmlscale!='0')
					$xmloptions[] = "scale: true";

				if ($this->_mp->kmlopenmethod!='0')
					$xmloptions[] = "iwmethod: '".$this->_mp->kmlopenmethod."'";
				
				if ($this->_mp->kmlsbsort=='asc') {
					$xmloptions[] = "sortbyname: 'asc'";
				}elseif ($this->_mp->kmlsbsort=='desc') {
					$xmloptions[] = "sortbyname: 'desc'";
				} else 	
					$xmloptions[] = "sortbyname: 'none'";
	
				if ($this->_mp->kmlclickablemarkers!='1')
					$xmloptions[] = "clickablemarkers: false";
					
				if ($this->_mp->kmlzoommarkers!='0')
					$xmloptions[] = "zoommarkers: '".$this->_mp->kmlzoommarkers."'";

				if ($this->_mp->kmlopendivmarkers!='')
					$xmloptions[] = "opendivmarkers: '".$this->_mp->kmlopendivmarkers."'";

				if ($this->_mp->kmlcontentlinkmarkers!='0')
					$xmloptions[] = "contentlinkmarkers: true";

				if ($this->_mp->kmllinkablemarkers!='0')
					$xmloptions[] = "linkablemarkers: true";

				if ($this->_mp->kmllinktarget!='')
					$xmloptions[] = "linktarget: '".$this->_mp->kmllinktarget."'";

				if ($this->_mp->kmllinkmethod!='')
					$xmloptions[] = "linkmethod: '".$this->_mp->kmllinkmethod."'";

				if (($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")) {
					$xmloptions[] = "polylabelopacity: '".$this->_mp->kmlpolylabel."'";
					$xmloptions[] = "polylabelclass: '".$this->_mp->kmlpolylabelclass."'";
				}
				if (($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!="")) {
					$xmloptions[] = "pointlabelopacity: '".$this->_mp->kmlmarkerlabel."'";
					$xmloptions[] = "pointlabelclass: '".$this->_mp->kmlmarkerlabelclass."'";
				}
				if ($this->_mp->icon!='')
					$xmloptions[] ="baseicon : markericon".$this->_mp->mapnm;
	
				if ($this->_mp->maxcluster!=''&&$this->_mp->gridsize!='') {
					$clusteroptions = array();
					if ($this->_mp->maxcluster!='')
						$clusteroptions[] ="maxVisibleMarkers : ".$this->_mp->maxcluster;
					if ($this->_mp->gridsize!='')
						$clusteroptions[] ="gridSize : ".$this->_mp->gridsize;
					if ($this->_mp->minmarkerscluster!='')
						$clusteroptions[] ="minMarkersPerCluster : ".$this->_mp->minmarkerscluster;
					if ($this->_mp->maxlinesinfocluster!='')
						$clusteroptions[] ="maxLinesPerInfoBox : ".$this->_mp->maxlinesinfocluster;
					if ($this->_mp->clusterinfowindow!='')
						$clusteroptions[] ="ClusterInfoWindow : '".$this->_mp->clusterinfowindow."'" ;
					if ($this->_mp->clusterzoom!='')
						$clusteroptions[] ="ClusterZoom : '".$this->_mp->clusterzoom."'" ;
					if ($this->_mp->clustermarkerzoom!='')
						$clusteroptions[] ="ClusterMarkerZoom : ".$this->_mp->clustermarkerzoom;
					if ($this->_mp->icon!='')
						$clusteroptions[] ="Icon : markericon".$this->_mp->mapnm;
	
					$xmloptions[] = "clustering : {".implode(",",$clusteroptions)."}";
				}
				
				$xmloptions[] = "titlestyle: ' '";
					
				$code .= "\nexml".$this->_mp->mapnm." = new GeoXml(\"exml".$this->_mp->mapnm."\", map".$this->_mp->mapnm.", kml".$this->_mp->mapnm.", {".implode(",",$xmloptions)."});";
				$code .= "\nexml".$this->_mp->mapnm.".parse(); ";
				if ($this->_inline_coords==0&&$this->_mp->corzoom!='0')
					$code .= "\nsetTimeout('map".$this->_mp->mapnm.".setZoom(map".$this->_mp->mapnm.".getZoom()+".$this->_mp->corzoom.")', 750);";
			}
		}
	
		if ($this->_mp->traffic=='1') {
			$code .= "\ntrafficInfo".$this->_mp->mapnm." = new GTrafficOverlay();";
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(trafficInfo".$this->_mp->mapnm.");";
		}
	
		if ($this->_mp->panoramio!="none") {
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('com.panoramio.".$this->_mp->panoramio."'));";
		}
		if ($this->_mp->panotype!="none") {
			$code .= "\n  var options = {
							order: '".$this->_mp->panoorder."',
							set: '".$this->_mp->panotype."', 
							to: '".$this->_mp->panomax."' };
						panoLayer".$this->_mp->mapnm." = new PanoramioLayer(map".$this->_mp->mapnm.", options);
						panoLayer".$this->_mp->mapnm.".enable();";
		}
		
		if ($this->_mp->youtube!="none") {
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('com.youtube.".$this->_mp->youtube."'));";
		}
	
		if ($this->_mp->wiki!="none") {
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('org.wikipedia.".$this->_mp->wiki."'));";
		}
		
		if (count($this->_mp->layer)>0) {
			foreach ($this->_mp->layer as $lay) {
				$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('".$lay."'));";
			}
		}
		
		if ($this->_mp->localsearch=='1') {
			$code .= "localsearch".$this->_mp->mapnm." = new google.maps.LocalSearch(".((!empty($searchoptions))?"{ ".$searchoptions." }":"").");";
			$code .= "map".$this->_mp->mapnm.".addControl(localsearch".$this->_mp->mapnm.", new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10,20)));";
			if (!empty($this->_mp->searchtext))
				$code .= "localsearch".$this->_mp->mapnm.".execute('".$this->_mp->searchtext."');";
		}
		
		if ($this->_mp->googlebar=='1') {
			$code .= "map".$this->_mp->mapnm.".enableGoogleBar();";
		}
	
		if ($this->_mp->adsmanager=='1') {
			$code .= "adsmanager".$this->_mp->mapnm." = new GAdsManager(map".$this->_mp->mapnm.", ".((!empty($this->_mp->adsense))?"'".$this->_mp->adsense."'":"''").", { style: 'adunit', maxAdsOnMap: ".$this->_mp->maxads.((!empty($this->_mp->searchtext))?", keywords: '".$this->_mp->searchtext."'":"").((!empty($this->_mp->channel)&&!empty($this->_mp->adsense))?", channel: '".$this->_mp->channel."'":"").(($this->_mp->localsearch=='1')?", position: new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(20,20))":"")."}); ";
			$code .= "adsmanager".$this->_mp->mapnm.".enable();";
		}
	
		if ($this->debug_plugin=="1")
			$code.="map".$this->_mp->mapnm.".addControl(new VersionControl());";
	
		if (((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->toaddress))&&$this->_mp->animdir=='0'&&$this->_mp->formaddress!='1') {
			// Route
			$xmloptions = array();
			if ($this->_mp->dirtype=='W')
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_WALKING";
			else
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_DRIVING";
			
			if ($this->_mp->avoidhighways=='1')
				$xmloptions[] = "avoidHighways : true";
			else
				$xmloptions[] = "avoidHighways : false";
			
			$code .= "var dirsidebar".$this->_mp->mapnm." = document.getElementById('dirsidebar".$this->_mp->mapnm."');";
			$code .= "if (directions".$this->_mp->mapnm.") {
							directions".$this->_mp->mapnm.".clear();
							if ( dirsidebar".$this->_mp->mapnm.".hasChildNodes() )
							{
								while ( dirsidebar".$this->_mp->mapnm.".childNodes.length >= 1 )
								{
									dirsidebar".$this->_mp->mapnm.".removeChild( dirsidebar".$this->_mp->mapnm.".firstChild );
								} 
							}
					} else {
							directions".$this->_mp->mapnm." = new GDirections(map".$this->_mp->mapnm.", dirsidebar".$this->_mp->mapnm.");
							GEvent.addListener(directions".$this->_mp->mapnm.", 'error', handleErrors".$this->_mp->mapnm.");
						}
				";
				
			if (is_array($this->_mp->waypoints)&&count($this->_mp->waypoints)>0) {
				if ($this->_mp->address!="")
					array_unshift($this->_mp->waypoints, $this->_mp->address);
				else if ($lat !=""&&$lon!="")
					array_unshift($this->_mp->waypoints, $lat.", ".$lon);
				
				if ($this->_mp->toaddress!="")
					array_push($this->_mp->waypoints, $this->_mp->toaddress);
				else if ($this->_mp->tolat!=""&&$this->_mp->tolon!="")
					array_push($this->_mp->waypoints, $this->_mp->tolat.", ".$this->_mp->tolon);
				
				$wpstring="";
				foreach ($this->_mp->waypoints as $wp) {
					if ($wpstring!="")
						$wpstring.= ", ";
					$wpstring .= "'".$wp."'";
				}
				$code.="\ndirections".$this->_mp->mapnm.".loadFromWaypoints([".$wpstring."], {".implode(",",$xmloptions)."});";
			} else
				$code.="\ndirections".$this->_mp->mapnm.".load('from: ".(($this->_mp->address!="")?$this->_mp->address:(($this->_mp->latitude!='')?$this->_mp->latitude:$this->_mp->deflatitude).", ".(($this->_mp->longitude!='')?$this->_mp->longitude:$this->_mp->deflongitude))." to: ".(($this->_mp->toaddress!="")?$this->_mp->toaddress:$this->_mp->tolat.", ".$this->_mp->tolon)."', {".implode(",",$xmloptions)."});";
		}
		
		switch (strtolower($this->_mp->mapType)) {
		case "satellite":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_SATELLITE_MAP);";
			break;
		
		case "hybrid":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_HYBRID_MAP);";
			break;
	
		case "terrain":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_PHYSICAL_MAP);";
			break;
	
		case "earth":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_SATELLITE_3D_MAP);";
			$code.="\nmap".$this->_mp->mapnm.".getEarthInstance(initearth".$this->_mp->mapnm.");";
			break;
		
		default:
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_NORMAL_MAP);";
			break;
		}
		
		$code .="\nvar mt = map".$this->_mp->mapnm.".getMapTypes();
		for (var i=0; i<mt.length; i++) {
			mt[i].getMinimumResolution = function() {return ".$this->_mp->minzoom.";};
			mt[i].getMaximumResolution = function() {return ".$this->_mp->maxzoom.";};
		}";
	
		if($this->_mp->zoomnew=='1'&&$this->_mp->controltype=='user')
		{
			$code.="
			map".$this->_mp->mapnm.".enableContinuousZoom();
			map".$this->_mp->mapnm.".enableDoubleClickZoom();
			";
		} else {
			$code.="
			map".$this->_mp->mapnm.".disableContinuousZoom();
			map".$this->_mp->mapnm.".disableDoubleClickZoom();
			";
		}
	
		if($this->_mp->zoomwheel=='1'&&$this->_mp->controltype=='user')
		{
			$code.="map".$this->_mp->mapnm.".enableScrollWheelZoom();
			";
		} 
	
		if (($this->_inline_coords == 0 && count($this->_mp->kml)==0) // No inline coordinates and no kml => standard configuration
			||($this->_mp->latitude !=''&&$this->_mp->longitude!=''&&!($this->_mp->geocoded==1&&$this->_mp->toaddress!=''&&$this->_mp->description==''))) { // Inline coordinates and text is not empty
			$options = '';
			
			if ($this->_mp->tooltip!='') 
				$options .= (($options!='')?', ':'')."title:\"".$this->_mp->tooltip."\"";
			if ($this->_mp->icon!='')
				$options .= (($options!='')?', ':'')."icon:markericon".$this->_mp->mapnm;
			
			$code.="var marker".$this->_mp->mapnm." = new GMarker(point".(($options!='')?', {'.$options.'}':'').");";
			
			$code.="map".$this->_mp->mapnm.".addOverlay(marker".$this->_mp->mapnm.");
			";
	
			if ($this->_mp->description!=''||$this->_mp->dir!='0') {
				// convert $this->_mp->description to maybe tabs?
				// Check <tab> tag
				$reg='/(<tab\s*?(title=\\\?"(.*?)\\\?")?>)(.*?)(<\/tab>)/si';
				$c=preg_match_all($reg,$this->_mp->description,$m);
	
				// if <tab> then make array of $this->_mp->description
				if ($c>0) {
					$this->_mp->description= array();
					for ($z=0;$z<$c;$z++) {
						// transform attribute title to title of tab
						$this->_mp->description[$z]->title = htmlspecialchars_decode($m[3][$z], ENT_NOQUOTES);
						$this->_mp->description[$z]->text = htmlspecialchars_decode($m[4][$z], ENT_NOQUOTES);
					}
				}
				if ($this->_mp->dir!='0') {
					$dirform="<form id='directionform".$this->_mp->mapnm."' action='".$this->protocol.$this->googlewebsite."/maps' method='get' target='_blank' onsubmit='DirectionMarkersubmit".$this->_mp->mapnm."(this);return false;' class='mapdirform'>";
					
					$dirform.=$this->_mp->txtdir."<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='radio' ")." ".(($this->_mp->dirdefault=='0')?"checked='checked'":"")." name='dir' value='to'>".(($this->_mp->txtto!='')?$this->_mp->txtto."&nbsp;":"")."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='radio' ").(($this->_mp->dirdefault=='1')?"checked='checked'":"")." name='dir' value='from'>".(($this->_mp->txtfrom!='')?$this->_mp->txtfrom:"");
					$dirform.="<br />".$this->_mp->txtdiraddr."<input type='text' class='inputbox' size='20' name='saddr' id='saddr' value='' /><br />";
	
					if ($this->_mp->txt_driving!=''||$this->_mp->dirtype=="D")
							$dirform.="<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"");
					if ($this->_mp->txt_avhighways!=''||$this->_mp->dirtype=="1")
						$dirform.="<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"");
					if ($this->_mp->txt_walking!=''||$this->_mp->dirtype=="W")
						$dirform.="<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"");
					if ($this->_mp->txt_driving!=''||$this->_mp->txt_avhighways!=''||$this->_mp->txt_walking!='')
						$dirform.="<br />";	
					$dirform.="<input value='".$this->_mp->txtgetdir."' class='button' type='submit' style='margin-top: 2px;'>";
					
					if ($this->_mp->dir=='2')
						$dirform.= "<input type='hidden' name='pw' value='2'/>";
	
					if ($this->_mp->lang!='') 
						$dirform.= "<input type='hidden' name='hl' value='".$this->_mp->lang."'/>";
	
					if (!empty($this->_mp->address))
						$dirform.="<input type='hidden' name='daddr' value='".$this->_mp->address."'/></form>";
					else
						$dirform.="<input type='hidden' name='daddr' value='".(($this->_mp->latitude!='')?$this->_mp->latitude:$this->_mp->deflatitude).", ".(($this->_mp->longitude!='')?$this->_mp->longitude:$this->_mp->deflongitude)."'/></form>";
					
					// Add form before div or at the end of the html.
					if (is_array($this->_mp->description)) {
						$this->_mp->description[$z+1]->title = $this->_mp->txtdir;
						$this->_mp->description[$z+1]->text = htmlspecialchars_decode($dirform, ENT_NOQUOTES);
					} else {
						$pat="/&lt;\/div&gt;$/";
						if (preg_match($pat, $this->_mp->description))
							$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
						else {
							$pat="/<\/div>$/";
							if (preg_match($pat, $this->_mp->description))
								$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
							else
								$this->_mp->description.=$dirform;
						}
					}
				}
				
				if (!is_array($this->_mp->description))
					$this->_mp->description = htmlspecialchars_decode($this->_mp->description, ENT_NOQUOTES);
	
				// If marker 
				if ($this->_mp->marker==1) {
					if (is_array($this->_mp->description)) {
						$code .= "marker".$this->_mp->mapnm.".openInfoWindowTabsHtml([";
						$first = true;
						foreach ($this->_mp->description as $tab) {
							if ($first) 
								$first = false;
							else 
								$code.=",  ";
								
							$code.= "new GInfoWindowTab(\"".$tab->title."\", \"".$tab->text."\")";
						}
						
						$code .= "]);";  
						
					} else
						$code.="marker".$this->_mp->mapnm.".openInfoWindowHtml(\"".$this->_mp->description."\");"; 
				}
				
				$code.="GEvent.addListener(marker".$this->_mp->mapnm.", 'click', function() {
						marker".$this->_mp->mapnm;
				if (is_array($this->_mp->description)) {
					$code .=".openInfoWindowTabsHtml([";
					$first = true;
					foreach ($this->_mp->description as $tab) {
						if ($first) 
							$first = false;
						else 
							$code.=",  ";
							
						$code.= "new GInfoWindowTab(\"".$tab->title."\", \"".$tab->text."\")";
					}
					
					$code .= "]);";  
					
				} else
					$code.=".openInfoWindowHtml(\"".$this->_mp->description."\");";
					
				$code.="});
				";
			}
		}
		
		if ($this->_mp->imageurl!='') {
			$code .= "imageovl".$this->_mp->mapnm." = new GScreenOverlay('{$this->_mp->imageurl}',
									new GScreenPoint({$this->_mp->imagex}, {$this->_mp->imagey}, '{$this->_mp->imagexyunits}', '{$this->_mp->imagexyunits}'),  // screenXY
									new GScreenPoint({$this->_mp->imageanchorx}, {$this->_mp->imageanchory}, '{$this->_mp->imageanchorunits}', '{$this->_mp->imageanchorunits}'),  // overlayXY
									new GScreenSize({$this->_mp->imagewidth}, {$this->_mp->imageheight})  // size on screen
								);
						map".$this->_mp->mapnm.".addOverlay(imageovl".$this->_mp->mapnm.");
				";
		}
		if ($this->_mp->animdir=='0'&&($this->_mp->sv=='top'||$this->_mp->sv=='bottom'||($this->_mp->sv!='none'&&$this->_mp->sv!='top'&&$this->_mp->sv!='bottom'))) {
			if ($this->_mp->sv!='none'&&$this->_mp->sv!='top'&&$this->_mp->sv!='bottom')
				$code.="\npanobj".$this->_mp->mapnm." = document.getElementById('".$this->_mp->sv."');
						";
			else
				$code.="\npanobj".$this->_mp->mapnm." = document.getElementById('svpanorama".$this->_mp->mapnm."');
						";
			$this->_mp->svopt = "";
			if ($this->_mp->svyaw!='0')
				$this->_mp->svopt .= "yaw:".$this->_mp->svyaw;
			if ($this->_mp->svpitch!='0')
				$this->_mp->svopt .= (($this->_mp->svopt=="")?"":", ")."pitch:".$this->_mp->svpitch;
			if ($this->_mp->svzoom!='')
				$this->_mp->svopt .= (($this->_mp->svopt=="")?"":", ")."zoom:".$this->_mp->svzoom;
				
			$code.="\nsvpanorama".$this->_mp->mapnm." = new GStreetviewPanorama(panobj".$this->_mp->mapnm.");
					svlastpoint".$this->_mp->mapnm." = map".$this->_mp->mapnm.".getCenter();
					svpanorama".$this->_mp->mapnm.".setLocationAndPOV(svlastpoint".$this->_mp->mapnm.", ".(($this->_mp->svopt!='')?"{".$this->_mp->svopt."}":'null').");
					svmarker".$this->_mp->mapnm." = new GMarker(svlastpoint".$this->_mp->mapnm.", {icon: guyIcon".$this->_mp->mapnm." , draggable: true});
					map".$this->_mp->mapnm.".addOverlay(svmarker".$this->_mp->mapnm.");
					GEvent.addListener(svmarker".$this->_mp->mapnm.", 'dragend', onDragEnd".$this->_mp->mapnm.");
					GEvent.addListener(svpanorama".$this->_mp->mapnm.", 'initialized', onNewLocation".$this->_mp->mapnm.");
					GEvent.addListener(svpanorama".$this->_mp->mapnm.", 'yawchanged', onYawChange".$this->_mp->mapnm."); 
					";
			if ($this->_mp->svautorotate=="1")		
				$code.="\npanobj".$this->_mp->mapnm.".addEventListener('mouseover', svmouseover".$this->_mp->mapnm.", true);
					panobj".$this->_mp->mapnm.".addEventListener('mouseout', svmouseout".$this->_mp->mapnm.", true);
					";
		}
	
		if ($this->_mp->animdir!="0") {
			$xmloptions = array();
			$xmloptions[] = "preserveViewport: false";
			$xmloptions[] = "getSteps: true";
			
			if ($this->_mp->dirtype=='W')
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_WALKING";
			else
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_DRIVING";
			
			if ($this->_mp->avoidhighways=='1')
				$xmloptions[] = "avoidHighways : true";
			else
				$xmloptions[] = "avoidHighways : false";
				
			$opts = array();
			if ($this->_mp->animspeed!=1)
				$opts[] = "Speed : ".$this->_mp->animspeed;
			if ($this->_mp->animautostart!=0)
				$opts[] = "AutoStart : true";
			if ($this->_mp->animunit!='')
				$opts[] = "Unit : '".$this->_mp->animunit."'";
	//					$opts[] = "zoomlevel : ".$this->_mp->zoom;
			if ($this->_mp->dirtype=='W')
				$opts[] = "travelMode : G_TRAVEL_MODE_WALKING";
			else
				$opts[] = "travelMode : G_TRAVEL_MODE_DRIVING";
			
			if ($this->_mp->avoidhighways=='1')
				$opts[] = "avoidHighways : true";
			else
				$opts[] = "avoidHighways : false";
	
			$code.="\nvar panobj = document.getElementById('svpanorama".$this->_mp->mapnm."');
					svpanorama".$this->_mp->mapnm." = new GStreetviewPanorama(panobj);
					directions".$this->_mp->mapnm." = new GDirections(map".$this->_mp->mapnm.");
					";
	
			$lang = "";
			foreach ($this->_langanim as $al) {
				$lang.=(($lang=='')?"":",")."'".$al."'";
			}
			
			$code.="\nopts = {".implode(",",$opts)."};
					lang = [".$lang."];
					";
			$code .="\nroute".$this->_mp->mapnm." = new Directionsobj('route".$this->_mp->mapnm."', map".$this->_mp->mapnm.", '".$this->_mp->mapnm."', svpanorama".$this->_mp->mapnm.", svclient".$this->_mp->mapnm.", directions".$this->_mp->mapnm.", centerpoint, opts, lang);";
			
			if (is_array($this->_mp->waypoints)&&count($this->_mp->waypoints)>0) {
				if ($this->_mp->address!="")
					array_unshift($this->_mp->waypoints, $this->_mp->address);
				if ($this->_mp->toaddress!="")

					array_push($this->_mp->waypoints, $this->_mp->toaddress);
				$wpstring="";
				foreach ($this->_mp->waypoints as $wp) {
					if ($wpstring!="")
						$wpstring.= ", ";
					$wpstring .= "'".$wp."'";
				}
				$code.="\ndirections".$this->_mp->mapnm.".loadFromWaypoints([".$wpstring."], {".implode(",",$xmloptions)."});";
			} else
				$code.="\ndirections".$this->_mp->mapnm.".load('from: ".$this->_mp->address." to: ".$this->_mp->toaddress."', {".implode(",",$xmloptions)."});";
		}
		
		if ($this->_mp->tilelayer!="") {
			$this->_mp->tilebounds=explode(",", $this->_mp->tilebounds);
			if (count($this->_mp->tilebounds)==4) {
				$code .="\nvar tileopts = {};";				
				if ($this->_mp->tilemethod!='maptiler') { 
					$this->_mp->tilemethod = str_replace('[', '{', $this->_mp->tilemethod);
					$this->_mp->tilemethod = str_replace(']', '}', $this->_mp->tilemethod);
					$this->_mp->tilemethod = str_replace('&amp;', '&', $this->_mp->tilemethod);
					$code .="\ntileopts.tileUrlTemplate = '".$this->_make_absolute($this->_mp->tilemethod)."';";
				}
				
				$code .="\ncopyright".$this->_mp->mapnm." = new GCopyrightCollection('');";
				$code .="copyright".$this->_mp->mapnm.".addCopyright(new GCopyright('', new GLatLngBounds(new GLatLng(".$this->_mp->tilebounds[0].", ".$this->_mp->tilebounds[1]."), new GLatLng(".$this->_mp->tilebounds[2].", ".$this->_mp->tilebounds[3].")), ".$this->_mp->tileminzoom.",''));";				
				$code .="\ntilelayer".$this->_mp->mapnm." = new GTileLayer(copyright".$this->_mp->mapnm.", ".$this->_mp->tileminzoom.", ".$this->_mp->tilemaxzoom.", tileopts);";
				
				$code .="\ntilelayer".$this->_mp->mapnm.".isPng = function() { return true;};
				tilelayer".$this->_mp->mapnm.".getOpacity = function() { return ".$this->_mp->tileopacity."; };";
				if ($this->_mp->tilemethod=='maptiler') {
					$code .="\nmercator".$this->_mp->mapnm." = new GMercatorProjection(".($this->_mp->tilemaxzoom+1).");
					tilelayer".$this->_mp->mapnm.".getTileUrl = function(tile,zoom) {
						if ((zoom < ".$this->_mp->tileminzoom.") || (zoom > ".$this->_mp->tilemaxzoom.")) {
							return '".$this->_make_absolute($this->_mp->tilelayer)."/none.png';
						} 
						var ymax = 1 << zoom;
						var y = ymax - tile.y -1;
						var tileBounds = new GLatLngBounds(
							mercator".$this->_mp->mapnm.".fromPixelToLatLng( new GPoint( (tile.x)*256, (tile.y+1)*256 ) , zoom ),
							mercator".$this->_mp->mapnm.".fromPixelToLatLng( new GPoint( (tile.x+1)*256, (tile.y)*256 ) , zoom )
						);
						if (tileBounds".$this->_mp->mapnm.".intersects(tileBounds)) {
							return '".$this->_make_absolute($this->_mp->tilelayer)."/'+zoom+'/'+tile.x+'/'+y+'.png';
						} else {
							return '".$this->_make_absolute($this->_mp->tilelayer)."/none.png';
						}
					};
					tileBounds".$this->_mp->mapnm." = new GLatLngBounds(new GLatLng(".$this->_mp->tilebounds[0].", ".$this->_mp->tilebounds[1]."), new GLatLng(".$this->_mp->tilebounds[2].", ".$this->_mp->tilebounds[3]."));";
				}

				$code .="\nvar overlay".$this->_mp->mapnm." = new GTileLayerOverlay( tilelayer".$this->_mp->mapnm.", {zPriority:0 } );
				map".$this->_mp->mapnm.".addOverlay(overlay".$this->_mp->mapnm.");";
			}
		}
		
		if($this->_mp->zoomwheel=='1')
		{
			$code.="GEvent.addDomListener(tst".$this->_mp->mapnm.", 'DOMMouseScroll', CancelEvent".$this->_mp->mapnm.");
					GEvent.addDomListener(tst".$this->_mp->mapnm.", 'mousewheel', CancelEvent".$this->_mp->mapnm.");
				";
		}
	
		/* remove link in google logo. Do not use
		$code.= "\nvar func".$this->_mp->mapnm." = function () {";
		$code.= "\n	var test_div = document.getElementById('googlemap".$this->_mp->mapnm."');";
		$code.= "\n	var test_obj = test_div.childNodes[1];";
		$code.= "\n	test_obj = test_obj.getElementsByTagName('a');";
		$code.= "\n	if (test_obj&&test_obj.length>0)";
		$code.= "\n		test_obj[0].href = '".$this->protocol.$this->googlewebsite."';";
		$code.= "\n};";
		$code.= "\nsetTimeout(func".$this->_mp->mapnm.", 1500);";
		*/
		
		/* remove copyright, terms and mapdata. Do not use 					
		$code.= "test_div = document.getElementById('googlemap".$this->_mp->mapnm."');";
		$code.= "test_obj = test_div.childNodes[1].style.display='none';";
		$code.= "test_obj = test_div.childNodes[2].style.display='none';";
		*/
	
		if($this->_client_geo == 1) {
			if ($this->clientgeotype=="local")
				$code.="	});
					localSearch.execute(address);";
			else
				$code.="		       
							  });";
		}
	
		// End of script voor showing the map 
		if ($this->_mp->show!=0)
			$code.="\n	}";
			
		$code.="\n}
		/*]]>*/</script>
		";
		
		// Call the Maps through timeout to render in IE also
		// Set an event for watching the changing of the map so it can refresh itself
		$code.= "<script type=\"text/javascript\">/*<![CDATA[*/
				if (GBrowserIsCompatible()) {
					obj = document.getElementById('mapbody".$this->_mp->mapnm."');
					obj.style.display = 'block';
					window.onunload=function(){window.onunload;GUnload()};
					tst".$this->_mp->mapnm.".setAttribute(\"oldValue\",0);
					tst".$this->_mp->mapnm.".setAttribute(\"refreshMap\",0);
					";
		
		if ($this->_mp->loadmootools=='1') {
		$code.= "if (window.MooTools==null)
					tstint".$this->_mp->mapnm."=setInterval(\"checkMap".$this->_mp->mapnm."()\",".$this->timeinterval.");
				else
					window.addEvent('domready', function() {
							tstint".$this->_mp->mapnm."=setInterval('checkMap".$this->_mp->mapnm."()', ".$this->timeinterval.");
						});
				";
		} else {
			$code.= "tstint".$this->_mp->mapnm."=setInterval(\"checkMap".$this->_mp->mapnm."()\",".$this->timeinterval.");
					";
		}
		
		$code.= "}
		/*]]>*/</script>
		";
	
		// Clean up variables except generated code and memory variables
		unset($fields, $value, $values, $coord, $tocoord, $client_togeo, $searchoption, $lboptions, $url, $la, $cam, $replace, $addr, $idx, $val, $xmloptions, $clusteroptions, $wpstring, $wp, $options, $reg, $c, $z, $dirform, $first, $opts, $al, $kmz);
		
		return array($code, $lbcode);
	}
	
	function _findgeoparam() {
		// Find latitude, longitude or address inside the text
		// Later tolat, tolon or toaddress
	
		$reg='/<td\b[^>]*><strong>Latitude:<\/strong>(.*?)<\/td>/si';
		$c=preg_match_all($reg,$this->_text,$m);
		if ($c>0) {
			$this->_mp->latitude=$this->_remove_html_tags($m[1][0]);
			$this->_inline_coords = 1;
		}
			
		$reg='/<td\b[^>]*><strong>Longitude:<\/strong>(.*?)<\/td>/si';
		$c=preg_match_all($reg,$this->_text,$m);
		if ($c>0) {
			$this->_mp->longitude=$this->_remove_html_tags($m[1][0]);
			$this->_inline_coords = 1;
		}

		$reg='/<td\b[^>]*><strong>City:<\/strong>(.*?)<\/td>/si';
		$c=preg_match_all($reg,$this->_text,$m);
		if ($c>0)
			$this->_mp->address = $m[1][0];
	}
	
	function _processMapv3() {
		// Variables of process
		$code='';
		$lbcode='';
		
		//Detect browsers for special changes
		$iphone = strpos($_SERVER['HTTP_USER_AGENT']," iPhone");
		$android = strpos($_SERVER['HTTP_USER_AGENT'],"Android");
		$ipod = strpos($_SERVER['HTTP_USER_AGENT']," iPod");
//		Setting width and height is not correct because in mobile browser it's a wesbite rendering and width 100% or height 100% i snot supported.
//		if($iphone || $android || $ipod) {
//			$this->_mp->width = '100%';
//			$this->_mp->height = '100%';
//		}
		
		// Iphone or Ipod add special meta tag
//		if($iphone || $ipod) {
//			$this->document->setMetaData("viewport", "initial-scale=1.0, user-scalable=no");
//		}
		
		// No inline coordinates and no kml => standard configuration show marker based on defaults
		if ($this->_inline_coords == 0 && $this->_client_geo != 1 && count($this->_mp->kml)==0) { 
			$this->_mp->latitude = $this->_mp->deflatitude;
			$this->_mp->longitude = $this->_mp->deflongitude;
		}
		
		if (is_array($this->_mp->waypoints)) {
			$waypoints = array();
			foreach ($this->_mp->waypoints as $wp) {
				array_push($waypoints, $wp);
			}
			$this->_mp->waypoints = $waypoints;
			unset($waypoints);
		}

		if ($this->_mp->styledmap)
			$this->_styledmap = $this->_mp->styledmap;
		else
			$this->_styledmap = "null";
		
		unset($this->_mp->styledmap);
		
		$this->_processMapv3_scripts();
		
		list ($code, $lbcode) = $this->_processMapv3_template();
		
		$this->_processMapv3_markers();
		$this->_processMapv3_kml();
		$this->_processMapv3_tiles();
		$code .= $this->_processMapv3_icons();
		$this->_processMapv3_streetview();
	
		$code.="\n<script type='text/javascript'>/*<![CDATA[*/";
		
		if ($this->_mp->kmlrenderer=='geoxml') {
			if ($this->_mp->proxy=="1") {
				if (substr($this->jversion,0,3)=="1.5")
					$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2_proxy.php?';";
				else
					$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2/plugin_googlemap2_proxy.php?';";
			}
			$code.="\ntop.publishdirectory = '".$this->base."/media/plugin_googlemap2/site/geoxml/';";
		}

		$code.= "\nvar mapconfig".$this->_mp->mapnm." = ".$this->json_encode($this->_mp).";";
		$code.= "\nvar mapstyled".$this->_mp->mapnm." = ".$this->_styledmap.";";
		$code.= "\nvar googlemap".$this->_mp->mapnm." = new GoogleMaps('".$this->_mp->mapnm."', mapconfig".$this->_mp->mapnm.", mapstyled".$this->_mp->mapnm.");";
		$code.= "\n/*]]>*/</script>";
		
		return array($code, $lbcode);
	}
	
	function json_encode($a=false)
	{
		if (!function_exists('json_encode')) {
			if (is_null($a)) return 'null';
			if ($a === false) return 'false';
			if ($a === true) return 'true';
			if (is_scalar($a))
			{
			  if (is_float($a))
			  {
				// Always use "." for floats.
				return floatval(str_replace(",", ".", strval($a)));
			  }
			
			  if (is_string($a))
			  {
				static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
				return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"';

			  }
			  else
				return $a;
			}
			$isList = true;
			for ($i = 0, reset($a); $i < count($a); $i++, next($a))
			{
			  if (key($a) !== $i)
			  {
				$isList = false;
				break;
			  }
			}
			$result = array();
			if ($isList)
			{
			  foreach ($a as $v) $result[] = $this->json_encode($v);
			  return '[' . join(",", $result) . ']';
			}
			else
			{
			  foreach ($a as $k => $v) $result[] = $this->json_encode($k).':'.$this->json_encode($v);
			  return '{' . join(",", $result) . '}';
			}
		} else
			return json_encode($a);
	}
	
	function _processMapv3_scripts() {
		// Only add the scripts and css once
		//Load mootools first because it's necessary for the extra functions like lightbox or effects
		// For effects we need to load mootools-more/framework true too
		if (($this->_mp->loadmootools=="1"&&$this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->effect!="none"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_mootools) {
			if ($this->event!='onAfterRender') {
				if (substr($this->jversion,0,3)=='1.5')
					JHTML::_('behavior.mootools');
				else
					JHtml::_('behavior.framework',(($this->_mp->effect!="none")?true:false));				
			} else {
				if (substr($this->jversion,0,3)=='1.5') {
					$url = $this->base."/plugins/system/mtupgrade/mootools.js";
					$this->_addscript($url);
				} else {
					$mooconfig = JFactory::getConfig();
		            $moodebug = $mooconfig->get('debug');
			        $moouncompressed   = $moodebug ? '-uncompressed' : '';
					$url = $this->base."/media/system/js/mootools-core".$moouncompressed.".js";
					$this->_addscript($url);
					if ($this->_mp->effect!="none") {
						$url = $this->base."/media/system/js/mootools-more".$moouncompressed.".js";
						$this->_addscript($url);
					}
					unset($mooconfig, $moodebug, $moouncompressed);
				}
			}
			$this->first_mootools = false;
		}
		
		if($this->first_google) {
			if ($this->protocol=='http://')
				$url = $this->protocol.$this->googlewebsite."/maps/api/js?v=".$this->google_API_version;
			else {
				$url = 'maps.googleapis.com';
				$url = $this->protocol.$url."/maps/api/js?v=".$this->google_API_version;
			}
			
			if ($this->googlekey!="")
				$url .= "&amp;key=".$this->googlekey;

			if ($this->_mp->lang!='') 
				$url .= "&amp;language=".$this->_mp->lang;
			if ($this->region!='') 
				$url .= "&amp;region=".$this->region;

			$library = array();
			if ($this->_mp->autocompl!='none')
				$library[]='places';
			if ($this->_mp->weather=='1'||$this->_mp->weathercloud=='1')
				$library[]='weather';				

			if (count($library)>0)
				$url .= "&amp;libraries=".implode(',', $library);
				
			$url .= "&amp;sensor=false";
			
			$this->_addscript($url);
			$this->first_google=false;
		}
		
		if ($this->_mp->mapType=='earth'||$this->_mp->showearthmaptype=="1") {
			$this->_addscript($this->protocol."www.google.com/jsapi?key=".$this->googlekey);
			$this->_addscript($this->protocol."www.google.com/uds/?file=earth&amp;v=1");
			$this->_addscript($this->base."/media/plugin_googlemap2/site/googleearthv3/googleearth.js");
			$this->first_googleearth = false;
		}
		
		if($this->first_googlemaps) {
			$url = $this->base."/media/plugin_googlemap2/site/googlemaps/googlemapsv3.js";
			$this->_addscript($url);
			if ($this->mapcss!='') {
				$url = $this->base."/media/plugin_googlemap2/site/googlemaps/googlemaps.css.php";
				$this->_addstylesheet($url);
			}
			$this->first_googlemaps=false;
		}		
		
		if ($this->first_kmlelabel&&(($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")||($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!=""))) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/elabel/elabel_v3.js");
			$this->first_kmlelabel = false;
		}

		if (($this->_mp->kmlrenderer=='geoxml'||count($this->_mp->kmlsb)!=0)&&$this->first_kmlrenderer) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/geoxmlv3/geoxmlv3.js");
			$this->first_kmlrenderer = false;
		}

		if (($this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_modalbox)	{
			if (substr($this->jversion,0,3)=='1.5')
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/modalbox1.2hackv3.js");
			else
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/moodalbox1.3hackv3.js");
			
			$this->_addstylesheet($this->base."/media/plugin_googlemap2/site/moodalbox/css/moodalbox.css");
			$this->first_modalbox = false;
		}
		
		if (($this->_mp->localsearch=="1"||$this->_mp->clientgeotype=='local')&&$this->first_localsearch) {
			$this->_addscript($this->protocol."www.google.com/uds/api?file=uds.js&amp;v=1.0&amp;key=".$this->googlekey);
			$style = "@import url('".$this->protocol."www.google.com/uds/css/gsearch.css');\n@import url('".$this->protocol."www.google.com/uds/solutions/localsearch/gmlocalsearch.css');";
			$this->_addstyledeclaration($style);
			$this->first_localsearch = false;
		}
		
		// Clean up variables except generated code and memory variables
		unset($url,$library);
	}
	
	function _processMapv3_markers() {
		$this->_mp->descr = ($this->_mp->description!='')?'1':'0';
		if ($this->_mp->description!=''||$this->_mp->dir!='0') {
			if ($this->_mp->dir!='0')
				$dirform =$this->_processMapv3_templatedirform('Marker');
			else
				$dirform = "";

			// Where to add dirform? tab or add the end of description?
			if (is_array($this->_mp->description)) {
				$this->_mp->description[$z+1]->title = $this->_mp->txtdir;
				$this->_mp->description[$z+1]->text = htmlspecialchars_decode($dirform, ENT_NOQUOTES);
			} else {
				$pat="/&lt;\/div&gt;$/";
				if (preg_match($pat, $this->_mp->description))
					$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
				else {
					$pat="/<\/div>$/";
					if (preg_match($pat, $this->_mp->description))
						$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
					else
						$this->_mp->description.=$dirform;
				}
			}

			
			if (!is_array($this->_mp->description))
				$this->_mp->description = htmlspecialchars_decode($this->_mp->description, ENT_NOQUOTES);
				
			// Encrypt description
			$this->_mp->description = htmlentities($this->_mp->description, ENT_QUOTES, "UTF-8");
		}
		$this->_mp->tooltip =  htmlentities($this->_mp->tooltip, ENT_QUOTES, "UTF-8");
	}
	
	function _processMapv3_tiles () {
		if ($this->_mp->tilelayer!="") {
			$this->_mp->tilebounds=explode(",", $this->_mp->tilebounds);
			if (count($this->_mp->tilebounds)==4) {
				$checkboundtiles = "if (googlemap".$this->_mp->mapnm.".checkboundTilelayer(coord, zoom)) {";
			} else {
				$checkboundtiles = "";
				unset($this->_mp->tilebounds);
			}
	
			if ($this->_mp->tilemethod!='maptiler') { 
				$this->_mp->tilemethod = str_replace('[', '{', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace(']', '}', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('&amp;', '&', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{x}', '"+coord.x+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{X}', '"+coord.x+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{y}', '"+coord.y+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{Y}', '"+coord.y+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{z}', '"+zoom+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{Z}', '"+zoom+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = "function(coord, zoom) {".$checkboundtiles." return \"".$this->_mp->tilemethod."\";} }";
			} else {
				$this->_mp->tilemethod = "function(coord, zoom) {".$checkboundtiles." var ymax = 1 << zoom; var y = ymax - coord.y -1; return '".$this->_make_absolute($this->_mp->tilelayer)."/'+zoom+'/'+coord.x+'/'+y+'.png';} }";
			}
			
			unset($checkboundtiles);
		}
	}
	
	function _processMapv3_icons () {
		$code = "";
		if ($this->_mp->icon!='') {
			$code .= "\n<img src='".$this->_mp->icon."' style='display:none' alt='icon' />";
			if ($this->_mp->iconshadow!='')
				$code .= "\n<img src='".$this->_mp->iconshadow."' style='display:none' alt='icon shadow' />";
		
			// icon
			$icon = new stdClass();
			$icon->name = "A";
			$icon->imageurl = $this->_mp->icon;
			$icon->iconwidth = $this->_mp->iconwidth;
			$icon->iconheight = $this->_mp->iconheight;
			$icon->iconshadow = $this->_mp->iconshadow;
			$icon->iconshadowwidth = $this->_mp->iconshadowwidth;
			$icon->iconshadowheight = $this->_mp->iconshadowheight;
			$icon->iconanchorx = $this->_mp->iconanchorx;
			$icon->iconanchory = $this->_mp->iconanchory;
			if ($this->_mp->iconimagemap!="")
				$icon->iconimagemap = $this->_mp->iconimagemap;
			else
				$icon->iconimagemap = 	"13,0,15,1,16,2,17,3,18,4,18,5,19,6,19,7,19,8,19,9,19,10,19,11,19,12,19,13,18,14,18,15,17,16,16,17,15,18,14,19,14,20,13,21,13,22,12,23,12,24,12,25,12,26,11,27,11,28,11,29,11,30,11,31,11,32,11,33,8,33,8,32,8,31,8,30,8,29,8,28,8,27,8,26,7,25,7,24,7,23,6,22,6,21,5,20,5,19,4,18,3,17,2,16,1,15,1,14,0,13,0,12,0,11,0,10,0,9,0,8,0,7,0,6,1,5,1,4,2,3,3,2,4,1,6,0,13,0";
	
			$this->_mp->markericon = array($icon);
			$this->_mp->icontype ="A";
		} else
			$this->_mp->icontype ="";

		unset($icon, $this->_mp->icon, $this->_mp->iconwidth, $this->_mp->iconheight, $this->_mp->iconshadow, $this->_mp->iconshadowwidth, $this->_mp->iconshadowheight, $this->_mp->iconanchorx, $this->_mp->iconanchory, $this->_mp->iconimagemap, $this->_mp->iconshadowanchorx, $this->_mp->iconshadowanchory, $this->_mp->iconshadowanchorx, $this->_mp->iconshadowanchory, $this->_mp->iconinfoanchorx, $this->_mp->iconinfoanchory, $this->_mp->icontransparent);
		
		return $code;
	}
	
	function _processMapv3_streetview() {
		if ($this->_mp->sv!='none'&&$this->_mp->animdir=='0') {
			if ($this->_mp->sv=='top'||$this->_mp->sv=='bottom')
				$this->_mp->sv = "svpanorama".$this->_mp->mapnm;
				
			$this->_mp->svopt = new stdClass();
			if ($this->_mp->svyaw!='0')
				$this->_mp->svopt->heading = (int) $this->_mp->svyaw;
			else
				$this->_mp->svopt->heading = 0;
			if ($this->_mp->svpitch!='0')
				$this->_mp->svopt->pitch = (int) $this->_mp->svpitch;
			else
				$this->_mp->svopt->pitch = 0;
			if ($this->_mp->svzoom!='')
				$this->_mp->svopt->zoom = (int) $this->_mp->svzoom;
			else
				$this->_mp->svopt->zoom = 1;
				
			if ($this->_mp->svaddress=='0')
				$this->_mp->svaddress = false;
			else
				$this->_mp->svaddress = true;
		}		
		
		unset($this->_mp->svyaw,$this->_mp->svpitch,$this->_mp->svzoom);
	}

	function _processMapv3_kml() {
		// Change kml url if proxy is used
		if ($this->_mp->proxy=='1') {
			foreach ($this->_mp->kml as $idx=>$val) {
				$this->_mp->kml[$idx] = $this->_make_absolute($val);
			}
		}

		// Rename parameter so they can be used by geoxml
		$this->_mp->geoxmloptions = new stdClass();
		
		// Set the style of the title of placemark to empty
		$this->_mp->geoxmloptions->titlestyle = ' ';
		
		if ($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right") {
			$this->_mp->geoxmloptions->sidebarid = 'kmlsidebar'.$this->_mp->mapnm;
		} else {
			if ($this->_mp->kmlsidebar!="none")
				$this->_mp->geoxmloptions->sidebarid = $this->_mp->kmlsidebar;
		}
		
		if ($this->_mp->kmlmessshow=='0') {
			$this->_mp->geoxmloptions->veryquiet = true;
			$this->_mp->geoxmloptions->quiet = true;
		}
	
		if ($this->_inline_coords==1)
			$this->_mp->geoxmloptions->nozoom = true;

		if ($this->_mp->dir!='0')
			$this->_mp->geoxmloptions->directions = true;
			
		if ($this->_mp->kmlfoldersopen!='0')
			$this->_mp->geoxmloptions->allfoldersopen = true;
			
		if ($this->_mp->kmlhide!='0')
			$this->_mp->geoxmloptions->hideall = true;

		if ($this->_mp->kmlscale!='0')
			$this->_mp->geoxmloptions->scale=  true;

		if ($this->_mp->kmlopenmethod!='0')
			$this->_mp->geoxmloptions->iwmethod = $this->_mp->kmlopenmethod;
		
		if ($this->_mp->kmlsbsort=='asc') {
			$this->_mp->geoxmloptions->sortbyname = 'asc';
		}elseif ($this->_mp->kmlsbsort=='desc') {
			$this->_mp->geoxmloptions->sortbyname= 'desc';
		} else 	
			$this->_mp->geoxmloptions->sortbyname = null;

		if ($this->_mp->kmlclickablemarkers!='1') {
			$this->_mp->geoxmloptions->clickablemarkers = false;
			$this->_mp->geoxmloptions->clickablelines = false;
			$this->_mp->geoxmloptions->dohilite = false;
		}
			
		if ($this->_mp->kmlzoommarkers!='0')
			$this->_mp->geoxmloptions->zoommarkers = $this->_mp->kmlzoommarkers;

		if ($this->_mp->kmlopendivmarkers!='')
			$this->_mp->geoxmloptions->opendivmarkers = $this->_mp->kmlopendivmarkers;

		if ($this->_mp->kmlcontentlinkmarkers!='0')
			$this->_mp->geoxmloptions->extcontentmarkers = true;

		if ($this->_mp->kmllinkablemarkers!='0')
			$this->_mp->geoxmloptions->contentlinkmarkers = true;

		if ($this->_mp->kmllinktarget!='')
			$this->_mp->geoxmloptions->linktarget = $this->_mp->kmllinktarget;

		if ($this->_mp->kmllinkmethod!='')
			$this->_mp->geoxmloptions->linkmethod = $this->_mp->kmllinkmethod;

		if (($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")) {
			$this->_mp->geoxmloptions->polylabelopacity = $this->_mp->kmlpolylabel;
			$this->_mp->geoxmloptions->polylabelclass = $this->_mp->kmlpolylabelclass;
		}
		if (($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!="")) {
			$this->_mp->geoxmloptions->pointlabelopacity = $this->_mp->kmlmarkerlabel;
			$this->_mp->geoxmloptions->pointlabelclass = $this->_mp->kmlmarkerlabelclass;
		}
		if ($this->_mp->icon!='')
			$this->_mp->geoxmloptions->baseicon = "A";

		if ($this->_mp->maxcluster!=''&&$this->_mp->gridsize!='') {
			$clusteroptions = array();
			if ($this->_mp->maxcluster!='')
				$clusteroptions[] ="maxVisibleMarkers : ".$this->_mp->maxcluster;
			if ($this->_mp->gridsize!='')
				$clusteroptions[] ="gridSize : ".$this->_mp->gridsize;
			if ($this->_mp->minmarkerscluster!='')
				$clusteroptions[] ="minMarkersPerCluster : ".$this->_mp->minmarkerscluster;
			if ($this->_mp->maxlinesinfocluster!='')
				$clusteroptions[] ="maxLinesPerInfoBox : ".$this->_mp->maxlinesinfocluster;
			if ($this->_mp->clusterinfowindow!='')
				$clusteroptions[] ="ClusterInfoWindow : '".$this->_mp->clusterinfowindow."'" ;
			if ($this->_mp->clusterzoom!='')
				$clusteroptions[] ="ClusterZoom : '".$this->_mp->clusterzoom."'" ;
			if ($this->_mp->clustermarkerzoom!='')
				$clusteroptions[] ="ClusterMarkerZoom : ".$this->_mp->clustermarkerzoom;
			if ($this->_mp->icon!='')
				$clusteroptions[] ="Icon : markericon".$this->_mp->mapnm;

			$this->_mp->geoxmloptions->clustering = $clusteroptions;
		}
		
		unset($this->_mp->kmlmessshow, $this->_mp->kmlfoldersopen, $this->_mp->kmlhide, $this->_mp->kmlscale, $this->_mp->kmlopenmethod, $this->_mp->kmlsbsort, $this->_mp->kmlsbsort, $this->_mp->kmlclickablemarkers, $this->_mp->kmlzoommarkers, $this->_mp->kmlopendivmarkers, $this->_mp->kmlcontentlinkmarkers, $this->_mp->kmllinkablemarkers, $this->_mp->kmllinktarget, $this->_mp->kmllinkmethod, $this->_mp->kmlpolylabel, $this->_mp->kmlpolylabelclass, $this->_mp->kmlmarkerlabel, $this->_mp->kmlmarkerlabelclass, $this->_mp->maxcluster, $this->_mp->gridsize, $this->_mp->maxcluster, $this->_mp->minmarkerscluster, $this->_mp->maxlinesinfocluster, $this->_mp->clusterinfowindow, $this->_mp->clusterzoom, $this->_mp->clustermarkerzoom, $clusteroptions, $idx, $val);
	}
	
	function _processMapv3_template() {
		$code = "";
		$lbcode = "";

		$code.= "<!-- fail nicely if the browser has no Javascript -->
				<noscript><blockquote class='warning'><p>".$this->no_javascript."</p></blockquote></noscript>";			

		if ($this->_mp->align!='none')
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none; text-align:".$this->_mp->align."\">";
		else
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none;\">";
			
		if ($this->_mp->lightbox=='1') {
			$lboptions = array();
			if ($this->_mp->lbxzoom!="")
				$lboptions[] = "zoom : ".$this->_mp->lbxzoom;
			if ($this->_mp->lbxcenterlat!=""&&$this->_mp->lbxcenterlon!="")
				$lboptions[] = "mapcenter : \"".$this->_mp->lbxcenterlat." ".$this->_mp->lbxcenterlon."\"";
				
			$this->_lbxwidthorig = (is_numeric($this->_lbxwidthorig)?(($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right")?$this->_lbxwidthorig+$this->_kmlsbwidthorig+5:$this->_lbxwidthorig)."px":$this->_lbxwidthorig);
			$lbname = (($this->_mp->gotoaddr=='1'||(($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))||$this->_mp->animdir!='0'||$this->_mp->sv=='top'||$this->_mp->sv=='bottom'||$this->_mp->searchlist=='div'||$this->_mp->dir=='5'||($this->_mp->formaddress==1&&$this->_mp->animdir==0))?"lightbox":"googlemap");
			
			if ($this->_mp->show==1) {
				$code.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", googlemap".$this->_mp->mapnm.".map, {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."' class='maplightbox' ".(($this->_mp->align!='none')?"style='text-align:".$this->_mp->align."'":"").">";
			} else {
				$lbcode.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", googlemap".$this->_mp->mapnm.".map, {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."' class='maplightbox' style='display:none;".(($this->_mp->align!='none')?"text-align:".$this->_mp->align.";":"")."'>";
			}
		}
		
		if ($this->_mp->gotoaddr=='1')	{
			$code.="<form id=\"gotoaddress".$this->_mp->mapnm."\" class=\"gotoaddress\" onSubmit=\"javascript:googlemap".$this->_mp->mapnm.".gotoAddress();return false;\">";
			$code.="	<input id=\"txtAddress".$this->_mp->mapnm."\" name=\"txtAddress".$this->_mp->mapnm."\" type=\"text\" size=\"25\" value=\"\">";
			$code.="	<input name=\"goto\" type=\"button\" class=\"button\" onClick=\"javascript:googlemap".$this->_mp->mapnm.".gotoAddress();return false;\" value=\"Goto\">";
			$code.="</form>";
		}

		if ($this->_mp->latitudeform=='1')	{
			$code.="<form id=\"latitudeform".$this->_mp->mapnm."\" class=\"latitudefrom\" onSubmit=\"javascript:googlemap".$this->_mp->mapnm.".showLatitude();return false;\">";
			$code.="	<input id=\"latitudeid".$this->_mp->mapnm."\" name=\"latitudeid".$this->_mp->mapnm."\" type=\"text\" size=\"25\" value=\"\">";
			$code.="	<input name=\"show\" type=\"button\" class=\"button\" onClick=\"javascript:googlemap".$this->_mp->mapnm.".showLatitude();return false;\" value=\"Show latitude location\">";
			$code.="</form>";
		}

		if ($this->_mp->formaddress==1)
			$code.=$this->_processMapv3_templatedirform('Form');
			
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<table style=\"width:100%;border-spacing:0px;\">
					<tr>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="left")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\" class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<td>";
			
		if ($this->_mp->sv=='top'||($this->_mp->animdir!='0'&&$this->_mp->animdir!='3')) {
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
		}
			
		$code.="<div id=\"googlemap".$this->_mp->mapnm."\" ".((!empty($this->_mp->mapclass))?"class=\"".$this->_mp->mapclass."\"" :"class=\"map\"")." style=\"" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->width."; height:".$this->_mp->height.";".(($this->_mp->show==0&&$this->_mp->lightbox==0)?"display:none;":"").(((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&$this->_mp->kmlsidebar=="right")||$this->_mp->animdir=='2')?"float:left;":"")."\"></div>";

		if ($this->_mp->sv=='bottom'||$this->_mp->animdir=="3") {
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";
		}

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</td>";
		
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="right")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\"  class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";
			
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</tr>
					</table>";

		if (((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->address)||($this->_mp->dir=='5'))&&($this->_mp->animdir!='2'||($this->_mp->animdir=='2'&&$this->_mp->showdir=='0')))
			$code.= "<div id=\"dirsidebar".$this->_mp->mapnm."\" class='directions' ".(($this->_mp->showdir=='0')?"style='display:none'":"")."></div>";

		if ($this->_mp->lightbox=='1')
			$code .= "</div>";

		// Close of mapbody div
		$code.="</div>";
		
		return array($code, $lbcode);
	}
	
	function _processMapv3_templatedirform($type) {
		$dirform="";
		$dirform="<form id='directionform".$this->_mp->mapnm."' action='".$this->protocol.$this->googlewebsite."/maps' method='get' target='_blank' onsubmit='javascript:googlemap".$this->_mp->mapnm.".DirectionMarkersubmit(this);return false;' class='mapdirform'>";
		
		$dirform.=$this->_mp->txtdir;
		
		if ($type=='Marker') {
			$dirform.="<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='radio' ")." ".(($this->_mp->dirdefault=='0')?"checked='checked'":"")." name='dir' value='to'>".(($this->_mp->txtto!='')?$this->_mp->txtto."&nbsp;":"")."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='radio' ").(($this->_mp->dirdefault=='1')?"checked='checked'":"")." name='dir' value='from'>".(($this->_mp->txtfrom!='')?$this->_mp->txtfrom:"");
			$dirform.="<br />".$this->_mp->txtdiraddr."<input type='text' class='inputbox' size='20' name='saddr' id='saddr' value='' />";
			
			if (!empty($this->_mp->address))
				$dirform.="<input type='hidden' name='daddr' value='".$this->_mp->address."'/>";
			else
				$dirform.="<input type='hidden' name='daddr' value='".(($this->_mp->latitude!='')?$this->_mp->latitude:$this->_mp->deflatitude).", ".(($this->_mp->longitude!='')?$this->_mp->longitude:$this->_mp->deflongitude)."'/>";
		}
		
		if ($type=='Form') {
			$dirform.=(($this->_mp->txtfrom=='')?"":"<br />").$this->_mp->txtfrom."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='saddr' id='saddr' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."' />";

			$dirform.=(($this->_mp->txtto=='')?"":"<br />").$this->_mp->txtto."<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='daddr' id='daddr' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."' />";
		}
		
		if ($this->_mp->txt_driving!=''||$this->_mp->txt_avhighways!=''||$this->_mp->txt_walking!='')
			$dirform.="<br />";	

		if ($this->_mp->txt_driving!=''||$this->_mp->dirtype=="D")
			$dirform.="<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"");
		if ($this->_mp->txt_avhighways!=''||$this->_mp->dirtype=="1")
			$dirform.="<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"");
		if ($this->_mp->txt_transit!=''||$this->_mp->dirtype=="R")
			$dirform.="<input ".(($this->_mp->txt_transit=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='r' ".(($this->_mp->dirtype=="R")?"checked='checked'":"")." />".$this->_mp->txt_transit.(($this->_mp->txt_transit!='')?"&nbsp;":"");
		if ($this->_mp->txt_bicycle!=''||$this->_mp->dirtype=="B")
			$dirform.="<input ".(($this->_mp->txt_bicycle=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='b' ".(($this->_mp->dirtype=="B")?"checked='checked'":"")." />".$this->_mp->txt_bicycle.(($this->_mp->txt_bicycle!='')?"&nbsp;":"");
		if ($this->_mp->txt_walking!=''||$this->_mp->dirtype=="W")
			$dirform.="<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"");
			
		$dirform.=(($this->_mp->txt_optimize!='')?"<br/>":"")."<input ".(($this->_mp->txt_optimize=='')?"type='hidden' ":"type='checkbox' ")."class='checkbox' name='diroptimize' value='1' ".(($this->_mp->diroptimize=='1')?"checked='checked'":"")." />".$this->_mp->txt_optimize;
		$dirform.=(($this->_mp->txt_alternatives!='')?"<br/>":"")."<input ".(($this->_mp->txt_alternatives=='')?"type='hidden' ":"type='checkbox' ")."class='checkbox' name='diralternatives' value='1' ".(($this->_mp->diralternatives=='1')?"checked='checked'":"")." />".$this->_mp->txt_alternatives;
			
		$dirform.="<br/><input value='".$this->_mp->txtgetdir."' class='button' type='submit' style='margin-top: 2px;'>";
		
		if ($this->_mp->dir=='2')
			$dirform.= "<input type='hidden' name='pw' value='2'/>";

		if ($this->_mp->lang!='') 
			$dirform.= "<input type='hidden' name='hl' value='".$this->_mp->lang."'/>";

		$dirform.="</form>";

		return $dirform;
	}
	
	function _getInitialParams() {
		if (substr($this->jversion,0,3)=="1.5")
			$filename = JPATH_SITE."/plugins/system/plugin_googlemap2.xml";
		else
			$filename = JPATH_SITE."/plugins/system/plugin_googlemap2/plugin_googlemap2.xml";

		if ($xml = simplexml_load_file($filename)) {
			if (substr($this->jversion,0,3)=="1.5")
				$root =& $xml;
			else if (isset($xml->config[0]->fields[0]))
				$root = $xml->config[0]->fields[0];
			else
				$root =& $xml;
		
			foreach ($root->children() as $params) {
				foreach($params->children() as $param) {
					if ($param->attributes()->export=='1') {
						$name = $param->attributes()->name;
						if ($name=='lat') {
							$this->initparams->deflatitude = $this->params->get($name, $param->attributes()->default);
						} elseif ($name=='lon') {
							$this->initparams->deflongitude = $this->params->get($name, $param->attributes()->default);
						} elseif (substr($name,0,3)=='txt') {
							$nm = strtolower($name);
							$this->initparams->$nm = $this->params->get($name, '');
						} else {
							$nm = strtolower($name);
							$this->initparams->$nm = (string) $this->params->get($name, $param->attributes()->default);
						}
					}
				}
			}
		}
		
		// Clean up generated variables
		unset($filename, $xml, $root, $params, $param, $name, $nm);
	}
	
	function _getURL($url) {
		$ok = false;
		$getpage = "";
		if (ini_get('allow_url_fopen')) { 
			if (file_exists($url)) {
				$getpage = file_get_contents($url);
				$ok = true;
			}
		} 
		
		if (!$ok) { 
			$this->_debug_log("URI couldn't be opened probably ALLOW_URL_FOPEN off");
			if (function_exists('curl_init')) {
				$this->_debug_log("curl_init does exists");
				$ch = curl_init();
				$timeout = 5; // set to zero for no timeout
				curl_setopt ($ch, CURLOPT_URL, $url);
				curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
				curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
				$getpage = curl_exec($ch);
				curl_close($ch);
			} else
				$this->_debug_log("curl_init doesn't exists");
		}
		$this->_debug_log("Returned page: ".htmlentities($getpage));
		
		// Clean up generated variables
		unset($ok, $ch, $timeout);
		
		return $getpage;
	}

	function get_geo($address)
	{
		$this->_debug_log("get_geo(".$address.")");
	
		$coords = '';
		$getpage='';
		$replace = array("\n", "\r", "&lt;br/&gt;", "&lt;br /&gt;", "&lt;br&gt;", "<br>", "<br />", "<br/>");
		$address = str_replace($replace, '', $address);

		// Convert address to utf-8 encoding
		if (function_exists('mb_detect_encoding')) {
			$enc = mb_detect_encoding($address);
			if (!empty($enc))
				$address = mb_convert_encoding($address, "utf-8", $enc);
			else
				$address = mb_convert_encoding($address, "utf-8");
		}

		$this->_debug_log("Address: ".$address);
		
		$uri = $this->protocol.$this->googlewebsite."/maps/geo?q=".urlencode($address)."&output=xml&key=".$this->googlekey;
		$this->_debug_log("get_geo(".$uri.")");
		$getpage = $this->_getURL($uri);

		if (function_exists('mb_detect_encoding')) {
			$enc = mb_detect_encoding($getpage);
			if (!empty($enc))
				$getpage = mb_convert_encoding($getpage, "utf-8", $enc);
		}

		if ($getpage <>'') {
			$expr = '/xmlns/';
			$getpage = preg_replace($expr, 'id', $getpage);
			$xml = new SimpleXMLElement($getpage);
			foreach($xml->xpath('//coordinates') as $coordinates) {
				$coords = $coordinates;
				break;
			}
			if ($coords=='') {
				$this->_debug_log("Coordinates: null");
			} else
				$this->_debug_log("Coordinates: ".join(", ", explode(",", $coords)));
		} else
			$this->_debug_log("get_geo totally wrong end!");
	
		// Clean up variables
		unset($coord, $getpage, $replace, $enc, $uri, $ok, $ch, $timeout, $expr, $xml, $coordinates);
		
		return $coords;
	}
	
	function _debug_log($text)
	{
		if ($this->debug_plugin =='1')
			$this->debug_text .= "\n// ".$text." (".round($this->_memory_get_usage()/1024)." KB)";
	
		return;
	}
	
	function _get_index($string)
	{
		if ($this->brackets=='{') {
			$string = preg_replace("/^(.*?)\[/", '', $string);
			$string = preg_replace("/\](.*?)$/", '', $string);
			
		} else {
			$string = preg_replace("/^.*\(/", '', $string);
			$string = preg_replace("/\).*$/", '', $string);
		}
		
		return $string;
	}
	
    function _memory_get_usage()
    {
		if ( function_exists( 'memory_get_usage' ) )
			return memory_get_usage(); 
		else
			return 0;
    }

	function _get_API_key () {
		$url = trim($this->urlsetting);
		$replace = array('http://', 'https://');
		$url = str_replace($replace, '', $url);


		$url = (($this->protocol=='https://')?$this->protocol:'').$url;
		$this->_debug_log("url: ".$url);
		$key = '';
		$multikey = trim($this->params->get( 'Google_Multi_API_key', '' ));
		if ($multikey!='') {
			$this->_debug_log("multikey: ".$multikey);
			$replace = array("\n", "\r", "<br/>", "<br />", "<br>");
			$sites = preg_split("/[\n\r]+/", $multikey);
			foreach($sites as $site)
			{
				$values = explode(";",$site, 2);
				if (count($values)>1) {
					$values[0] = trim(str_replace($replace, '', $values[0]));
					$values[1] = str_replace($replace, '', $values[1]);
					$this->_debug_log("values[0]: ".$values[0]);
					$this->_debug_log("values[1]: ".$values[1]);
					if ($url==$values[0])
					{
						$key = trim($values[1]);
						break;
					}
				}
			}
		}
		if ($key=='')
			$key = trim($this->params->get( 'Google_API_key', '' ));

		// Clean up variables
		unset($url, $replace, $multikey, $sites, $site, $values);
		$this->_debug_log("key: ".$key);
		return $key;
	}
	
	function _randomkeys($length)
	{
		$key = "";
		$pattern = "1234567890abcdefghijklmnopqrstuvwxyz";
		for($i=0;$i<$length;$i++)
		{
			$key .= $pattern{rand(0,35)};
		}
		
		// Clean up variables
		unset($i, $pattern);
		return $key;
	}

	function _translate($orgtext, $lang) {
		$langtexts = preg_split("/[\n\r]+/", $orgtext);
		$text = "";

		if (is_array($langtexts)) {
			$replace = array("\n", "\r", "<br/>", "<br />", "<br>");
			$firsttext = "";
			foreach($langtexts as $langtext) {
				$values = explode(";",$langtext, 2);
				if (count($values)>1) {
					$values[0] = trim(str_replace($replace, '', $values[0]));
					if ($firsttext == "")
						$firsttext = $values[1];
						
					if (trim($lang)==$values[0])
					{
						$text = $values[1];
						break;
					}
				}
			}
			// Not found
			if ($text=="")
				$text = $firsttext;
		}	
		
		if ($text=="")
			$text = $orgtext;
	
		$text = htmlspecialchars_decode($text, ENT_NOQUOTES);
	
		// Clean up variables
		unset($langtexts, $replace, $langtext, $values);
		return $text;
	}
	
	function _getlang() {
		$this->_debug_log("langtype: ".$this->langtype);

		if ($this->langtype == 'site') {
			$lang = $this->lang->getTag();
			$this->_debug_log("Joomla lang: ".$lang);
			// Chinese and portugal use full iso code to indicate language
			if (!($lang=='zh'||$lang=='pt')) {
				$locale_parts = explode('-', $this->lang->getTag());
				$lang = $locale_parts[0];
			}
			$this->_debug_log("site lang: ".$lang);
		} else if ($this->langtype == 'config') {
			$lang = $this->params->get( 'lang', '' );
			$this->_debug_log("config lang: ".$lang);
		} else if ($this->langtype == 'joomfish'&&isset($_COOKIE['jfcookie'])) {
			$lang = $_COOKIE['jfcookie']['lang']; 
			$this->_debug_log("Joomfish lang: ".$lang);
		} else {
			$lang = '';
			$this->_debug_log("No language: ".$lang);
		} 
		
		// Clean up variables
		unset($locale_parts);
		return $lang;
	}
	
	function _remove_html_tags($text) {
		$reg[] = "/<span[^>]*?>/si";
		$repl[] = '';
		$reg[] = "/<\/span>/si";
		$repl[] = '';
		$text = preg_replace( $reg, $repl, $text );
		
		// Clean up variables
		unset($reg, $repl);
		return $text;
	}
	
	function _make_absolute($link) {
		if(substr($link,0, 7)!='http://'&&substr($link,0, 7)!='https://') {
			if(substr($link,0,1)=='/') {
				return $this->url.$link;
			} else {
				return $this->url.'/'.$link;
			}
		}
		return $link;
	}
	
	function _addscript($url) {
		// The method depends on event type. onAfterRender is complex and others are simple based on framework
		if ($this->event!='onAfterRender')
			$this->document->addScript($url);
		else {
			// Get header
			$reg = "/(<HEAD[^>]*>)(.*?)(<\/HEAD>)(.*)/si";
			$count = preg_match_all($reg,$this->_text,$html);	
			if ($count>0) {
				$head=$html[2][0];
			} else {
				$head='';
			}
			// clean browser if statements
			$reg = "/<!--\[if(.*?)<!\[endif\]-->/si";
			$head = preg_replace($reg, '', $head);

			// define scripts regex
			$reg = '/<script.*src=[\'\"](.*?)[\'\"][^>]*[^<]*(<\/script>)?/i';
			$found = false;
			
			$count = preg_match_all($reg,$head,$scripts,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);	

			if ($count>0)
				foreach ($scripts[1] as $script) {
					if ($script[0]==$url) {
						$found = true;
						break;
					}
				}
				
			if (!$found) {
				$script = "\n<script type='text/javascript' src='".$url."'></script>\n";
				if ($count==0) {
					// No scripts then just add it before </head>
					$this->_text = preg_replace("/<head(| .*?)>(.*?)<\/head>/is", "<head$1>$2".$script."</head>", $this->_text);
				} else {
					//add script after the last script
					// position last script and add length
					$pos = strpos($this->_text, trim($scripts[0][$count-1][0]))+strlen(trim($scripts[0][$count-1][0]));
					$this->_text = substr($this->_text,0, $pos).$script.substr($this->_text,$pos);
				}
			}
			
			// Clean up variables
			unset($reg, $count, $head, $found, $scripts, $script, $pos);
		}
	}
	
	function _addstylesheet($url) {
		// The method depends on event type. onAfterRender is complex and others are simple based on framework
		if ($this->event!='onAfterRender')
			$this->document->addStyleSheet($url);
		else {
			// Get header
			$reg = "/(<HEAD[^>]*>)(.*?)(<\/HEAD>)(.*)/si";
			$count = preg_match_all($reg,$this->_text,$html);	
			if ($count>0) {
				$head=$html[2][0];
			} else {
				$head='';
			}
			
			// clean browser if statements
			$reg = "/<!--\[if(.*?)<!\[endif\]-->/si";
			$head = preg_replace($reg, '', $head);

			// define scripts regex
			$reg = '/<link.*href=[\'\"](.*?)[\'\"][^>]*[^<]*(<\/link>)?/i';
			$found = false;
			
			$count = preg_match_all($reg,$head,$styles,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);	
			if ($count>0)
				foreach ($styles[1] as $style) {
					if ($style[0]==$url) {
						$found = true;
						break;
					}
				}
				
			if (!$found) {
				$style = "\n<link href='".$url."' rel='stylesheet' type='text/css' />\n";
				if ($count==0) {
					// No styles then just add it before </head>
					$this->_text = preg_replace("/<head(| .*?)>(.*?)<\/head>/is", "<head$1>$2".$style."</head>", $this->_text);
				} else {
					//add style after the last style
					// position last style and add length
					$pos = strpos($this->_text, trim($styles[0][$count-1][0]))+strlen(trim($styles[0][$count-1][0]));
					$this->_text = substr($this->_text,0, $pos).$style.substr($this->_text,$pos);
				}
			}
			
			// Clean up variables
			unset($reg, $count, $head, $found, $styles, $style, $pos);
		}
	}
	function _addstyledeclaration($source) {
		// The method depends on event type. onAfterRender is complex and others are simple based on framework
		if ($this->event!='onAfterRender')
			$this->document->addStyleDeclaration($source);
		else {
			// Get header
			$reg = "/(<HEAD[^>]*>)(.*?)(<\/HEAD>)(.*)/si";
			$count = preg_match_all($reg,$this->_text,$html);	
			if ($count>0) {
				$head=$html[2][0];
			} else {
				$head='';
			}
			
			// clean browser if statements
			$reg = "/<!--\[if(.*?)<!\[endif\]-->/si";
			$head = preg_replace($reg, '', $head);

			// define scripts regex
			$reg = '/<style[^>]*>(.*?)<\/style>/si';
			$found = false;
			
			$count = preg_match_all($reg,$head,$styles,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);	
			if ($count>0)
				foreach ($styles[1] as $style) {
					if ($style[0]==$source) {
						$found = true;
						break;
					}
				}
				
			if (!$found) {
				$source = "\n<style type='text/css'>\n".$source."\n</style>\n";
				if ($count==0) {
					// No styles then just add it before </head>
					$this->_text = preg_replace("/<head(| .*?)>(.*?)<\/head>/is", "<head$1>$2".$source."</head>", $this->_text);
				} else {
					//add style after the last style
					// position last style and add length
					$pos = strpos($this->_text, trim($styles[0][$count-1][0]))+strlen(trim($styles[0][$count-1][0]));
					$this->_text = substr($this->_text,0, $pos).$source.substr($this->_text,$pos);
				}
			}
			
			// Clean up variables
			unset($reg, $count, $head, $found, $styles, $style, $pos);
		}
	}
	

	function _is_utf8($string) { // v1.01
	//	define('_is_utf8_split',5000);
	//	if (strlen($string) > _is_utf8_split) {
		if (strlen($string) > 5000) {
			// Based on: http://mobile-website.mobi/php-utf8-vs-iso-8859-1-59
			for ($i=0,$s=_is_utf8_split,$j=ceil(strlen($string)/_is_utf8_split);$i < $j;$i++,$s+=_is_utf8_split) {

				if (is_utf8(substr($string,$s,_is_utf8_split)))
					return true;
			}
			return false;
		} else {
			// From http://w3.org/International/questions/qa-forms-utf-8.html
			return preg_match('%^(?:
					[\x09\x0A\x0D\x20-\x7E]            # ASCII
				| [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
				|  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
				| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
				|  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
				|  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
				| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
				|  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
			)*$%xs', $string);
		}
	} 
}

?>PK��#]r��88,system/remember/plugin_googlemap2/index.htmlnu�[���<html>

<body bgcolor="#FFFFFF">

</body>

</html>PK��#]�
�O.O.Csystem/remember/plugin_googlemap2/plugin_googlemap2_twitter_kml.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2_twitter.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2012 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

@define('_JEXEC', 1);
if (!defined('DS'))
	@define( 'DS', DIRECTORY_SEPARATOR );

// Fix magic quotes.
@ini_set('magic_quotes_runtime', 0);
 
// Maximise error reporting.
//@ini_set('zend.ze1_compatibility_mode', '0');
//error_reporting(E_ALL);
//@ini_set('display_errors', 1);
 
/*
 * Ensure that required path constants are defined.
 */
if (!defined('JPATH_BASE'))
{
	$path = dirname(__FILE__);
	// Joomla 1.6.x/1.7.x/2.5.x
	$path = str_replace('/plugins/system/plugin_googlemap2', '', $path);
	$path = str_replace('\plugins\system\plugin_googlemap2', '', $path);
	// Joomla 1.5.x
	$path = str_replace('/plugins/system', '', $path);
	$path = str_replace('\plugins\system', '', $path);
	
	define('JPATH_BASE', $path);
}

require_once ( JPATH_BASE.'/includes/defines.php' );
 
if (!file_exists(JPATH_LIBRARIES . '/import.legacy.php')) {
	// Joomla 1.5
	require_once ( JPATH_BASE.'/includes/framework.php' );
	/* To use Joomla's Database Class */
	require_once ( JPATH_BASE.'/libraries/joomla/factory.php' );
	$mainframe =& JFactory::getApplication('site');
	$mainframe->initialise();
	$user =& JFactory::getUser();
	$session =& JFactory::getSession();
} else {
	// Joomla 1.6.x/1.7.x/2.5.x
	/**
	 * Import the platform. This file is usually in JPATH_LIBRARIES 
	 */
	require_once JPATH_BASE . '/configuration.php';
	require_once JPATH_LIBRARIES . '/import.legacy.php';
}
 
class Twitter {
	private $user = null;
	private $tweets = null;
	
	function __construct($user) {
		$this->user = $user;
	}
	
	function getUserTimeLine($count = 19, $retweets=0) {
		$ch = curl_init();

		curl_setopt($ch, CURLOPT_URL, 'http://api.twitter.com/1/statuses/user_timeline.json?screen_name='.$this->user.'&count='.$count.'&&include_rts='.$retweets);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$data = curl_exec($ch);
		curl_close($ch);
		
		$this->tweets = json_decode($data);
		
		if (is_object($this->tweets)&&isset($this->tweets->errors))
			$this->tweets = array();
		
		if (count($this->tweets)==0)
			$this->tweets = array();
		
		return $this->tweets;
	}
	
	function getProfile() {
		$profile = array();

		if(!empty($this->tweets)&&!isset($this->tweets->errors)) {
			$profile = $this->tweets[0]->user;
		}
		
		return $profile;
	}
	
	function timeSince($date) {
		$datetime = strtotime($date);
		$offset = time() - $datetime;
		
		$units = array(
			'second' => 1,
			'minute' => 60,
			'hour' => 3600,
			'day' => 86400,
			'month' => 2629743,
			'year' => 31556926);
		
		foreach($units as $unit => $value) {
			if($offset >= $value) {
				$result = floor($offset / $value);
				
				if(!in_array($unit, array('month','year'))) {
					if($result > 1) {
						$unit .= 's';
					}
					
					$timeAgo = 'About'.' '.$result.' '.$unit.' '.'Ago';
				} else {
					return date('j M Y', $datetime);
				}
			}
		}
		
		return $timeAgo;
	}
	
	function parseText($text) {
		// url
		$text = preg_replace( "/(([[:alnum:]]+:\/\/)|www\.)([^[:space:]]*)([[:alnum:]#?\/&=])/i", "<a href=\"\\1\\3\\4\" target=\"_blank\">\\1\\3\\4</a>", ' '.$text);
		$text = str_replace('href="www.', 'href="http://www.', $text);
		// mailto
		$text = preg_replace( "/(([a-z0-9_]|\\-|\\.)+@([^[:space:]]*)([[:alnum:]-]))/i", "<a href=\"mailto:\\1\">\\1</a>", $text);
		// user
		$text = preg_replace( "/ +@([a-z0-9_]*) ?/i", " <a href=\"http://twitter.com/\\1\" target=\"_blank\">@\\1</a> ", $text);
		// argument
		$text = preg_replace( "/ +#([a-z0-9_]*) ?/i", " <a href=\"http://twitter.com/search?q=%23\\1\" target=\"_blank\">#\\1</a> ", $text);
		// truncates long url
		$text = preg_replace("/>(([[:alnum:]]+:\/\/)|www\.)([^[:space:]]{30,40})([^[:space:]]*)([^[:space:]]{10,20})([[:alnum:]#?\/&=])</", ">\\3...\\5\\6<", $text);
		
		return trim($text);
	}

}

class plugin_googlemap2_twitter_kml
{
		/**
		 * Display the application.
		 */
		function doExecute(){
			// Get config
			$plugin = JPluginHelper::getPlugin('system', 'plugin_googlemap2');
			
			$jversion = JVERSION;
			// In Joomla 1.5 get the parameters in Joomla 1.6 and higher the plugin already has them, but need to be rendered with JRegistry
			if (substr($jversion,0,3)=="1.5")
				$params = new JParameter($plugin->params);
			else {
				$params = new JRegistry();
				$params->loadString($plugin->params);
			}
			
			// Get params
			$twittername = urldecode(JRequest::getVar('twittername', ''));
			if ($twittername=="")
				$twittername = $params->get('twittername', '');
				
			$twittertweets = urldecode(JRequest::getVar('twittertweets', ''));
			if ($twittertweets=="")
				$twittertweets = $params->get('twittertweets', '15');
				
			$line = urldecode(JRequest::getVar('twitterline', ''));
			if ($line=="")
				$line = $params->get('twitterline', '#ff0000ff');
				
			$twitterlinewidth = urldecode(JRequest::getVar('twitterlinewidth', ''));
			if ($twitterlinewidth=="")
				$twitterlinewidth = $params->get('twitterlinewidth', '5');

			$twitterstartloc = urldecode(JRequest::getVar('twitterstartloc', ''));
			if ($twitterstartloc=="")
				$twitterstartloc = $params->get('twitterstartloc', '5');
				
			$twitter = new Twitter(ltrim(rtrim($twittername)));
			$tweets = $twitter->getUserTimeLine(ltrim(rtrim($twittertweets)), 1);
			$profile = $twitter->getProfile();
			
			// Start KML file, create parent node
			$dom = new DOMDocument('1.0','UTF-8');
			
			//Create the root KML element and append it to the Document
			$node = $dom->createElementNS('http://earth.google.com/kml/2.1','kml');
			$parNode = $dom->appendChild($node);
			
			//Create a Folder element and append it to the KML element
			$docnode = $dom->createElement('Document');
			$parNode = $parNode->appendChild($docnode);
			
			$twitterStyleNode = $dom->createElement('Style');
			$twitterStyleNode->setAttribute('id', 'tweetStyle');
			$twitterIconstyleNode = $dom->createElement('IconStyle');
			$twitterIconstyleNode->setAttribute('id', 'tweetIcon');
			$twitterIconNode = $dom->createElement('Icon');
			$twitterHref = $dom->createElement('href', $params->get('twittericon', ''));
			
			$twitterIconNode->appendChild($twitterHref);
			$twitterIconstyleNode->appendChild($twitterIconNode);
			$twitterStyleNode->appendChild($twitterIconstyleNode);
			$docnode->appendChild($twitterStyleNode);

			if ($line!='') {
				// Create a line of travelling
				$twitterStyleNode = $dom->createElement('Style');
				$twitterStyleNode->setAttribute('id', 'lineStyle');
				$twitterLinestyleNode = $dom->createElement('LineStyle');
				$twitterColorNode = $dom->createElement('color', ltrim(rtrim($line)));
				$twitterLinestyleNode->appendChild($twitterColorNode);
				$twitterWidthNode = $dom->createElement('width', ltrim(rtrim($twitterlinewidth)));
				$twitterLinestyleNode->appendChild($twitterWidthNode);
				$twitterStyleNode->appendChild($twitterLinestyleNode);
				$docnode->appendChild($twitterStyleNode);
			}
			
			//Create a Folder element and append it to the KML element
			$fnode = $dom->createElement('Folder');
			$folderNode = $parNode->appendChild($fnode);
			$nameNode = $dom->createElement('name', 'Tweets '.$twittername);
			$folderNode->appendChild($nameNode);
			
			$tweets = array_reverse($tweets);
			$prev_location = explode(',', $twitterstartloc);
			// swap lat and long values. In kml is it different first long then lat
			$lat = $prev_location[0];
			$prev_location[0] = $prev_location[1];
			$prev_location[1] = $lat;
			
			foreach($tweets as $tweet) {
				if ($tweet->coordinates=="")
					$tweet->coordinates->coordinates = $prev_location;
				else
					$prev_location = $tweet->coordinates->coordinates;
			}
			$tweets = array_reverse($tweets);

			foreach($tweets as $tweet) {
				//Create a Placemark and append it to the document

				$node = $dom->createElement('Placemark');
				$placeNode = $folderNode->appendChild($node);
				
				//Create an id attribute and assign it the value of id column
				$placeNode->setAttribute('id','tweet_'.$tweet->id_str);
				
				//Create name, description, and address elements and assign them the values of 
				//the name, type, and address columns from the results
				
				$nameNode = $dom->createElement('name', date('d m Y g:i:s', strtotime($tweet->created_at)));
				$placeNode->appendChild($nameNode);
				
				$styleUrl = $dom->createElement('styleUrl', '#tweetStyle');
				$placeNode->appendChild($styleUrl);
				
				$descText  = "";
				$descText .="<a href='http://www.twitter.com/".$profile->screen_name."' target='_blank' title='Follow us'><h4 class='tw_user'><img src='".$profile->profile_image_url."' alt='".$profile->name."' />".$profile->name."</h4></a>";
				
				$descText .= "<span class='tw_text'>".$twitter->parseText($tweet->text)."</span>";
				$descText .="<br/><span class='tw_date'>".$twitter->timeSince($tweet->created_at)."</span>";
				
				$descNode = $dom->createElement('description', '');
				$cdataNode = $dom->createCDATASection($descText);
				$descNode->appendChild($cdataNode);
				$placeNode->appendChild($descNode);
				
				$pointNode = $dom->createElement('Point');
				$placeNode->appendChild($pointNode);
			
				$coor_pointNode = $dom->createElement('coordinates',implode(",",$tweet->coordinates->coordinates));
				$pointNode->appendChild($coor_pointNode);
			}
			
			if ($line!=''&&count($tweets)>0) {
				// Create a line of travelling
				
				//Create a Placemark and append it to the document
				$node = $dom->createElement('Placemark');
				$placeNode = $folderNode->appendChild($node);
				
				//Create an id attribute and assign it the value of id column
				$placeNode->setAttribute('id','tweetline');
				
				//Create name, description, and address elements and assign them the values of 
				//the name, type, and address columns from the results
				
				$nameNode = $dom->createElement('name','');
				$placeNode->appendChild($nameNode);
				
				$styleUrl = $dom->createElement('styleUrl', '#lineStyle');
				$placeNode->appendChild($styleUrl);

				//Create a LineString element
				$lineNode = $dom->createElement('LineString');
				$placeNode->appendChild($lineNode);
				$exnode = $dom->createElement('extrude', '1');
				$lineNode->appendChild($exnode);
				$almodenode =$dom->createElement('altitudeMode','relativeToGround');
				$lineNode->appendChild($almodenode);
				
				$coordinates = "";
				
				foreach($tweets as $tweet) {
					$coordinates .= " ".implode(",",$tweet->coordinates->coordinates);
				}
				//Create a coordinates element and give it the value of the lng and lat columns from the results
				$coorNode = $dom->createElement('coordinates',$coordinates);
				$lineNode->appendChild($coorNode);
			}
			
			$kmlOutput = $dom->saveXML();
			
			//assign the KML headers. 
			header('Content-type: application/vnd.google-earth.kml+xml');
			echo $kmlOutput;
 		}
}
// Instantiate the application.
$web = new plugin_googlemap2_twitter_kml;
 
// Run the application
$web->doExecute();

?>PK��#]��d�5�57system/remember/plugin_googlemap2/plugin_googlemap2.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2011 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.plugin.plugin' );
jimport( 'joomla.html.parameter' ); 

class plgSystemPlugin_googlemap2 extends JPlugin
{
	var $config;
	var $subject;
	var $jversion;
	var $params;
	var $regex;
	var $document;
	var $doctype;
	var $published;
	var $plugincode;
	var $brackets;
	var $countmatch;
	var $event;
	var $helper;
	
	/**
	 * Constructor
	 *
	 * @access      protected
	 * @param       object  $subject The object to observe
	 * @param       array   $config  An array that holds the plugin configuration
	 * @since       1.0
	 */
	public function __construct( &$subject, $config )
	{
		parent::__construct( $subject, $config );
		$this->event = 'construct';
		// Do some extra initialisation in this constructor if required
		$this->subject = $subject;
		$this->config = $config;
		// Version of Joomla
		$this->jversion = JVERSION;
		// In Joomla 1.5 get the parameters in Joomla 1.6 and higher the plugin already has them
		if (substr($this->jversion,0,3)=="1.5") {
			$plugin = JPluginHelper::getPlugin('system', 'plugin_googlemap2');
			$this->params = new JParameter( $plugin->params);
		}
		// Load the language files for the plugin for Joomla 1.6 and higher
		if (substr($this->jversion,0,3)!="1.5")
			$this->loadLanguage();
		// Check if the params are defined and set so the initial defaults can be removed.
		$this->_restore_permanent_defaults();
		// Set document and doctype to null. Can only be retrievedwhen events are triggered. otherwise the language of the site magically changes.
		$this->document = NULL;
		$this->doctype = NULL;
		// Get params
		$this->publ = $this->params->get( 'publ', 1 );
		$this->plugincode = $this->params->get( 'plugincode', 'mosmap' );
		$this->brackets = $this->params->get( 'brackets', '{' );
		// define the regular expression for the bot
		if ($this->brackets=="both") {
			$this->regex="/(<p\b[^>]*>\s*)?(\{|\[)".$this->plugincode.".*?(([a-z0-9A-Z]+((\{|\[)[0-9]+(\}|\]))?='[^']+'.*?\|?.*?)*)(\}|\])(\s*<\/p>)?/msi";
			$this->countmatch = 3;
		} elseif ($this->brackets=="[") {
			$this->regex="/(<p\b[^>]*>\s*)?\[".$this->plugincode.".*?(([a-z0-9A-Z]+(\{[0-9]+\})?='[^']+'.*?\|?.*?)*)\](\s*<\/p>)?/msi";
			$this->countmatch = 2;
		} else {
			$this->regex="/(<p\b[^>]*>\s*)?\{".$this->plugincode.".*?(([a-z0-9A-Z]+(\[[0-9]+\])?='[^']+'.*?\|?.*?)*)\}(\s*<\/p>)?/msi";
			$this->countmatch = 2;
		}
		// The helper class
		$this->helper = null;

		// Clean up variables
		unset($plugin, $option, $view, $task, $layout);
	}
	
	/**
	 * Do something onAfterInitialise 
	 */
	public function onAfterInitialise()
	{
		$this->event = 'onAfterInitialise';
	}
	
	/**
	 * onPrepareContent is rename in Joomla 1.6 to onContentPrepare
	 */
	public function onContentPrepare($context, &$article, &$params, $limitstart=0)
	{
		$this->event = 'onContentPrepare';
		
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// Check if fields exists. If article and text does not exists then stop
		if (isset($article)&&isset($article->text))
			$text = &$article->text;
		else
			return true;
			
		if (isset($article)&&isset($article->introtext))
			$introtext = &$article->introtext;
		else
			$introtext = "";
			
		// check whether plugin has been unpublished
		// PDF or feed can't show maps so remove it
		if ( !$this->publ ||($this->doctype=='pdf'||$this->doctype=='feed') ) {
			$text = preg_replace( $this->regex, '', $text );
			$introtext = preg_replace( $this->regex, '', $introtext );
			unset($app, $text, $introtext);
			return true;
		}
		
		// perform the replacement in a normal way, but this has the disadvantage that other plugins
		// can't add information to the mosmap, other later added content is not checked and modules can't be checked
		// $this->_replace( $text );	
		// $this->_replace( $introtext );
		
		// Clean up variables
		unset($app, $text, $introtext);
	}
	
	/**
	 * onPrepareContent is for Joomla 1.5
	 */
	public function onPrepareContent(&$article)
	{
		$this->event = 'onPrepareContent';
	
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// Check if fields exists. If article and text does not exists then stop
		if (isset($article)&&isset($article->text))
			$text = &$article->text;
		else
			return true;
			
		if (isset($article)&&isset($article->introtext))
			$introtext = &$article->introtext;
		else
			$introtext = "";
			
		// check whether plugin has been unpublished
		// PDF or feed can't show maps so remove it
		if ( !$this->publ ||($this->doctype=='pdf'||$this->doctype=='feed') ) {
			$text = preg_replace( $this->regex, '', $text );
			$introtext = preg_replace( $this->regex, '', $introtext );
			unset($app, $text, $introtext);
			return true;
		}
		
		// perform the replacement in a normal way, but this has the disadvantage that other plugins
		// can't add information to the mosmap, other later added content is not checked and modules can't be checked
		//$this->_replace( $text );	
		//$this->_replace( $introtext );	
		
		// Clean up variables
		unset($app, $text, $introtext);
	}
	
	/**
	 * Do something onAfterRoute 
	 */
	public function onAfterRoute()
	{
		$this->event = 'onAfterRoute';
	}
	
	/**
	 * Do something onAfterDispatch 
	 */
	public function onAfterDispatch()
	{
		$this->event = 'onAfterDispatch';
		
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// FEED
		if ($this->doctype=='feed'&&isset($this->document->items)) {
			foreach($this->document->items as $item) {
				$text = &$item->description;
				$text = preg_replace( $this->regex, '', $text );
			}
			// Clean up variables
			unset($app, $item, $text);
			return true;
		}
		
		// PDF can't show maps so remove it
		if ($this->doctype=='pdf') {
			$text = $this->document->getBuffer("component");
			$text = preg_replace( $this->regex, '', $text );
			$this->document->setBuffer($text, "component"); 
			// Clean up variables
			unset($app, $item, $text);
			return true;
		}
		
		// In other components or leftovers
		$text = $this->document->getBuffer("component");
		if (strlen($text)>0) {
			
			// check whether plugin has been unpublished
			if ( !$this->publ )
				$text = preg_replace( $this->regex, '', $text );
			else
				$this->_replace($text);			
			$this->document->setBuffer($text, "component"); 
		}
		
		// Clean up variables
		unset($app, $item, $text);
	}
	
	/**
	 * Do something onAfterRender 
	 */
	public function onAfterRender()
	{
		$this->event = 'onAfterRender';
		
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// Get the rendered body text
		$text = JResponse::getBody();
		
		// check whether plugin has been unpublished
		if ( !$this->publ ) {
			$text = preg_replace( $this->regex, '', $text );
			// Clean up variables
			unset($app, $text);
			return true;
		}
		
		// PDF or feed can't show maps so remove it
		if ($this->doctype=='pdf'||$this->doctype=='feed') {
			$text = preg_replace( $this->regex, '', $text );
			// Clean up variables
			unset($app, $text);
			return true;
		}
		
		// perform the replacement
		$this->_replace( $text );
		
		// Set the body text with the replaced result
        JResponse::setBody($text);

		// Clean up variables
		unset($app, $text);
	}
	
	function _getdoc() {
		if ($this->document==NULL) {
			$this->document = JFactory::getDocument();
			$this->doctype = $this->document->getType();
		}
	}
	
	function _replace(&$text) {
		$matches = array();
		$text=preg_replace("/&#0{0,2}39;/",'\'',$text);
		preg_match_all($this->regex,$text,$matches,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);
//		print_r($matches);
		// Remove plugincode that are in head of the page
		$matches = $this->_checkhead($text, $matches);
		// Remove plugincode that are in the editor and textarea
		$matches = $this->_checkeditorarea($text, $matches);
		$cnt = count($matches[0]);
//		print_r($matches);
		if ($cnt>0) {
			if ($this->helper==null) {
				if (substr($this->jversion,0,3)=="1.5")
					$filename = JPATH_SITE."/plugins/system/plugin_googlemap2_helper.php";
				else
					$filename = JPATH_SITE."/plugins/system/plugin_googlemap2/plugin_googlemap2_helper.php";
				
				include_once($filename);
				$this->helper = new plgSystemPlugin_googlemap2_helper($this->jversion, $this->params, $this->regex, $this->document, $this->brackets);
			}
			// Process the found {mosmap} codes
			for($counter = 0; $counter < $cnt; $counter++) {
				// Very strange the first match is the plugin code??
				$this->helper->process($matches[0][$counter][0], $matches[$this->countmatch][$counter][0], $text, $counter, $this->event);
			}
		}
		
		// Clean up variables
		unset($matches, $cnt, $counter, $content, $filename);
	}
	
	function _checkhead($text, $plgmatches) {
		$result = array(array(),array(),array(),array());
		$cnt = count($plgmatches[0]);
		// Get head location
		$end = stripos($text, '</head>');
		// check if match plugin is the head
		for($counter = 0; $counter < $cnt; $counter++) {
			if (!($plgmatches[0][$counter][1] > 0 &&$plgmatches[0][$counter][1]< $end)) {
					$result[0][] = $plgmatches[0][$counter];
					$result[1][] = $plgmatches[1][$counter];
					$result[2][] = $plgmatches[2][$counter];
					$result[3][] = $plgmatches[3][$counter];
			}
		}

		return $result;
	}
	
	function _checkeditorarea($text, $plgmatches) {
		$edmatches = array_merge($this->_getEditorPositions($text), $this->_getTextAreaPositions($text));
		$result = array(array(),array(),array(),array());
		if (count($edmatches)>0) {
			$cnt = count($plgmatches[0]);
			// check if match plugin is in match editor
			for($counter = 0; $counter < $cnt; $counter++) {
				$oke = true;
				foreach ($edmatches as $ed) {
					if ($plgmatches[0][$counter][1] > $ed['start']&&$plgmatches[0][$counter][1]< $ed['end'])
						$oke= false;
				}
				if ($oke) {
					$result[0][] = $plgmatches[0][$counter];
					$result[1][] = $plgmatches[1][$counter];
					$result[2][] = $plgmatches[2][$counter];
					$result[3][] = $plgmatches[3][$counter];
				}
			}
		} else
			$result = $plgmatches;
			
		// Clean up variables
		unset($edmatches, $cnt, $counter, $ed);
		
		return $result;
	}
	
	function _getEditorPositions($strBody) {
		if (substr($this->jversion,0,3)=="1.5"||substr($this->jversion,0,3)=="1.6"||$this->jversion=="1.7.0"||$this->jversion=="1.7.1"||$this->jversion=="1.7.2")
			preg_match_all("/<!-- Start Editor -->(.*)<!-- End Editor -->/Ums", $strBody, $strEditor, PREG_PATTERN_ORDER);
		else
			preg_match_all("/<div class=\"edit item-page\">(.*)<\/form>\n<\/div>/Ums", $strBody, $strEditor, PREG_PATTERN_ORDER);

		$intOffset = 0;
		$intIndex = 0;
		$intEditorPositions = array();

		foreach($strEditor[0] as $strFullEditor) {
			$intEditorPositions[$intIndex] = array('start' => (strpos($strBody, $strFullEditor, $intOffset)), 'end' => (strpos($strBody, $strFullEditor, $intOffset) + strlen($strFullEditor)));
			$intOffset += strlen($strFullEditor);
			$intIndex++;
		}
		
		// Clean up variables
		unset($strEditor, $intOffset, $strFullEditor, $intIndex);
		
		return $intEditorPositions;
	}
	
	function _getTextAreaPositions($strBody) {
		preg_match_all("/<textarea\b[^>]*>(.*)<\/textarea>/Ums", $strBody, $strTextArea, PREG_PATTERN_ORDER);

		$intOffset = 0;
		$intIndex = 0;
		$intTextAreaPositions = array();

		foreach($strTextArea[0] as $strFullTextArea) {
			$intTextAreaPositions[$intIndex] = array('start' => (strpos($strBody, $strFullTextArea, $intOffset)), 'end' => (strpos($strBody, $strFullTextArea, $intOffset) + strlen($strFullTextArea)));
			$intOffset += strlen($strFullTextArea);
			$intIndex++;
		}
		
		// Clean up variables
		unset($strTextArea, $intOffset, $strFullTextArea, $intIndex);
		
		return $intTextAreaPositions;
	}
	
	function _restore_permanent_defaults() {
		$app = JFactory::getApplication();
		if($app->isSite()) {
			return;
		}
		if ($this->params->get( 'publ', '' )!='') {
			jimport('joomla.filesystem.file');
			
			if (substr($this->jversion,0,3)=="1.5")
				$dir = JPATH_SITE."/plugins/system/";
			else
				$dir = JPATH_SITE."/plugins/system/plugin_googlemap2/";
			
			if (file_exists($dir.'plugin_googlemap2.perm')) {
				if (JFile::move ($dir.'plugin_googlemap2.xml', $dir.'plugin_googlemap2.init')) {
					if (JFile::move ($dir.'plugin_googlemap2.perm', $dir.'plugin_googlemap2.xml'))
						JFile::delete($dir.'plugin_googlemap2.init');
					else
						JFile::move ($dir.'plugin_googlemap2.init', $dir.'plugin_googlemap2.xml');
				}
			}
		}
	}
}

?>PK��#]�y5	5	7system/remember/plugin_googlemap2/plugin_googlemap2.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="1.6.0" type="plugin" group="system" method="upgrade">
	<name>Google Maps</name>
	<author>Mike Reumer</author>
	<creationDate>June 2012</creationDate>
	<copyright>(C) 2012 Reumer</copyright>
	<license>http://www.gnu.org/copyleft/gpl.html GNU/GPL</license>
	<authorEmail>tech@reumer.net</authorEmail>
	<authorUrl>tech.reumer.net</authorUrl>
	<version>2.18</version>
	<description>PLUGIN_GOOGLE_MAPS_INSTALLATION</description>
	<files>
		<filename plugin="plugin_googlemap2">plugin_googlemap2.php</filename>
		<filename>plugin_googlemap2_helper.php</filename>
		<filename>plugin_googlemap2_proxy.php</filename>
		<filename>plugin_googlemap2_twitter_kml.php</filename>
		<filename>gpl.txt</filename>
		<filename>index.html</filename>
	</files>
	<media folder="media" destination="plugin_googlemap2">
		<folder>site</folder>
		<filename>index.html</filename>	
    </media>
	<languages>
	   <language tag="en-GB">language/en-GB.plg_system_plugin_googlemap2.ini</language>
	   <language tag="en-GB">language/en-GB.plg_system_plugin_googlemap2.sys.ini</language>
	   <language tag="it-IT">language/it-IT.plg_system_plugin_googlemap2.ini</language>
	   <language tag="it-IT">language/it-IT.plg_system_plugin_googlemap2.sys.ini</language>
	   <language tag="es-ES">language/es-ES.plg_system_plugin_googlemap2.ini</language>
	   <language tag="es-ES">language/es-ES.plg_system_plugin_googlemap2.sys.ini</language>
	   <language tag="fr-FR">language/fr-FR.plg_system_plugin_googlemap2.ini</language>
	   <language tag="fr-FR">language/fr-FR.plg_system_plugin_googlemap2.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="GOOGLEMAP_BASIC">
				<field name="publ" type="radio" size="1" default="1" export='0' label="Published" description="GOOGLEMAP_TT_CONFIG_PUBLISHED">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="debug" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_DEBUG" description="GOOGLEMAPS_TT_MAPS_DEBUG">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="plugincode" type="text" size= "40" default="mosmap" export='0' label="GOOGLEMAPS_PLUGINCODE" description="GOOGLEMAPS_TT_PLUGINCODE" />
				<field name="brackets" type="radio" size= "1" default="{" export='0' label="GOOGLEMAPS_BRACKETS" description="GOOGLEMAPS_TT_BRACKETS">
					<option value="{">{}</option>
					<option value="[">[]</option>
					<option value="both">GOOGLEMAPS_BRACKETS_BOTH</option>
				</field>
				<field name="Google_API_version" type="text" size= "5" default="3.x" export='0' label="GOOGLEMAPS_GOOGLEAPIVERSION" description="GOOGLEMAPS_TT_GOOGLEAPIVERSION" />
				<field name="show" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAP_SHOW" description="GOOGLEMAPS_TT_MAP_SHOW">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="mapclass" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAP_CLASS" description="GOOGLEMAPS_TT_MAP_CLASS" />
				<field name="mapcss" type="textarea" rows="3" cols="40" default="/* For img in the map remove borders, shadow, no margin and no max-width&#13;*/&#13;.map img {&#13;    border: 0px;&#13;    box-shadow: 0px;&#13;    margin: 0px;&#13;    max-width: none !important;&#13;}&#13;&#13;/* Make sure the directions are below the map&#13;*/&#13;.directions {&#13;    clear: left;&#13;}&#13;&#13;/* Solve problems in chrome with the show of the direction steps in full width&#13;*/&#13;.adp-placemark {&#13;    width : 100%&#13;}" export='0' label="GOOGLEMAPS_MAPS_CSS" description="GOOGLEMAPS_TT_MAPS_CSS" />
				<field name="loadmootools" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_LOADWITHMOOTOOLS" description="GOOGLEMAPS_TT_LOADWITHMOOTOOLS">
					<option value="1">GOOGLEMAPS_LOADWITHMOOTOOLSMOOTOOLS</option>
					<option value="0">GOOGLEMAPS_LOADWITHMOOTOOLSTIMEINTERVAL</option>
				</field>
				<field name="timeinterval" type="text" size= "4" default="500" export='0' label="GOOGLEMAPS_TIMEINTERVAL" description="GOOGLEMAPS_TT_TIMEINTERVAL" />
				<field name="Google_API_key" type="text" size="60" maxsize="255" default="" export='0' label="GOOGLEMAPS_API_KEY" description="GOOGLEMAPS_TT_API_KEY" />
				<field name="Google_Multi_API_key" type="textarea" rows="5" cols="40" default="" export='0' label="GOOGLEMAPS_MULTI_API_KEY" description="GOOGLEMAPS_TT_MULTI_API_KEY" />
				<field name="urlsetting" type="radio" size= "1" default="http_host" export='0' label="GOOGLEMAPS_URLWEBSITE" description="GOOGLEMAPS_TT_URLWEBSITE">
					<option value="Joomla">GOOGLEMAPS_URLWEBSITE_JOOMLA</option>
					<option value="http_host">HTTP_HOST</option>
				</field>
				<field name="googlewebsite" type="list" size= "1" default="maps.google.com" export='1' label="GOOGLEMAPS_GOOGLEWEBSITE" description="GOOGLEMAPS_TT_GOOGLEWEBSITE">
					<option value='maps.google.com'>United States - www.google.com (Default)</option>
					<option value='maps.google.com'>United States - maps.google.com</option>
					<option value='maps.google.com.af'>Afghanistan - maps.google.com.af</option>
					<option value='maps.google.as'>American Samoa - maps.google.as</option>
					<option value='maps.google.ad'>Andorra - maps.google.ad</option>
					<option value='maps.google.it.ao'>Angola - maps.google.it.ao</option>
					<option value='maps.google.com.ai'>Anguilla - maps.google.com.ai</option>
					<option value='maps.google.com.ar'>Argentina - maps.google.com.ar</option>
					<option value='maps.google.am'>Armenia - maps.google.am</option>
					<option value='maps.google.com.au'>Australia - maps.google.com.au</option>
					<option value='maps.google.at'>Austria - maps.google.at</option>
					<option value='maps.google.az'>Azerbaijan - maps.google.az</option>
					<option value='maps.google.bs'>Bahamas - maps.google.bs</option>
					<option value='maps.google.com.bh'>Bahrain - maps.google.com.bh</option>
					<option value='maps.google.com.bd'>Bangladesh - maps.google.com.bd</option>
					<option value='maps.google.by'>Belarus - maps.google.by</option>
					<option value='maps.google.be'>Belgium - maps.google.be</option>
					<option value='maps.google.com.bz'>Belize - maps.google.com.bz</option>
					<option value='maps.google.com.bo'>Bolivia - maps.google.com.bo</option>
					<option value='maps.google.ba'>Bosnia and Herzegovina - maps.google.ba</option>
					<option value='maps.google.co.bw'>Botswana - maps.google.co.bw</option>
					<option value='maps.google.com.br'>Brazil - maps.google.com.br</option>
					<option value='maps.google.vg'>British Virgin Islands - maps.google.vg</option>
					<option value='maps.google.com.bn'>Brunei - maps.google.com.bn</option>
					<option value='maps.google.bg'>Bulgaria - maps.google.bg</option>
					<option value='maps.google.bi'>Burundi - maps.google.bi</option>
					<option value='maps.google.kh'>Cambodia - maps.google.kh</option>
					<option value='maps.google.ca'>Canada - maps.google.ca</option>
					<option value='maps.google.cl'>Chile - maps.google.cl</option>
					<option value='maps.google.cn'>China - maps.google.cn</option>
					<option value='maps.google.com.co'>Colombia - maps.google.com.co</option>
					<option value='maps.google.co.ck'>Cook Islands - maps.google.co.ck</option>
					<option value='maps.google.co.cr'>Costa Rica - maps.google.co.cr</option>
					<option value='maps.google.ci'>Côte d\'Ivoire - maps.google.ci</option>
					<option value='maps.google.hr'>Croatia - maps.google.hr</option>
					<option value='maps.google.com.cu'>Cuba - maps.google.com.cu</option>
					<option value='maps.google.cz'>Czech Republic - maps.google.cz</option>
					<option value='maps.google.cd'>Dem. Rep. of the Congo - maps.google.cd</option>
					<option value='maps.google.dk'>Denmark - maps.google.dk</option>
					<option value='maps.google.dj'>Djibouti - maps.google.dj</option>
					<option value='maps.google.dm'>Dominica - maps.google.dm</option>
					<option value='maps.google.com.do'>Dominican Republic - maps.google.com.do</option>
					<option value='maps.google.com.ec'>Ecuador - maps.google.com.ec</option>
					<option value='maps.google.com.eg'>Egypt - maps.google.com.eg</option>
					<option value='maps.google.com.sv'>El Salvador - maps.google.com.sv</option>
					<option value='maps.google.ee'>Estonia - maps.google.ee</option>
					<option value='maps.google.com.et'>Ethiopia - maps.google.com.et</option>
					<option value='maps.google.fm'>Fed. States of Micronesia - maps.google.fm</option>
					<option value='maps.google.com.fj'>Fiji - maps.google.com.fj</option>
					<option value='maps.google.fi'>Finland - maps.google.fi</option>
					<option value='maps.google.fr'>France - maps.google.fr</option>
					<option value='maps.google.gm'>Gambia - maps.google.gm</option>
					<option value='maps.google.ge'>Georgia - maps.google.ge</option>
					<option value='maps.google.de'>Germany - maps.google.de</option>
					<option value='maps.google.com.gh'>Ghana - maps.google.com.gh</option>
					<option value='maps.google.com.gi'>Gibraltar - maps.google.com.gi</option>
					<option value='maps.google.gr'>Greece - maps.google.gr</option>
					<option value='maps.google.gl'>Greenland - maps.google.gl</option>
					<option value='maps.google.gp'>Guadeloupe - maps.google.gp</option>
					<option value='maps.google.com.gt'>Guatemala - maps.google.com.gt</option>
					<option value='maps.google.gg'>Guernsey - maps.google.gg</option>
					<option value='maps.google.com.gy'>Guyana - maps.google.com.gy</option>
					<option value='maps.google.ht'>Haiti - maps.google.ht</option>
					<option value='maps.google.hn'>Honduras - maps.google.hn</option>
					<option value='maps.google.com.hk'>Hong Kong - maps.google.com.hk</option>
					<option value='maps.google.hu'>Hungary - maps.google.hu</option>
					<option value='maps.google.is'>Iceland - maps.google.is</option>
					<option value='maps.google.co.in'>India - maps.google.co.in</option>
					<option value='maps.google.co.id'>Indonesia - maps.google.co.id</option>
					<option value='maps.google.ie'>Ireland - maps.google.ie</option>
					<option value='maps.google.im'>Isle of Man - maps.google.im</option>
					<option value='maps.google.co.il'>Israel - maps.google.co.il</option>
					<option value='maps.google.it'>Italy - maps.google.it</option>
					<option value='maps.google.com.jm'>Jamaica - maps.google.com.jm</option>
					<option value='maps.google.co.jp'>Japan - maps.google.co.jp</option>
					<option value='maps.google.je'>Jersey - maps.google.je</option>
					<option value='maps.google.jo'>Jordan - maps.google.jo</option>
					<option value='maps.google.kg'>Kazakhstan - maps.google.kg</option>
					<option value='maps.google.kz'>Kazakhstan - maps.google.kz</option>
					<option value='maps.google.co.ke'>Kenya - maps.google.co.ke</option>
					<option value='maps.google.ki'>Kiribati - maps.google.ki</option>
					<option value='maps.google.la'>Laos - maps.google.la</option>
					<option value='maps.google.lv'>Latvia - maps.google.lv</option>
					<option value='maps.google.co.ls'>Lesotho - maps.google.co.ls</option>
					<option value='maps.google.com.ly'>Libya - maps.google.com.ly</option>
					<option value='maps.google.li'>Liechtenstein - maps.google.li</option>
					<option value='maps.google.lt'>Lithuania - maps.google.lt</option>
					<option value='maps.google.lu'>Luxembourg - maps.google.lu</option>
					<option value='maps.google.mw'>Malawi - maps.google.mw</option>
					<option value='maps.google.com.my'>Malaysia - maps.google.com.my</option>
					<option value='maps.google.mv'>Maldives - maps.google.mv</option>
					<option value='maps.google.mt'>Malta - maps.google.mt</option>
					<option value='maps.google.mu'>Mauritus - maps.google.mu</option>
					<option value='maps.google.com.mx'>Mexico - maps.google.com.mx</option>
					<option value='maps.google.md'>Moldova - maps.google.md</option>
					<option value='maps.google.mn'>Mongolia - maps.google.mn</option>
					<option value='maps.google.ms'>Montserrat - maps.google.ms</option>
					<option value='maps.google.co.ma'>Morocco - maps.google.co.ma</option>
					<option value='maps.google.com.na'>Namibia - maps.google.com.na</option>
					<option value='maps.google.nr'>Nauru - maps.google.nr</option>
					<option value='maps.google.com.np'>Nepal - maps.google.com.np</option>
					<option value='maps.google.nl'>Netherlands - maps.google.nl</option>
					<option value='maps.google.co.nz'>New Zealand - maps.google.co.nz</option>
					<option value='maps.google.com.ni'>Nicaragua - maps.google.com.ni</option>
					<option value='maps.google.com.ng'>Nigeria - maps.google.com.ng</option>
					<option value='maps.google.nu'>Niue - maps.google.nu</option>
					<option value='maps.google.com.nf'>Norfolk Island - maps.google.com.nf</option>
					<option value='maps.google.no'>Norway - maps.google.no</option>
					<option value='maps.google.com.om'>Oman - maps.google.com.om</option>
					<option value='maps.google.com.pk'>Pakistan - maps.google.com.pk</option>
					<option value='maps.google.com.pa'>Panama - maps.google.com.pa</option>
					<option value='maps.google.com.py'>Parguay - maps.google.com.py</option>
					<option value='maps.google.com.pe'>Peru - maps.google.com.pe</option>
					<option value='maps.google.com.ph'>Philippines - maps.google.com.ph</option>
					<option value='maps.google.pn'>Pitcairn Islands - maps.google.pn</option>
					<option value='maps.google.pl'>Poland - maps.google.pl</option>
					<option value='maps.google.pt'>Portugal - maps.google.pt</option>
					<option value='maps.google.com.pr'>Puerto Rico - maps.google.com.pr</option>
					<option value='maps.google.com.qa'>Qatar - maps.google.com.qa</option>
					<option value='maps.google.cg'>Rep. of the Congo - maps.google.cg</option>
					<option value='maps.google.ru'>Russia - maps.google.ru</option>
					<option value='maps.google.rw'>Rwanda - maps.google.rw</option>
					<option value='maps.google.sh'>Saint Helena - maps.google.sh</option>
					<option value='maps.google.com.vc'>Saint Vincent and the Grenadines - maps.google.com.vc</option>
					<option value='maps.google.ws'>Samoa - maps.google.ws</option>
					<option value='maps.google.st'>Sao Tome and Principe - maps.google.st</option>
					<option value='maps.google.com.sa'>Saudi Arabia - maps.google.com.sa</option>
					<option value='maps.google.sn'>Senegal - maps.google.sn</option>
					<option value='maps.google.rs'>Serbia - maps.google.rs</option>
					<option value='maps.google.sc'>Seychelles - maps.google.sc</option>
					<option value='maps.google.com.sg'>Singapore - maps.google.com.sg</option>
					<option value='maps.google.com.sb'>Solomon Islands - maps.google.com.sb</option>
					<option value='maps.google.co.za'>South Africa - maps.google.co.za</option>
					<option value='maps.google.co.kr'>South Korea - maps.google.co.kr</option>
					<option value='maps.google.lk'>Sri Lanka - maps.google.lk</option>
					<option value='maps.google.com.tj'>Tajikistan - maps.google.com.tj</option>
					<option value='maps.google.co.th'>Thailand - maps.google.co.th</option>
					<option value='maps.google.tl'>Timor Leste - maps.google.tl</option>
					<option value='maps.google.tk'>Tokelau - maps.google.tk</option>
					<option value='maps.google.to'>Tonga - maps.google.to</option>
					<option value='maps.google.tt'>Trinidad and Tobago - maps.google.tt</option>
					<option value='maps.google.tm'>Turkmenistan - maps.google.tm</option>
					<option value='maps.google.co.vi'>U.S. Virgin Islands - maps.google.co.vi</option>
					<option value='maps.google.co.ug'>Uganda - maps.google.co.ug</option>
					<option value='maps.google.ae'>United Arab Emirates - maps.google.ae</option>
					<option value='maps.google.com.uy'>Uruguay - maps.google.com.uy</option>
					<option value='maps.google.co.uz'>Uzbekistan - maps.google.co.uz</option>
					<option value='maps.google.vu'>Vanuatu - maps.google.vu</option>
					<option value='maps.google.co.ve'>Venzuela - maps.google.co.ve</option>
					<option value='maps.google.com.vn'>Vietnam - maps.google.com.vn</option>
					<option value='maps.google.co.zm'>Zambia - maps.google.co.zm</option>
					<option value='maps.google.co.zw'>Zimbabwe - maps.google.co.zw</option>
					<option value='maps.google.ch'>Switzerland - maps.google.ch</option>
					<option value='maps.google.es'>Spain - maps.google.es</option>
					<option value='maps.google.se'>Sweden - maps.google.se</option>
					<option value='maps.google.tw'>Taiwan - maps.google.tw</option>
					<option value='maps.google.co.uk'>United Kingdom - maps.google.co.uk</option>
				</field>
				<field name="googleindexing" type="radio" size= "1" default="1" export='0' label="GOOGLEMAPS_INDEXING" description="GOOGLEMAPS_TT_INDEXING">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="styledmap" type="textarea" rows="5" cols="40" default="" export='1' label="GOOGLEMAPS_MAPS_STYLEDMAP" description="GOOGLEMAPS_TT_MAPS_STYLEDMAP" />
				<field name="align" type="list" size= "4" default="center" export='1' label="GOOGLEMAPS_MAPS_ALIGN" description="GOOGLEMAPS_TT_MAPS_ALIGN">
					<option value="left">GOOGLEMAPS_MAPS_ALIGNLEFT</option>
					<option value="center">GOOGLEMAPS_MAPS_ALIGNCENTER</option>
					<option value="right">GOOGLEMAPS_MAPS_ALIGNRIGHT</option>
					<option value="none">GOOGLEMAPS_MAPS_ALIGNNONE</option>
				</field>
				<field name="langtype" type="list" size="1" default="site" export='0' label="GOOGLEMAPS_LANGUAGE_OPTION" description="GOOGLEMAPS_TT_LANGUAGE_OPTION">
					<option value="site">GOOGLEMAPS_LANGTYPE_SITE</option>
					<option value="joomfish">GOOGLEMAPS_LANGTYPE_JOOMFISH</option>
					<option value="user">GOOGLEMAPS_LANGTYPE_USER</option>
					<option value="config">GOOGLEMAPS_LANGTYPE_CONFIG</option>
				</field>
				<field name="lang" type="text" size= "5" default="" export='0' label="GOOGLEMAPS_LANGUAGE" description="GOOGLEMAPS_TT_LANGUAGE" />
				<field name="width" type="text" size= "10" default="500" export='1' label="GOOGLEMAPS_MAPS_WIDTH" description="GOOGLEMAPS_TT_MAPS_WIDTH" />
				<field name="height" type="text" size= "10" default="400" export='1' label="GOOGLEMAPS_MAPS_HEIGHT" description="GOOGLEMAPS_TT_MAPS_HEIGHT" />
				<field name="effect" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_EFFECT" description="GOOGLEMAPS_TT_MAPS_EFFECT">
					<option value="none">GOOGLEMAPS_MAPS_EFFECTNONE</option>
					<option value="horizontal">GOOGLEMAPS_MAPS_EFFECTHORZ</option>
					<option value="vertical">GOOGLEMAPS_MAPS_EFFECTVERT</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_LOCATION">
				<field name="lat" type="text" size= "15" default="52.075581" export='1' label="GOOGLEMAPS_MAPS_LAT" description="GOOGLEMAPS_TT_MAPS_LAT" />
				<field name="lon" type="text" size= "15" default="4.541513" export='1' label="GOOGLEMAPS_MAPS_LNG" description="GOOGLEMAPS_TT_MAPS_LNG" />
				<field name="centerlat" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_CENTERLAT" description="GOOGLEMAPS_TT_MAPS_CENTERLAT" />
				<field name="centerlon" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_CENTERLNG" description="GOOGLEMAPS_TT_MAPS_CENTERLNG" />
				<field name="address" type="text" size= "80" default="" export='1' label="GOOGLEMAPS_MAPS_ADRESS" description="GOOGLEMAPS_TT_MAPS_ADRESS" />
				<field name="latitudeid" type="text" size= "30" default="" export='1' label="GOOGLEMAPS_MAPS_LATITUDEID" description="GOOGLEMAPS_TT_MAPS_LATITUDEID" />
				<field name="latitudedesc" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_LATITUDEDESC" description="GOOGLEMAPS_TT_MAPS_LATITUDEDESC">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>		
				<field name="latitudecoord" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_LATITUDECOORD" description="GOOGLEMAPS_TT_MAPS_LATITUDECOORD">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="latitudeform" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_LATITUDEFORM" description="GOOGLEMAPS_TT_MAPS_LATITUDEFORM">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_CONTROL">
				<field name="controltype" type="radio" size= "5" default="UI" export='1' label="GOOGLEMAPS_MAPS_CONTROLTYPE" description="GOOGLEMAPS_TT_MAPS_CONTROLTYPE">
					<option value="UI">GOOGLEMAPS_MAPS_CONTROLTYPEAUTOMATIC</option>
					<option value="user">GOOGLEMAPS_MAPS_CONTROLTYPEUSER</option>
				</field>
				<field name="zoomType" type="radio" size= "10" default="3D-large" export='1' label="GOOGLEMAPS_MAPS_MAPCONTROL" description="GOOGLEMAPS_TT_MAPS_MAPCONTROL">
					<option value="Large">GOOGLEMAPS_MAPS_MAPCONTROLLARGE</option>
					<option value="Small">GOOGLEMAPS_MAPS_MAPCONTROLSMALL</option>
					<option value="3D-large">GOOGLEMAPS_MAPS_MAPCONTROL3DLARGE</option>
					<option value="3D-largeSV">GOOGLEMAPS_MAPS_MAPCONTROL3DLARGESV</option>
					<option value="3D-small">GOOGLEMAPS_MAPS_MAPCONTROL3DSMALL</option>
					<option value="None">GOOGLEMAPS_MAPS_MAPCONTROLNONE</option>
				</field>
				<field name="svcontrol" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SVCONTROL" description="GOOGLEMAPS_TT_MAPS_SVCONTROL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>		
				<field name="zoom" type="list" size= "1" default="10" export='1' label="GOOGLEMAPS_MAPS_ZOOM" description="GOOGLEMAPS_TT_MAPS_ZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="corzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_CORZOOM" description="GOOGLEMAPS_TT_MAPS_CORZOOM">
					<option value="10">+10</option>
					<option value="9">+9</option>
					<option value="8">+8</option>
					<option value="7">+7</option>
					<option value="6">+6</option>
					<option value="5">+5</option>
					<option value="4">+4</option>
					<option value="3">+3</option>
					<option value="2">+2</option>
					<option value="1">+1</option>
					<option value="0">0</option>
					<option value="-1">-1</option>
					<option value="-2">-2</option>
					<option value="-3">-3</option>
					<option value="-4">-4</option>
					<option value="-5">-5</option>
					<option value="-6">-6</option>
					<option value="-7">-7</option>
					<option value="-8">-8</option>
					<option value="-9">-9</option>
					<option value="-10">-10</option>
				</field>
				<field name="minzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_MINZOOM" description="GOOGLEMAPS_TT_MAPS_MINZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="maxzoom" type="list" size= "1" default="19" export='1' label="GOOGLEMAPS_MAPS_MAXZOOM" description="GOOGLEMAPS_TT_MAPS_MAXZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="rotation" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_ROTATION" description="GOOGLEMAPS_TT_MAPS_ROTATION">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>		
				<field name="zoomnew" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ZOOMNEW" description="GOOGLEMAPS_TT_MAPS_ZOOMNEW">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="zoomWheel" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_MOUSEWHEEL" description="GOOGLEMAPS_TT_MAPS_MOUSEWHEEL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="keyboard" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KEYBOARD" description="GOOGLEMAPS_TT_MAPS_KEYBOARD">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="mapType" type="radio" size= "9" default="Normal" export='1' label="GOOGLEMAPS_MAPS_MAPTYPE" description="GOOGLEMAPS_TT_MAPS_MAPTYPE">
					<option value="Normal">GOOGLEMAPS_MAPS_MAPTYPENORMAL</option>
					<option value="Satellite">GOOGLEMAPS_MAPS_MAPTYPESATELLITE</option>
					<option value="Hybrid">GOOGLEMAPS_MAPS_MAPTYPEHYBRID</option>
					<option value="Terrain">GOOGLEMAPS_MAPS_MAPTYPETERRAIN</option>
					<option value="Earth">GOOGLEMAPS_MAPS_MAPTYPEEARTH</option>
				</field>
				<field name="showmaptype" type="radio" size= "1" export='1' default="1" label="GOOGLEMAPS_MAPS_SHOWMAPTYPE" description="GOOGLEMAPS_TT_MAPS_SHOWMAPTYPE">
					<option value="0">GOOGLEMAPS_MAPS_SHOWMAPTYPENONE</option>
					<option value="1">GOOGLEMAPS_MAPS_SHOWMAPTYPEHORZMENU</option>
					<option value="2">GOOGLEMAPS_MAPS_SHOWMAPTYPEHIERMENU</option>
					<option value="3">GOOGLEMAPS_MAPS_SHOWMAPTYPEVERTMENU</option>
				</field>
				<field name="showNormalMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWNORMAL" description="GOOGLEMAPS_MAPS_TT_SHOWNORMAL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showSatelliteMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWSATELLITE" description="GOOGLEMAPS_MAPS_TT_SHOWSATELLITE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showHybridMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWHYBRID" description="GOOGLEMAPS_MAPS_TT_SHOWHYBRID">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showTerrainMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWTERRAIN" description="GOOGLEMAPS_MAPS_TT_SHOWTERRAIN">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showEarthMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWEARTH" description="GOOGLEMAPS_MAPS_TT_SHOWEARTH">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showscale" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_SCALE" description="GOOGLEMAPS_TT_MAPS_SCALE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="overview" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_OVERVIEW" description="GOOGLEMAPS_TT_MAPS_OVERVIEW">
					<option value="0">GOOGLEMAPS_MAPS_OVERVIEWDISABLED</option>
					<option value="1">GOOGLEMAPS_MAPS_OVERVIEWENABLED</option>
					<option value="2">GOOGLEMAPS_MAPS_OVERVIEWENABLEDCLOSED</option>
				</field>
				<field name="ovzoom" type="list" size= "1" default="-3" export='1' label="GOOGLEMAPS_MAPS_OVZOOM" description="GOOGLEMAPS_TT_MAPS_OVZOOM">
					<option value="10">+10</option>
					<option value="9">+9</option>
					<option value="8">+8</option>
					<option value="7">+7</option>
					<option value="6">+6</option>
					<option value="5">+5</option>
					<option value="4">+4</option>
					<option value="3">+3</option>
					<option value="2">+2</option>
					<option value="1">+1</option>
					<option value="">0</option>
					<option value="-1">-1</option>
					<option value="-2">-2</option>
					<option value="-3">-3</option>
					<option value="-4">-4</option>
					<option value="-5">-5</option>
					<option value="-6">-6</option>
					<option value="-7">-7</option>
					<option value="-8">-8</option>
					<option value="-9">-9</option>
					<option value="-10">-10</option>
				</field>
				<field name="navlabel" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_NAVLABEL" description="GOOGLEMAPS_TT_MAPS_NAVLABEL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="dragging" type="radio" size="1" default="1" export='1' label="GOOGLEMAPS_MAPS_DRAGGING" description="GOOGLEMAPS_TT_MAPS_DRAGGING">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="marker" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_INFOWINDOW" description="GOOGLEMAPS_MAPS_TT_INFOWINDOW">
				<option value="1">GOOGLEMAPS_MAPS_INFOWINDOWOPEN</option>
				<option value="0">GOOGLEMAPS_MAPS_INFOWINDOWCLOSED</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_ICON">
				<field name="icon" type="text" size="40" maxsize="255" default="" export='1' label="GOOGLEMAPS_ICONS_IMAGE" description="GOOGLEMAPS_TT_ICONS_IMAGE" />
				<field name="iconwidth" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_WIDTH" description="GOOGLEMAPS_TT_ICONS_WIDTH" />
				<field name="iconheight" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_HEIGHT" description="GOOGLEMAPS_TT_ICONS_HEIGHT" />
				<field name="iconanchorx" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_ANCHORX" description="GOOGLEMAPS_TT_ICONS_ANCHORX" />
				<field name="iconanchory" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_ANCHORY" description="GOOGLEMAPS_TT_ICONS_ANCHORY" />
				<field name="iconshadow" type="text" size="60" maxsize="255" default="" export='1' label="GOOGLEMAPS_ICONS_SHADOW" description="GOOGLEMAPS_TT_ICONS_SHADOW" />
				<field name="iconshadowwidth" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_SHADOWWIDTH" description="GOOGLEMAPS_TT_ICONS_SHADOWWIDTH" />
				<field name="iconshadowheight" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_SHADOWHEIGHT" description="GOOGLEMAPS_TT_ICONS_SHADOWHEIGHT" />
				<field name="iconinfoanchorx" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_INFOANCHORX" description="GOOGLEMAPS_TT_ICONS_INFOANCHORX" />
				<field name="iconinfoanchory" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_INFOANCHORY" description="GOOGLEMAPS_TT_ICONS_INFOANCHORY" />
				<field name="icontransparent" type="text" size="60" maxsize="255" default="" export='1' label="GOOGLEMAPS_ICONS_TRANSPARENT" description="GOOGLEMAPS_TT_ICONS_TRANSPARENT" />
				<field name="iconimagemap" type="textarea" rows="5" cols="60" default="" export='1' label="GOOGLEMAPS_ICONS_IMAGEMAP" description="GOOGLEMAPS_TT_ICONS_IMAGEMAP" />
			</fieldset>
			<fieldset name="GOOGLEMAP_LAYERS">
				<field name="traffic" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_TRAFFIC" description="GOOGLEMAPS_TT_MAPS_TRAFIC">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="transit" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_TRANSIT" description="GOOGLEMAPS_TT_MAPS_TRANSIT">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="bicycle" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_BICYCLE" description="GOOGLEMAPS_TT_MAPS_BICYCLE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="panoramio" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_PANORAMIO" description="GOOGLEMAPS_TT_MAPS_PANORAMIO">
					<option value="none">GOOGLEMAPS_MAPS_PANORAMIONO</option>
					<option value="all">GOOGLEMAPS_MAPS_PANORAMIOALL</option>
					<option value="popular">GOOGLEMAPS_MAPS_PANORAMIOPOPULAR</option>
				</field>
				<field name="panotype" type="text" size="8" default="none" export='1' label="GOOGLEMAPS_MAPS_PANORAMIOTYPE" description="GOOGLEMAPS_TT_MAPS_PANORAMIOTYPE" />
				<field name="panoorder" type="radio" size= "1" default="popularity" export='1' label="GOOGLEMAPS_MAPS_PANORAMIOORDER" description="GOOGLEMAPS_TT_MAPS_PANORAMIOORDER">
					  <option value="popularity">GOOGLEMAPS_MAPS_PANORAMIOORDERPOPULARITY</option>
					  <option value="upload_date">GOOGLEMAPS_MAPS_PANORAMIOORDERUPLOADDATE</option>
				</field>
				<field name="panomax" type="text" size="3" default="50" export='1' label="GOOGLEMAPS_MAPS_PANORAMIOMAX" description="GOOGLEMAPS_TT_MAPS_PANORAMIOMAX" />
				<field name="youtube" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_YOUTUBE" description="GOOGLEMAPS_TT_MAPS_YOUTUBE">
					<option value="all">Yes</option>
					<option value="none">No</option>
				</field>
				<field name="wiki" type="text" size= "8" default="none" export='1' label="GOOGLEMAPS_MAPS_WIKI" description="GOOGLEMAPS_TT_MAPS_WIKI" />
				<field name="adsmanager" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ADS" description="GOOGLEMAPS_TT_MAPS_ADS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="maxads" type="text" size="3" default="3" export='1' label="GOOGLEMAPS_MAPS_ADSMAX" description="GOOGLEMAPS_TT_MAPS_ADSMAX" />
				<field name="localsearch" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_LOCALSEARCH" description="GOOGLEMAPS_TT_MAPS_LOCALSEARCH">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="adsense" type="text" size="40" default="" export='1' label="GOOGLEMAPS_ADSENSE" description="GOOGLEMAPS_TT_ADSENSE" />
				<field name="channel" type="text" size="40" default="" export='1' label="GOOGLEMAPS_MAPS_ADSENSECHANNEL" description="GOOGLEMAPS_TT_MAPS_ADSENSECHANNEL" />
				<field name="googlebar" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_GOOGLEBAR" description="GOOGLEMAPS_TT_MAPS_GOOGLEBAR">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="searchlist" type="text" size="40" default="inline" export='1' label="GOOGLEMAPS_MAPS_SEARCHLISTTYPE" description="GOOGLEMAPS_TT_MAPS_SEARCHLISTTYPE" />
				<field name="searchtarget" type="radio" size= "7" default="_blank" export='1' label="GOOGLEMAPS_MAPS_SEARCHLINKTARGET" description="GOOGLEMAPS_TT_MAPS_SEARCHLINKTARGET">
					<option value="_blank">GOOGLEMAPS_MAPS_SEARCHLINKTARGETBLANK</option>
					<option value="_self">GOOGLEMAPS_MAPS_SEARCHLINKTARGETSELF</option>
					<option value="_top">GOOGLEMAPS_MAPS_SEARCHLINKTARGETTOP</option>
					<option value="_parent">GOOGLEMAPS_MAPS_SEARCHLINKTARGETPARENT</option>
				</field>
				<field name="searchzoompan" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SEARCHZOOM" description="GOOGLEMAPS_TT_MAPS_SEARCHZOOM">
				<option value="1">GOOGLEMAPS_MAPS_SEARCHZOOMPANZOOM</option>
				<option value="0">GOOGLEMAPS_MAPS_SEARCHZOOMNOZOOM</option>
				</field>
				<field name="weather" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_WEATHER" description="GOOGLEMAPS_TT_MAPS_WEATHER">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="weathercloud" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_WEATHERCLOUD" description="GOOGLEMAPS_TT_MAPS_WEATHERCLOUD">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="weatherinfo" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_WEATHERINFO" description="GOOGLEMAPS_TT_MAPS_WEATHERINFO">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="weathertempunit" type="radio" size= "1" default="celsius" export='1' label="GOOGLEMAPS_MAPS_WEATHERTEMPUNIT" description="GOOGLEMAPS_TT_MAPS_WEATHERTEMPUNIT">
					<option value="celsius">GOOGLEMAPS_MAPS_WEATHERCELSIUS</option>
					<option value="fahrenheit">GOOGLEMAPS_MAPS_WEATHERFAHRENHEIT</option>
				</field>
				<field name="weatherwindunit" type="radio" size= "1" default="km" export='1' label="GOOGLEMAPS_MAPS_WEATHERWINDUNIT" description="GOOGLEMAPS_TT_MAPS_WEATHERWINDUNIT">
					<option value="km">GOOGLEMAPS_MAPS_WEATHERKM</option>
					<option value="m">GOOGLEMAPS_MAPS_WEATHERM</option>
					<option value="miles">GOOGLEMAPS_MAPS_WEATHERMILES</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_DIRECTIONS">
				<field name="dir" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIR" description="GOOGLEMAPS_TT_MAPS_DIR">
					<option value="0">GOOGLEMAPS_MAPS_DIRNONE</option>
					<option value="1">GOOGLEMAPS_MAPS_DIREXTERNALGOOGLE</option>
					<option value="2">GOOGLEMAPS_MAPS_DIREXTERNALDIR</option>
					<option value="3">GOOGLEMAPS_MAPS_DIRLIGHTBOX</option>
					<option value="4">GOOGLEMAPS_MAPS_DIRLIGHTBOXGOOGLE</option>
					<option value="5">GOOGLEMAPS_MAPS_DIRONMAP</option>
				</field>
				<field name="dirtype" type="radio" size= "1" default="D" export='1' label="GOOGLEMAPS_MAPS_DIRTYPE" description="GOOGLEMAPS_TT_MAPS_DIRTYPE">
					<option value="D">GOOGLEMAPS_MAPS_DIRTYPEDRIVING</option>
					<option value="W">GOOGLEMAPS_MAPS_DIRTYPEWALKING</option>
					<option value="B">GOOGLEMAPS_MAPS_DIRTYPEBICYCLE</option>
					<option value="R">GOOGLEMAPS_MAPS_DIRTYPETRANSIT</option>
				</field>
				<field name="avoidhighways" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_AVOIDHIGHWAYS" description="GOOGLEMAPS_TT_MAPS_AVOIDHIGHWAYS">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="diroptimize" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIROPTIMIZE" description="GOOGLEMAPS_TT_MAPS_DIROPTIMIZE">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="diralternatives" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIRALTERNATIVES" description="GOOGLEMAPS_TT_MAPS_DIRALTERNATIVES">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="showdir" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWDIR" description="GOOGLEMAPS_TT_MAPS_SHOWDIR">
				<option value="0">No</option>
				<option value="1">Yes</option>
				</field>
				<field name="animdir" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ANIMDIR" description="GOOGLEMAPS_TT_MAPS_ANIMDIR">
				  <option value="0">No</option>
				  <option value="1">GOOGLEMAPS_MAPS_ANIMDIRTOP</option>
				  <option value="2">GOOGLEMAPS_MAPS_ANIMDIRBOTTOM</option>
				</field>
				<field name="animspeed" type="text" size="3" default="1" export='1' label="GOOGLEMAPS_MAPS_ANIMSPEED" description="GOOGLEMAPS_TT_MAPS_ANIMSPEED" />
				<field name="animautostart" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ANIMAUTOSTART" description="GOOGLEMAPS_TT_MAPS_ANIMAUTOSTART">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="animunit" type="radio" size="1" default="kilometers" export='1' label="GOOGLEMAPS_MAPS_ANIMUNIT" description="GOOGLEMAPS_TT_MAPS_ANIMUNIT">
					<option value="kilometers">GOOGLEMAPS_TT_MAPS_ANIMUNITKILOMETERS</option>
					<option value="miles">GOOGLEMAPS_TT_MAPS_ANIMUNITMILES</option>
				</field>
				<field name="formspeed" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_FORMSPEED" description="GOOGLEMAPS_TT_MAPS_FORMSPEED">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="formdirtype" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIRSHOWTYPE" description="GOOGLEMAPS_TT_MAPS_DIRSHOWTYPE">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>		
				<field name="formaddress" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_FORMADDRESS" description="GOOGLEMAPS_TT_MAPS_FORMADDRESS">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="formdir" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_FORMDIR" description="GOOGLEMAPS_TT_MAPS_FORMDIR">
					<option value="0">GOOGLEMAPS_MAPS_FORMDIRNO</option>
					<option value="1">GOOGLEMAPS_MAPS_FORMDIRFROM</option>
					<option value="2">GOOGLEMAPS_MAPS_FORMDIRTO</option>
				</field>
				<field name="autocompl" type="radio" size= "1" default="both" export='1' label="GOOGLEMAPS_MAPS_AUTOCOMPL" description="GOOGLEMAPS_TT_MAPS_AUTOCOMPL">
					<option value="none">GOOGLEMAPS_MAPS_AUTOCOMPL_NONE</option>
					<option value="establishment">GOOGLEMAPS_MAPS_AUTOCOMPL_ESTABL</option>
					<option value="geocode">GOOGLEMAPS_MAPS_AUTOCOMPL_GEOCODE</option>
					<option value="both">GOOGLEMAPS_MAPS_AUTOCOMPL_BOTH</option>
				</field>
				<field name="langanim" type="textarea" filter="raw" rows="3" cols="40" default="en;The requested panorama could not be displayed|Could not generate a route for the current start and end addresses|Street View coverage is not available for this route|You have reached your destination|miles|miles|ft|kilometers|kilometer|meters|In|You will reach your destination|Stop|Drive|Press Drive to follow your route|Route|Speed|Fast|Medium|Slow" export='0' label="GOOGLEMAPS_MAPS_LANGANIM" description="GOOGLEMAPS_TT_MAPS_LANGANIM" />
				<field name="txtdir" type="textarea" filter="raw" rows="3" cols="40" default="Directions: " export='1' label="GOOGLEMAPS_MAPS_TITLEDIR" description="GOOGLEMAPS_TT_MAPS_TITLEDIR" />
				<field name="txtgetdir" type="textarea" filter="raw" rows="3" cols="40" default="Get Directions" export='1' label="GOOGLEMAPS_MAPS_BUTTONDIR" description="GOOGLEMAPS_TT_MAPS_BUTTONDIR" />
				<field name="txtfrom" type="textarea" filter="raw" rows="3" cols="40" default="" export='1' label="GOOGLEMAPS_MAPS_TXTFROMDIR" description="GOOGLEMAPS_TT_MAPS_TXTFROMDIR" />
				<field name="txtto" type="textarea" filter="raw" rows="3" cols="40" default="" export='1' label="GOOGLEMAPS_MAPS_TXTTODIR" description="GOOGLEMAPS_TT_MAPS_TXTTODIR" />
				<field name="txtdiraddr" type="textarea" filter="raw" rows="3" cols="40" default="Address: " export='1' label="GOOGLEMAPS_MAPS_TXTLABELADDR" description="GOOGLEMAPS_TT_MAPS_TXTLABELADDR" />
				<field name="txt_driving" type="textarea" filter="raw" rows="3" cols="40" default="" value="Driving" export='1' label="GOOGLEMAPS_MAPS_TXTLABELDRIVING" description="GOOGLEMAPS_TT_MAPS_TXTLABELDRIVING" />
				<field name="txt_avhighways" type="textarea" filter="raw" rows="3" cols="40" default="" value="Avoid highways" export='1' label="GOOGLEMAPS_MAPS_TXTAVOIDHIGHWAYS" description="GOOGLEMAPS_TT_MAPS_TXTAVOIDHIGHWAYS" />
				<field name="txt_walking" type="textarea" filter="raw" rows="3" cols="40" default="" value="Walking" export='1' label="GOOGLEMAPS_MAPS_TXTWALKING" description="GOOGLEMAPS_TT_MAPS_TXTWALKING" />
				<field name="txt_bicycle" type="textarea" rows="3" cols="40" default="" value="Bicycle" export='1' label="GOOGLEMAPS_MAPS_TXTBICYCLE" description="GOOGLEMAPS_TT_MAPS_TXTBICYCLE" />
				<field name="txt_transit" type="textarea" rows="3" cols="40" default="" value="Transit" export='1' label="GOOGLEMAPS_MAPS_TXTTRANSIT" description="GOOGLEMAPS_TT_MAPS_TXTTRANSIT" />
				<field name="txt_optimize" type="textarea" rows="3" cols="40" default="" value="Optimize route" export='1' label="GOOGLEMAPS_MAPS_TXTOPTIMIZE" description="GOOGLEMAPS_TT_MAPS_TXTOPTIMIZE" />
				<field name="txt_alternatives" type="textarea" rows="3" cols="40" default="" value="Route alternatives" export='1' label="GOOGLEMAPS_MAPS_TXTALTERNATIVES" description="GOOGLEMAPS_TT_MAPS_TXTALTERNATIVES" />
				<field name="dirdefault" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_FROMTODEFAULT" description="GOOGLEMAPS_TT_MAPS_FROMTODEFAULT">
				<option value="0">GOOGLEMAPS_MAPS_FROMTODEFAULTTO</option>
				<option value="1">GOOGLEMAPS_MAPS_FROMTODEFAULTFROM</option>
				</field>
				<field name="gotoaddr" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_GOTOADDR" description="GOOGLEMAPS_TT_MAPS_GOTOADDR">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="gotoaddrzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_GOTOADDRZOOM" description="GOOGLEMAPS_TT_MAPS_GOTOADDRZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="txtaddr" type="textarea" filter="raw" rows="3" cols="40" default="Address: ##" export='1' label="GOOGLEMAPS_MAPS_TXTADDRESSINFOWINDOW" description="GOOGLEMAPS_TT_MAPS_TXTADDRESSINFOWINDOW" />
				<field name="erraddr" type="textarea" filter="raw" rows="3" cols="40" default="Address ## not found!" export='1' label="GOOGLEMAPS_MAPS_ADDRERRTXT" description="GOOGLEMAPS_TT_MAPS_ADDRERRTXT" />
				<field name="clientgeotype" type="radio" size= "1" default="google" export='1' label="GOOGLEMAPS_MAPS_GEOTYPE" description="GOOGLEMAPS_TT_MAPS_GEOTYPE">
					<option value="google">GOOGLEMAPS_MAPS_GEOTYPE_GOOGLE</option>
					<option value="local">GOOGLEMAPS_MAPS_GEOTYPE_LOCAL</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_LIGHTBOX">
				<field name="lightbox" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_LIGHTBOX" description="GOOGLEMAPS_TT_MAPS_LIGHTBOX">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="txtlightbox" type="textarea" filter="raw" rows="3" cols="40" default="Open lightbox" export='1' label="GOOGLEMAPS_MAPS_TXTLIGHTBOX" description="GOOGLEMAPS_TT_MAPS_TXTLIGHTBOX" />
				<field name="lbxcaption" type="text" size="40" default="" export='1' label="GOOGLEMAPS_MAPS_LBXCAPTION" description="GOOGLEMAPS_TT_MAPS_LBXCAPTION" />
				<field name="lbxwidth" type="text" size= "10" default="500" export='1' label="GOOGLEMAPS_MAPS_LBWIDTH" description="GOOGLEMAPS_TT_MAPS_LBWIDTH" />
				<field name="lbxheight" type="text" size= "10" default="700" export='1' label="GOOGLEMAPS_MAPS_LBHEIGHT" description="GOOGLEMAPS_TT_MAPS_LBHEIGHT" />
				<field name="lbxcenterlat" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_LBXCENTERLAT" description="GOOGLEMAPS_TT_MAPS_LBXCENTERLAT" />
				<field name="lbxcenterlon" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_LBXCENTERLNG" description="GOOGLEMAPS_TT_MAPS_LBXCENTERLNG" />
				<field name="lbxzoom" type="list" size= "1" default="" export='1' label="GOOGLEMAPS_MAPS_LBXZOOM" description="GOOGLEMAPS_TT_MAPS_LBXZOOM">
					<option value="">GOOGLEMAPS_MAPS_LBXZOOMFROMMAP</option>
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_STREETVIEW">
				<field name="sv" type="text" size="40" default="none" export='1' label="GOOGLEMAPS_MAPS_SV" description="GOOGLEMAPS_TT_MAPS_SV" />
				<field name="svwidth" type="text" size= "10" default="100%" export='1' label="GOOGLEMAPS_MAPS_SVWIDTH" description="GOOGLEMAPS_TT_MAPS_SVWIDTH" />
				<field name="svheight" type="text" size= "10" default="300" export='1' label="GOOGLEMAPS_MAPS_SVHEIGHT" description="GOOGLEMAPS_TT_MAPS_SVHEIGHT" />
				<field name="svyaw" type="text" size= "10" default="0" export='1' label="GOOGLEMAPS_MAPS_SVYAW" description="GOOGLEMAPS_TT_MAPS_SVYAW" />
				<field name="svpitch" type="text" size= "10" default="0" export='1' label="GOOGLEMAPS_MAPS_SVPITCH" description="GOOGLEMAPS_TT_MAPS_SVPITCH" />
				<field name="svzoom" type="text" size= "10" default="" export='1' label="GOOGLEMAPS_MAPS_SVZOOM" description="GOOGLEMAPS_TT_MAPS_SVZOOM" />
				<field name="svautorotate" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_SVAUTOROTATE" description="GOOGLEMAPS_TT_MAPS_SVAUTOROTATE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="svaddress" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SVADDRESS" description="GOOGLEMAPS_TT_MAPS_SVADDRESS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_EARTH">
				<field name="earthtimeout" type="text" size= "4" default="100" export='1' label="GOOGLEMAPS_MAPS_EARTHTIMEOUT" description="GOOGLEMAPS_TT_MAPS_EARTHTIMEOUT" />
				<field name="earthborders" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_EARTHBORDERS" description="GOOGLEMAPS_TT_MAPS_EARTHBORDERS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="earthbuildings" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_EARTHBUILDINGS" description="GOOGLEMAPS_TT_MAPS_EARTHBUILDINGS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="earthroads" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_EARTHROADS" description="GOOGLEMAPS_TT_MAPS_EARTHROADS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="earthterrain" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_EARTHTERRAIN" description="GOOGLEMAPS_TT_MAPS_EARTHTERRAIN">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_KML">
				<field name="kmlrenderer" type="list" size= "3" default="google" export='1' label="GOOGLEMAPS_MAPS_KMLRENDERER" description="GOOGLEMAPS_TT_MAPS_KMLRENDERER">
					<option value="google">GOOGLEMAPS_MAPS_KMLRENDERERGOOGLE</option>
					<option value="geoxml">GOOGLEMAPS_MAPS_KMLRENDERERGEOXML</option>
					<option value="arcgis">GOOGLEMAPS_MAPS_KMLRENDERERARCGIS</option>
				</field>
				<field name="kmlsidebar" type="text" size="40" default="none" export='1' label="GOOGLEMAPS_MAPS_KMLSIDEBAR" description="GOOGLEMAPS_TT_MAPS_KMLSIDEBAR" />
				<field name="kmlsbwidth" type="text" size= "10" default="200" export='1' label="GOOGLEMAPS_MAPS_KMLSIDEBARWIDTH" description="GOOGLEMAPS_TT_MAPS_KMLSIDEBARWIDTH" />
				<field name="kmlfoldersopen" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLFOLDERSOPEN" description="GOOGLEMAPS_TT_MAPS_KMLFOLDERSOPEN">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlhide" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLHIDE" description="GOOGLEMAPS_TT_MAPS_KMLHIDE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlscale" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLSCALE" description="GOOGLEMAPS_TT_MAPS_KMLSCALE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlopenmethod" type="radio" size="1" default="click" export='1' label="GOOGLEMAPS_MAPS_KMLINFOEVENT" description="GOOGLEMAPS_TT_MAPS_KMLINFOEVENT">
					<option value="click">GOOGLEMAPS_MAPS_KMLINFOEVENTCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_KMLINFOEVENTDOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_KMLINFOEVENTMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_KMLINFOEVENTMOUSEDOWN</option>
				</field>
				<field name="kmlsbsort" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_KMLSORTSIDEBAR" description="GOOGLEMAPS_TT_MAPS_KMLSORTSIDEBAR">
					<option value="none">GOOGLEMAPS_MAPS_KMLSORTSIDEBARNONE</option>
					<option value="asc">GOOGLEMAPS_MAPS_KMLSORTSIDEBARASC</option>
					<option value="desc">GOOGLEMAPS_MAPS_KMLSORTSIDEBARDESC</option>
				</field>
				<field name="kmllightbox" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLLIGHTBOX" description="GOOGLEMAPS_TT_MAPS_KMLLIGHTBOX">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlmessshow" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLSHOWMESS" description="GOOGLEMAPS_TT_MAPS_KMLSHOWMESS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlclickablemarkers" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWKMLINFO" description="GOOGLEMAPS_TT_MAPS_SHOWKMLINFO">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlzoommarkers" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ZOOMMARKERS" description="GOOGLEMAPS_TT_MAPS_ZOOMMARKERS">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="kmlopendivmarkers" type="text" size= "30" default="" export='1' label="GOOGLEMAPS_MAPS_SHOWINFOINDIV" description="GOOGLEMAPS_TT_MAPS_SHOWINFOINDIV" />
				<field name="kmlcontentlinkmarkers" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLSHOWEXTCONTENT" description="GOOGLEMAPS_TT_MAPS_KMLSHOWEXTCONTENT">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmllinkablemarkers" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLMARKERLINK" description="GOOGLEMAPS_TT_MAPS_KMLMARKERLINK">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmllinktarget" type="radio" size= "1" default="_self" export='1' label="GOOGLEMAPS_MAPS_KMLLINKTARGET" description="GOOGLEMAPS_TT_MAPS_KMLLINKTARGET">
					<option value="_self">GOOGLEMAPS_MAPS_KMLLINKTARGETOWNWINTAB</option>
					<option value="_blank">GOOGLEMAPS_MAPS_KMLLINKTARGETNEWWINTAB</option>
				</field>
				<field name="kmllinkmethod" type="radio" size="1" default="dblclick" export='1' label="GOOGLEMAPS_MAPS_KMLMARKERLINKMETHOD" description="GOOGLEMAPS_TT_MAPS_KMLMARKERLINKMETHOD">
					<option value="click">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODDOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODMOUSEDOWN</option>
				</field>
				<field name="kmlmarkerlabel" type="text" size= "3" default="100" export='1' label="GOOGLEMAPS_MAPS_LABELOPACITYMARKER" description="GOOGLEMAPS_TT_MAPS_LABELOPACITYMARKER" />
				<field name="kmlmarkerlabelclass" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAPS_LABELCLASSMARKER" description="GOOGLEMAPS_TT_MAPS_LABELCLASSMARKER" />
				<field name="kmlpolylabel" type="text" size= "3" default="100" export='1' label="GOOGLEMAPS_MAPS_LABELOPACITYPOLYGON" description="GOOGLEMAPS_TT_MAPS_LABELOPACITYPOLYGON" />
				<field name="kmlpolylabelclass" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAPS_LABELCLASSPOLYGON" description="GOOGLEMAPS_TT_MAPS_LABELCLASSPOLYGON" />
				<field name="proxy" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_KMLPROXY" description="GOOGLEMAPS_TT_MAPS_KMLPROXY">
				<option value="1">Yes</option>
				<option value="0">No</option>
				</field>
				<field name="maxcluster" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERMAXMARKERS" description="GOOGLEMAPS_TT_MAPS_CLUSTERMAXMARKERS" />
				<field name="gridsize" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERGRIDSIZE" description="GOOGLEMAPS_TT_MAPS_CLUSTERGRIDSIZE" />
				<field name="minmarkerscluster" type="text" size= "2" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERMINMARKERS" description="GOOGLEMAPS_TT_MAPS_CLUSTERMINMARKERS" />
				<field name="maxlinesinfocluster" type="text" size= "4" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERINFOMAXLINES" description="GOOGLEMAPS_TT_MAPS_CLUSTERINFOMAXLINES" />
				<field name="clusterinfowindow" type="radio" size="1" default="click" export='1' label="GOOGLEMAPS_MAPS_CLUSTERINFOMETHOD" description="GOOGLEMAPS_TT_MAPS_CLUSTERINFOMETHOD">
					<option value="click">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODDOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODMOUSEDOWN</option>
				</field>
				<field name="clusterzoom" type="radio" size="1" default="dblclick" export='1' label="GOOGLEMAPS_MAPS_CLUSTERZOOMINTO" description="GOOGLEMAPS_TT_MAPS_CLUSTERZOOMINTO">
					<option value="click">GOOGLEMAPS_MAPS_CLUSTERZOOMINTOCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_CLUSTERZOOMINTODOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_CLUSTERZOOMINTOMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_CLUSTERZOOMINTOMOUSEDOWN</option>
				</field>
				<field name="clustermarkerzoom" type="list" size= "1" default="16" export='1' label="GOOGLEMAPS_MAPS_CLUSTERMARKERZOOM" description="GOOGLEMAPS_TT_MAPS_CLUSTERMARKERZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_CUSTOMTILE">
				<field name="tilelayer" type="text" size= "80" default="" export='1' label="GOOGLEMAPS_MAPS_TILELAYER" description="GOOGLEMAPS_TT_MAPS_TILELAYER" />
				<field name="tilemethod" type="text" size= "80" default="" export='1' label="GOOGLEMAPS_MAPS_TILEMETHOD" description="GOOGLEMAPS_TT_MAPS_TILEMETHOD" />
				<field name="tileopacity" type="text" size= "4" default="1" export='1' label="GOOGLEMAPS_MAPS_TILEOPACITY" description="GOOGLEMAPS_TT_MAPS_TILEOPACITY" />
				<field name="tilebounds" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAPS_TILEBOUNDS" description="GOOGLEMAPS_TT_MAPS_TILEBOUNDS" />
				<field name="tileminzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_TILEMINZOOM" description="GOOGLEMAPS_TT_MAPS_TILEMINZOOM">
				  <option value="19">19</option>
				  <option value="18">18</option>
				  <option value="17">17</option>
				  <option value="16">16</option>
				  <option value="15">15</option>
				  <option value="14">14</option>
				  <option value="13">13</option>
				  <option value="12">12</option>
				  <option value="11">11</option>
				  <option value="10">10</option>
				  <option value="9">9</option>
				  <option value="8">8</option>
				  <option value="7">7</option>
				  <option value="6">6</option>
				  <option value="5">5</option>
				  <option value="4">4</option>
				  <option value="3">3</option>
				  <option value="2">2</option>
				  <option value="1">1</option>
				  <option value="0">0</option>
				</field>
				<field name="tilemaxzoom" type="list" size= "1" default="19" export='1' label="GOOGLEMAPS_MAPS_TILEMAXZOOM" description="GOOGLEMAPS_TT_MAPS_TILEMAXZOOM">
				  <option value="19">19</option>
				  <option value="18">18</option>
				  <option value="17">17</option>
				  <option value="16">16</option>
				  <option value="15">15</option>
				  <option value="14">14</option>
				  <option value="13">13</option>
				  <option value="12">12</option>
				  <option value="11">11</option>
				  <option value="10">10</option>
				  <option value="9">9</option>
				  <option value="8">8</option>
				  <option value="7">7</option>
				  <option value="6">6</option>
				  <option value="5">5</option>
				  <option value="4">4</option>
				  <option value="3">3</option>
				  <option value="2">2</option>
				  <option value="1">1</option>
				  <option value="0">0</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_IMAGEOVERLAY">
				<field name="imageurl" type="text" size="40" maxsize="255" default="" export='1' label="GOOGLEMAPS_IMAGE_IMAGE_URL" description="GOOGLEMAPS_TT_IMAGE_URL" />
				<field name="imagex" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_X" description="GOOGLEMAPS_TT_IMAGE_X" />
				<field name="imagey" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_Y" description="GOOGLEMAPS_TT_IMAGE_Y" />
				<field name="imagexyunits" type="radio" size= "8" default="pixels" export='1' label="GOOGLEMAPS_IMAGE_XYUNITS" description="GOOGLEMAPS_TT_IMAGE_XYUNITS">
					<option value="fraction">GOOGLEMAPS_IMAGE_UNITFRACTION</option>
					<option value="pixels">GOOGLEMAPS_IMAGE_UNITPIXELS</option>
				</field>		
				<field name="imagewidth" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_WIDTH" description="GOOGLEMAPS_TT_IMAGE_WIDTH" />
				<field name="imageheight" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_HEIGHT" description="GOOGLEMAPS_TT_IMAGE_HEIGHT" />
				<field name="imageanchorx" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_ANCHORX" description="GOOGLEMAPS_TT_IMAGE_ANCHORX" />
				<field name="imageanchory" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_ANCHORY" description="GOOGLEMAPS_TT_IMAGE_ANCHORY" />
				<field name="imageanchorunits" type="radio" size= "8" default="pixels" export='1' label="GOOGLEMAPS_IMAGE_ANCHORUNITS" description="GOOGLEMAPS_TT_IMAGE_ANCHORUNITS">
					<option value="fraction">GOOGLEMAPS_IMAGE_UNITFRACTION</option>
					<option value="pixels">GOOGLEMAPS_IMAGE_UNITPIXELS</option>
				</field>		
			</fieldset>
			<fieldset name="GOOGLEMAP_TWITTER">
				<field name="twittername" type="text" size= "60" default="" export='1' label="GOOGLEMAPS_TWITTER_NAME" description="GOOGLEMAPS_TT_TWITTER_NAME" />
				<field name="twittertweets" type="text" size= "3" default="15" export='1' label="GOOGLEMAPS_TWITTER_TWEETS" description="GOOGLEMAPS_TT_TWITTER_TWEETS" />
				<field name="twittericon" type="text" size= "255" default="/media/plugin_googlemap2/site/Twitter/twitter_map_icon.png" export='1' label="GOOGLEMAPS_TWITTER_ICON" description="GOOGLEMAPS_TT_TWITTER_ICON" />
				<field name="twitterline" type="text" size= "10" default="#ff0000ff" export='1' label="GOOGLEMAPS_TWITTER_LINE" description="GOOGLEMAPS_TT_TWITTER_LINE" />
				<field name="twitterlinewidth" type="text" size= "2" default="4" export='1' label="GOOGLEMAPS_TWITTER_LINEWIDTH" description="GOOGLEMAPS_TT_TWITTER_LINEWIDTH" />
				<field name="twitterstartloc" type="text" size= "30" default="0,0,0" export='1' label="GOOGLEMAPS_TWITTER_STARTLOC" description="GOOGLEMAPS_TT_TWITTER_STARTLOC" />
			</fieldset>
		</fields>
	</config>
	<updateservers>
		<server type="extension" priority="1" name="Plugin Googlemap Update Site">http://tech.reumer.net/update/plugin_googlemap2/extension.xml</server>
	</updateservers>	
</extension>PK��#]���
�
system/remember/remember.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.remember
 *
 * @copyright   (C) 2007 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! System Remember Me Plugin
 *
 * @since  1.5
 */

class PlgSystemRemember extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app;

	/**
	 * Remember me method to run onAfterInitialise
	 * Only purpose is to initialise the login authentication process if a cookie is present
	 *
	 * @return  void
	 *
	 * @since   1.5
	 * @throws  InvalidArgumentException
	 */
	public function onAfterInitialise()
	{
		// Get the application if not done by JPlugin. This may happen during upgrades from Joomla 2.5.
		if (!$this->app)
		{
			$this->app = JFactory::getApplication();
		}

		// No remember me for admin.
		if ($this->app->isClient('administrator'))
		{
			return;
		}

		// Check for a cookie if user is not logged in
		if (JFactory::getUser()->get('guest'))
		{
			$cookieName = 'joomla_remember_me_' . JUserHelper::getShortHashedUserAgent();

			// Try with old cookieName (pre 3.6.0) if not found
			if (!$this->app->input->cookie->get($cookieName))
			{
				$cookieName = JUserHelper::getShortHashedUserAgent();
			}

			// Check for the cookie
			if ($this->app->input->cookie->get($cookieName))
			{
				$this->app->login(array('username' => ''), array('silent' => true));
			}
		}
	}

	/**
	 * Imports the authentication plugin on user logout to make sure that the cookie is destroyed.
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (remember, autoregister, group).
	 *
	 * @return  boolean
	 */
	public function onUserLogout($user, $options)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		$cookieName = 'joomla_remember_me_' . JUserHelper::getShortHashedUserAgent();

		// Check for the cookie
		if ($this->app->input->cookie->get($cookieName))
		{
			// Make sure authentication group is loaded to process onUserAfterLogout event
			JPluginHelper::importPlugin('authentication');
		}

		return true;
	}

	/**
	 * Method is called before user data is stored in the database
	 * Invalidate all existing remember-me cookies after a password change
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isnew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return    boolean
	 *
	 * @since   3.8.6
	 */
	public function onUserBeforeSave($user, $isnew, $data)
	{
		// Irrelevant on new users
		if ($isnew)
		{
			return true;
		}

		// Irrelevant, because password was not changed by user
		if (empty($data['password_clear']))
		{
			return true;
		}

		/*
		 * But now, we need to do something 
		 * Delete all tokens for this user!
		 */
		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->delete('#__user_keys')
			->where($db->quoteName('user_id') . ' = ' . $db->quote($user['username']));
		try
		{
			$db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// Log an alert for the site admin
			JLog::add(
				sprintf('Failed to delete cookie token for user %s with the following error: %s', $user['username'], $e->getMessage()),
				JLog::WARNING,
				'security'
			);
		}

		return true;
	}
}
PK��#]�-��system/remember/remember.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_remember</name>
	<author>Joomla! Project</author>
	<creationDate>April 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_REMEMBER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="remember">remember.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_remember.ini</language>
		<language tag="en-GB">en-GB.plg_system_remember.sys.ini</language>
	</languages>
</extension>
PK��#]�
��� system/admintools/autoloader.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die();

if (!defined('ATSYSTEM_AUTOLOADER'))
{
	define('ATSYSTEM_AUTOLOADER', 1);
}

/**
 * The class autoloader for Admin Tools system plugin
 *
 * @package     AdminTools
 * @subpackage  plugin.system.admintools
 * @since       3.2.0
 */
class AdmintoolsAutoloaderPlugin
{
	/**
	 * An instance of this autoloader
	 *
	 * @var   AdmintoolsAutoloaderPlugin
	 */
	public static $autoloader = null;

	/**
	 * The path to the root directory
	 *
	 * @var   string
	 */
	public static $pluginPath = null;

	/**
	 * Initialise this autoloader
	 *
	 * @return  AdmintoolsAutoloaderPlugin
	 */
	public static function init()
	{
		if (self::$autoloader == null)
		{
			self::$autoloader = new self;
		}

		return self::$autoloader;
	}

	/**
	 * Public constructor. Registers the autoloader with PHP.
	 */
	public function __construct()
	{
		self::$pluginPath = __DIR__;

		spl_autoload_register(array($this, 'autoload_admintools_system_plugin'));
	}

	/**
	 * The actual autoloader
	 *
	 * @param   string  $class_name  The name of the class to load
	 *
	 * @return  void
	 */
	public function autoload_admintools_system_plugin($class_name)
	{
		// Make sure the class has an Atsystem prefix
		if (substr($class_name, 0, 8) != 'Atsystem')
		{
			return;
		}

		// Remove the prefix
		$class = substr($class_name, 8);

		// Change from camel cased (e.g. FeatureFoobar) into a lowercase array (e.g. 'feature','foobar')
		$class = preg_replace('/(\s)+/', '_', $class);
		$class = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $class));
		$class = explode('_', $class);

		// First try finding in structured directory format, e.g. feature/foobar.php
		$path = self::$pluginPath . '/' . implode('/', $class) . '.php';

		if (@file_exists($path))
		{
			include_once $path;
		}

		// Then try the duplicate last name structured directory format, e.g. feature/foobar/foobar.php
		if (!class_exists($class_name, false))
		{
			reset($class);
			$lastPart = end($class);
			$path = self::$pluginPath . '/' . implode('/', $class) . '/' . $lastPart . '.php';

			if (@file_exists($path))
			{
				include_once $path;
			}
		}
	}
}
PK��#]騸S��'system/admintools/feature/httpsizer.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureHttpsizer extends AtsystemFeatureAbstract
{
	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		// We only use this feature in the front-end
		if ($this->container->platform->isBackend())
		{
			return false;
		}

		// The feature must be enabled
		if ($this->cparams->getValue('httpsizer', 0) != 1)
		{
			return false;
		}

		// Make sure we're accessed over SSL (HTTPS)
		$uri = JUri::getInstance();
		$protocol = $uri->toString(array('scheme'));

		if ($protocol != 'https://')
		{
			return false;
		}


		return true;
	}

	/**
	 * Converts all HTTP URLs to HTTPS URLs when the site is accessed over SSL
	 */
	public function onAfterRenderLatebound()
	{
		if (method_exists($this->app, 'getBody'))
		{
			$buffer = $this->app->getBody();
		}
		else
		{
			$buffer = JResponse::getBody();
		}

		$buffer = str_replace('http://', 'https://', $buffer);

		if (method_exists($this->app, 'setBody'))
		{
			$this->app->setBody($buffer);
		}
		else
		{
			JResponse::setBody($buffer);
		}

		unset($buffer);
	}
}PK��#]dm+system/admintools/feature/criticalfiles.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureCriticalfiles extends AtsystemFeatureAbstract
{
	protected $loadOrder = 999;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->cparams->getValue('criticalfiles', 0) == 1);
	}

	public function onAfterRender()
	{
		$mustSaveData    = false;

		$criticalFiles = $this->getCriticalFiles();
		$loadedFiles   = $this->load();
		$alteredFiles  = [];
		$filesToSave   = [];

		foreach ($criticalFiles as $relPath)
		{
			$curInfo = $this->getFileInfo($relPath);

			if ($curInfo == false)
			{
				// Did that file exist? If so, we need to save the critical files list.
				if (is_array($loadedFiles) && array_key_exists($relPath, $loadedFiles))
				{
					$mustSaveData = true;
				}

				continue;
			}

			$filesToSave[$relPath] = $curInfo;

			// If the file was not present before continue with the next file
			if (!array_key_exists($relPath, $loadedFiles))
			{
				continue;
			}

			// Did the file change?
			$oldInfo = $loadedFiles[$relPath];

			if ($oldInfo !== $curInfo)
			{
				$mustSaveData = true;

				$alteredFiles[$relPath] = [$oldInfo, $curInfo];
			}
		}

		if ($mustSaveData)
		{
			 $this->save($filesToSave);
		}

		if (!empty($alteredFiles))
		{
			$this->sendEmail($alteredFiles);
		}
	}

	/**
	 * Get the critical files, i.e. the files which get most commonly hacked in Joomla: configuration.php, the index.php
	 * files in front- and backend and the index.php, error.php and component.php files of the installed templates.
	 *
	 * @return  array  The list of critical files (relative paths)
	 */
	protected function getCriticalFiles()
	{
		// Yes, JLoader::import is required. JFolder does not follow the autoloader conventions.
		JLoader::import('joomla.filesystem.folder');

		$criticalFiles = [
			'configuration.php',
			'index.php',
			'administrator/index.php',
		];

		$templateFiles = ['index.php', 'error.php', 'component.php'];
		$templates = JFolder::folders(JPATH_SITE . '/templates');

		if (is_array($templates) && !empty($templates))
		{
			foreach ($templates as $template)
			{
				foreach ($templateFiles as $templateFile)
				{
					$relPath = 'templates/' . $template . '/' . $templateFile;

					if (file_exists(JPATH_SITE . '/' .$relPath))
					{
						$criticalFiles[] = $relPath;
					}
				}
			}
		}

		$templates = JFolder::folders(JPATH_ADMINISTRATOR . '/templates');

		if (is_array($templates) && !empty($templates))
		{
			foreach ($templates as $template)
			{
				foreach ($templateFiles as $templateFile)
				{
					$relPath = 'templates/' . $template . '/' . $templateFile;

					if (file_exists(JPATH_ADMINISTRATOR . '/' .$relPath))
					{
						$criticalFiles[] = $relPath;
					}
				}
			}
		}

		return $criticalFiles;
	}

	/**
	 * Returns information about a file
	 *
	 * @param   string  $relPath  The path to the file relative to the site's root
	 *
	 * @return  null|array  Null if the file is not there, object with information otherwise
	 */
	protected function getFileInfo($relPath)
	{
		$absolutePath = JPATH_SITE . '/' . $relPath;

		if (!file_exists($absolutePath))
		{
			return null;
		}

		return [
			'size'      => @filesize($absolutePath),
			'timestamp' => filemtime($absolutePath),
			'md5'       => @md5_file($absolutePath),
			'sha1'      => @sha1_file($absolutePath),
		];
	}

	/**
	 * Save the critical file information to the database
	 *
	 * @param   array  $fileList  The list of critical file information
	 *
	 * @return  void
	 */
	protected function save(array $fileList)
	{
		$db   = $this->container->db;
		$data = json_encode($fileList);

		$query = $db->getQuery(true)
		            ->delete($db->quoteName('#__admintools_storage'))
		            ->where($db->quoteName('key') . ' = ' . $db->quote('criticalfiles'));
		$db->setQuery($query);
		$db->execute();

		$object = (object) array(
			'key'   => 'criticalfiles',
			'value' => $data
		);

		$db->insertObject('#__admintools_storage', $object);
	}

	/**
	 * Load the critical file information from the database
	 *
	 * @return  array
	 */
	protected function load()
	{
		$db    = $this->container->db;
		$query = $db->getQuery(true)
		            ->select($db->quoteName('value'))
		            ->from($db->quoteName('#__admintools_storage'))
		            ->where($db->quoteName('key') . ' = ' . $db->quote('criticalfiles'));
		$db->setQuery($query);

		$error = 0;

		try
		{
			$jsonData = $db->loadResult();
		}
		catch (Exception $e)
		{
			$error = $e->getCode();
		}

		if (method_exists($db, 'getErrorNum') && $db->getErrorNum())
		{
			$error = $db->getErrorNum();
		}

		if ($error)
		{
			$jsonData = null;
		}

		if (empty($jsonData))
		{
			return [];
		}

		return json_decode($jsonData, true);
	}

	/**
	 * Sends a warning email to the addresses set up to receive security exception emails
	 *
	 * @param   array $alteredFiles The files which were modified
	 *
	 * @return  void
	 */
	private function sendEmail($alteredFiles)
	{
		if (empty($alteredFiles))
		{
			// What are you doing here? There are no altered files.
			return;
		}

		// Load the component's administrator translation files
		$jlang = JFactory::getLanguage();
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

		// Get the site name
		$config   = $this->container->platform->getConfig();
		$sitename = $config->get('sitename');

		// Convert the list of modified files to HTML
		$htmlAlteredFiles = <<< HTML
<ul>
HTML;

		foreach ($alteredFiles as $fileName => $fileSet)
		{
			list($oldInfo, $curInfo) = $fileSet;

			$oldTime = Date::getInstance($oldInfo['timestamp']);
			$curTime = Date::getInstance($curInfo['timestamp']);
			$oldInfo['timestamp'] = $oldTime->format(JText::_('DATE_FORMAT_LC2'));
			$curInfo['timestamp'] = $curTime->format(JText::_('DATE_FORMAT_LC2'));

			$htmlAlteredFiles .= <<< HTML
	<li>
		$fileName
	</li>
HTML;

		}

		$htmlAlteredFiles .= <<< HTML
</ul>

HTML;

		// Construct the replacement table
		$substitutions = array(
			'[SITENAME]'  => $sitename,
			'[DATE]'      => gmdate('Y-m-d H:i:s') . " GMT",
			'[INFO]'      => $htmlAlteredFiles,
		);

		// Let's get the most suitable email template
		$template = $this->exceptionsHandler->getEmailTemplate('criticalfiles', true);

		// Got no template, the user didn't published any email template, or the template doesn't want us to
		// send a notification email. Anyway, let's stop here.
		if (!$template)
		{
			return;
		}

		$subject = $template[0];
		$body = $template[1];

		foreach ($substitutions as $k => $v)
		{
			$subject = str_replace($k, $v, $subject);
			$body    = str_replace($k, $v, $body);
		}

		try
		{
			$config = $this->container->platform->getConfig();
			$mailer = JFactory::getMailer();

			$mailfrom = $config->get('mailfrom');
			$fromname = $config->get('fromname');

			$recipients = explode(',', $this->cparams->getValue('emailbreaches', ''));
			$recipients = array_map('trim', $recipients);

			foreach ($recipients as $recipient)
			{
				if (empty($recipient))
				{
					continue;
				}

				// This line is required because SpamAssassin is BROKEN
				$mailer->Priority = 3;

				$mailer->isHtml(true);
				$mailer->setSender(array($mailfrom, $fromname));

				if ($mailer->addRecipient($recipient) === false)
				{
					// Failed to add a recipient?
					continue;
				}

				$mailer->setSubject($subject);
				$mailer->setBody($body);
				$mailer->Send();
			}
		}
		catch (\Exception $e)
		{
			// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
		}
	}

} PK��#]�gt���'system/admintools/feature/apache401.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

/**
 * This handles Apache 401 Authorisation required messages. It is required when using .htaccess Maker (or Joomla!'s
 * own .htaccess as shipped in htaccess.txt) and administrator password protection and have also set an INVALID custom
 * ErrorDocument in Apache for HTTP 401 (Authorisation required). Apache will attempt to load the error document before
 * sending the HTTP basic authorisation headers to the browser. If the error document does not exist (it is an invalid
 * internal file path, typically with a .html or .shtml extension) the .htaccess SEF URL rewrwite rules will kick in and
 * ask Joomla! to handle the request. Since Joomla! cannot find a SEF URL of that name it returns an HTTP 404 Not Found
 * response. Apache sees that and freaks out, ending up in showing the 404 error page instead of sending the HTTP Basic
 * Authentication headers to the browser! This trick below detects the missing 401 custom error page redirection and
 * returns a **valid** HTTP 401 message, letting Apache continue its business.
 *
 * FOR CRYING OUT LOUD PEOPLE, FIX YOUR CRAPPY SERVERS!!!
 */
class AtsystemFeatureApache401 extends AtsystemFeatureAbstract
{
	protected $loadOrder = 1;

	public function onAfterInitialise()
	{
		if (!isset($_SERVER['REDIRECT_STATUS']))
		{
			return;
		}

		if ($_SERVER['REDIRECT_STATUS'] != 401)
		{
			return;
		}

			header('HTTP/1.0 401');
			echo <<< HTML
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Authorization Required</title>
</head><body>
<h1>Authorization Required</h1>
<p>This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
</body></html>
HTML;

		$this->app->close();
	}
} PK��#]V٘X��*system/admintools/feature/awayschedule.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureAwayschedule extends AtsystemFeatureAbstract
{
	protected $loadOrder = 70;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isBackend())
		{
			return false;
		}

		if (!$this->cparams->getValue('awayschedule_from') || !$this->cparams->getValue('awayschedule_to'))
		{
			return false;
		}

		return true;
	}

	/**
	 * Checks if the secret word is set in the URL query, or redirects the user
	 * back to the home page.
	 */
	public function onAfterInitialise()
	{
		$timezone = $this->container->platform->getConfig()->get('offset', 'UTC');
		
		$now  = new Date('now', $timezone);
		$from = new Date($this->cparams->getValue('awayschedule_from'), $timezone);
		$to   = new Date($this->cparams->getValue('awayschedule_to'), $timezone);

		// Wait, FROM is later than TO? This means that the user set an interval like this: 17:30 - 11:00
		// Let's move the FROM constrain one day back
		if($from > $to)
		{
			$from = $from->modify('-1 day');
		}

		// Login attempt, while we set the away schedule, let's ban the user
		if ($now > $from && $now < $to)
		{
			$this->redirectAdminToHome();
		}
	}
}PK��#],.��&&*system/admintools/feature/wafblacklist.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Input\Input;

defined('_JEXEC') or die;

class AtsystemFeatureWafblacklist extends AtsystemFeatureAbstract
{
	protected $loadOrder = 25;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return true;
	}

	/**
	 * Filters visitor access using WAF blacklist rules
	 */
	public function onAfterRoute()
	{
		$db = $this->db;

		$method = array($db->q(''), $db->q(strtoupper($_SERVER['REQUEST_METHOD'])));
		$option = array($db->q(''));
		$view   = array($db->q(''));
		$task   = array($db->q(''));

		if ($this->input->getCmd('option', ''))
		{
			$option[] = $db->q($this->input->getCmd('option', ''));
		}

		if ($this->input->getCmd('view', ''))
		{
			$view[] = $db->q($this->input->getCmd('view', ''));
		}

		if ($this->input->getCmd('task', ''))
		{
			$task[] = $db->q($this->input->getCmd('task', ''));
		}

		// Let's get the rules for the current input values or the empty ones
		$query = $db->getQuery(true)
		            ->select('*')
		            ->from($db->qn('#__admintools_wafblacklists'))
		            ->where($db->qn('verb') . ' IN(' . implode(',', $method) . ')')
		            ->where($db->qn('option') . ' IN(' . implode(',', $option) . ')')
		            ->where($db->qn('view') . ' IN(' . implode(',', $view) . ')')
		            ->where($db->qn('task') . ' IN(' . implode(',', $task) . ')')
		            ->where($db->qn('enabled') . ' = ' . $db->q(1))
		            ->group($db->qn('query'))
		            ->order($db->qn('query') . ' ASC');;

		try
		{
			$rules = $db->setQuery($query)->loadObjectList();
		}
		catch (Exception $e)
		{
			return;
		}

		if (!$rules)
		{
			return;
		}

		// We need FOF 3 loaded for this feature to work
		if (!defined('FOF30_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof30/include.php'))
		{
			// FOF 3.0 is not installed
			return;
		}

		// I can't use JInput since it will fetch data from cookies, too.
		$inputSources = array('get', 'post');

		// Ok, let's analyze all the matching rules
		$block = false;

		foreach ($rules as $rule)
		{
			// Empty query => block everything for this VERB/OPTION/VIEW/TASK combination
			if (!$rule->query)
			{
				$block = true;
				break;
			}

			foreach ($inputSources as $inputSource)
			{
				$inputObject = new Input($inputSource);

				foreach ($inputObject->getData() as $key => $value)
				{
					if ($this->isBlockedByRule($rule, $key, $value))
					{
						$block = true;

						break 3;
					}
				}
			}
		}

		if ($block)
		{
			$extraInfo = '';

			// If the rule matched any variable, let's print the variables that caused the block, so we can inspect later
			if (isset($inputSource) && isset($inputObject))
			{
				// PLEASE NOTE! If POST data is passed, but the GET array is empty, Input will use the whole $_REQUEST
				// array, so $inputSource will be GET even if we truly had a POST request. However this is an edge case
				$extraInfo  = "Hash      : ".strtoupper($inputSource)."\n";
				$extraInfo .= "Variables :\n";
				$extraInfo .= print_r($inputObject->getData(), true);
				$extraInfo .= "\n";
			}

			$this->exceptionsHandler->blockRequest('wafblacklist', null, $extraInfo);
		}
	}

	private function isBlockedByRule($rule, $key, $value, $prefix = '')
	{
		// Handle array values
		if (is_array($value))
		{
			foreach ($value as $subKey => $subValue)
			{
				// Default: assume no prefix was set, in which case the key is the new prefix (array name).
				$newPrefix = $key;

				// If a prefix was set then we have a sub-subkey. The prefix should be prefix[key] instead
				if ($prefix)
				{
					$newPrefix = $prefix . '[' . $key . ']';
				}

				if ($this->isBlockedByRule($rule, $subKey, $subValue, $newPrefix))
				{
					return true;
				}
			}

			return false;
		}

		if ($prefix)
		{
			$key = $prefix . '[' . $key . ']';
		}

		$ruleQuery = $rule->query;

		$found = false;

		// Partial match

		if ($rule->query_type == 'P')
		{
			if (stripos($key, $ruleQuery) !== false)
			{
				$found = true;
			}
		}
		// RegEx match
		elseif ($rule->query_type == 'R')
		{
			$regex  = $ruleQuery;
			$negate = false;

			if (substr($regex, 0, 1) == '!')
			{
				$negate = true;
				$regex  = substr($regex, 1);
			}

			$found = @preg_match($regex, $key) > 0;

			if ($negate)
			{
				$found = !$found;
			}
		}
		// Exact match
		else
		{
			if ($key == $ruleQuery)
			{
				$found = true;
			}
		}

		// Ok, the query parameter is set, do I have any specific rule about the content?
		if ($found)
		{
			// Empty => always block, no matter what
			if (!$rule->query_content)
			{
				return true;
			}

			// I have to run a regex on the value
			$negate = false;
			$regex  = $rule->query_content;

			if (substr($regex, 0, 1) == '!')
			{
				$negate = true;
				$regex  = substr($regex, 1);
			}

			$isFiltered = @preg_match($regex, $value) >= 1;

			if ($negate)
			{
				$isFiltered = !$isFiltered;
			}

			if ($isFiltered)
			{
				return true;
			}
		}

		return false;
	}
}PK��#]�0�OSS+system/admintools/feature/linkmigration.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureLinkmigration extends AtsystemFeatureAbstract
{
	/** @var null|array The domains to migrate from */
	protected $oldDomains = null;

	/** @var null|string The domain of this site */
	protected $myDomain = null;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		// We only use this feature in the front-end
		if ($this->container->platform->isBackend())
		{
			return false;
		}

		// The feature must be enabled
		if ($this->cparams->getValue('linkmigration', 0) != 1)
		{
			return false;
		}

		// Populate the old domains array
		$this->populateOldDomains();

		// If there are no old domains to migrate from, what exactly am I doing here?
		if (empty($this->oldDomains))
		{
			return false;
		}

		return true;
	}

	/**
	 * Provides link migration services. All absolute links pointing to any of the old domain names
	 * are being rewritten to point to the current domain name. This runs a full page replacement
	 * using Regular Expressions, so even menus with absolute URLs will be migrated!
	 */
	public function onAfterRenderLatebound()
	{
		$this->populateOldDomains();

		if (empty($this->oldDomains))
		{
			// If there are no old domains to migrate from, what exactly am I doing here?
			return;
		}

		$this->populateMyDomain();

		if (method_exists($this->app, 'getBody'))
		{
			$buffer = $this->app->getBody();
		}
		else
		{
			$buffer = JResponse::getBody();
		}

		$pattern = '/(href|src)=\"([^"]*)\"/i';
		$number_of_matches = preg_match_all($pattern, $buffer, $matches, PREG_OFFSET_CAPTURE);

		if ($number_of_matches > 0)
		{
			$substitutions = $matches[2];
			$last_position = 0;
			$temp = '';

			// Loop all URLs
			foreach ($substitutions as &$entry)
			{
				// Copy unchanged part, if it exists
				if ($entry[1] > 0)
				{
					$temp .= substr($buffer, $last_position, $entry[1] - $last_position);
				}

				// Add the new URL
				$temp .= $this->replaceDomain($entry[0]);

				// Calculate next starting offset
				$last_position = $entry[1] + strlen($entry[0]);
			}

			// Do we have any remaining part of the string we have to copy?
			if ($last_position < strlen($buffer))
			{
				$temp .= substr($buffer, $last_position);
			}

			// Replace content with the processed one
			unset($buffer);

			if (method_exists($this->app, 'setBody'))
			{
				$this->app->setBody($temp);
			}
			else
			{
				JResponse::setBody($temp);
			}

			unset($temp);
		}
	}

	/**
	 * Replaces a URL's domain name (if it is in the substitution list) with the
	 * current site's domain name
	 *
	 * @param $url string The URL to process
	 *
	 * @return string The processed URL
	 */
	protected function replaceDomain($url)
	{
		foreach ($this->oldDomains as $domain)
		{
			if (substr($url, 0, strlen($domain)) == $domain)
			{
				return $this->myDomain . substr($url, strlen($domain));
			}
			elseif (substr($url, 0, strlen($domain) + 7) == 'http://' . $domain)
			{
				return 'http://' . $this->myDomain . substr($url, strlen($domain) + 7);
			}
			elseif (substr($url, 0, strlen($domain) + 8) == 'https://' . $domain)
			{
				return 'https://' . $this->myDomain . substr($url, strlen($domain) + 8);
			}
		}

		return $url;
	}

	/**
	 * Populates the oldDomains array
	 *
	 * @return  void
	 */
	protected function populateOldDomains()
	{
		$this->oldDomains = array();

		$list = $this->cparams->getValue('migratelist', '');

		// Do not run if we don't have anything
		if (!$list)
		{
			return;
		}

		// Sanitize input
		$list = str_replace("\r", "", $list);

		$temp = explode("\n", $list);

		if (!empty($temp))
		{
			foreach ($temp as $entry)
			{
				// Skip empty lines
				if (!$entry)
				{
					continue;
				}

				if (substr($entry, -1) == '/')
				{
					$entry = substr($entry, 0, -1);
				}

				if (substr($entry, 0, 7) == 'http://')
				{
					$entry = substr($entry, 7);
				}

				if (substr($entry, 0, 8) == 'https://')
				{
					$entry = substr($entry, 8);
				}

				$this->oldDomains[] = $entry;
			}
		}
	}

	/**
	 * Populates the myDomain variable
	 *
	 * @return  void
	 */
	protected function populateMyDomain()
	{
		$this->myDomain = JUri::base(false);

		if (substr($this->myDomain, -1) == '/')
		{
			$this->myDomain = substr($this->myDomain, 0, -1);
		}

		if (substr($this->myDomain, 0, 7) == 'http://')
		{
			$this->myDomain = substr($this->myDomain, 7);
		}

		if (substr($this->myDomain, 0, 8) == 'https://')
		{
			$this->myDomain = substr($this->myDomain, 8);
		}
	}
}PK��#]�W�

'system/admintools/feature/rfishield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureRfishield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 350;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		// Only allow in front-end
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		// Disable on whitelisted IPs
		if ($this->skipFiltering)
		{
			return false;
		}

		// Deactivate if it's not enabled
		if ($this->cparams->getValue('rfishield', 1) != 1)
		{
			return false;
		}

		/**
		 * Automatically disabled when we detect this feature is not required
		 *
		 * See See https://www.akeebabackup.com/home/news/1674-not-a-vulnerability-in-admin-tools.html
		 */

		// Conditional activation during integration testing
		if ($this->cparams->getValue('integration_test_switch', 0) == 1234)
		{
			return true;
		}

		// Do not activate when Enable IP Workarounds is active.
		if ($this->cparams->getValue('ipworkarounds', -1) == 1)
		{
			return false;
		}

		// Do not activate when allow_url_include is disabled.
		if (function_exists('ini_get'))
		{
			if (!ini_get('allow_url_include'))
			{
				return false;
			}
		}

		return true;
	}

	/**
	 * Simple Remote Files Inclusion block. If any query string parameter contains a reference to an http[s]:// or ftp[s]://
	 * address it will be scanned. If the remote file looks like a PHP script, we block access.
	 */
	public function onAfterInitialise()
	{
		$hashes = array('get', 'post');
		$regex = '#(http|ftp){1,1}(s){0,1}://.*#i';

		foreach ($hashes as $hash)
		{
			$input = $this->input->$hash;
			$ref = new ReflectionProperty($input, 'data');
			$ref->setAccessible(true);
			$allVars = $ref->getValue($input);

			if (empty($allVars))
			{
				continue;
			}

			if ($this->match_array_and_scan($regex, $allVars))
			{
				$extraInfo = "Hash      : $hash\n";
				$extraInfo .= "Variables :\n";
				$extraInfo .= print_r($allVars, true);
				$extraInfo .= "\n";
				$this->exceptionsHandler->blockRequest('rfishield', null, $extraInfo);
			}
		}
	}

	private function match_array_and_scan($regex, $array)
	{
		$result = false;

		if (is_array($array))
		{
			foreach ($array as $key => $value)
			{
				if (!empty($this->exceptions) && in_array($key, $this->exceptions))
				{
					continue;
				}

				if (is_array($value))
				{
					$result = $this->match_array_and_scan($regex, $value);
				}
				else
				{
					$result = preg_match($regex, $value);
				}

				if ($result)
				{
					// Can we fetch the file directly?
					$fContents = @file_get_contents($value);

					if (!empty($fContents))
					{
						$result = (strstr($fContents, '<?php') !== false);

						if ($result)
						{
							break;
						}
					}
					else
					{
						$result = false;
					}
				}
			}
		}
		elseif (is_string($array))
		{
			$result = preg_match($regex, $array);

			if ($result)
			{
				// Can we fetch the file directly?
				$fContents = @file_get_contents($array);

				if (!empty($fContents))
				{
					$result = (strstr($fContents, '<?php') !== false);

					if ($result)
					{
						return $result;
					}
				}
				else
				{
					$result = false;
				}
			}
		}

		return $result;
	}
} PK��#]1�j��&system/admintools/feature/badwords.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureBadwords extends AtsystemFeatureAbstract
{
	protected $loadOrder = 380;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('antispam', 0) == 1);
	}

	/**
	 * The simplest anti-spam solution imaginable. Just blocks a request if a prohibited word is found.
	 */
	public function onAfterInitialise()
	{
		$db = $this->db;
		$sql = $db->getQuery(true)
			->select($db->qn('word'))
			->from($db->qn('#__admintools_badwords'))
			->group($db->qn('word'));
		$db->setQuery($sql);

		try
		{
			$badwords = $db->loadColumn();
		}
		catch (Exception $e)
		{
			// Do nothing if the query fails
			$badwords = null;
		}

		if (empty($badwords))
		{
			return;
		}

		$hashes = array('get', 'post');

		foreach ($hashes as $hash)
		{
			$input = $this->input->$hash;
			$ref = new ReflectionProperty($input, 'data');
			$ref->setAccessible(true);
			$allVars = $ref->getValue($input);

			if (empty($allVars))
			{
				continue;
			}

			foreach ($badwords as $word)
			{
				$regex = '#\b' . $word . '\b#i';

				if ($this->match_array($regex, $allVars, true))
				{
					$extraInfo = "Hash      : $hash\n";
					$extraInfo .= "Variables :\n";
					$extraInfo .= print_r($allVars, true);
					$extraInfo .= "\n";
					$this->exceptionsHandler->blockRequest('antispam', null, $extraInfo);
				}
			}
		}
	}
} PK��#]b�4��/system/admintools/feature/blockemaildomains.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureBlockemaildomains extends AtsystemFeatureAbstract
{
	protected $loadOrder = 930;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		$domains = $this->cparams->getValue('blockedemaildomains', '');

		if (empty($domains))
		{
			return false;
		}


		return true;
	}

	public function onUserBeforeSave($olduser, $isnew, $user)
	{
		$domains = $this->cparams->getValue('blockedemaildomains', '');

		$domains = str_replace("\r", "\n", $domains);
		$domains = str_replace("\n\n", "\n", $domains);
		$domains = explode("\n", $domains);

		foreach ($domains as $domain)
		{
			// The user used a blocked domain, let's prevent
			if (strpos($user['email'], trim($domain)) !== false)
			{
				// Load the component's administrator translation files
				$jlang = JFactory::getLanguage();
				$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
				$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
				$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

				throw new Exception(JText::sprintf('COM_ADMINTOOLS_ERR_BLOCKEDEMAILDOMAINS', $domain));
			}
		}

		return true;
	}
}PK��#]NQ��>>)system/admintools/feature/customblock.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureCustomblock extends AtsystemFeatureAbstract
{
	/**
	 * Shows the Admin Tools custom block message
	 */
	public function onAfterRoute()
	{
		if ($this->container->platform->getSessionVar('block', false, 'com_admintools'))
		{
			// This is an underhanded way to short-circuit Joomla!'s internal router.
			$input = JFactory::getApplication()->input;
			$input->set('option', 'com_admintools');
			$input->set('view', 'Blocks');
			$input->set('task', 'browse');

			if (class_exists('JRequest'))
			{
				JRequest::set(array(
					'option' => 'com_admintools',
					'view' => 'blocks'
				), 'get', true);
			}
		}
	}
}PK��#]6�N++-system/admintools/feature/autoipfiltering.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureAutoipfiltering extends AtsystemFeatureAbstract
{
	protected $loadOrder = 10;

	/**
	 * Blocks visitors coming from an automatically banned IP.
	 */
	public function onAfterInitialise()
	{
		if (!$this->isIPBlocked())
		{
			return;
		}

		@ob_end_clean();
		header("HTTP/1.0 403 Forbidden");

		$ip = AtsystemUtilFilter::getIp();

		$spammerMessage = $this->cparams->getValue('spammermessage', '');
		$spammerMessage = str_replace('[IP]', $ip, $spammerMessage);

		echo $spammerMessage;

		$this->app->close();
	}

	/**
	 * Is the IP blocked by an auto-blocking rule?
	 *
	 * @param   string  $ip  The IP address to check. Skip or pass empty string / null to use the current visitor's IP.
	 *
	 * @return  bool
	 */
	public function isIPBlocked($ip = null)
	{
		if (empty($ip))
		{
			// Get the visitor's IP address
			$ip = AtsystemUtilFilter::getIp();
		}

		// Let's get a list of blocked IP ranges
		$db  = $this->db;
		$sql = $db->getQuery(true)
		          ->select('*')
		          ->from($db->qn('#__admintools_ipautoban'))
		          ->where($db->qn('ip') . ' = ' . $db->q($ip));
		$db->setQuery($sql);

		try
		{
			$record = $db->loadObject();
		}
		catch (Exception $e)
		{
			$record = null;
		}

		if (empty($record))
		{
			return false;
		}

		// Is this record expired?
		JLoader::import('joomla.utilities.date');

		$jNow   = new Date();
		$jUntil = new Date($record->until);
		$now    = $jNow->toUnix();
		$until  = $jUntil->toUnix();

		if ($now > $until)
		{
			// Ban expired. Move the entry and allow the request to proceed.
			$history     = clone $record;
			$history->id = null;

			try
			{
				$db->insertObject('#__admintools_ipautobanhistory', $history, 'id');
			}
			catch (Exception $e)
			{
				// Oops...
			}

			$sql = $db->getQuery(true)
			          ->delete($db->qn('#__admintools_ipautoban'))
			          ->where($db->qn('ip') . ' = ' . $db->q($ip));
			$db->setQuery($sql);

			try
			{
				$db->execute();
			}
			catch (Exception $e)
			{
				// Oops...
			}

			return false;
		}

		// Move old entries - The fastest way is to create a INSERT with a SELECT statement
		$sql = 'INSERT INTO ' . $db->qn('#__admintools_ipautobanhistory') . ' (' . $db->qn('id') . ', ' . $db->qn('ip') . ', ' . $db->qn('reason') . ', ' . $db->qn('until') . ')' .
			' SELECT NULL, ' . $db->qn('ip') . ', ' . $db->qn('reason') . ', ' . $db->qn('until') .
			' FROM ' . $db->qn('#__admintools_ipautoban') .
			' WHERE ' . $db->qn('until') . ' < ' . $db->q($jNow->toSql());

		try
		{
			$r = $db->setQuery($sql)->execute();
		}
		catch (Exception $e)
		{
			// Oops...
		}

		$sql = $db->getQuery(true)
		          ->delete($db->qn('#__admintools_ipautoban'))
		          ->where($db->qn('until') . ' < ' . $db->q($jNow->toSql()));
		$db->setQuery($sql);

		try
		{
			$db->execute();
		}
		catch (Exception $e)
		{
			// Oops...
		}

		return true;
	}
} PK��#]�$##'system/admintools/feature/cleantemp.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureCleantemp extends AtsystemFeatureAbstract
{
	protected $loadOrder = 650;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->params->get('cleantemp', 0) == 1);
	}

	public function onAfterInitialise()
	{
		$minutes = (int)$this->params->get('cleantemp_freq', 0);

		if ($minutes <= 0)
		{
			return;
		}

		$lastJob = $this->getTimestamp('clean_temp');
		$nextJob = $lastJob + $minutes * 60;

		JLoader::import('joomla.utilities.date');
		$now = new Date();

		if ($now->toUnix() >= $nextJob)
		{
			$this->setTimestamp('clean_temp');
			$this->tempDirectoryCleanup();
		}
	}

	/**
	 * Cleans up the temporary director
	 */
	private function tempDirectoryCleanup()
	{
		if (!defined('FOF30_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof30/include.php'))
		{
			// FOF 3.0 is not installed
			return;
		}

		$container = \FOF30\Container\Container::getInstance('com_admintools');
		
		try
		{
			/** @var \Akeeba\AdminTools\Admin\Model\CleanTempDirectory $model */
			$model = $container->factory->model('CleanTempDirectory')->tmpInstance();
			
			// This also runs the first batch of deletions
			$model->startScanning();

			// and this runs more deletions until the time is up
			$model->run();
		}
		catch (Exception $e)
		{
			// Avoid any blank page on error
		}
	}
}PK��#]�tH�ww%system/admintools/feature/utf8mb4.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

/**
 * Allows Joomla! to use MySQL's UTF8MB4 connection type, supporting proper multibyte UTF-8 characters such as Emoji
 */
class AtsystemFeatureUtf8mb4 extends AtsystemFeatureAbstract
{
	protected $loadOrder = 0;

	public function onAfterInitialise()
	{
		$db = $this->container->db;

		// If it's not MySQL I don't have to do anything at all
		if (stristr($db->name, 'mysql') === false)
		{
			return;
		}

		// Get the current collation
		$collation = $db->getCollation();

		// If it's not a UTF-8 multibyte (utf8mb4) collation I don't have to do anything at all
		if (substr($collation, 0, 8) != 'utf8mb4_')
		{
			return;
		}

		// Try to force a UTF8MB4 connection
		try
		{
			$db->setQuery('SET NAMES utf8mb4 COLLATE ' . $collation)->execute();

			return;
		}
		catch (\Exception $e)
		{
			// If we failed don't worry, the next statement will revert the connection to plain old UTF-8
		}

		$db->setQuery('SET NAMES utf8')->execute();
	}
} PK��#]��ν--,system/admintools/feature/superuserslist.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

/**
 * Keep track of Super Users on the site and send an email when users are added. Optionally automatically block these
 * new Super Users.
 */
class AtsystemFeatureSuperuserslist extends AtsystemFeatureAbstract
{
	protected $loadOrder = 998;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->cparams->getValue('superuserslist', 1) == 1);
	}

	/**
	 * Checks if a backend Super User is saving another Super User account. We have to run this check onAfterRoute since
	 * com_users will perform an immediate redirect upon saving, without hitting onAfterRender. For the same reason the
	 * detected ID of the Super User being saved has to be saved in the session to persist the successive page loads.
	 */
	public function onAfterRoute()
	{
		if (!$this->isBackendSuperUser())
		{
			return;
		}

		$safeIDs = $this->getSafeIDs();

		if (empty($safeIDs))
		{
			return;
		}

		$this->container->platform->setSessionVar('superuserslist.safeids', $safeIDs, 'com_admintools');
	}

	public function onAfterRender()
	{
		$safeIDs = [];

		if ($this->isBackendSuperUser())
		{
			$safeIDs = $this->container->platform->getSessionVar('superuserslist.safeids', [], 'com_admintools');
			$this->container->platform->setSessionVar('superuserslist.safeids', null, 'com_admintools');

			if (empty($safeIDs))
			{
				$safeIDs = [];
			}
		}

		$savedSuperUserIDs   = $this->load();
		$superUserGroups     = $this->getSuperUserGroups();
		$currentSuperUserIDs = $this->getUsersInGroups($superUserGroups);

		if (empty($savedSuperUserIDs))
		{
			$this->save($currentSuperUserIDs);

			return;
		}

		$newSuperUsers = array_diff($currentSuperUserIDs, $savedSuperUserIDs);
		// Do NOT remove this variable! It catches the case were Super Users are added BUT THEN REMOVED FROM $newSuperUsers WITH array_diff. WE MUST SAVE IN THIS CASE!
		$hasNewSuperUsers  = !empty($newSuperUsers);
		$newSuperUsers     = array_diff($newSuperUsers, $safeIDs);
		$removedSuperUsers = array_diff($savedSuperUserIDs, $currentSuperUserIDs);

		if (empty($newSuperUsers) && empty($removedSuperUsers))
		{
			// In case Super Users ARE added BUT are in the safe IDs list THEN we MUST save the new list!
			if ($hasNewSuperUsers)
			{
				$this->save($currentSuperUserIDs);
			}

			return;
		}

		$this->sendEmail($newSuperUsers);

		foreach ($newSuperUsers as $id)
		{
			$user        = $this->container->platform->getUser($id);
			$user->block = 1;
			$user->save();
		}

		$currentSuperUserIDs = array_diff($currentSuperUserIDs, $newSuperUsers);
		$newSuperUsers       = [];

		if (!empty($newSuperUsers) || !empty($removedSuperUsers))
		{
			$this->save($currentSuperUserIDs);
		}
	}

	/**
	 * Save the list of users to the database
	 *
	 * @param   array $userList The list of User IDs
	 *
	 * @return  void
	 */
	private function save(array $userList)
	{
		$db   = $this->container->db;
		$data = json_encode($userList);

		$query = $db->getQuery(true)
		            ->delete($db->quoteName('#__admintools_storage'))
		            ->where($db->quoteName('key') . ' = ' . $db->quote('superuserslist'));
		$db->setQuery($query);
		$db->execute();

		$object = (object) array(
			'key'   => 'superuserslist',
			'value' => $data
		);

		$db->insertObject('#__admintools_storage', $object);
	}

	/**
	 * Load the saved list of Super User IDs from the database
	 *
	 * @return  array
	 */
	private function load()
	{
		$db    = $this->container->db;
		$query = $db->getQuery(true)
		            ->select($db->quoteName('value'))
		            ->from($db->quoteName('#__admintools_storage'))
		            ->where($db->quoteName('key') . ' = ' . $db->quote('superuserslist'));
		$db->setQuery($query);

		$error = 0;

		try
		{
			$jsonData = $db->loadResult();
		}
		catch (Exception $e)
		{
			$error = $e->getCode();
		}

		if (method_exists($db, 'getErrorNum') && $db->getErrorNum())
		{
			$error = $db->getErrorNum();
		}

		if ($error)
		{
			$jsonData = null;
		}

		if (empty($jsonData))
		{
			return [];
		}

		return json_decode($jsonData, true);
	}

	/**
	 * Sends a warning email to the addresses set up to receive security exception emails
	 *
	 * @param   array  $superUsers  The IDs of Super Users added
	 *
	 * @return  void
	 */
	private function sendEmail(array $superUsers)
	{
		if (empty($superUsers))
		{
			// What are you doing here?
			return;
		}

		// Load the component's administrator translation files
		$jlang = JFactory::getLanguage();
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

		// Get the site name
		$config   = $this->container->platform->getConfig();
		$sitename = $config->get('sitename');

		// Convert the list of added Super Users
		$htmlUsersList = <<< HTML
<ul>
HTML;

		foreach ($superUsers as $id)
		{
			$user = $this->container->platform->getUser($id);

			$htmlUsersList .= <<< HTML
	<li>
		#$id &ndash; <b>{$user->username}</b> &ndash; {$user->name} &lt;{$user->email}&gt;
	</li>
HTML;

		}

		$htmlUsersList .= <<< HTML
</ul>

HTML;

		// Construct the replacement table
		$substitutions = array(
			'[SITENAME]'  => $sitename,
			'[DATE]'      => gmdate('Y-m-d H:i:s') . " GMT",
			'[INFO]'      => $htmlUsersList,
		);

		// Let's get the most suitable email template
		$template = $this->exceptionsHandler->getEmailTemplate('superuserslist', true);

		// Got no template, the user didn't published any email template, or the template doesn't want us to
		// send a notification email. Anyway, let's stop here.
		if (!$template)
		{
			return;
		}

		$subject = $template[0];
		$body = $template[1];

		foreach ($substitutions as $k => $v)
		{
			$subject = str_replace($k, $v, $subject);
			$body    = str_replace($k, $v, $body);
		}

		try
		{
			$config = $this->container->platform->getConfig();
			$mailer = JFactory::getMailer();

			$mailfrom = $config->get('mailfrom');
			$fromname = $config->get('fromname');

			$recipients = explode(',', $this->cparams->getValue('emailbreaches', ''));
			$recipients = array_map('trim', $recipients);

			foreach ($recipients as $recipient)
			{
				if (empty($recipient))
				{
					continue;
				}

				// This line is required because SpamAssassin is BROKEN
				$mailer->Priority = 3;

				$mailer->isHtml(true);
				$mailer->setSender(array($mailfrom, $fromname));

				if ($mailer->addRecipient($recipient) === false)
				{
					// Failed to add a recipient?
					continue;
				}

				$mailer->setSubject($subject);
				$mailer->setBody($body);
				$mailer->Send();
			}
		}
		catch (\Exception $e)
		{
			// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
		}
	}

	/**
	 * Get the user groups with Super User privileges
	 *
	 * @return  array
	 */
	private function getSuperUserGroups()
	{
		static $ret = null;

		if (!is_array($ret))
		{
			$db  = $this->container->db;
			$ret = [];

			try
			{
				$query = $db->getQuery(true)
				            ->select($db->qn('rules'))
				            ->from($db->qn('#__assets'))
				            ->where($db->qn('parent_id') . ' = ' . $db->q(0));
				$db->setQuery($query, 0, 1);
				$rulesJSON = $db->loadResult();
			}
			catch (Exception $exc)
			{
				return $ret;
			}

			$rules     = json_decode($rulesJSON, true);
			$rawGroups = $rules['core.admin'];

			if (empty($rawGroups))
			{
				return $ret;
			}

			foreach ($rawGroups as $g => $enabled)
			{
				if (!$enabled)
				{
					continue;
				}

				$ret[] = $g;
			}
		}

		return $ret;
	}

	/**
	 * Get the IDs of users who are members of one or more groups in the $groups list
	 *
	 * @param   array  $groups  The users must be a member of at least one of these groups
	 *
	 * @return  array
	 */
	private function getUsersInGroups(array $groups)
	{
		$db  = $this->container->db;
		$ret = [];
		$groups = array_map(array($db, 'q'), $groups);

		try
		{
			$query = $db->getQuery(true)
			            ->select($db->qn('user_id'))
			            ->from($db->qn('#__user_usergroup_map') . ' AS ' . $db->qn('m'))
			            ->innerJoin($db->qn('#__users') . ' AS ' . $db->qn('u') . 'ON(' .
				            $db->qn('u.id') . ' = ' . $db->qn('m.user_id')
			            . ')')
			            ->where($db->qn('group_id') . ' IN(' . implode(',', $groups) . ')' )
			            ->where($db->qn('block') . ' = ' . $db->q('0') )
						// Don't look only for empty string. Joomla! considers '' and '0' identical and will let you log in!
			            ->where('(' .
							'(' . $db->qn('activation') . ' = ' . $db->q('0') . ') OR ' .
							'(' . $db->qn('activation') . ' = ' . $db->q('') . ')' .
						')')
			;
			$db->setQuery($query);
			$rawUserIDs = $db->loadColumn(0);
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		if (empty($rawUserIDs))
		{
			return $ret;
		}

		return array_unique($rawUserIDs);
	}

	/**
	 * Returns a list of safe Super User IDs. These are the IDs of the Super Users being saved by another Super User in
	 * the backend of the site through com_users.
	 *
	 * @return  array
	 */
	public function getSafeIDs()
	{
		$app = JFactory::getApplication();

		if (!$this->isBackendSuperUser())
		{
			return [];
		}

		// Get the option and task parameters
		$option = $app->input->getCmd('option', 'com_foobar');
		$task   = $app->input->getCmd('task');

		// Not com_users?
		if ($option != 'com_users')
		{
			return [];
		}

		// Special case: unblock with one click. There's no jform here, the ID is passed in the 'cid' query string parameter
		if ($task == 'users.unblock')
		{
			$cid = $app->input->get('cid', [], 'array');

			if (empty($cid))
			{
				return [];
			}

			if (!is_array($cid))
			{
				$cid = [$cid];
			}

			return $cid;
		}

		// Note Save or Save & Close?
		if (!in_array($task, ['user.apply', 'user.save']))
		{
			return [];
		}

		// Get the user IDs from the form
		$jForm = $app->input->get('jform', [], 'array');

		if (!is_array($jForm) || empty($jForm))
		{
			return [];
		}

		// No user ID or group information?
		if (!isset($jForm['groups']) || !isset($jForm['id']))
		{
			return [];
		}

		// Is it a Super User?
		$superUserGroups = $this->getSuperUserGroups();
		$groups          = $jForm['groups'];
		$isSuperUser     = false;

		if (empty($groups))
		{
			return [];
		}

		foreach ($groups as $group)
		{
			if (in_array($group, $superUserGroups))
			{
				$isSuperUser = true;

				break;
			}
		}

		if (!$isSuperUser)
		{
			return [];
		}

		// Get the user ID being saved and return it
		$id = $jForm['id'];

		if (empty($id))
		{
			return [];
		}

		return [$id];
	}

	/**
	 * Are we currently in the backend, with a logged in Super User?
	 *
	 * @return  bool
	 */
	private function isBackendSuperUser()
	{
		$app = JFactory::getApplication();

		// Not a valid application object?
		if (!is_object($app) || !($app instanceof JApplicationCms))
		{
			return false;
		}

		// Are we in the backend?
		$isAdmin = method_exists($app, 'isAdmin') ? $app->isAdmin() : $app->isClient('administrator');

		if (!$isAdmin)
		{
			return false;
		}

		// Not a Super User?
		if (!$this->container->platform->getUser()->authorise('core.admin'))
		{
			return false;
		}

		return true;
	}
} PK��#]ZD�%""-system/admintools/feature/projecthoneypot.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureProjecthoneypot extends AtsystemFeatureAbstract
{
	protected $loadOrder = 300;

	/** @var  string  Extra info to log when blocking an IP */
	private $extraInfo = null;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		return ($this->cparams->getValue('httpblenable', 0) == 1);
	}

	/**
	 * Runs the Project Honeypot HTTP:BL integration
	 */
	public function onAfterInitialise()
	{
		if (!$this->isIPBlocked())
		{
			return;
		}

		$this->exceptionsHandler->blockRequest('httpbl', '', $this->extraInfo);
	}

	/**
	 * Is the IP blocked by a Geo-blocking rule?
	 *
	 * @param   string  $ip  The IP address to check. Skip or pass empty string / null to use the current visitor's IP.
	 *
	 * @return  bool
	 */
	public function isIPBlocked($ip = null)
	{
		if (empty($ip))
		{
			// Get the visitor's IP address
			$ip = AtsystemUtilFilter::getIp();
		}

		// Load parameters
		$httpbl_key = $this->cparams->getValue('bbhttpblkey', '');
		$minthreat  = $this->cparams->getValue('httpblthreshold', 25);
		$maxage     = $this->cparams->getValue('httpblmaxage', 30);
		$suspicious = $this->cparams->getValue('httpblblocksuspicious', 0);

		// Make sure we have an HTTP:BL  key set
		if (empty($httpbl_key))
		{
			return false;
		}

		if ($ip == '0.0.0.0')
		{
			return false;
		}

		if (strpos($ip, '::') === 0)
		{
			$ip = substr($ip, strrpos($ip, ':') + 1);
		}

		// No point continuing if we can't get an address, right?
		if (empty($ip))
		{
			return false;
		}

		// IPv6 addresses are not supported by HTTP:BL yet
		if (strpos($ip, ":"))
		{
			return false;
		}

		$find   = implode('.', array_reverse(explode('.', $ip)));
		$result = gethostbynamel($httpbl_key . ".${find}.dnsbl.httpbl.org.");

		if (empty($result))
		{
			return false;
		}

		$ip = explode('.', $result[0]);

		// Make sure it's a valid response
		if ($ip[0] != 127)
		{
			return false;
		}

		// Do not block search engines
		if ($ip[3] == 0)
		{
			return false;
		}

		// Block harvesters and comment spammers
		$block = ($ip[3] & 2) || ($ip[3] & 4);

		// Do not block "suspicious" (not confirmed) IPs unless asked so
		if (!$suspicious && ($ip[3] & 1))
		{
			$block = false;
		}

		$block = $block && ($ip[1] <= $maxage);
		$block = $block && ($ip[2] >= $minthreat);

		if (!$block)
		{
			return false;
		}

		$classes = array();

		if ($ip[3] & 1)
		{
			$classes[] = 'Suspicious';
		}

		if ($ip[3] & 2)
		{
			$classes[] = 'Email Harvester';
		}

		if ($ip[3] & 4)
		{
			$classes[] = 'Comment Spammer';
		}

		$class = implode(', ', $classes);
		$this->extraInfo = <<<ENDINFO
HTTP:BL analysis for blocked spammer's IP address $ip
	Attacker class		: $class
	Last activity		: $ip[1] days ago
	Threat level		: $ip[2] --> see http://is.gd/mAwMTo for more info

ENDINFO;

		return true;
	}

}PK��#]^v�$$,system/admintools/feature/templateswitch.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureTemplateswitch extends AtsystemFeatureAbstract
{
	protected $loadOrder = 400;

	private static $siteTemplates = null;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		if ($this->cparams->getValue('template', 0) != 1)
		{
			return false;
		}

		JLoader::import('joomla.filesystem.folder');
		self::$siteTemplates = JFolder::folders(JPATH_SITE . '/templates');

		return true;
	}

	/**
	 * Disable template switching in the URL
	 */
	public function onAfterInitialise()
	{
		$template = JFactory::getApplication()->input->getCmd('template', null);
		$block = true;

		if (!empty($template))
		{
			// Exception: existing site templates are allowed
			if ($this->input->getCmd('option', '') == 'com_mailto')
			{
				// com_email URLs in Joomla! 1.7 and later have template= defined; force $allowsitetemplate in this case
				$allowsitetemplate = true;
			}
			else
			{
				// Otherwise, allow only of the switch is set
				$allowsitetemplate = $this->cparams->getValue('allowsitetemplate', 0);
			}

			if ($allowsitetemplate)
			{
				$block = !in_array($template, self::$siteTemplates);
			}

			if ($block)
			{
				$this->exceptionsHandler->blockRequest('template');
			}
		}
	}
} PK��#]����
�
)system/admintools/feature/ipblacklist.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureIpblacklist extends AtsystemFeatureAbstract
{
	protected $loadOrder = 20;

	/** @var  string  Extra info to log when blocking an IP */
	private $extraInfo = null;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->cparams->getValue('ipbl', 0) == 1);
	}

	/**
	 * Filters visitor access by IP. If the IP of the visitor is included in the
	 * blacklist, she gets a 403 error
	 */
	public function onAfterInitialise()
	{
		if (!$this->isIPBlocked())
		{
			return;
		}

		$message = $this->cparams->getValue('custom403msg', '');

		if (empty($message))
		{
			$message = 'ADMINTOOLS_BLOCKED_MESSAGE';
		}

		// Merge the default translation with the current translation
		$jlang = JFactory::getLanguage();

		// Front-end translation
		$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, null, true);

		// Do we have an override?
		$langOverride = $this->params->get('language_override', '');

		if (!empty($langOverride))
		{
			$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, $langOverride, true);
		}

		$message = JText::_($message);

		if ($message == 'ADMINTOOLS_BLOCKED_MESSAGE')
		{
			$message = "Access Denied";
		}

		// Show the 403 message
		if ($this->cparams->getValue('use403view', 0))
		{
			// Using a view
			if (!$this->container->platform->getSessionVar('block', false, 'com_admintools') || $this->container->platform->isBackend())
			{
				// This is inside an if-block so that we don't end up in an infinite redirection loop
				$this->container->platform->setSessionVar('block', true, 'com_admintools');
				$this->container->platform->setSessionVar('message', $message, 'com_admintools');

				// Close the session (logs out the user)
				JFactory::getSession()->close();

				$base = JUri::base();

				if ($this->container->platform->isBackend())
				{
					$base = rtrim($base);
					$base = substr($base, 0, -13);
				}

				$this->container->platform->redirect($base);
			}

			return;
		}

		if ($this->container->platform->isBackend())
		{
			// You can't use Joomla!'s error page in the admin area. Improvise!
			header('HTTP/1.1 403 Forbidden');
			echo $message;

			$this->app->close();
		}

		// Using Joomla!'s error page
		throw new Exception($message, 403);
	}

	/**
	 * Is the IP blocked by a permanent IP blacklist rule?
	 *
	 * @param   string  $ip  The IP address to check. Skip or pass empty string / null to use the current visitor's IP.
	 *
	 * @return  bool
	 */
	public function isIPBlocked($ip = null)
	{
		if (empty($ip))
		{
			// Get the visitor's IP address
			$ip = AtsystemUtilFilter::getIp();
		}

		// Let's get a list of blocked IP ranges
		$db = $this->db;
		$sql = $db->getQuery(true)
		          ->select($db->qn('ip'))
		          ->from($db->qn('#__admintools_ipblock'));
		$db->setQuery($sql);

		try
		{
			$ipTable = $db->loadColumn();
		}
		catch (Exception $e)
		{
			// Do nothing if the query fails
			$ipTable = null;
		}

		if (empty($ipTable))
		{
			return false;
		}

		$inList = AtsystemUtilFilter::IPinList($ipTable, $ip);

		return ($inList === true);
	}
}PK��#]�#a/system/admintools/feature/customadminfolder.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

/**
 * Allows users to "rename" their administrator directory. In fact, the "rename" is a smokes and mirrors trick,
 * manipulating Joomla!'s SEF routing to mask the administrator directory.
 */
class AtsystemFeatureCustomadminfolder extends AtsystemFeatureAbstract
{
	protected $loadOrder = 40;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		$config = $this->container->platform->getConfig();
		$folder = $this->cparams->getValue('adminlogindir');

		// Custom admin folder is disabled
		if (!$folder || !$config->get('sef') || !$config->get('sef_rewrite'))
		{
			return false;
		}

		return true;
	}

	/**
	 * Hooks to Joomla!'s earliest plugin handler
	 */
	public function onAfterInitialise()
	{
		$this->customAdminFolder();

		if ($this->isAdminAccessAttempt())
		{
			$this->checkCustomAdminFolder();
		}

		if ($this->isAdminLogout())
		{
			$this->setLogoutCookie();
		}
	}

	/**
	 * If the user is trying to access the custom admin folder set the necessary cookies and redirect them to the
	 * administrator page.
	 */
	protected function customAdminFolder()
	{
		$ip = AtsystemUtilFilter::getIp();

		// I couldn't detect the ip, let's stop here
		if (empty($ip) || ($ip == '0.0.0.0'))
		{
			return;
		}

		// Some user agents don't set a UA string at all
		if (!array_key_exists('HTTP_USER_AGENT', $_SERVER))
		{
			return;
		}

		$ua             = $this->app->client;
		$uaString       = $ua->userAgent;
		$browserVersion = $ua->browserVersion;

		$uaShort = str_replace($browserVersion, 'abcd', $uaString);

		$uri = JUri::getInstance();
		$db = $this->db;

		// We're not trying to access to the custom folder
		$folder = $this->cparams->getValue('adminlogindir');

		if (str_replace($uri->root(), '', trim($uri->current(), '/')) != $folder)
		{
			return;
		}

		JLoader::import('joomla.user.helper');

		$hash = JUserHelper::hashPassword($ip . $uaShort);

		$data = (object)array(
			'series'      => JUserHelper::genRandomPassword(64),
			'client_hash' => $hash,
			'valid_to'    => date('Y-m-d H:i:s', time() + 180)
		);

		$db->insertObject('#__admintools_cookies', $data);

		$config = $this->container->platform->getConfig();
		$cookie_domain = $config->get('cookie_domain', '');
		$cookie_path = $config->get('cookie_path', '/');
		$isSecure = $config->get('force_ssl', 0) ? true : false;

		setcookie('admintools', $data->series, time() + 180, $cookie_path, $cookie_domain, $isSecure, true);
		setcookie('admintools_logout', null, 1, $cookie_path, $cookie_domain, $isSecure, true);

		$uri->setPath(str_replace($folder, 'administrator/index.php', $uri->getPath()));

		$this->container->platform->redirect($uri->toString());
	}

	/**
	 * When the user is trying to access the administrator folder without being logged in make sure they had already
	 * entered the custom administrator folder before coming here. Otherwise they are unauthorised and must be booted to
	 * the site's front-end page.
	 */
	protected function checkCustomAdminFolder()
	{
		// Initialise
		$seriesFound = false;
		$db = $this->db;

		// Get the series number from the cookie
		$series = $this->input->cookie->get('admintools', null);

		// If we are told that this is a user logging out redirect them to the front-end home page, do not log a
		// security exception, expire the cookie
		$logout = $this->input->cookie->get('admintools_logout', null, 'string');
		if ($logout == '!!!LOGOUT!!!')
		{
			$config = $this->container->platform->getConfig();
			$cookie_domain = $config->get('cookie_domain', '');
			$cookie_path = $config->get('cookie_path', '/');
			$isSecure = $config->get('force_ssl', 0) ? true : false;
			setcookie('admintools_logout', null, 1, $cookie_path, $cookie_domain, $isSecure, true);

			$this->redirectAdminToHome();

			return;
		}

		// Do we have a series?
		$isValid = !empty($series);

		// Does the series exist in the db? If so, load it
		if ($isValid)
		{
			$query = $db->getQuery(true)
				->select('*')
				->from($db->qn('#__admintools_cookies'))
				->where($db->qn('series') . ' = ' . $db->q($series));
			$db->setQuery($query);
			$storedData = $db->loadObject();

			$seriesFound = true;

			if (!is_object($storedData))
			{
				$isValid = false;
				$seriesFound = false;
			}
		}

		// Is the series still valid or did someone manipulate the cookie expiration?
		if ($isValid)
		{
			$jValid = strtotime($storedData->valid_to);

			if ($jValid < time())
			{
				$isValid = false;
			}
		}

		// Does the UA match the stored series?
		if ($isValid)
		{
			$ip = AtsystemUtilFilter::getIp();

			$ua = $this->app->client;
			$uaString = $ua->userAgent;
			$browserVersion = $ua->browserVersion;

			$uaShort = str_replace($browserVersion, 'abcd', $uaString);

			$notSoSecret = $ip . $uaShort;

			JLoader::import('joomla.user.helper');

			$isValid = JUserHelper::verifyPassword($notSoSecret, $storedData->client_hash);
		}

		// Last check: session state variable
		if ($this->container->platform->getSessionVar('adminlogindir', 0, 'com_admintools'))
		{
			$isValid = true;
		}

		// Delete the series cookie if found
		if ($seriesFound)
		{
			$query = $db->getQuery(true)
				->delete($db->qn('#__admintools_cookies'))
				->where($db->qn('series') . ' = ' . $db->q($series));
			$db->setQuery($query);
			$db->execute();
		}

		// Log an exception and redirect to homepage if we can't validate the user's cookie / session parameter
		if (!$isValid)
		{
			$this->exceptionsHandler->logAndAutoban('admindir');

			$this->redirectAdminToHome();

			return;
		}

		// Otherwise set the session parameter
		if ($seriesFound)
		{
			$this->container->platform->setSessionVar('adminlogindir', 1, 'com_admintools');
		}
	}

	protected function setLogoutCookie()
	{
		$config = $this->container->platform->getConfig();
		$cookie_domain = $config->get('cookie_domain', '');
		$cookie_path = $config->get('cookie_path', '/');
		$isSecure = $config->get('force_ssl', 0) ? true : false;

		setcookie('admintools_logout', '!!!LOGOUT!!!', time() + 180, $cookie_path, $cookie_domain, $isSecure, true);
	}

	/**
	 * Checks if a user is trying to log out
	 *
	 * @return bool
	 */
	protected function isAdminLogout()
	{
		// Not back-end at all. Bail out.
		if (!$this->container->platform->isBackend())
		{
			return false;
		}

		// If the user is not already logged in we don't have a logout attempt
		$user = $this->container->platform->getUser();

		if ($user->guest)
		{
			return false;
		}

		$input = $this->input;
		$option = $input->getCmd('option', null);
		$task = $input->getCmd('task', null);

		if (($option == 'com_login') && ($task == 'logout'))
		{
			return true;
		}

		// Check for malicious direct post without a valid token. In this case it's not a logout.
		JLoader::import('joomla.utiltiites.utility');
		$token = null;

		if (class_exists('JUtility'))
		{
			if (method_exists('JUtility', 'getToken'))
			{
				$token = JUtility::getToken();
			}
		}

		if (is_null($token))
		{
			$token = $this->container->platform->getToken(true);
		}

		$token = $this->input->get($token, false, 'raw');

		if (($token === false) && method_exists('JSession', 'checkToken'))
		{
			return JSession::checkToken('request');
		}

		return false;
	}
}PK��#]��\f)system/admintools/feature/nonewadmins.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureNonewadmins extends AtsystemFeatureAbstract
{
	protected $loadOrder = 210;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		$fromBackend = $this->cparams->getValue('nonewadmins', 0) == 1;
		$fromFrontend = $this->cparams->getValue('nonewfrontendadmins', 1) == 1;

		$enabled = $fromBackend && $this->container->platform->isBackend();
		$enabled |= $fromFrontend && $this->container->platform->isFrontend();

		return $enabled;
	}

	/**
	 * Disables creating new admins or updating new ones
	 */
	public function onAfterInitialise()
	{
		$input  = $this->input;
		$option = $input->getCmd('option', '');
		$task   = $input->getCmd('task', '');
		$gid    = $input->getInt('gid', 0);

		if ($option != 'com_users' && $option != 'com_admin')
		{
			return;
		}

		$jform = $this->input->get('jform', array(), 'array');

		$allowedTasks = array('save', 'apply', 'user.apply', 'user.save', 'user.save2new', 'profile.apply', 'profile.save');

		if (!in_array($task, $allowedTasks))
		{
			return;
		}

		// Not editing, just core devs using the same task throughout the component, dammit
		if (empty($jform))
		{
			return;
		}

		$groups = array();

		if(isset($jform['groups']))
		{
			$groups = $jform['groups'];
		}

		$user = $this->container->platform->getUser((int)$jform['id']);

		// Sometimes $user->groups is null... let's be 100% sure that we loaded all the groups of the user
		if(empty($user->groups))
		{
			$user->groups = JUserHelper::getUserGroups($user->id);
		}

		if (!empty($user->groups))
		{
			foreach ($user->groups as $title => $gid)
			{
				if (!in_array($gid, $groups))
				{
					$groups[] = $gid;
				}
			}
		}

		$isAdmin = $this->hasAdminGroup($groups);

		if ($isAdmin)
		{
			// Get the correct reason (was the user being created in front- or back-end)?
			$reason = $this->container->platform->isBackend() ? 'nonewadmins' : 'nonewfrontendadmins';

			// Log and autoban security exception
			$extraInfo = "Submitted JForm Variables :\n";
			$extraInfo .= print_r($jform, true);
			$extraInfo .= "\n";
			$this->exceptionsHandler->logAndAutoban($reason, $extraInfo);

			// Throw an exception to prevent Joomla! processing this form
			$jlang = JFactory::getLanguage();
			$jlang->load('joomla', JPATH_ROOT, 'en-GB', true);
			$jlang->load('joomla', JPATH_ROOT, $jlang->getDefault(), true);
			$jlang->load('joomla', JPATH_ROOT, null, true);

			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), '403');
		}
	}

	/**
	 * Hooks into the Joomla! models before a user is saved. This catches the case where a 3PD extension tries to create
	 * a new user instead of going through com_users.
	 *
	 * @param   JUser  $oldUser  The existing user record
	 * @param   bool   $isNew    Is this a new user?
	 * @param   array  $data     The data to be saved
	 *
	 * @throws  Exception  When we catch a security exception
	 */
	public function onUserBeforeSave($oldUser, $isNew, $data)
	{
		$isAdmin = $this->hasAdminGroup($data['groups']);

		if ($isAdmin)
		{
			// Get the correct reason (was the user being created in front- or back-end)?
			$reason = $this->container->platform->isBackend() ? 'nonewadmins' : 'nonewfrontendadmins';

			// Log and autoban security exception
			$extraInfo = "User Data Variables :\n";
			$extraInfo .= print_r($data, true);
			$extraInfo .= "\n";
			$this->exceptionsHandler->logAndAutoban($reason, $extraInfo);

			// Throw an exception to prevent Joomla! processing this form
			$jlang = JFactory::getLanguage();
			$jlang->load('joomla', JPATH_ROOT, 'en-GB', true);
			$jlang->load('joomla', JPATH_ROOT, $jlang->getDefault(), true);
			$jlang->load('joomla', JPATH_ROOT, null, true);

			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), '403');
		}
	}

	/**
	 * Does any of the groups in the list have backend privileges
	 *
	 * @param   array  $groups
	 *
	 * @return  bool
	 */
	private function hasAdminGroup($groups)
	{
		$isAdmin = false;

		if (!empty($groups))
		{
			foreach ($groups as $group)
			{
				// First try to see if the group has explicit backend login privileges
				$backend = JAccess::checkGroup($group, 'core.login.admin', 1);

				// If not, is it a Super Admin (ergo inherited privileges)?
				if (is_null($backend))
				{
					$backend = JAccess::checkGroup($group, 'core.admin', 1);
				}

				$isAdmin |= $backend;
			}

			return $isAdmin;
		}

		return $isAdmin;
	}
}PK��#]zɃ%��+system/admintools/feature/sessionshield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureSessionshield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 305;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('sessionshield', 1) == 1);
	}

	/**
	 * Protect against session hijacking data
	 */
	public function onAfterInitialise()
	{
		$patterns = array(
			// pipe or :, O, :	integer : " identifier " : integer : {
			'@[\|:]O:\d{1,}:"[\w_][\w\d_]{0,}":\d{1,}:{@i',
			// pipe or :, a, :	integer :{
			'@[\|:]a:\d{1,}:{@i',
		);

		$hashes = array('get', 'post');

		foreach ($hashes as $hash)
		{
			$input = $this->input->$hash;
			$ref = new ReflectionProperty($input, 'data');
			$ref->setAccessible(true);
			$allVars = $ref->getValue($input);

			if (empty($allVars))
			{
				continue;
			}

			foreach ($patterns as $regex)
			{
				if ($this->match_array($regex, $allVars, true))
				{
					$extraInfo = "Hash      : $hash\n";
					$extraInfo .= "Variables :\n";
					$extraInfo .= print_r($allVars, true);
					$extraInfo .= "\n";
					$this->exceptionsHandler->blockRequest('sessionshield', null, $extraInfo);
				}
			}
		}
	}
} PK��#]�m&uR	R	.system/admintools/feature/saveusersignupip.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureSaveusersignupip extends AtsystemFeatureAbstract
{
	protected $loadOrder = 910;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->cparams->getValue('saveusersignupip', 0) != 1)
		{
			return false;
		}

		return true;
	}

	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		$process = true;

		// Only trigger on successful user creation
		if (!$success)
		{
			$process = false;
		}

		// Only trigger on new user creation, not subsequent edits
		if (!$isnew)
		{
			$process = false;
		}

		// Only trigger on front-end user creation.
		if (!$this->container->platform->isFrontend())
		{
			$process = false;
		}

		if (!$process)
		{
			return;
		}

		// Create a new user note

		// Get the user's ID
		$user_id = (int)$user['id'];

		// Get the IP address
		$ip = AtsystemUtilFilter::getIp();

		if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
		{
			$ip = substr($ip, strrpos($ip, ':') + 1);
		}

		// Get the user agent string
		$user_agent = $_SERVER['HTTP_USER_AGENT'];

		// Get current date and time in database format
		JLoader::import('joomla.utilities.date');
		$now = new Date();
		$now = $now->toSql();

		// Load the component's administrator translation files
		$jlang = JFactory::getLanguage();
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

		// Create and save the user note
		$userNote = (object)array(
			'user_id'         => $user_id,
			'catid'           => 0,
			'subject'         => JText::_('COM_ADMINTOOLS_LBL_CONFIGUREWAF_SIGNUPIP_SUBJECT'),
			'body'            => JText::sprintf('COM_ADMINTOOLS_LBL_CONFIGUREWAF_SIGNUPIP_BODY', $ip, $user_agent),
			'state'           => 1,
			'created_user_id' => 42,
			'created_time'    => $now
		);

		try
		{
			$this->db->insertObject('#__user_notes', $userNote, 'id');
		}
		catch (Exception $e)
		{
			// Do nothing if the save fails
		}
	}
}PK��#]��>�11)system/admintools/feature/nofesalogin.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureNofesalogin extends AtsystemFeatureAbstract
{
	protected $loadOrder = 900;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->cparams->getValue('nofesalogin', 0) != 1)
		{
			return false;
		}

		return true;
	}

	public function onUserLogin($user, $options)
	{
		$instance = $this->getUserObject($user, $options);

		$isSuperAdmin = $instance->authorise('core.admin');

		if (!$isSuperAdmin)
		{
			return true;
		}

		$newopts = array();
		$this->app->logout($instance->id, $newopts);

		// Since Joomla! 2.5.5 you have to close the session before throwing an error, otherwise the user isn't
		// logged out.
		$session = JFactory::getSession();
		$session->close();

		// Throw error
		throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
	}

	function &getUserObject($user, $options = array())
	{
		JLoader::import('joomla.user.helper');
		$instance = new JUser();

		if ($id = intval(JUserHelper::getUserId($user['username'])))
		{
			$instance->load($id);

			return $instance;
		}

		JLoader::import('joomla.application.component.helper');
		$config = JComponentHelper::getParams('com_users');
		$defaultUserGroup = $config->get('new_usertype', 2);

		$instance->set('id', 0);
		$instance->set('name', $user['fullname']);
		$instance->set('username', $user['username']);
		$instance->set('email', $user['email']); // Result should contain an email (check)
		$instance->set('usertype', 'deprecated');
		$instance->set('groups', array($defaultUserGroup));

		return $instance;
	}
}PK��#]\x��$$1system/admintools/feature/thirdpartyexception.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureThirdpartyexception extends AtsystemFeatureAbstract
{
	/**
	 * Log a security exception coming from a third party application. It's
	 * supposed to be used by 3PD to log security exceptions in Admin Tools'
	 * log.
	 *
	 * @param   string  $reason    The blocking reason to show to the administrator. MANDATORY.
	 * @param   string  $message   The message to show to the user being blocked. MANDATORY.
	 * @param   array   $extraInfo Any extra information to record to the log file (hash array).
	 * @param   boolean $autoban   OBSOLETE. No longer used.
	 *
	 * @return  void
	 */
	public function onAdminToolsThirdpartyException($reason, $message, $extraInfo = array(), $autoban = false)
	{
		if (empty($message))
		{
			return;
		}

		// Block the request
		$this->exceptionsHandler->blockRequest('external', $message, $extraInfo, $reason);
	}
} PK��#]�o���)system/admintools/feature/ipwhitelist.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureIpwhitelist extends AtsystemFeatureAbstract
{
	protected $loadOrder = 50;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->isAdminAccessAttempt())
		{
			return false;
		}

		return ($this->cparams->getValue('ipwl', 0) == 1);
	}

	/**
	 * Filters back-end access by IP. If the IP of the visitor is not included
	 * in the whitelist, he gets redirected to the home page
	 */
	public function onAfterInitialise()
	{
		// Let's get a list of allowed IP ranges
		$db = $this->db;
		$sql = $db->getQuery(true)
			->select($db->qn('ip'))
			->from($db->qn('#__admintools_adminiplist'));
		$db->setQuery($sql);

		try
		{
			$ipTable = $db->loadColumn();
		}
		catch (Exception $e)
		{
			// Do nothing if the query fails
			$ipTable = null;
		}


		if (empty($ipTable))
		{
			return;
		}

		$inList = AtsystemUtilFilter::IPinList($ipTable);

		if ($inList === false)
		{
			if (!$this->exceptionsHandler->logAndAutoban('ipwl'))
			{
				return;
			}

			$this->redirectAdminToHome();
		}
	}
}PK��#]��A��,system/admintools/feature/deleteinactive.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureDeleteinactive extends AtsystemFeatureAbstract
{
	protected $loadOrder = 100;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->params->get('deleteinactive', 0) == 1);
	}

	/**
	 * Deletes inactive users (not activated or not visited the site for too long).
	 */
	public function onAfterInitialise()
	{
		// If the days are not at least 1, bail out
		$filtertype = (int)$this->params->get('deleteinactive', 1);
		$days       = (int)$this->params->get('deleteinactive_days', 0);

		if ($days <= 0)
		{
			return;
		}

		// Get up to 5 ids of users to remove
		$db = $this->db;

		$sql = $db->getQuery(true)
			->select($db->qn('id'))
			->from($db->qn('#__users'))
			->where($db->qn('lastvisitDate') . ' = ' . $db->q($db->getNullDate()))
			->where($db->qn('registerDate') . ' <= ' . "DATE_SUB(NOW(), INTERVAL $days DAY)");

		switch ($filtertype)
		{
			case 1:
				// Only users not yet activated
				$sql->where($db->qn('activation') . ' != ' . $db->quote(''));
				break;

			case 2:
				// Only users already activated
				$sql->where($db->qn('activation') . ' = ' . $db->quote(''));
				break;

			case 3:
				// All users who haven't logged in
				break;
		}


		$db->setQuery($sql, 0, 5);

		$ids = $db->loadColumn();

		// Remove those inactive users
		if (!empty($ids))
		{
			foreach ($ids as $id)
			{
				$userToKill = $this->container->platform->getUser($id);
				$userToKill->delete();
			}
		}
	}
} PK��#]��[dII(system/admintools/feature/sqlishield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureSqlishield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 310;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('sqlishield', 0) == 1);
	}

	/**
	 * Fend off most common types of SQLi attacks. See the comments in the code
	 * for more security-minded information.
	 */
	public function onAfterInitialise()
	{
		// We filter all hashes separately to guard against underhanded injections.
		// For example, if the parameter registration to the $_REQUEST array is
		// GPCS, a GET variable will "hide" a POST variable during a POST request.
		// If the vulnerable component is, however, *explicitly* asking for the
		// POST variable, if we only check the $_REQUEST superglobal array we will
		// miss the attack: we will see the innocuous GET variable which is
		// registered to the $_REQUEST array due to higher precedence, while the
		// malicious POST payload makes it through to the component. When you are
		// talking about security you can leave NOTHING in the hands of Fate, or
		// it will come back to bite your sorry ass.
		$hashes = array('get', 'post');
		$regex = '#(union([\s]{1,}|/\*(.*)\*/){1,}(all([\s]{1,}|/\*(.*)\*/){1,})?select|select(([\s]{1,}|/\*(.*)\*/|`){1,}([\w]|_|-|\.|\*){1,}([\s]{1,}|/\*(.*)\*/|`){1,}(,){0,})*from([\s]{1,}|/\*(.*)\//){1,}[a-z0-9]{1,}_|select([\s]{1,}|/\*(.*)\*/|\(){1,}(COUNT|MID|FLOOR|LIMIT|RAND|SLEEP|ELT)|select([\s]{1,}|/\*(.*)\*/|`){1,}.*from([\s]{1,}|/\*(.*)\//){1,}INFORMATION_SCHEMA\.|EXTRACTVALUE([\s]{1,}|\(){1,}|(insert|replace)(([\s]{1,}|/\*(.*)\*/){1,})((low_priority|delayed|high_priority|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}into|drop([\s]{1,}|/\*(.*)\*/){1,}(database|schema|event|procedure|function|trigger|view|index|server|(temporary([\s]{1,}|/\*(.*)\*/){1,}){0,1}table){1,1}([\s]{1,}|/\*(.*)\*/){1,}|update([\s]{1,}|/\*[^\w]*\/){1,}(low_priority([\s]{1,}|/\*[^\w]*\/){1,}|ignore([\s]{1,}|/\*[^\w]*\/){1,})?`?[\w]*_.*set|delete([\s]{1,}|/\*(.*)\*/){1,}((low_priority|quick|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}from|benchmark([\s]{1,}|/\*(.*)\*/){0,}\(([\s]{1,}|/\*(.*)\*/){0,}[0-9]{1,}){1,}#i';

		foreach ($hashes as $hash)
		{
			$input = $this->input->$hash;

			$ref = new ReflectionProperty($input, 'data');
			$ref->setAccessible(true);
			$allVars = $ref->getValue($input);

			if (empty($allVars))
			{
				continue;
			}

			if ($this->match_array($regex, $allVars, false, function($v) {
				// Empty values are processed as-is
				if (empty($v))
				{
					return $v;
				}

				// Non-SQL values are processed as-is
				if (preg_match('#^[\p{L}\d,\s]+$#iu', $v) >= 1)
				{
					return $v;
				}

				// Strip SQL comments (inline OR rest of the line) and convert them to the semantically equivalent space character
				$regex = '@(--|#).+\n@iu';
				$regex2 = '#\/\*(.*?)\*\/#iu';
				$v = preg_replace($regex2, ' ', $v);
				$v = preg_replace($regex, ' ', $v);
				// Convert stray newlines to the semantically equivalent space character
				$v = str_replace(array("\n", "\r"), ' ', $v);

				return $v;
			}))
			{
				$extraInfo = "Hash      : $hash\n";
				$extraInfo .= "Variables :\n";
				$extraInfo .= print_r($allVars, true);
				$extraInfo .= "\n";
				$this->exceptionsHandler->blockRequest('sqlishield', null, $extraInfo);
			}
		}
	}
} PK��#]�0�\��(system/admintools/feature/csrfshield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureCsrfshield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 340;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('csrfshield', 0) != 0);
	}

	public function onAfterInitialise()
	{
		$shieldSetting = $this->cparams->getValue('csrfshield', 0);

		if ($shieldSetting == 1)
		{
			$this->CSRFShield_BASIC();

			return;
		}

		$this->CSRFShield_ADVANCED();
	}

	public function onAfterRender()
	{
		if ($this->cparams->getValue('csrfshield', 0) != 2)
		{
			return;
		}

		$this->CSRFShield_PROCESS();
	}

	private function CSRFShield_BASIC()
	{
		// Do not activate on GET, HEAD and TRACE requests
		$method = strtoupper($_SERVER['REQUEST_METHOD']);

		if (in_array($method, array('GET', 'HEAD', 'TRACE')))
		{
			return;
		}

		// Check the referer, if available
		$valid = true;

		$referer = array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : '';

		if (!empty($referer))
		{
			$jRefURI = JUri::getInstance($referer);
			$refererURI = $jRefURI->toString(array('host', 'port'));

			$jSiteURI = JUri::getInstance();
			$siteURI = $jSiteURI->toString(array('host', 'port'));

			$valid = ($siteURI == $refererURI);
		}

		if (!$valid)
		{
			$this->exceptionsHandler->blockRequest('csrfshield');
		}
	}

	/**
	 * Applies basic HTTP referer filtering to POST, PUT, DELETE etc HTTP requests,
	 * usually associated with form submission.
	 */
	private function CSRFShield_GetFieldName()
	{
		static $fieldName = null;

		if (empty($fieldName))
		{
			$config = $this->container->platform->getConfig();

			$sitename = $config->get('sitename');
			$secret = $config->get('secret');

			$fieldName = md5($sitename . $secret);
		}

		return $fieldName;
	}

	/**
	 * Applies advanced reverse CAPTCHA checks to POST, PUT, DELETE etc HTTP
	 * requests, usually associated with form submission.
	 */
	private function CSRFShield_ADVANCED()
	{
		// Do not activate on GET, HEAD and TRACE requests
		$method = strtoupper($_SERVER['REQUEST_METHOD']);

		if (in_array($method, array('GET', 'HEAD', 'TRACE')))
		{
			return;
		}

		// Check for the existence of a hidden field
		$valid  = true;
		$hashes = array('get', 'post');

		$hiddenFieldName = $this->CSRFShield_GetFieldName();

		foreach ($hashes as $hash)
		{
			$input = $this->input->$hash;
			$ref = new ReflectionProperty($input, 'data');
			$ref->setAccessible(true);
			$allVars = $ref->getValue($input);

			if (!array_key_exists($hiddenFieldName, $allVars))
			{
				continue;
			}

			if (!empty($allVars[$hiddenFieldName]))
			{
				$this->exceptionsHandler->blockRequest('csrfshield');
			}
		}
	}

	/**
	 * Processes all forms on the page, adding a reverse CAPTCHA field
	 * for advanced filtering
	 */
	private function CSRFShield_PROCESS()
	{
		$hiddenFieldName = $this->CSRFShield_GetFieldName();

		if (method_exists($this->app, 'getBody'))
		{
			$buffer = $this->app->getBody();
		}
		else
		{
			$buffer = JResponse::getBody();
		}

		$buffer = preg_replace('#<[\s]*/[\s]*form[\s]*>#iU', '<input type="text" name="' . $hiddenFieldName . '" value="" style="float: left; position: absolute; z-index: 1000000; left: -10000px; top: -10000px;" /></form>', $buffer);

		if (method_exists($this->app, 'setBody'))
		{
			$this->app->setBody($buffer);
		}
		else
		{
			JResponse::setBody($buffer);
		}
	}
} PK��#]"���	�	'system/admintools/feature/phpshield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

/**
 * This class will intercept and block all variables that start with the php:// string.
 * Such kind of attacks are used in LFI vulnerabilitis to actually _read_ the contents of the file.
 * For example:
 *  include($something . ".php");
 *
 * could be exploited with:
 *  http://localhost/index.php?page=php://filter/convert.base64-encode/resource=index
 *
 * PHP won't interpret the resource as code, but will encode it in base64, displaying the source code
 *
 */
class AtsystemFeaturePhpshield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 355;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('phpshield', 1) == 1);
	}

	/**
	 * PHP wrapper inclusion block. If any query string parameter starts with the php:// string it will be blocked
	 */
	public function onAfterInitialise()
	{
		$hashes = array('get', 'post');
		// Block every request that contain the php:// wrapper, such as
		// http://localhost/ex1.php?page=php://filter/convert.base64-encode/resource=PAGE
		$pattern = 'php://';

		foreach ($hashes as $hash)
		{
			$input = $this->input->$hash;
			$ref = new ReflectionProperty($input, 'data');
			$ref->setAccessible(true);
			$allVars = $ref->getValue($input);

			if (empty($allVars))
			{
				continue;
			}

			if ($this->match_array_and_scan($pattern, $allVars))
			{
				$extraInfo = "Hash      : $hash\n";
				$extraInfo .= "Variables :\n";
				$extraInfo .= print_r($allVars, true);
				$extraInfo .= "\n";
				$this->exceptionsHandler->blockRequest('phpshield', null, $extraInfo);
			}
		}
	}

	private function match_array_and_scan($pattern, $array)
	{
		$result = false;

		if (is_array($array))
		{
			foreach ($array as $key => $value)
			{
				if (!empty($this->exceptions) && in_array($key, $this->exceptions))
				{
					continue;
				}

				if (is_array($value))
				{
					$result = $this->match_array_and_scan($pattern, $value);
				}
				else
				{
					$result = (stripos($value, $pattern) === 0);
				}
			}
		}
		elseif (is_string($array))
		{
			$result = (stripos($array, $pattern) === 0);
		}

		return $result;
	}
}PK��#]�3����,system/admintools/feature/resetjoomlatfa.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureResetjoomlatfa extends AtsystemFeatureAbstract
{
	protected $loadOrder = 920;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->cparams->getValue('resetjoomlatfa', 0) != 1)
		{
			return false;
		}

		$option = $this->input->getCmd('option', 'com_foobar');
		$task   = $this->input->getCmd('task', 'default');

		if (!(($option == 'com_users') && ($task == 'complete')))
		{
			return false;
		}

		return true;
	}

	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		$db = $this->db;

		$query = $db->getQuery(true)
			->update($db->qn('#__users'))
			->set(array(
				$db->qn('otpKey') . ' = ' . $db->q(''),
				$db->qn('otep') . ' = ' . $db->q(''),
			))
			->where($db->qn('id') . ' = ' . $db->q($user['id']));

		$db->setQuery($query);

		try
		{
			$db->execute();
		}
		catch (Exception $e)
		{
			// Do nothing if the query fails
		}
	}
}PK��#]D$.]AA*system/admintools/feature/cachecleaner.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureCachecleaner extends AtsystemFeatureAbstract
{
	protected $loadOrder = 630;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->params->get('cachecleaner', 0) == 1);
	}

	public function onAfterInitialise()
	{
		$minutes = (int)$this->params->get('cache_freq', 0);

		if ($minutes <= 0)
		{
			return;
		}

		$lastJob = $this->getTimestamp('cache_clean');
		$nextJob = $lastJob + $minutes * 60;

		JLoader::import('joomla.utilities.date');
		$now = new Date();

		if ($now->toUnix() >= $nextJob)
		{
			$this->setTimestamp('cache_clean');
			$this->purgeCache();
		}
	}

	/**
	 * Completely purges the cache
	 */
	private function purgeCache()
	{
		JLoader::import('joomla.application.helper');
		JLoader::import('joomla.cms.application.helper');

		// Site client
		$client = JApplicationHelper::getClientInfo(0);

		$er = @error_reporting(0);
		$cache = JFactory::getCache('');
		$cache->clean('sillylongnamewhichcantexistunlessyouareacompletelyparanoiddeveloperinwhichcaseyoushouldnotbewritingsoftwareokay', 'notgroup');
		@error_reporting($er);
	}
}PK��#]��~���*system/admintools/feature/emailonlogin.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureEmailonlogin extends AtsystemFeatureAbstract
{
	protected $loadOrder = 220;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isBackend())
		{
			return false;
		}

		if ($this->isAdminAccessAttempt())
		{
			return false;
		}

		$user = $this->container->platform->getUser();

		if ($user->guest)
		{
			return false;
		}

		$email = $this->cparams->getValue('emailonadminlogin', '');

		return !empty($email);
	}

	/**
	 * Sends an email upon accessing an administrator page other than the login screen
	 */
	public function onAfterInitialise()
	{
		$user = $this->container->platform->getUser();

		// Check if the session flag is set (avoid sending thousands of emails!)
		$flag = $this->container->platform->getSessionVar('waf.loggedin', 0, 'plg_admintools');

		if ($flag == 1)
		{
			return;
		}

		// Set the flag to prevent sending more emails
		$this->container->platform->setSessionVar('waf.loggedin', 1, 'plg_admintools');

		// Load the component's administrator translation files
		$jlang = JFactory::getLanguage();
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

		// Get the username
		$username = $user->username;
		// Get the site name
		$config = $this->container->platform->getConfig();

		$sitename = $config->get('sitename');

		// Get the IP address
		$ip = AtsystemUtilFilter::getIp();

		if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
		{
			$ip = substr($ip, strrpos($ip, ':') + 1);
		}

		$country = '';
		$continent = '';

		if (class_exists('AkeebaGeoipProvider'))
		{
			$geoip     = new AkeebaGeoipProvider();
			$country   = $geoip->getCountryCode($ip);
			$continent = $geoip->getContinent($ip);
		}

		if (empty($country))
		{
			$country = '(unknown country)';
		}

		if (empty($continent))
		{
			$continent = '(unknown continent)';
		}

		$uri = JUri::getInstance();
		$url = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'));

		$ip_link = $this->cparams->getValue('iplookupscheme', 'http') . '://' . $this->cparams->getValue('iplookup', 'ip-lookup.net/index.php?ip={ip}');
		$ip_link = str_replace('{ip}', $ip, $ip_link);

		// Construct the replacement table
		$substitutions = array(
			'[SITENAME]'  => $sitename,
			'[REASON]'	  => JText::_('COM_ADMINTOOLS_WAFEMAILTEMPLATE_REASON_ADMINLOGINSUCCESS'),
			'[DATE]'      => gmdate('Y-m-d H:i:s') . " GMT",
			'[URL]'       => $url,
			'[USER]'      => $username,
			'[IP]'        => $ip,
			'[LOOKUP]'    => '<a href="' . $ip_link . '">IP Lookup</a>',
			'[COUNTRY]'   => $country,
			'[CONTINENT]' => $continent,
			'[UA]'		  => $_SERVER['HTTP_USER_AGENT'],
		);

		// Let's get the most suitable email template
		$template = $this->exceptionsHandler->getEmailTemplate('adminloginsuccess', true);

		// Got no template, the user didn't published any email template, or the template doesn't want us to
		// send a notification email. Anyway, let's stop here.
		if (!$template)
		{
			return true;
		}
		else
		{
			$subject = $template[0];
			$body = $template[1];
		}

		foreach ($substitutions as $k => $v)
		{
			$subject = str_replace($k, $v, $subject);
			$body = str_replace($k, $v, $body);
		}

		// Send the email
		try
		{
			$mailer = JFactory::getMailer();

			$mailfrom = $config->get('mailfrom');
			$fromname = $config->get('fromname');

			$recipients = explode(',', $this->cparams->getValue('emailonadminlogin', ''));
			$recipients = array_map('trim', $recipients);

			foreach ($recipients as $recipient)
			{
				if (empty($recipient))
				{
					continue;
				}

				// This line is required because SpamAssassin is BROKEN
				$mailer->Priority = 3;

				$mailer->isHtml(true);
				$mailer->setSender(array($mailfrom, $fromname));

				if ($mailer->addRecipient($recipient) === false)
				{
					// Failed to add a recipient?
					continue;
				}

				$mailer->setSubject($subject);
				$mailer->setBody($body);
				$mailer->Send();
			}
		}
		catch (\Exception $e)
		{
			// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
		}
	}
} PK��#]��G��*system/admintools/feature/removeoldlog.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureRemoveoldlog extends AtsystemFeatureAbstract
{
	protected $loadOrder = 110;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->params->get('maxlogentries', 0) > 0);
	}

	/**
	 * Deletes old log entries, keeping up to maxlogentries entries.
	 */
	public function onAfterInitialise()
	{
		// Delete up to 100 old entries
		$maxEntries = $this->params->get('maxlogentries', 0);
		$db = $this->db;
		$query = $db->getQuery(true)
			->select($db->qn('id'))
			->from($db->qn('#__admintools_log'))
			->order($db->qn('id') . ' DESC');
		$db->setQuery($query, $maxEntries, 100);
		$ids = $db->loadColumn(0);

		if (!count($ids))
		{
			return;
		}

		$temp = array();

		foreach ($ids as $id)
		{
			$temp[] = $db->q($id);
		}

		$ids = implode(',', $temp);

		$query = $db->getQuery(true)
			->delete($db->qn('#__admintools_log'))
			->where($db->qn('id') . ' IN(' . $ids . ')');
		$db->setQuery($query);

		try
		{
			$db->execute();
		}
		catch (Exception $exc)
		{
			// Do nothing on DB exception
		}
	}
} PK��#]|��%%&system/admintools/feature/abstract.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

use Akeeba\AdminTools\Admin\Helper\Storage;
use FOF30\Container\Container;
use FOF30\Date\Date;

class AtsystemFeatureAbstract
{
	/** @var   JRegistry   Component parameters */
	protected $params = null;

	/** @var   Storage   WAF parameters */
	protected $cparams = null;

	/** @var   JInput  The Joomla! application input */
	protected $input = null;

	/** @var   AtsystemUtilExceptionshandler  The security exceptions handler */
	protected $exceptionsHandler = null;

	/** @var   array  The applicable WAF Exceptions which prevent filtering from taking place */
	protected $exceptions = array();

	/** @var   bool   Should I skip filtering (because of whitelisted IPs, WAF Exceptions etc) */
	protected $skipFiltering = false;

	/** @var   JApplicationWeb  The CMS application */
	protected $app = null;

	/** @var   JDatabaseDriver  The database driver */
	protected $db = null;

	/** @var   int  The load order of each feature */
	protected $loadOrder = 9999;

	/** @var null|bool Is this a CLI application? */
	protected static $isCLI = null;

	/** @var null|bool Is this an administrator application? */
	protected static $isAdmin = null;

	/** @var plgSystemAdmintools  Our parent plugin */
	protected $parentPlugin = null;

	/** @var   array  Timestamps of the last run of each scheduled task */
	private $timestamps = array();

	/**
	 * The container of the component
	 *
	 * @var   \FOF30\Container\Container
	 */
	protected $container;

	/**
	 * Public constructor. Creates the feature class.
	 *
	 * @param   JApplication                              $app               The CMS application
	 * @param   JDatabase                                 $db                The database driver
	 * @param   JRegistry                                 $params            Plugin parameters
	 * @param   Storage                                   $componentParams   Component parameters
	 * @param   JInput                                    $input             Global input object
	 * @param   AtsystemUtilExceptionshandler             $exceptionsHandler Security exceptions handler class (or null if the feature is not implemented)
	 * @param   array                                     $exceptions        A list of WAF exceptions
	 * @param   bool                                      $skipFiltering     Should I skip the filtering?
	 * @param   Container                                 $container         The component container
	 * @param   plgSystemAdmintools                       $parentPlugin      The plugin we belong to
	 */
	public function __construct($app, $db, JRegistry &$params, Storage &$componentParams, JInput &$input, &$exceptionsHandler, array &$exceptions, &$skipFiltering, $container, $parentPlugin)
	{
		$this->container         = $container;
		$this->app               = $app;
		$this->db                = $db;
		$this->params            = $params;
		$this->cparams           = $componentParams;
		$this->input             = $input;
		$this->exceptionsHandler = $exceptionsHandler;
		$this->exceptions        = $exceptions;
		$this->skipFiltering     = $skipFiltering;
		$this->parentPlugin      = $parentPlugin;
	}

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return true;
	}

	/**
	 * Returns the load order of this plugin
	 *
	 * @return int
	 */
	public function getLoadOrder()
	{
		return $this->loadOrder;
	}

	/**
	 * Checks if a non logged in user is trying to access the administrator application
	 *
	 * @param bool $onlySubmit bool Return true only if the login form is submitted
	 *
	 * @return bool
	 */
	protected function isAdminAccessAttempt($onlySubmit = false)
	{
		// Not back-end at all. Bail out.
		if (!$this->container->platform->isBackend())
		{
			return false;
		}

		// If the user is already logged in we don't have a login attempt
		$user = $this->container->platform->getUser();

		if (!$user->guest)
		{
			return false;
		}

		// If we have option=com_login&task=login then the user is submitting the login form. Otherwise Joomla! is
		// just displaying the login form.
		$input              = JFactory::getApplication()->input;
		$option             = $input->getCmd('option', null);
		$task               = $input->getCmd('task', null);
		$isPostingLoginForm = ($option == 'com_login') && ($task == 'login');

		// If the user is submitting the login form we return depending on whether we are asked for posting access
		// or not.
		if ($isPostingLoginForm)
		{
			return $onlySubmit;
		}

		// This is a regular admin access attempt
		if ($onlySubmit)
		{
			// Since we were asked to only return true for login form posting and this is not the case we have to
			// return false (the login form is not being posted)
			return false;
		}

		// In any other case we return true.
		return true;
	}

	/**
	 * Redirects an administrator request back to the home page
	 */
	protected function redirectAdminToHome()
	{
		// Get the current URI
		$myURI = JUri::getInstance();
		$path = $myURI->getPath();

		// Pop the administrator from the URI path
		$path_parts = explode('/', $path);
		$path_parts = array_slice($path_parts, 0, count($path_parts) - 2);
		$path = implode('/', $path_parts);
		$myURI->setPath($path);

		// Unset any query parameters
		$myURI->setQuery('');

		// Redirect
		$this->container->platform->redirect($myURI->toString());
	}

	/**
	 * Runs a RegEx match against a string or recursively against an array.
	 * In the case of an array, the first positive match against any level element
	 * of the array returns true and breaks the RegEx matching loop. If you pass
	 * any other data type except an array or string, it returns false.
	 *
	 * @param string    $regex         The regular expressions to feed to preg_match
	 * @param mixed     $array         The array to scan
	 * @param bool      $striptags     Should I strip tags? Default: no
	 * @param callable  $precondition  A callable to precondition each value before preg_match
	 *
	 * @return bool|int
	 */
	protected function match_array($regex, $array, $striptags = false, $precondition = null)
	{
		$result = false;

		if (!is_array($array) && !is_string($array))
		{
			return false;
		}

		if (!is_array($array))
		{
			$v = $striptags ? strip_tags($array) : $array;

			if (!empty($precondition) && is_callable($precondition))
			{
				$v = call_user_func($precondition, $v);
			}

			return preg_match($regex, $v);
		}

		foreach ($array as $key => $value)
		{
			if (!empty($this->exceptions) && in_array($key, $this->exceptions))
			{
				continue;
			}

			if (is_array($value))
			{
				$result = $this->match_array($regex, $value, $striptags, $precondition);

				if ($result)
				{
					break;
				}

				continue;
			}

			$v = $striptags ? strip_tags($value) : $value;

			if (!empty($precondition) && is_callable($precondition))
			{
				$v = call_user_func($precondition, $v);
			}

			$result = preg_match($regex, $v);

			if ($result)
			{
				break;
			}
		}

		return $result;
	}

	/**
	 * Loads the timestamps of all scheduled tasks
	 */
	protected function loadTimestamps()
	{
		$db = $this->db;

		$query = $db->getQuery(true)
			->select('*')
			->from($db->quoteName('#__admintools_storage'))
			->where($db->quoteName('key') . ' LIKE ' . $db->quote('timestamp_%'));
		$db->setQuery($query);
		$temp = $db->loadAssocList();

		$this->timestamps = array();

		if (!empty($temp))
		{
			foreach ($temp as $item)
			{
				$this->timestamps[$item['key']] = $item['value'];
			}
		}
	}

	/**
	 * Sets the timestamp for a specific scheduled task
	 *
	 * @param $key string The scheduled task key to set the timestamp parameter for
	 */
	protected function setTimestamp($key)
	{
		JLoader::import('joomla.utilities.date');
		$date = new Date();

		$pk = 'timestamp_' . $key;
		$timestamp = $date->toUnix();
		$oldTimestamp = $this->getTimestamp($key); // Make sure the array is populated, do not remove
		$db = $this->container->db;

		// This is necessary because using an UPDATE query results in Joomla!
		// throwing a JLIB_APPLICATION_ERROR_COMPONENT_NOT_LOADING or blank
		// page. HUH!!!!!!
		$query = $db->getQuery(true)
			->delete($db->qn('#__admintools_storage'))
			->where($db->qn('key') . ' = ' . $db->q($pk));
		$db->setQuery($query);

		try
		{
			$db->execute();
		}
		catch (Exception $e)
		{
			// If that failed, sorry, we can't set the timestamp :(
			return;
		}

		$query = $db->getQuery(true)
			->insert($db->qn('#__admintools_storage'))
			->columns(array(
				$db->qn('key'),
				$db->qn('value'),
			))->values(
				$db->q($pk) . ', ' . $db->q($timestamp)
			);
		$db->setQuery($query);

		try
		{
			$db->execute();
		}
		catch (Exception $e)
		{
			// If that failed, sorry, we can't set the timestamp :(
			return;
		}

		$this->timestamps[$pk] = $timestamp;
	}

	/**
	 * Gets the last recorded timestamp for a specific scheduled task
	 *
	 * @param $key string The scheduled task key to retrieve the timestamp parameter
	 *
	 * @return int UNIX timestamp
	 */
	protected function getTimestamp($key)
	{
		if (empty($this->timestamps))
		{
			$this->loadTimestamps();
		}

		JLoader::import('joomla.utilities.date');
		$pk = 'timestamp_' . $key;

		if (!array_key_exists($pk, $this->timestamps))
		{
			return 0;
		}

		return $this->timestamps[$pk];
	}
}PK��#]�����(system/admintools/feature/tmplswitch.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureTmplswitch extends AtsystemFeatureAbstract
{
	protected $loadOrder = 390;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('tmpl', 0) == 1);
	}

	/**
	 * Disable template switching in the URL
	 */
	public function onAfterInitialise()
	{
		$tmpl = JFactory::getApplication()->input->getCmd('tmpl', null);

		if (empty($tmpl))
		{
			return;
		}

		$whitelist = $this->cparams->getValue('tmplwhitelist', 'component,system');

		if (empty($whitelist))
		{
			$whitelist = 'component,system';
		}

		$temp = explode(',', $whitelist);
		$whitelist = array();

		foreach ($temp as $item)
		{
			$whitelist[] = trim($item);
		}

		$whitelist = array_merge(array('component', 'system'), $whitelist);

		if (!is_null($tmpl) && !in_array($tmpl, $whitelist))
		{
			if (!$this->exceptionsHandler->blockRequest('tmpl'))
			{
				return;
			}
		}
	}
} PK��#]i\k,system/admintools/feature/sessioncleaner.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureSessioncleaner extends AtsystemFeatureAbstract
{
	protected $loadOrder = 610;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->params->get('sescleaner', 0) == 1);
	}

	/**
	 * Run the session cleaner (garbage collector) on a schedule
	 */
	public function onAfterInitialise()
	{
		$minutes = (int)$this->params->get('ses_freq', 0);

		if ($minutes <= 0)
		{
			return;
		}

		$lastJob = $this->getTimestamp('session_clean');
		$nextJob = $lastJob + $minutes * 60;

		JLoader::import('joomla.utilities.date');
		$now = new Date();

		if ($now->toUnix() >= $nextJob)
		{
			$this->setTimestamp('session_clean');
			$this->purgeSession();
		}
	}

	/**
	 * Purges expired sessions
	 */
	private function purgeSession()
	{
		JLoader::import('joomla.session.session');

		$options = array();

		$conf = $this->container->platform->getConfig();

		$handler = $conf->get('session_handler', 'none');

		// config time is in minutes
		$options['expire'] = ($conf->get('lifetime')) ? $conf->get('lifetime') * 60 : 900;

		$storage = JSessionStorage::getInstance($handler, $options);
		$storage->gc($options['expire']);
	}
}PK��#]R^�4��(system/admintools/feature/secretword.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureSecretword extends AtsystemFeatureAbstract
{
	protected $loadOrder = 60;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isBackend())
		{
			return false;
		}

		$password = $this->cparams->getValue('adminpw', '');

		return !empty($password);
	}

	public function onAfterInitialise()
	{
		$input  = $this->input;
		$option = $input->getCmd('option', '');

		if ($this->isAdminAccessAttempt())
		{
			// com_ajax must be allowed even when we are not logged in since it _may_ be used by login plugins.
			if ($option == 'com_ajax')
			{
				return;
			}

			$this->checkSecretWord();

			return;
		}

		// If there is an administrator secret word set, upon logout redirect to the site's home page
		$password = $this->cparams->getValue('adminpw', '');

		if (!empty($password))
		{
			$task   = $input->getCmd('task', '');
			$uid    = $input->getInt('uid', 0);

			$loggingMeOut = true;

			if (!empty($uid))
			{
				$myUID = $this->container->platform->getUser()->id;
				$loggingMeOut = ($myUID == $uid);
			}

			if (($option == 'com_login') && ($task == 'logout') && $loggingMeOut)
			{
				$input = $this->app->input;
				$method = $input->getMethod();

				$input->$method->set('return', base64_encode('index.php?' . urlencode($password)));
			}
		}
	}

	/**
	 * Checks if the secret word is set in the URL query, or redirects the user
	 * back to the home page.
	 */
	protected function checkSecretWord()
	{
		$password = $this->cparams->getValue('adminpw', '');

		$myURI = JUri::getInstance();

		// If the "password" query param is not defined, the default value
		// "thisisnotgood" is returned. If it is defined, it will return null or
		// the value after the equal sign.
		$check = $myURI->getVar($password, 'thisisnotgood');

		if ($check == 'thisisnotgood')
		{
			// Uh oh... Unauthorized access! Let's redirect the intruder back to the site's home page.
			if (!$this->exceptionsHandler->logAndAutoban('adminpw'))
			{
				return;
			}

			$this->redirectAdminToHome();
		}
	}
}PK��#]0y���*system/admintools/feature/uploadshield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureUploadshield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 370;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('uploadshield', 1) == 1);
	}

	/**
	 * Scans all uploaded files for PHP tags. This prevents uploading PHP files or crafted
	 * images with raw PHP code in them which may lead to arbitrary code execution under
	 * several common circumstances. It will also block files with null bytes in their
	 * filenames or with double extensions which include PHP in them (e.g. .php.jpg).
	 */
	public function onAfterInitialise()
	{
		// Do we have uploaded files?
		$input = $this->input->files;

		$ref = new ReflectionProperty($input, 'data');
		$ref->setAccessible(true);
		$filesHash = $ref->getValue($input);

		if (empty($filesHash))
		{
			return;
		}

		$extraInfo = '';
		foreach ($filesHash as $key => $temp_descriptor)
		{
			if (is_array($temp_descriptor) && !array_key_exists('tmp_name', $temp_descriptor))
			{
				$descriptors = $temp_descriptor;
			}
			else
			{
				$descriptors[] = $temp_descriptor;
			}

			unset($temp_descriptor);

			foreach ($descriptors as $descriptor)
			{
				$files = array();

				if (is_array($descriptor['tmp_name']))
				{
					foreach ($descriptor['tmp_name'] as $key => $value)
					{
						$files[] = array(
							'name'     => $descriptor['name'][$key],
							'type'     => $descriptor['type'][$key],
							'tmp_name' => $descriptor['tmp_name'][$key],
							'error'    => $descriptor['error'][$key],
							'size'     => $descriptor['size'][$key],
						);
					}
				}
				else
				{
					$files[] = $descriptor;
				}

				foreach ($files as $fileDescriptor)
				{
					$tempNames = $fileDescriptor['tmp_name'];
					$intendedNames = $fileDescriptor['name'];

					if (!is_array($tempNames))
					{
						$tempNames = array($tempNames);
					}

					if (!is_array($intendedNames))
					{
						$intendedNames = array($intendedNames);
					}

					$len = count($tempNames);

					for ($i = 0; $i < $len; $i++)
					{
						$tempName = array_shift($tempNames);
						$intendedName = array_shift($intendedNames);

						$extraInfo = "File descriptor :\n";
						$extraInfo .= print_r($fileDescriptor, true);
						$extraInfo .= "\n";

						// 1. Null byte check
						if (strstr($intendedName, "\u0000"))
						{
							$this->exceptionsHandler->blockRequest('uploadshield', null, $extraInfo);

							return;
						}

						// 2. PHP-in-extension check
						$explodedName = explode('.', $intendedName);
						$explodedName = array_reverse($explodedName);

						// 2a. File extension is .php
						if ((count($explodedName) > 1) && (strtolower($explodedName[0]) == 'php'))
						{
							$this->exceptionsHandler->blockRequest('uploadshield', null, $extraInfo);

							return;
						}

						// 2a. File extension is php.xxx
						if ((count($explodedName) > 2) && (strtolower($explodedName[1]) == 'php'))
						{
							$this->exceptionsHandler->blockRequest('uploadshield', null, $extraInfo);

							return;
						}

						// 2b. File extensions is php.xxx.yyy
						if ((count($explodedName) > 3) && (strtolower($explodedName[2]) == 'php'))
						{
							$this->exceptionsHandler->blockRequest('uploadshield', null, $extraInfo);

							return;
						}

						// 3. Contents scanner
						$fp = @fopen($tempName, 'r');

						if ($fp !== false)
						{
							// Initialise
							$data = '';
							$extension = strtolower($explodedName[0]);
							$possibleFileForShortTagSyntax = in_array($extension, array(
								'inc', 'phps', 'class', 'php3', 'php4', 'txt', 'dat',  'tpl', 'tmpl'
							));

							// Process the file in 128Kb chunks
							while (!feof($fp))
							{
								// Read 128Kb and add it to the existing data (the last 4 bytes of the previous scan)
								$buffer = @fread($fp, 131072);
								$data .= $buffer;

								// Do we have a regular PHP tag?
								if (stristr($buffer, '<?php'))
								{
									$this->exceptionsHandler->blockRequest('uploadshield', null, $extraInfo);

									return;
								}

								// If we have text file which may have the short tag (<?) in it...
								if ($possibleFileForShortTagSyntax)
								{
									// ...do I have a short tag?
									if (strstr($buffer, '<?'))
									{
										$this->exceptionsHandler->blockRequest('uploadshield', null, $extraInfo);

										return;
									}
								}

								// Keep the last 4 bytes of data to make sure we can catch partial strings.
								$data = substr($data, -4);

								// WARNING: Do NOT try seek to an earlier position! Here's how it all works.
								//
								// We just need to keep the last four bytes in $data so we can append the next 128Kb.
								// This way if the start of the tag is in the previous block and the rest is in the next
								// 128Kb block we can still scan it. The value 4 is not random. <?php is 5 characters
								// and the longest string we're trying to detect. If it existed in this block we'd have
								// already found it and blocked it. Therefore the only possibility is that this block
								// ended in <, <?, <?p or <?ph with the rest of the string (?php, php, hp or p
								// respectively) being present in the next block. The longest of these partial strings
								// is "<?ph" which is FOUR characters.
								//
								// Do NOT seek to an earlier file position. It would be a rather silly thing to do.
							}

							fclose($fp);
						}
					}
				}
			}
		}
	}
}PK��#]x��UU+system/admintools/feature/configmonitor.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

/**
 * Monitors com_config changes and emails the user
 */
class AtsystemFeatureConfigmonitor extends AtsystemFeatureAbstract
{
	/** @var   int  The load order of each feature */
	protected $loadOrder = 220;

	/**
	 * Should we monitor changes to Global Configuration?
	 *
	 * @var   bool
	 */
	private $enabledGlobal = false;

	/**
	 * Should we monitor changes to Component Configuration?
	 *
	 * @var   bool
	 */
	private $enabledComponents = false;

	/**
	 * Which action should I take when a change is detected? 'email' for sending a warning email, 'block' for treating
	 * the request as a security exception.
	 *
	 * @var   string
	 */
	private $action = 'email';

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		$this->enabledGlobal     = $this->cparams->getValue('configmonitor_global', 0) == 1;
		$this->enabledComponents = $this->cparams->getValue('configmonitor_components', 0) == 1;
		$this->action            = $this->cparams->getValue('configmonitor_action', 'email');

		return $this->enabledGlobal || $this->enabledComponents;
	}

	/**
	 * Disables creating new admins or updating new ones
	 */
	public function onAfterInitialise()
	{
		$input  = $this->input;
		$option = $input->getCmd('option', '');
		$task   = $input->getCmd('task', '');

		if ($option != 'com_config')
		{
			return;
		}

		$block = false;

		if ($this->enabledGlobal)
		{
			$block |= in_array($task, ['config.save.application.apply', 'config.save.application.save']);
		}

		if ($this->enabledComponents)
		{
			$block |= in_array($task, ['config.save.component.apply', 'config.save.component.save']);
		}

		if (!$block)
		{
			return;
		}

		// Get the correct reason (is this Global Configuration or component configuration)?
		$id            = $input->getInt('id', 0);
		$component     = $input->getCmd('component', '');
		$componentName = $this->getComponentName($id, $component);

		// Default reason for blocking / reporting: Global Configuration
		$jlang = JFactory::getLanguage();
		$jlang->load('com_cpanel', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('com_cpanel', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('com_cpanel', JPATH_ADMINISTRATOR, null, true);
		$extraInfo = JText::_('COM_CPANEL_LINK_GLOBAL_CONFIG');

		// If, however, there is a component we need to report extension configuration monitor as the reason
		if (!empty($componentName))
		{
			$jlang = JFactory::getLanguage();
			$jlang->load($componentName . '.sys', JPATH_ADMINISTRATOR, 'en-GB', true);
			$jlang->load($componentName . '.sys', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
			$jlang->load($componentName . '.sys', JPATH_ADMINISTRATOR, null, true);

			// Now set the extra information
			$extraInfo = JText::_($componentName);
		}

		// If we are set to block requests hook into Admin Tools' log and block system
		if ($this->action == 'block')
		{
			$this->exceptionsHandler->blockRequest('configmonitor', null, null, $extraInfo);

			return;
		}

		// Otherwise we need to send an email
		$this->sendEmail($extraInfo);
	}

	/**
	 * Get the component name based either on the extension ID or (preferably) the component name from the request.
	 *
	 * @param   int     $id         An extension ID passed in the request. Must belong to a component.
	 * @param   string  $component  A component name passed in the request.
	 *
	 * @return  string  The component name, or an empty string if there is no corresponding component.
	 */
	private function getComponentName($id, $component)
	{
		$component = trim(strtolower($component));

		// We have a component name
		if (!empty($component))
		{
			return $component;
		}

		// We don't have a component name or ID. Nothing to do
		if (empty($id))
		{
			return '';
		}

		// We have an ID. Try to get the component name from the #__extensions table.
		$db = $this->container->db;
		$query = $db->getQuery(true)
			->select($db->qn('element'))
			->from($db->qn('#__extensions'))
			->where($db->qn('extension_id') . ' = ' . $db->q((int) $id))
			->where($db->qn('type') . ' = ' . $db->q('component'));
		$componentName = $db->setQuery($query)->loadResult();

		if (empty($componentName))
		{
			return '';
		}

		return $componentName;
	}

	/**
	 * Sends a warning email to the addresses set up to receive security exception emails
	 *
	 * @param   string  $configArea  The human readable name of the configuration area being edited
	 */
	private function sendEmail($configArea)
	{
		// Load the component's administrator translation files
		$jlang = JFactory::getLanguage();
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

		// Get the site name
		$config = $this->container->platform->getConfig();

		$sitename = $config->get('sitename');

		// Get the IP address
		$ip = AtsystemUtilFilter::getIp();

		if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
		{
			$ip = substr($ip, strrpos($ip, ':') + 1);
		}

		$country = '';
		$continent = '';

		if (class_exists('AkeebaGeoipProvider'))
		{
			$geoip     = new AkeebaGeoipProvider();
			$country   = $geoip->getCountryCode($ip);
			$continent = $geoip->getContinent($ip);
		}

		if (empty($country))
		{
			$country = '(unknown country)';
		}

		if (empty($continent))
		{
			$continent = '(unknown continent)';
		}

		$uri = JUri::getInstance();
		$url = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'));

		$ip_link = $this->cparams->getValue('iplookupscheme', 'http') . '://' . $this->cparams->getValue('iplookup', 'ip-lookup.net/index.php?ip={ip}');
		$ip_link = str_replace('{ip}', $ip, $ip_link);

		// Construct the replacement table
		$substitutions = array(
			'[SITENAME]'  => $sitename,
			'[REASON]'	  => JText::_('COM_ADMINTOOLS_WAFEMAILTEMPLATE_REASON_ADMINLOGINFAIL'),
			'[DATE]'      => gmdate('Y-m-d H:i:s') . " GMT",
			'[URL]'       => $url,
			'[AREA]'      => $configArea,
			'[IP]'        => $ip,
			'[LOOKUP]'    => '<a href="' . $ip_link . '">IP Lookup</a>',
			'[COUNTRY]'   => $country,
			'[CONTINENT]' => $continent,
			'[UA]'		  => $_SERVER['HTTP_USER_AGENT'],
			'[USER]'	  => $this->container->platform->getUser()->username,
		);

		// Let's get the most suitable email template
		$template = $this->exceptionsHandler->getEmailTemplate('configmonitor', true);

		// Got no template, the user didn't published any email template, or the template doesn't want us to
		// send a notification email. Anyway, let's stop here.
		if (!$template)
		{
			return true;
		}
		else
		{
			$subject = $template[0];
			$body = $template[1];
		}

		foreach ($substitutions as $k => $v)
		{
			$subject = str_replace($k, $v, $subject);
			$body    = str_replace($k, $v, $body);
		}

		try
		{
			$config = $this->container->platform->getConfig();
			$mailer = JFactory::getMailer();

			$mailfrom = $config->get('mailfrom');
			$fromname = $config->get('fromname');

			$recipients = explode(',', $this->cparams->getValue('emailbreaches', ''));
			$recipients = array_map('trim', $recipients);

			foreach ($recipients as $recipient)
			{
				if (empty($recipient))
				{
					continue;
				}

				// This line is required because SpamAssassin is BROKEN
				$mailer->Priority = 3;

				$mailer->isHtml(true);
				$mailer->setSender(array($mailfrom, $fromname));

				if ($mailer->addRecipient($recipient) === false)
				{
					// Failed to add a recipient?
					continue;
				}

				$mailer->setSubject($subject);
				$mailer->setBody($body);
				$mailer->Send();
			}
		}
		catch (\Exception $e)
		{
			// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
		}
	}
}PK��#]o]�992system/admintools/feature/emailfailedadminlong.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureEmailfailedadminlong extends AtsystemFeatureAbstract
{
	protected $loadOrder = 810;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if ($this->cparams->getValue('trackfailedlogins', 0) == 1)
		{
			// When track failed logins is enabled we don't send emails through this feature
			return false;
		}

		if (!$this->container->platform->isBackend())
		{
			return false;
		}

		$emailonfailedadmin = $this->cparams->getValue('emailonfailedadminlogin', '');

		if (empty($emailonfailedadmin))
		{
			return false;
		}

		return true;
	}

	/**
	 * Sends an email upon a failed administrator login
	 *
	 * @param JAuthenticationResponse $response
	 *
	 * @return  void
	 */
	public function onUserLoginFailure($response)
	{
		// Make sure we don't fire unless someone is still in the login page
		$user = $this->container->platform->getUser();

		if (!$user->guest)
		{
			return;
		}

		$option = $this->input->getCmd('option');
		$task   = $this->input->getCmd('task');

		if (($option != 'com_login') && ($task != 'login'))
		{
			return;
		}

		// Exit if the IP is blacklisted; logins originating from blacklisted IPs will be blocked anyway
		if ($this->parentPlugin->runBooleanFeature('isIPBlocked', false, []))
		{
			return;
		}

		// If we are STILL in the login task WITHOUT a valid user, we had a login failure.
		// Load the component's administrator translation files
		$jlang = JFactory::getLanguage();
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

		// Fetch the username
		$username = JFactory::getApplication()->input->getString('username');

		// Get the site name
		$config = $this->container->platform->getConfig();

		$sitename = $config->get('sitename');

		// Get the IP address
		$ip = AtsystemUtilFilter::getIp();

		if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
		{
			$ip = substr($ip, strrpos($ip, ':') + 1);
		}

		$country = '';
		$continent = '';

		if (class_exists('AkeebaGeoipProvider'))
		{
			$geoip     = new AkeebaGeoipProvider();
			$country   = $geoip->getCountryCode($ip);
			$continent = $geoip->getContinent($ip);
		}

		if (empty($country))
		{
			$country = '(unknown country)';
		}

		if (empty($continent))
		{
			$continent = '(unknown continent)';
		}

		$uri = JUri::getInstance();
		$url = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'));

		$ip_link = $this->cparams->getValue('iplookupscheme', 'http') . '://' . $this->cparams->getValue('iplookup', 'ip-lookup.net/index.php?ip={ip}');
		$ip_link = str_replace('{ip}', $ip, $ip_link);

		// Construct the replacement table
		$substitutions = array(
			'[SITENAME]'  => $sitename,
			'[REASON]'	  => JText::_('COM_ADMINTOOLS_WAFEMAILTEMPLATE_REASON_ADMINLOGINFAIL'),
			'[DATE]'      => gmdate('Y-m-d H:i:s') . " GMT",
			'[URL]'       => $url,
			'[USER]'      => $username,
			'[IP]'        => $ip,
			'[LOOKUP]'    => '<a href="' . $ip_link . '">IP Lookup</a>',
			'[COUNTRY]'   => $country,
			'[CONTINENT]' => $continent,
			'[UA]'		  => $_SERVER['HTTP_USER_AGENT'],
		);

		// Let's get the most suitable email template
		$template = $this->exceptionsHandler->getEmailTemplate('adminloginfail', true);

		// Got no template, the user didn't published any email template, or the template doesn't want us to
		// send a notification email. Anyway, let's stop here.
		if (!$template)
		{
			return true;
		}
		else
		{
			$subject = $template[0];
			$body = $template[1];
		}

		foreach ($substitutions as $k => $v)
		{
			$subject = str_replace($k, $v, $subject);
			$body    = str_replace($k, $v, $body);
		}

		// Send the email
		try
		{
			$mailer = JFactory::getMailer();

			$mailfrom = $config->get('mailfrom');
			$fromname = $config->get('fromname');

			$recipients = explode(',', $this->cparams->getValue('emailonfailedadminlogin', ''));
			$recipients = array_map('trim', $recipients);

			foreach ($recipients as $recipient)
			{
				if (empty($recipient))
				{
					continue;
				}

				// This line is required because SpamAssassin is BROKEN
				$mailer->Priority = 3;

				$mailer->isHtml(true);
				$mailer->setSender(array($mailfrom, $fromname));

				if ($mailer->addRecipient($recipient) === false)
				{
					// Failed to add a recipient?
					continue;
				}

				$mailer->setSubject($subject);
				$mailer->setBody($body);
				$mailer->Send();
			}
		}
		catch (\Exception $e)
		{
			// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
		}
	}
}PK��#]��u		/system/admintools/feature/trackfailedlogins.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureTrackfailedlogins extends AtsystemFeatureAbstract
{
	protected $loadOrder = 800;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->cparams->getValue('trackfailedlogins', 0) == 1);
	}

	/**
	 * Treat failed logins as security exceptions
	 *
	 * @param JAuthenticationResponse $response
	 */
	public function onUserLoginFailure($response)
	{
		// Exit if the IP is blacklisted; logins originating from blacklisted IPs will be blocked anyway
		if ($this->parentPlugin->runBooleanFeature('isIPBlocked', false, []))
		{
			return;
		}

		$user = $this->input->getString('username', null);
		$pass = $this->input->getString('password', null);

		if (empty($pass))
		{
			$pass = $this->input->getString('passwd', null);
		}

		$extraInfo = null;

		if (!empty($user))
		{
			$extraInfo = 'Username: ' . $user;

			if ($this->cparams->getValue('showpwonloginfailure', 1))
			{
				$extraInfo = 'Username: ' . $user . ' -- Password: ' . $pass;
			}
		}

		$this->exceptionsHandler->logAndAutoban('loginfailure', $user, $extraInfo);

		$this->deactivateUser($user);
	}

	private function deactivateUser($username)
	{
		$userParams = JComponentHelper::getParams('com_users');

		// User registration disabled or no user activation - Let's stop here
		if (!$userParams->get('allowUserRegistration') || ($userParams->get('useractivation') == 0))
		{
			return;
		}

		$ip = AtsystemUtilFilter::getIp();

		// If I can't detect the IP there's not point in continuing
		if (!$ip)
		{
			return;
		}

		$limit     = $this->cparams->getValue('deactivateusers_num', 3);
		$numfreq   = $this->cparams->getValue('deactivateusers_numfreq', 1);
		$frequency = $this->cparams->getValue('deactivateusers_frequency', 'hour');

		// The user didn't set any limit nor frequency value, let's stop here
		if (!$limit || !$numfreq)
		{
			return;
		}

		$userid = JUserHelper::getUserId($username);

		// The user doesn't exists, let's stop here
		if (!$userid)
		{
			return;
		}

		$user = $this->container->platform->getUser($userid);

		// Username doesn't match, the user is blocked or is not active? Let's stop here
		if ($user->username != $username || $user->block || !(empty($user->activation)))
		{
			return;
		}

		// If I'm here, it means that this is a valid user, let's see if I have to deactivate him
		$where = array(
			'ip'     => $ip,
			'reason' => 'loginfailure'
		);

		$deactivate = $this->checkLogFrequency($limit, $numfreq, $frequency, $where);

		if (!$deactivate)
		{
			return;
		}

		JPluginHelper::importPlugin('user');
		$db = $this->db;

		$data['activation'] = JApplication::getHash(JUserHelper::genRandomPassword());
		$data['block'] = 1;
		$data['lastvisitDate'] = $db->getNullDate();

		// If an admin needs to activate the user, I have to set the activate flag
		if ($userParams->get('useractivation') == 2)
		{
			$user->setParam('activate', 1);
		}

		if (!$user->bind($data))
		{
			return;
		}

		if (!$user->save())
		{
			return;
		}

		// Ok, now it's time to send the activation email again
		$template = $this->exceptionsHandler->getEmailTemplate('user-reactivate', true);

		// Well, this should never happen...
		if (!$template)
		{
			return;
		}

		$subject = $template[0];
		$body = $template[1];

		$config = $this->container->platform->getConfig();

		try
		{
			$mailer = JFactory::getMailer();

			$sitename = $config->get('sitename');
			$mailfrom = $config->get('mailfrom');
			$fromname = $config->get('fromname');

			$uri = JUri::getInstance();
			$base = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port'));
			$activate = $base . JRoute::_('index.php?option=com_users&task=registration.activate&token=' . $data['activation'], false);

			// Send e-mail to the user
			if ($userParams->get('useractivation') == 1)
			{
				$mailer->addRecipient($user->email);
			}
			// Send e-mail to Super Users
			elseif ($userParams->get('useractivation') == 2)
			{
				// get all admin users
				$query = $db->getQuery(true)
							->select($db->qn(array('name', 'email', 'sendEmail', 'id')))
							->from($db->qn('#__users'))
							->where($db->qn('sendEmail') . ' = ' . 1);

				$rows = $db->setQuery($query)->loadObjectList();

				// Send mail to all users with users creating permissions and receiving system emails
				foreach ($rows as $row)
				{
					$usercreator = $this->container->platform->getUser($row->id);

					if ($usercreator->authorise('core.create', 'com_users') && !empty($usercreator->email))
					{
						$mailer->addRecipient($usercreator->email);
					}
				}
			}
			else
			{
				// Future-proof check
				return;
			}

			$tokens = array(
				'[SITENAME]' => $sitename,
				'[DATE]'     => gmdate('Y-m-d H:i:s') . " GMT",
				'[USER]'     => $username,
				'[IP]'       => $ip,
				'[ACTIVATE]' => '<a href="' . $activate . '">' . $activate . '</a>',
			);

			$subject = str_replace(array_keys($tokens), array_values($tokens), $subject);
			$body = str_replace(array_keys($tokens), array_values($tokens), $body);

			// This line is required because SpamAssassin is BROKEN
			$mailer->Priority = 3;

			$mailer->isHtml(true);
			$mailer->setSender(array($mailfrom, $fromname));
			$mailer->setSubject($subject);
			$mailer->setBody($body);
			$mailer->Send();
		}
		catch (\Exception $e)
		{
			// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
		}
	}

	/**
	 * @param       $limit
	 * @param       $numfreq
	 * @param       $frequency
	 * @param array $extraWhere
	 *
	 * @return bool
	 */
	private function checkLogFrequency($limit, $numfreq, $frequency, array $extraWhere)
	{
		JLoader::import('joomla.utilities.date');
		$db = $this->db;

		$mindatestamp = 0;

		switch ($frequency)
		{
			case 'second':
				break;

			case 'minute':
				$numfreq *= 60;
				break;

			case 'hour':
				$numfreq *= 3600;
				break;

			case 'day':
				$numfreq *= 86400;
				break;

			case 'ever':
				$mindatestamp = 946706400; // January 1st, 2000
				break;
		}

		$jNow = new Date();

		if ($mindatestamp == 0)
		{
			$mindatestamp = $jNow->toUnix() - $numfreq;
		}

		$jMinDate = new Date($mindatestamp);
		$minDate = $jMinDate->toSql();

		$sql = $db->getQuery(true)
			->select('COUNT(*)')
			->from($db->qn('#__admintools_log'))
			->where($db->qn('logdate') . ' >= ' . $db->q($minDate));

		foreach ($extraWhere as $column => $value)
		{
			$sql->where($db->qn($column) . ' = ' . $db->q($value));
		}

		$db->setQuery($sql);

		try
		{
			$numOffenses = $db->loadResult();
		}
		catch (Exception $e)
		{
			$numOffenses = 0;
		}

		if ($numOffenses < $limit)
		{
			return false;
		}

		return true;
	}
}PK��#]���6RR'system/admintools/feature/dfishield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureDfishield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 360;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('dfishield', 1) == 1);
	}

	/**
	 * Simple Direct Files Inclusion block.
	 */
	public function onAfterInitialise()
	{
		$input  = JFactory::getApplication()->input;
		$option = $input->getCmd('option', '');
		$view   = $input->getCmd('view', '');
		$layout = $input->getCmd('layout', '');

		// Special case: JCE
		if (($option == 'com_jce') && ($view == 'editor') && ($layout == 'plugin'))
		{
			return;
		}

		$hashes = array('get', 'post');

		foreach ($hashes as $hash)
		{
			$input = $this->input->$hash;
			$ref = new ReflectionProperty($input, 'data');
			$ref->setAccessible(true);
			$allVars = $ref->getValue($input);

			if (empty($allVars))
			{
				continue;
			}

			if ($this->match_array_dfi($allVars))
			{
				$extraInfo = "Hash      : $hash\n";
				$extraInfo .= "Variables :\n";
				$extraInfo .= print_r($allVars, true);
				$extraInfo .= "\n";
				$this->exceptionsHandler->blockRequest('dfishield', null, $extraInfo);
			}
		}
	}

	private function match_array_dfi($array)
	{
		$result = false;

		if (is_array($array))
		{
			foreach ($array as $key => $value)
			{
				if (!empty($this->exceptions) && in_array($key, $this->exceptions))
				{
					continue;
				}

				// If there's a null byte in the key, break
				if (strstr($key, "\u0000"))
				{
					$result = true;
					break;
				}

				// If there's no value, treat the key as a value
				if (empty($value))
				{
					$value = $key;
				}

				// Scan the value
				if (is_array($value))
				{
					$result = $this->match_array_dfi($value);
				}
				else
				{
					// If there's a null byte, break
					if (strstr($value, "\u0000"))
					{
						$result = true;
						break;
					}

					// If the value starts with a /, ../ or [a-z]{1,2}:, block
					$value = str_replace('\\', '/', $value);
					if (preg_match('#^(/|\.\.|[a-z]{1,2}:\\\)#i', $value))
					{
						// Fix 2.0.1: Check that the file exists
						$result = @file_exists($value);

						if (!$result)
						{
							$sillyParts = explode('../', $value);
							$realParts = array();

							foreach ($sillyParts as $p)
							{
								if (!empty($p))
								{
									$realParts[] = $p;
								}
							}

							$path = implode('/', $realParts);
							$result = @file_exists($path);
						}
						break;
					}

					if ($result)
					{
						break;
					}
				}
			}
		}

		return $result;
	}
} PK��#]cOO
O
'system/admintools/feature/muashield.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureMuashield extends AtsystemFeatureAbstract
{
	protected $loadOrder = 330;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		if ($this->skipFiltering)
		{
			return false;
		}

		return ($this->cparams->getValue('muashield', 0) == 1);
	}

	/**
	 * Protects against a malicious User Agent string
	 */
	public function onAfterInitialise()
	{
		// Some PHP binaries don't set the $_SERVER array under all platforms
		if (!isset($_SERVER))
		{
			return;
		}

		if (!is_array($_SERVER))
		{
			return;
		}

		$this->blockUserAgent();

		$this->blockForwardHeader();
	}

	private function blockUserAgent()
	{
		// Some user agents don't set a UA string at all
		if (!array_key_exists('HTTP_USER_AGENT', $_SERVER))
		{
			return;
		}

		$mua = $_SERVER['HTTP_USER_AGENT'];
		$mua = trim($mua);

		if (strstr($mua, '<?'))
		{
			$this->exceptionsHandler->blockRequest('muashield');
		}

		// Serialised data in the MUA string?
		$patterns = array(
			'@"feed_url@', // feed_url isn't your typical UA but it sure as hell is part of an exploit
			'@}__(.*)|O:@', // Typical start of serialised data
			'@J?Simple(p|P)ie(Factory)?@', // If SimplePie or JSimplepieFactory is referenced
		);

		foreach ($patterns as $pattern)
		{
			if (preg_match($pattern, $mua) == 1)
			{
				// Neuter the attack
				$neuterMUA                  = 'HACKING ATTEMPT DETECTED';
				// 1. Reset the User Agent string reported by the server
				$_SERVER['HTTP_USER_AGENT'] = $neuterMUA;
				// 2. Replace the saved User Agent in the session storage to something non-malicious
				JFactory::getSession()->set('session.client.browser', $neuterMUA);
				// 3. KILL THE SESSION (may not work, depends on the session handler)
				JFactory::getSession()->destroy();

				// Immediately block the scumbag
				$this->exceptionsHandler->blockRequest('muashield');
			}
		}
	}

	private function blockForwardHeader()
	{
		// Do I have a HTTP_X_FORWARDED_FOR header?
		if(!isset($_SERVER['HTTP_X_FORWARDED_FOR']))
		{
			return;
		}

		// The same attack could be performed using the HTTP_X_FORWARDED_FOR header
		$header = $_SERVER['HTTP_X_FORWARDED_FOR'];
		$header = trim($header);

		$patterns = array(
			'@"feed_url@', // feed_url isn't your typical UA but it sure as hell is part of an exploit
			'@}__(.*)|O:@', // Typical start of serialised data
			'@"J?Simple(p|P)ie(Factory)?"@', // If SimplePie or JSimplepieFactory is referenced
		);

		foreach ($patterns as $pattern)
		{
			if (preg_match($pattern, $header))
			{
				// Neuter the attack
				$neuterMUA                  = 'HACKING ATTEMPT DETECTED';
				// 1. Reset the Forwarded header reported by the server
				$_SERVER['HTTP_X_FORWARDED_FOR'] = $neuterMUA;
				// 2. Replace the saved Forwarded header in the session storage to something non-malicious
				JFactory::getSession()->set('session.client.forwarded', $neuterMUA);
				// 3. KILL THE SESSION (may not work, depends on the session handler)
				JFactory::getSession()->destroy();

				// Immediately block the scumbag
				$this->exceptionsHandler->blockRequest('muashield');
			}
		}
	}
}PK��#]�>���(system/admintools/feature/quickstart.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use Akeeba\AdminTools\Admin\Helper\Storage;

defined('_JEXEC') or die;

/**
 * Detect if the Quick Start Wizard has ran (or Admin Tools has been manually configured). Otherwise display a message
 * reminding the user to run the wizard.
 */
class AtsystemFeatureQuickstart extends AtsystemFeatureAbstract
{
	protected $loadOrder = 999;

	public function onBeforeRender()
	{
		if (!$this->container->platform->isBackend())
		{
			return;
		}

		if ($this->container->platform->getUser()->guest)
		{
			return;
		}

		/** @var Storage $storage */
		$storage      = Storage::getInstance();
		$wizardHasRan = $storage->getValue('quickstart', 0);

		if ($wizardHasRan)
		{
			return;
		}

		if (!$this->container->platform->getUser()->authorise('core.manage', 'admintools.security'))
		{
			return;
		}

		if (!$this->container->platform->getUser()->authorise('core.manage', 'admintools.maintenance'))
		{
			return;
		}

		$jlang = JFactory::getLanguage();
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB');
		$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

		$msg = JText::sprintf('COM_ADMINTOOLS_QUICKSTART_MSG_PLEASERUNWIZARD', 'index.php?option=com_admintools&view=QuickStart');
		JFactory::getApplication()->enqueueMessage($msg, 'error');
	}
} PK��#]tD����)system/admintools/feature/selfprotect.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

/**
 * Self protection.
 *
 * Monitors whenever someone tries to unpublish the Admin Tools pluign, overriding the action.
 */
class AtsystemFeatureSelfprotect extends AtsystemFeatureAbstract
{
	protected $loadOrder = 200;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		$enabled = $this->cparams->getValue('selfprotect', 1) == 1;

		return $enabled & $this->container->platform->isBackend();
	}

	/**
	 * Disables creating new admins or updating new ones
	 */
	public function onAfterInitialise()
	{
		$input  = $this->input;
		$option = $input->getCmd('option', '');
		$task   = $input->getCmd('task', '');

		if ($option != 'com_plugins')
		{
			return;
		}

		$this->onDirectUnpublish($task);

		$this->onApplyOrSave($task);
	}

	/**
	 * Gets the extennsion ID for the System - Admin Tools plugin
	 *
	 * @return  int|null  The ID or null on failure
	 */
	protected function getPluginId()
	{
		$db = $this->container->db;
		$query = $db->getQuery(true)
					->select($db->qn('extension_id'))
					->from($db->qn('#__extensions'))
					->where($db->qn('type') . ' = ' . $db->q('plugin'))
					->where($db->qn('element') . ' = ' . $db->q('admintools'))
					->where($db->qn('folder') . ' = ' . $db->q('system'));

		try
		{
			return $db->setQuery($query)->loadResult();
		}
		catch (Exception $e)
		{
			return null;
		}
	}

	/**
	 * Handles the case of someone directly unpublishing the plugin from the Plugin Manager interface
	 *
	 * @param   string  $task
	 */
	private function onDirectUnpublish($task)
	{
		$allowedTasks = array('unpublish', 'plugins.unpublish');

		if (!in_array($task, $allowedTasks))
		{
			return;
		}

		// Get a list of all IDs in the request
		$ids   = $this->input->get('cid', array(), 'array');
		$ids[] = $this->input->getInt('id', null);

		// Get the plugin ID for System - Admin Tools
		$ourId = $this->getPluginId();

		if (is_null($ourId) || empty($ourId))
		{
			return;
		}

		// Does the ID exist in the array? We need to be thorough, we can't do a simple in_array.
		foreach ($ids as $id)
		{
			$id = (int)trim($id);

			if ($id == $ourId)
			{
				throw new RuntimeException(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
			}
		}
	}

	/**
	 * Handles the case of someone directly unpublishing the plugin from the Plugin Manager interface
	 *
	 * @param   string  $task
	 */
	private function onApplyOrSave($task)
	{
		$allowedTasks = array('apply', 'save', 'plugins.apply', 'plugins.save', 'plugin.apply', 'plugin.save');

		if (!in_array($task, $allowedTasks))
		{
			return;
		}

		// Get a list of all IDs in the request
		$ids   = $this->input->get('cid', array(), 'array');
		$ids[] = $this->input->getInt('id', null);
		$ids[] = $this->input->getInt('extension_id', null);

		// Get the plugin ID for System - Admin Tools
		$ourId = $this->getPluginId();

		if (is_null($ourId) || empty($ourId))
		{
			return;
		}

		// Does the ID exist in the array? We need to be thorough, we can't do a simple in_array.
		$found = false;

		foreach ($ids as $id)
		{
			$id = (int)trim($id);

			if ($id == $ourId)
			{
				$found = true;

				break;
			}
		}

		if (!$found)
		{
			return;
		}

		// Get the form data and look for the enabled field
		$jform = $this->input->get('jform', array(), 'array');

		if (!isset($jform['enabled']))
		{
			// Not saving the "enabled" value
			return;
		}

		if ($jform['enabled'] == 1)
		{
			// The plugin is being activated
			return;
		}

		// Apparently someone tries to activate the plugin. NOPE.
		throw new RuntimeException(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
	}
}PK��#]���ֈ�&system/admintools/feature/urlredir.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureUrlredir extends AtsystemFeatureAbstract
{
	protected $loadOrder = 500;

	private static $siteTemplates = null;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		return ($this->cparams->getValue('urlredirection', 1) == 1);
	}

	/**
	 * Performs custom redirections defined in the back-end of the component.
	 */
	public function onAfterInitialise()
	{
		// Get the base path
		$basepath = ltrim(JUri::base(true), '/');

		$myURL   = JUri::getInstance();
		$fullurl = ltrim($myURL->toString(array('path', 'query', 'fragment')), '/');
		$path    = ltrim($myURL->getPath(), '/');

		$pathLength = strlen($path);
		$baseLength = strlen($basepath);

		if ($baseLength != 0)
		{
			if ($pathLength > $baseLength)
			{
				$path = ltrim(substr($path, $baseLength), '/');
			}
			elseif ($pathLength == $baseLength)
			{
				$path = '';
			}
		}

		$pathLength = strlen($fullurl);

		if ($baseLength != 0)
		{
			if ($pathLength > $baseLength)
			{
				$fullurl = ltrim(substr($fullurl, $baseLength), '/');
			}
			elseif ($pathLength = $baseLength)
			{
				$fullurl = '';
			}
		}

		$db = $this->container->db;

		$sql = $db->getQuery(true)
			->select(array($db->qn('source'), $db->qn('keepurlparams')))
			->from($db->qn('#__admintools_redirects'))
			->where(
				'((' . $db->qn('dest') . ' = ' . $db->q($path) . ')' .
				' OR ' .
				'(' . $db->qn('dest') . ' = ' . $db->q($fullurl) . ')' .
				' OR ' .
				'(' . $db->q($fullurl) . ' LIKE ' . $db->qn('dest') . '))'
			)->where($db->qn('published') . ' = ' . $db->q('1'))
			->order($db->qn('ordering') . ' DESC');
		$db->setQuery($sql, 0, 1);

		try
		{
			$newURLStruct = $db->loadRow();
		}
		catch (Exception $e)
		{
			$newURLStruct = null;
		}

		if (!empty($newURLStruct))
		{
			list ($newURL, $keepQueryParams) = $newURLStruct;

			$new      = JUri::getInstance($newURL);
			$host     = $new->getHost();
			$fragment = $new->getFragment();
			$query    = $new->getQuery();

			if (empty($host))
			{
				$base = JUri::getInstance(JUri::base());
				$new->setHost($base->getHost());
				$new->setPort($base->getPort());
				$new->setScheme($base->getScheme());
			}

			// Keep URL Params == 1 (override all)
			if ($keepQueryParams == 1)
			{
				$myUrlParams = $myURL->getQuery(true);

				foreach ($myUrlParams as $k => $v)
				{
					$new->setVar($k, $v);
				}

				$myFragment = $myURL->getFragment();
				if (!empty($myFragment))
				{
					$new->setFragment($myURL->getFragment());
				}

				$new->setScheme($myURL->getScheme());
			}
			// Keep URL Params == 2 (add only)
			elseif ($keepQueryParams == 2)
			{
				$newUrlParams = $new->getQuery(true);
				$myUrlParams = $myURL->getQuery(true);

				foreach ($myUrlParams as $k => $v)
				{
					if (!isset($newUrlParams[$k]))
					{
						$new->setVar($k, $v);
					}
				}

				$myFragment = $myURL->getFragment();
				$newFragment = $new->getFragment();

				if (!empty($myFragment) && empty($newFragment))
				{
					$new->setFragment($myURL->getFragment());
				}

				$new->setScheme($myURL->getScheme());
			}

			$path = $new->getPath();

			if (!empty($path))
			{
				if (substr($path, 0, 1) != '/')
				{
					$new->setPath('/' . rtrim($basepath, '/') . '/' . $path);
				}
				elseif (strlen($path) > 1)
				{
					$new->setPath('/' . $path);
				}
			}

			$targetURL = $new->toString();

			$this->container->platform->redirect($targetURL, 301);
		}
	}
}PK��#]�oQ�)system/admintools/feature/cacheexpire.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureCacheexpire extends AtsystemFeatureAbstract
{
	protected $loadOrder = 640;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->params->get('cacheexpire', 0) == 1);
	}

	public function onAfterInitialise()
	{
		$minutes = (int)$this->params->get('cacheexp_freq', 0);

		if ($minutes <= 0)
		{
			return;
		}

		$lastJob = $this->getTimestamp('cache_expire');
		$nextJob = $lastJob + $minutes * 60;

		JLoader::import('joomla.utilities.date');
		$now = new Date();

		if ($now->toUnix() >= $nextJob)
		{
			$this->setTimestamp('cache_expire');
			$this->expireCache();
		}
	}

	/**
	 * Expires cache items
	 */
	private function expireCache()
	{
		$er = @error_reporting(0);
		$cache = JFactory::getCache('');
		$cache->gc();
		@error_reporting($er);
	}
}PK��#]���iB
B
.system/admintools/feature/sessionoptimiser.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use FOF30\Date\Date;

defined('_JEXEC') or die;

class AtsystemFeatureSessionoptimiser extends AtsystemFeatureAbstract
{
	protected $loadOrder = 600;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return ($this->params->get('sesoptimizer', 0) == 1);
	}

	public function onAfterInitialise()
	{
		$minutes = (int)$this->params->get('sesopt_freq', 0);

		if ($minutes <= 0)
		{
			return;
		}

		$lastJob = $this->getTimestamp('session_optimize');
		$nextJob = $lastJob + $minutes * 60;

		JLoader::import('joomla.utilities.date');
		$now = new Date();

		if ($now->toUnix() >= $nextJob)
		{
			$this->setTimestamp('session_optimize');
			$this->sessionOptimize();
		}
	}

	/**
	 * Optimizes the session table. The idea is that as users log in and out,
	 * vast amounts of records are created and deleted, slowly fragmenting the
	 * underlying database file and slowing down user session operations. At
	 * some point, your site might even crash. By doing a periodic optimization
	 * of the sessions table this is prevented. An optimization per hour should
	 * be adequate, even for huge sites.
	 *
	 * Note: this is not necessary if you're not using the database to save
	 * session data. Using disk files, memcache, APC or other alternative caches
	 * has no impact on your database performance. In this case you should not
	 * enable this option, as you have nothing to gain.
	 */
	private function sessionOptimize()
	{
		$db = $this->db;

		// First, make sure this is MySQL!
		$dbClass = get_class($db);

		if (substr($dbClass, 0, 15) == 'JDatabaseDriver')
		{
			$dbClass = substr($dbClass, 15);
		}
		else
		{
			$dbClass = str_replace('JDatabase', '', $dbClass);
		}

		if (!in_array(strtolower($dbClass), array('mysql', 'mysqli')))
		{
			return;
		}

		$db->setQuery('CHECK TABLE ' . $db->quoteName('#__session'));
		$result = $db->loadObjectList();

		$isOK = false;

		if (!empty($result))
		{
			foreach ($result as $row)
			{
				if (($row->Msg_type == 'status') && (
						($row->Msg_text == 'OK') ||
						($row->Msg_text == 'Table is already up to date')
					)
				)
				{
					$isOK = true;
				}
			}
		}

		// Run a repair only if it is required
		if (!$isOK)
		{
			// The table needs repair
			$db->setQuery('REPAIR TABLE ' . $db->quoteName('#__session'));
			$db->execute();
		}

		// Finally, optimize
		$db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__session'));
		$db->execute();
	}
}PK��#]�r�4}}-system/admintools/feature/customgenerator.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureCustomgenerator extends AtsystemFeatureAbstract
{
	protected $loadOrder = 700;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		if (!$this->container->platform->isFrontend())
		{
			return false;
		}

		return ($this->cparams->getValue('custgenerator', 0) != 0);
	}

	/**
	 * Cloak the generator meta tag in feeds. This method deals with the hardcoded Joomla! reference. Yeah, I know,
	 * hardcoded?
	 */
	public function onAfterRender()
	{
		if ($this->input->getCmd('format', 'html') != 'feed')
		{
			return;
		}

		$generator = $this->cparams->getValue('generator', '');

		if (empty($generator))
		{
			$generator = 'MYOB';
		}

		if (method_exists($this->app, 'getBody'))
		{
			$buffer = $this->app->getBody();
		}
		else
		{
			$buffer = JResponse::getBody();
		}

		$buffer = preg_replace('#<generator uri(.*)/generator>#iU', '<generator>' . $generator . '</generator>', $buffer);

		if (method_exists($this->app, 'setBody'))
		{
			$this->app->setBody($buffer);
		}
		else
		{
			JResponse::setBody($buffer);
		}
	}

	/**
	 * Override the generator
	 */
	public function onAfterDispatch()
	{
		$generator = $this->cparams->getValue('generator', 'MYOB');

		// Mind Your Own Business
		if (empty($generator))
		{
			$generator = 'MYOB';
		}

		$document = JFactory::getDocument();

		if (!method_exists($document, 'setGenerator'))
		{
			return;
		}

		$document->setGenerator($generator);
	}
}PK��#]5d��&system/admintools/feature/geoblock.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemFeatureGeoblock extends AtsystemFeatureAbstract
{
	protected $loadOrder = 30;

	/** @var  string  Extra info to log when geo-blocking an IP */
	private $extraInfo = null;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		$cnt = $this->cparams->getValue('geoblockcountries', '');
		$con = $this->cparams->getValue('geoblockcontinents', '');

		return ((!empty($cnt) || !empty($con)) && class_exists('AkeebaGeoipProvider'));
	}

	public function onAfterInitialise()
	{
		if (!$this->isIPBlocked())
		{
			return;
		}

		$this->exceptionsHandler->blockRequest('geoblocking', null, $this->extraInfo);
	}

	/**
	 * Is the IP blocked by a Geo-blocking rule?
	 *
	 * @param   string  $ip  The IP address to check. Skip or pass empty string / null to use the current visitor's IP.
	 *
	 * @return  bool
	 */
	public function isIPBlocked($ip = null)
	{
		if (empty($ip))
		{
			// Get the visitor's IP address
			$ip = AtsystemUtilFilter::getIp();
		}

		$continents = $this->cparams->getValue('geoblockcontinents', '');
		$continents = empty($continents) ? array() : explode(',', $continents);
		$countries  = $this->cparams->getValue('geoblockcountries', '');
		$countries  = empty($countries) ? array() : explode(',', $countries);

		$geoip     = new AkeebaGeoipProvider();
		$country   = $geoip->getCountryCode($ip);
		$continent = $geoip->getContinent($ip);

		if (empty($country))
		{
			$country = '(unknown country)';
		}

		if (empty($continent))
		{
			$continent = '(unknown continent)';
		}

		if (($continent) && !empty($continents) && in_array($continent, $continents))
		{
			$this->extraInfo = 'Continent : ' . $continent;

			return true;
		}

		if (($country) && !empty($countries) && in_array($country, $countries))
		{
			$this->extraInfo = 'Country : ' . $country;

			return true;
		}

		return false;
	}
}PK��#]���cc,system/admintools/util/exceptionshandler.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

use Akeeba\AdminTools\Admin\Helper\Storage;
use FOF30\Container\Container;
use FOF30\Date\Date;

class AtsystemUtilExceptionshandler
{
	/** @var   JRegistry  Plugin parameters */
	protected $params = null;

	/** @var   Storage  Component parameters */
	protected $cparams = null;

	/** @var   Container  The component's container */
	protected $container;

	public function __construct(JRegistry &$params, Storage &$cparams)
	{
		$this->params    = $params;
		$this->cparams   = $cparams;
		$this->container = Container::getInstance('com_admintools');
	}

	/**
	 * Logs security exceptions and processes the IP auto-ban for this IP
	 *
	 * @param string $reason                   Block reason code
	 * @param string $extraLogInformation      Extra information to be written to the text log file
	 * @param string $extraLogTableInformation Extra information to be written to the extradata field of the log table (useful for JSON format)
	 *
	 * @return bool
	 */
	public function logAndAutoban($reason, $extraLogInformation = '', $extraLogTableInformation = '')
	{
		$ret = $this->logBreaches($reason, $extraLogInformation, $extraLogTableInformation);

		$autoban = $this->cparams->getValue('tsrenable', 0);

		if ($autoban)
		{
			$this->autoBan($reason);
		}

		return $ret;
	}

	/**
	 * Blocks the request in progress and, optionally, logs the details of the
	 * blocked request for the admin to review later
	 *
	 * @param string $reason                   Block reason code
	 * @param string $message                  The message to be shown to the user
	 * @param string $extraLogInformation      Extra information to be written to the text log file
	 * @param string $extraLogTableInformation Extra information to be written to the extradata field of the log table (useful for JSON format)
	 *
	 * @throws Exception
	 */
	public function blockRequest($reason = 'other', $message = '', $extraLogInformation = '', $extraLogTableInformation = '')
	{
		if (empty($message))
		{
			$customMessage = $this->cparams->getValue('custom403msg', '');

			if (!empty($customMessage))
			{
				$message = $customMessage;
			}
			else
			{
				$message = 'ADMINTOOLS_BLOCKED_MESSAGE';
			}
		}

		$r = $this->logBreaches($reason, $extraLogInformation, $extraLogTableInformation);

		if (!$r)
		{
			return;
		}

		$autoban = $this->cparams->getValue('tsrenable', 0);

		if ($autoban)
		{
			$this->autoBan($reason);
		}

		// Merge the default translation with the current translation
		$jlang = JFactory::getLanguage();
		// Front-end translation
		$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
		$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
		$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, null, true);

		if ((JText::_('ADMINTOOLS_BLOCKED_MESSAGE') == 'ADMINTOOLS_BLOCKED_MESSAGE') && ($message == 'ADMINTOOLS_BLOCKED_MESSAGE'))
		{
			$message = "Access Denied";
		}
		else
		{
			$message = JText::_($message);
		}

		// Show the 403 message
		if ($this->cparams->getValue('use403view', 0))
		{
			// Using a view
			if (!$this->container->platform->getSessionVar('block', false, 'com_admintools'))
			{

				// This is inside an if-block so that we don't end up in an infinite redirection loop
				$this->container->platform->setSessionVar('block', true, 'com_admintools');
				$this->container->platform->setSessionVar('message', $message, 'com_admintools');

				if (!$this->container->platform->isCli())
				{
					JFactory::getSession()->close();
				}

				$this->container->platform->redirect(JUri::base());
			}
		}
		else
		{
			// Using Joomla!'s error page
			JFactory::getApplication()->input->set('template', null);

			throw new Exception($message, 403);
		}
	}

	/**
	 * Logs security exceptions
	 *
	 * @param string $reason                   Block reason code
	 * @param string $extraLogInformation      Extra information to be written to the text log file
	 * @param string $extraLogTableInformation Extra information to be written to the extradata field of the log table (useful for JSON format)
	 *
	 * @return bool
	 */
	public function logBreaches($reason, $extraLogInformation = '', $extraLogTableInformation = '')
	{
		$reasons_nolog     = $this->cparams->getValue('reasons_nolog', 'geoblocking');
		$reasons_noemail   = $this->cparams->getValue('reasons_noemail', 'geoblocking');
		$whitelist_domains = $this->cparams->getValue('whitelist_domains', '.googlebot.com,.search.msn.com');

		$reasons_nolog     = explode(',', $reasons_nolog);
		$reasons_noemail   = explode(',', $reasons_noemail);
		$whitelist_domains = explode(',', $whitelist_domains);

		// === SANITY CHECK - BEGIN ===
		// Get our IP address
		$ip = AtsystemUtilFilter::getIp();

		if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
		{
			$ip = substr($ip, strrpos($ip, ':') + 1);
		}

		// No point continuing if we can't get an address, right?
		if (empty($ip) || ($ip == '0.0.0.0'))
		{
			return false;
		}

		// Make sure it's not an IP in the safe list
		$safeIPs = $this->cparams->getValue('neverblockips', '');

		if (!empty($safeIPs))
		{
			$safeIPs = explode(',', $safeIPs);

			if (!empty($safeIPs))
			{
				if (AtsystemUtilFilter::IPinList($safeIPs))
				{
					return false;
				}
			}
		}

		// Make sure we don't have a list in the administrator white list
		if ($this->cparams->getValue('ipwl', 0) == 1)
		{
			$db = $this->container->db;
			$sql = $db->getQuery(true)
					->select($db->qn('ip'))
					->from($db->qn('#__admintools_adminiplist'));

			$db->setQuery($sql);

			try
			{
				$ipTable = $db->loadColumn();
			}
			catch (Exception $e)
			{
				$ipTable = null;
			}

			if (!empty($ipTable))
			{
				if (AtsystemUtilFilter::IPinList($ipTable))
				{
					return false;
				}
			}
		}

		// Make sure this IP doesn't resolve to a whitelisted domain
		if (!empty($whitelist_domains))
		{
			$remote_domain = @gethostbyaddr($ip);

			if (!empty($remote_domain))
			{
				foreach ($whitelist_domains as $domain)
				{
					$domain = trim($domain);

					if (strrpos($remote_domain, $domain) !== false)
					{
						return true;
					}
				}
			}
		}

		// === SANITY CHECK - END ===

		// Is this a private network IP and IP workaround is off? If so let's raise the flag so we can notify the user
		// I'll use the Container so I can easily set the flag and then save back to the database
		try
		{
			$this->flagPrivateNetworkIPs();
		}
		catch (Exception $e)
		{
			// Ignore any failures, they are not show stoppers
		}

		// Do I have any kind of log? Let's get some extra info
		if (
			($this->cparams->getValue('logbreaches', 0) && !in_array($reason, $reasons_nolog)) ||
			($this->cparams->getValue('emailbreaches', '') && !in_array($reason, $reasons_noemail))
		)
		{
			$uri = JUri::getInstance();
			$url = $uri->toString(['scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment']);

			JLoader::import('joomla.utilities.date');
			$date = new Date();

			$user      = $this->container->platform->getUser();

			if ($user->guest)
			{
				$username = 'Guest';
			}
			else
			{
				$username = $user->username . ' (' . $user->name . ' <' . $user->email . '>)';
			}

			$country   = '';
			$continent = '';

			if (class_exists('AkeebaGeoipProvider'))
			{
				$geoip     = new AkeebaGeoipProvider();
				$country   = $geoip->getCountryCode($ip);
				$continent = $geoip->getContinent($ip);
			}

			if (empty($country))
			{
				$country = '(unknown country)';
			}

			if (empty($continent))
			{
				$continent = '(unknown continent)';
			}
		}

		if ($this->cparams->getValue('logbreaches', 0) && !in_array($reason, $reasons_nolog))
		{
			// Logging to file
			$config = $this->container->platform->getConfig();

			$logpath = $config->get('log_path');

			$fname = $logpath . DIRECTORY_SEPARATOR . 'admintools_breaches.log';

			// -- Check the file size. If it's over 1Mb, archive and start a new log.
			if (@file_exists($fname))
			{
				$fsize = filesize($fname);

				if ($fsize > 1048756)
				{
					if (@file_exists($fname . '.1'))
					{
						unlink($fname . '.1');
					}

					@copy($fname, $fname . '.1');
					@unlink($fname);
				}
			}

			// -- Log the exception
			$fp = @fopen($fname, 'at');

			if ($fp !== false)
			{
				fwrite($fp, str_repeat('-', 79) . "\n");
				fwrite($fp, "Blocking reason: " . $reason . "\n" . str_repeat('-', 79) . "\n");
				fwrite($fp, 'Date/time : ' . gmdate('Y-m-d H:i:s') . " GMT\n");
				fwrite($fp, 'URL       : ' . $url . "\n");
				fwrite($fp, 'User      : ' . $username . "\n");
				fwrite($fp, 'IP        : ' . $ip . "\n");
				fwrite($fp, 'Country   : ' . $country . "\n");
				fwrite($fp, 'Continent : ' . $continent . "\n");
				fwrite($fp, 'UA        : ' . $_SERVER['HTTP_USER_AGENT'] . "\n");

				if (!empty($extraLogInformation))
				{
					fwrite($fp, $extraLogInformation . "\n");
				}

				fwrite($fp, "\n\n");
				fclose($fp);
			}

			// ...and write a record to the log table
			$db = $this->container->db;
			$logEntry = (object)array(
				'logdate'   => $date->toSql(),
				'ip'        => $ip,
				'url'       => $url,
				'reason'    => $reason,
				'extradata' => $extraLogTableInformation,
			);

			try
			{
				$db->insertObject('#__admintools_log', $logEntry);
			}
			catch (Exception $e)
			{
				// Do nothing if the query fails
			}
		}

		$emailbreaches = $this->cparams->getValue('emailbreaches', '');

		if (!empty($emailbreaches) && !in_array($reason, $reasons_noemail))
		{
			// Load the component's administrator translation files
			$jlang = JFactory::getLanguage();
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

			// Get the site name
			$config = $this->container->platform->getConfig();

			$sitename = $config->get('sitename');

			// Create a link to lookup the IP
			$ip_link = $this->cparams->getValue('iplookupscheme', 'http') . '://' . $this->cparams->getValue('iplookup', 'ip-lookup.net/index.php?ip={ip}');
			$ip_link = str_replace('{ip}', $ip, $ip_link);

			// Get the reason in human readable format
			$txtReason = JText::_('COM_ADMINTOOLS_LBL_SECURITYEXCEPTION_REASON_' . strtoupper($reason));

			// Get extra information
			if ($extraLogTableInformation)
			{
				list($logReason,) = explode('|', $extraLogTableInformation);
				$txtReason .= " ($logReason)";
			}

			// Send the email
			try
			{
				$mailer = JFactory::getMailer();

				$mailfrom = $config->get('mailfrom');
				$fromname = $config->get('fromname');

				// Let's get the most suitable email template
				$template = $this->getEmailTemplate($reason);

				// Got no template, the user didn't published any email template, or the template doesn't want us to
				// send a notification email. Anyway, let's stop here
				if (!$template)
				{
					return true;
				}
				else
				{
					$subject = $template[0];
					$body = $template[1];
				}

				$tokens = array(
					'[SITENAME]'  => $sitename,
					'[REASON]'    => $txtReason,
					'[DATE]'      => gmdate('Y-m-d H:i:s') . " GMT",
					'[URL]'       => $url,
					'[USER]'      => $username,
					'[IP]'        => $ip,
					'[LOOKUP]'    => '<a href="' . $ip_link . '">IP Lookup</a>',
					'[COUNTRY]'   => $country,
					'[CONTINENT]' => $continent,
					'[UA]'        => $_SERVER['HTTP_USER_AGENT']
				);

				$subject = str_replace(array_keys($tokens), array_values($tokens), $subject);
				$body = str_replace(array_keys($tokens), array_values($tokens), $body);

				$recipients = explode(',', $emailbreaches);
				$recipients = array_map('trim', $recipients);

				foreach ($recipients as $recipient)
				{
					if (empty($recipient))
					{
						continue;
					}

					// This line is required because SpamAssassin is BROKEN
					$mailer->Priority = 3;

					$mailer->isHtml(true);
					$mailer->setSender(array($mailfrom, $fromname));

					if ($mailer->addRecipient($recipient) === false)
					{
						// Failed to add a recipient?
						continue;
					}

					$mailer->setSubject($subject);
					$mailer->setBody($body);
					$mailer->Send();
				}
			}
			catch (\Exception $e)
			{
				// Joomla 3.5 is written by incompetent bonobos
			}
		}

		return true;
	}

	/**
	 * Checks if an IP address should be automatically banned for raising too many security exceptions over a predefined
	 * time period.
	 *
	 * @param   string $reason The reason of the ban
	 *
	 * @return  void
	 */
	public function autoBan($reason = 'other')
	{
		// We need to be able to get our own IP, right?
		if (!function_exists('inet_pton'))
		{
			return;
		}

		// Get the IP
		$ip = AtsystemUtilFilter::getIp();

		// No point continuing if we can't get an address, right?
		if (empty($ip) || ($ip == '0.0.0.0'))
		{
			return;
		}

		// Check for repeat offenses
		$db = $this->container->db;
		$strikes = $this->cparams->getValue('tsrstrikes', 3);
		$numfreq = $this->cparams->getValue('tsrnumfreq', 1);
		$frequency = $this->cparams->getValue('tsrfrequency', 'hour');
		$mindatestamp = 0;

		switch ($frequency)
		{
			case 'second':
				break;

			case 'minute':
				$numfreq *= 60;
				break;

			case 'hour':
				$numfreq *= 3600;
				break;

			case 'day':
				$numfreq *= 86400;
				break;

			case 'ever':
				$mindatestamp = 946706400; // January 1st, 2000
				break;
		}

		JLoader::import('joomla.utilities.date');
		$jNow = new Date();

		if ($mindatestamp == 0)
		{
			$mindatestamp = $jNow->toUnix() - $numfreq;
		}

		$jMinDate = new Date($mindatestamp);
		$minDate = $jMinDate->toSql();

		$sql = $db->getQuery(true)
			->select('COUNT(*)')
			->from($db->qn('#__admintools_log'))
			->where($db->qn('logdate') . ' >= ' . $db->q($minDate))
			->where($db->qn('ip') . ' = ' . $db->q($ip));
		$db->setQuery($sql);
		try
		{
			$numOffenses = $db->loadResult();
		}
		catch (Exception $e)
		{
			$numOffenses = 0;
		}

		if ($numOffenses < $strikes)
		{
			return;
		}

		// Block the IP
		$myIP = @inet_pton($ip);

		if ($myIP === false)
		{
			return;
		}

		$myIP = inet_ntop($myIP);

		$until     = $jNow->toUnix();
		$numfreq   = $this->cparams->getValue('tsrbannum', 1);
		$frequency = $this->cparams->getValue('tsrbanfrequency', 'hour');

		switch ($frequency)
		{
			case 'second':
				$until += $numfreq;
				break;

			case 'minute':
				$numfreq *= 60;
				$until += $numfreq;
				break;

			case 'hour':
				$numfreq *= 3600;
				$until += $numfreq;
				break;

			case 'day':
				$numfreq *= 86400;
				$until += $numfreq;
				break;

			case 'ever':
				$until = 2145938400; // January 1st, 2038 (mind you, UNIX epoch runs out on January 19, 2038!)
				break;
		}

		JLoader::import('joomla.utilities.date');

		$jMinDate = new Date($until);
		$minDate = $jMinDate->toSql();

		$record = (object)array(
			'ip'     => $myIP,
			'reason' => $reason,
			'until'  => $minDate
		);

		// If I'm here it means that we have to ban the user. Let's see if this is a simple autoban or
		// we have to issue a permaban as a result of several attacks
		if ($this->cparams->getValue('permaban', 0))
		{
			// Ok I have to check the number of autoban
			$query = $db->getQuery(true)
				->select('COUNT(*)')
				->from($db->qn('#__admintools_ipautobanhistory'))
				->where($db->qn('ip') . ' = ' . $db->q($myIP));

			try
			{
				$bans = $db->setQuery($query)->loadResult();
			}
			catch (Exception $e)
			{
				$bans = 0;
			}

			$limit = (int)$this->cparams->getValue('permabannum', 0);

			if ($limit && ($bans >= $limit))
			{
				$block = (object)array(
					'ip'          => $myIP,
					'description' => 'IP automatically blocked after being banned automatically ' . $bans . ' times'
				);

				try
				{
					$db->insertObject('#__admintools_ipblock', $block);
				}
				catch (Exception $e)
				{
					// This should never happen, however let's prevent a white page if anything goes wrong
				}
			}
		}

		try
		{
			$db->insertObject('#__admintools_ipautoban', $record);
		}
		catch (Exception $e)
		{
			// If the IP was already blocked and I have to block it again, I'll have to update the current record
			$db->updateObject('#__admintools_ipautoban', $record, 'ip');
		}

		// Send an optional email
		if ($this->cparams->getValue('emailafteripautoban', ''))
		{
			// Load the component's administrator translation files
			$jlang = JFactory::getLanguage();
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

			// Get the site name
			$config = $this->container->platform->getConfig();

			$sitename = $config->get('sitename');

			$country = '';
			$continent = '';

			if (class_exists('AkeebaGeoipProvider'))
			{
				$geoip = new AkeebaGeoipProvider();
				$country = $geoip->getCountryCode($ip);
				$continent = $geoip->getContinent($ip);
			}

			if (empty($country))
			{
				$country = '(unknown country)';
			}

			if (empty($continent))
			{
				$continent = '(unknown continent)';
			}

			$uri = JUri::getInstance();
			$url = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'));

			$ip_link = $this->cparams->getValue('iplookupscheme', 'http') . '://' . $this->cparams->getValue('iplookup', 'ip-lookup.net/index.php?ip={ip}');
			$ip_link = str_replace('{ip}', $ip, $ip_link);

			$substitutions = array(
				'[SITENAME]'  => $sitename,
				'[REASON]'	  => JText::_('COM_ADMINTOOLS_WAFEMAILTEMPLATE_REASON_IPAUTOBAN'),
				'[DATE]'      => gmdate('Y-m-d H:i:s') . " GMT",
				'[URL]'       => $url,
				'[USER]'      => '',
				'[IP]'        => $ip,
				'[LOOKUP]'    => '<a href="' . $ip_link . '">IP Lookup</a>',
				'[COUNTRY]'   => $country,
				'[CONTINENT]' => $continent,
				'[UA]'		  => $_SERVER['HTTP_USER_AGENT'],
				'[UNTIL]'     => $minDate
			);

			// Load the component's administrator translation files
			$jlang = JFactory::getLanguage();
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
			$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);

			// Let's get the most suitable email template
			$template = $this->getEmailTemplate('ipautoban', true);

			// Got no template, the user didn't published any email template, or the template doesn't want us to
			// send a notification email. Anyway, let's stop here.
			if (!$template)
			{
				return;
			}
			else
			{
				$subject = $template[0];
				$body    = $template[1];
			}

			foreach ($substitutions as $k => $v)
			{
				$subject = str_replace($k, $v, $subject);
				$body = str_replace($k, $v, $body);
			}

			// Send the email
			try
			{
				$mailer = JFactory::getMailer();

				$mailfrom = $config->get('mailfrom');
				$fromname = $config->get('fromname');

				// This line is required because SpamAssassin is BROKEN
				$mailer->Priority = 3;

				$mailer->isHtml(true);
				$mailer->setSender(array($mailfrom, $fromname));
				$mailer->addRecipient($this->cparams->getValue('emailafteripautoban', ''));

				if ($this->cparams->getValue('emailafteripautoban', '') === false)
				{
					// Failed to add a recipient?
					throw new RuntimeException('Email address for auto-banned IP notification is empty', 500);
				}

				$mailer->setSubject($subject);
				$mailer->setBody($body);
				$mailer->Send();
			}
			catch (\Exception $e)
			{
				// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
			}
		}
	}

	/**
	 * Gets the email template for a specific security exception reason
	 *
	 * @param   string  $reason  The security exception reason for which to fetch the email template
	 * @param   bool    $exact   Require an exact match of the reason
	 *
	 * @return  array
	 */
	public function getEmailTemplate($reason, $exact = false)
	{
		// Let's get the subject and the body from email templates
		$jlang = JFactory::getLanguage();
		$db = $this->container->db;
		$languages = array($db->q('*'), $db->q('en-GB'), $db->q($jlang->getDefault()));
		$stack = array();

		$query = $db->getQuery(true)
			->select('*')
			->from($db->qn('#__admintools_waftemplates'))
			->where($db->qn('reason') . ' IN(' . $db->q($reason) . ', ' . $db->q('all') . ')')
			->where($db->qn('language') . ' IN(' . implode(',', $languages) . ')')
			->where($db->qn('enabled') . ' = ' . $db->q('1'));

		if ($exact)
		{
			$query->where($db->qn('reason') . ' = ' . $db->q($reason));
		}

		try
		{
			$templates = $db->setQuery($query)->loadObjectList();
		}
		catch (Exception $e)
		{
			return array();
		}

		foreach ($templates as $template)
		{
			$score = 0;

			if ($template->reason == $reason)
			{
				$score += 10;
			}

			if ($template->language == $jlang->getDefault())
			{
				$score += 10;
			}
			elseif ($template->language == '*')
			{
				$score += 5;
			}
			elseif ($template->language == 'en-GB')
			{
				$score += 1;
			}

			$stack[$score] = $template;
		}

		ksort($stack);
		$best = array_pop($stack);

		if (!$best)
		{
			return array();
		}

		if ($this->cparams->getValue('email_throttle', 1))
		{
			// Ok I found out the best template, HOWEVER, should I really send out an email? Let's do some checks vs frequency limits
			$emails       = $best->email_num ? $best->email_num : 5;
			$numfreq      = $best->email_numfreq ? $best->email_numfreq : 1;
			$frequency    = $best->email_freq ? $best->email_freq : 'hour';
			$mindatestamp = 0;

			switch ($frequency)
			{
				case 'second':
					break;

				case 'minute':
					$numfreq *= 60;
					break;

				case 'hour':
					$numfreq *= 3600;
					break;

				case 'day':
					$numfreq *= 86400;
					break;

				case 'ever':
					$mindatestamp = 946706400; // January 1st, 2000
					break;
			}

			JLoader::import('joomla.utilities.date');
			$jNow = new Date();

			if ($mindatestamp == 0)
			{
				$mindatestamp = $jNow->toUnix() - $numfreq;
			}

			$jMinDate = new Date($mindatestamp);
			$minDate = $jMinDate->toSql();

			$sql = $db->getQuery(true)
				->select('COUNT(*)')
				->from($db->qn('#__admintools_log'))
				->where($db->qn('logdate') . ' >= ' . $db->q($minDate))
				->where($db->qn('reason') . ' = ' . $db->q($reason));
			$db->setQuery($sql);
			try
			{
				$numOffenses = $db->loadResult();
			}
			catch (Exception $e)
			{
				$numOffenses = 0;
			}

			if ($numOffenses > $emails)
			{
				return array();
			}
		}

		// Because SpamAssassin is a piece of shit that blacklists our domain when it misidentifies an email as spam.
		$replaceThat = array(
			'<p style=\"text-align: right; font-size: 7pt; color: #ccc;\">Powered by <a style=\"color: #ccf; text-decoration: none;\" href=\"https://www.akeebabackup.com/products/admin-tools.html\">Akeeba AdminTools</a></p>',
			'<p style=\"text-align: right; font-size: 7pt; color: #ccc;\">Powered by <a style=\"color: #ccf; text-decoration: none;\" href=\"https://www.akeebabackup.com/products/admin-tools.html\">Akeeba AdminTools</a></p>',
			'https://www.akeebabackup.com',
			'http://www.akeebabackup.com',
			'http://akeebabackup.com',
			'https://akeebabackup.com',
			'www.akeebabackup.com',
			'akeebabackup.com',
		);

		foreach ($replaceThat as $find)
		{
			$best->subject  = str_ireplace($find, '', $best->subject);
			$best->template = str_ireplace($find, '', $best->template);
		}

		// Because SpamAssassin demands there is a body and surrounding html tag even though it's not necessary.
		if (strpos($best->template, '<body') == false)
		{
			$best->template = '<body>' . $best->template . '</body>';
		}

		if (strpos($best->template, '<html') == false)
		{
			$best->template = <<< SPAMASSASSINSUCKS
<html>
<head>
<title>{$best->subject}</title>
</head>
$best->template
</html>
SPAMASSASSINSUCKS;

		}

		// And now return the template
		return array(
			$best->subject,
			$best->template
		);
	}

	/**
	 * Flag security exceptions coming from private network IPs so we can notify the user
	 *
	 * @return  void
	 *
	 * @since   4.1.1
	 */
	private function flagPrivateNetworkIPs()
	{
		// Make sure FOF 3 can be loaded, or fail gracefuly
		if (!defined('FOF30_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof30/include.php'))
		{
			return;
		}

		$params = $this->container->params;

		// Run the check only if IP workarounds are off AND the flag is set to 0 (ie not detected)
		// There's no need to run this check if the user decided to ignore the warning (value: -1) or we already detected something (value: 1)
		if (($this->cparams->getValue('ipworkarounds', -1) == -1) || ($params->get('detected_exceptions_from_private_network', 0) != 0))
		{
			return;
		}

		$privateNetwork = array(
			'10.0.0.0-10.255.255.255',
			'172.16.0.0-172.31.255.255',
			'192.168.0.0-192.168.255.255'
		);

		if (!AtsystemUtilFilter::IPinList($privateNetwork))
		{
			return;
		}

		// This IP belongs to a private network, let's raise the flag and then notify the user
		$params->set('detected_exceptions_from_private_network', 1);
		$params->save();
	}
}PK��#]���Z!Z!!system/admintools/util/filter.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

class AtsystemUtilFilter
{
	/** @var   string  The IP address of the current visitor */
	protected static $ip = null;

	/**
	 * Get the current visitor's IP address
	 *
	 * @return string
	 */
	public static function getIp()
	{
		if (is_null(static::$ip))
		{
			$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';

			if (!empty($ip) && ($ip != '0.0.0.0') && function_exists('inet_pton') && function_exists('inet_ntop'))
			{
				$myIP = @inet_pton($ip);

				if ($myIP !== false)
				{
					$ip = inet_ntop($myIP);
				}
			}

			static::setIp($ip);
		}

		return static::$ip;
	}

	/**
	 * Set the IP address of the current visitor (to be used in testing)
	 *
	 * @param   string  $ip
	 *
	 * @return  void
	 */
	public static function setIp($ip)
	{
		static::$ip = $ip;
	}

	/**
	 * Checks if the user's IP is contained in a list of IPs or IP expressions
	 *
	 * This code has been copied from FOF to lower the amount of dependencies required
	 *
	 * @param   array   $ipTable  The list of IP expressions
	 * @param   string  $ip       The user's IP address, leave empty / null to get the current IP address
	 *
	 * @return  null|bool  True if it's in the list, null if the filtering can't proceed
	 */
	public static function IPinList($ipTable = array(), $ip = null)
	{
		// Get our IP address
		if (empty($ip))
		{
			$ip = static::getIp();
		}

		// No point proceeding with an empty IP list
		if (empty($ipTable))
		{
			return false;
		}

		// If the IP list is not an array, convert it to an array
		if (!is_array($ipTable))
		{
			if (strpos($ipTable, ',') !== false)
			{
				$ipTable = explode(',', $ipTable);
				$ipTable = array_map(function($x) { return trim($x); }, $ipTable);
			}
			else
			{
				$ipTable = trim($ipTable);
				$ipTable = array($ipTable);
			}
		}

		// If no IP address is found, return false
		if ($ip == '0.0.0.0')
		{
			return false;
		}

		// If no IP is given, return false
		if (empty($ip))
		{
			return false;
		}

		// Sanity check
		if (!function_exists('inet_pton'))
		{
			return false;
		}

		// Get the IP's in_adds representation
		$myIP = @inet_pton($ip);

		// If the IP is in an unrecognisable format, quite
		if ($myIP === false)
		{
			return false;
		}

		$ipv6 = self::isIPv6($ip);

		foreach ($ipTable as $ipExpression)
		{
			$ipExpression = trim($ipExpression);

			// Inclusive IP range, i.e. 123.123.123.123-124.125.126.127
			if (strstr($ipExpression, '-'))
			{
				list($from, $to) = explode('-', $ipExpression, 2);

				if ($ipv6 && (!self::isIPv6($from) || !self::isIPv6($to)))
				{
					// Do not apply IPv4 filtering on an IPv6 address
					continue;
				}
				elseif (!$ipv6 && (self::isIPv6($from) || self::isIPv6($to)))
				{
					// Do not apply IPv6 filtering on an IPv4 address
					continue;
				}

				$from = @inet_pton(trim($from));
				$to = @inet_pton(trim($to));

				// Sanity check
				if (($from === false) || ($to === false))
				{
					continue;
				}

				// Swap from/to if they're in the wrong order
				if ($from > $to)
				{
					list($from, $to) = array($to, $from);
				}

				if (($myIP >= $from) && ($myIP <= $to))
				{
					return true;
				}
			}
			// Netmask or CIDR provided
			elseif (strstr($ipExpression, '/'))
			{
				$binaryip = self::inet_to_bits($myIP);

				list($net, $maskbits) = explode('/', $ipExpression, 2);
				if ($ipv6 && !self::isIPv6($net))
				{
					// Do not apply IPv4 filtering on an IPv6 address
					continue;
				}
				elseif (!$ipv6 && self::isIPv6($net))
				{
					// Do not apply IPv6 filtering on an IPv4 address
					continue;
				}
				elseif ($ipv6 && strstr($maskbits, ':'))
				{
					// Perform an IPv6 CIDR check
					if (self::checkIPv6CIDR($myIP, $ipExpression))
					{
						return true;
					}

					// If we didn't match it proceed to the next expression
					continue;
				}
				elseif (!$ipv6 && strstr($maskbits, '.'))
				{
					// Convert IPv4 netmask to CIDR
					$long = ip2long($maskbits);
					$base = ip2long('255.255.255.255');
					$maskbits = 32 - log(($long ^ $base) + 1, 2);
				}

				// Convert network IP to in_addr representation
				$net = @inet_pton($net);

				// Sanity check
				if ($net === false)
				{
					continue;
				}

				// Get the network's binary representation
				$binarynet = self::inet_to_bits($net);
				$expectedNumberOfBits = $ipv6 ? 128 : 24;
				$binarynet = str_pad($binarynet, $expectedNumberOfBits, '0', STR_PAD_RIGHT);

				// Check the corresponding bits of the IP and the network
				$ip_net_bits = substr($binaryip, 0, $maskbits);
				$net_bits = substr($binarynet, 0, $maskbits);

				if ($ip_net_bits == $net_bits)
				{
					return true;
				}
			}
			else
			{
				// IPv6: Only single IPs are supported
				if ($ipv6)
				{
					$ipExpression = trim($ipExpression);

					if (!self::isIPv6($ipExpression))
					{
						continue;
					}

					$ipCheck = @inet_pton($ipExpression);
					if ($ipCheck === false)
					{
						continue;
					}

					if ($ipCheck == $myIP)
					{
						return true;
					}
				}
				else
				{
					// Standard IPv4 address, i.e. 123.123.123.123 or partial IP address, i.e. 123.[123.][123.][123]
					$dots = 0;
					if (substr($ipExpression, -1) == '.')
					{
						// Partial IP address. Convert to CIDR and re-match
						foreach (count_chars($ipExpression, 1) as $i => $val)
						{
							if ($i == 46)
							{
								$dots = $val;
							}
						}

						$netmask = '255.255.255.255';

						switch ($dots)
						{
							case 1:
								$netmask = '255.0.0.0';
								$ipExpression .= '0.0.0';
								break;

							case 2:
								$netmask = '255.255.0.0';
								$ipExpression .= '0.0';
								break;

							case 3:
								$netmask = '255.255.255.0';
								$ipExpression .= '0';
								break;

							default:
								$dots = 0;
						}

						if ($dots)
						{
							$binaryip = self::inet_to_bits($myIP);

							// Convert netmask to CIDR
							$long = ip2long($netmask);
							$base = ip2long('255.255.255.255');
							$maskbits = 32 - log(($long ^ $base) + 1, 2);

							$net = @inet_pton($ipExpression);

							// Sanity check
							if ($net === false)
							{
								continue;
							}

							// Get the network's binary representation
							$binarynet = self::inet_to_bits($net);
							$expectedNumberOfBits = $ipv6 ? 128 : 24;
							$binarynet = str_pad($binarynet, $expectedNumberOfBits, '0', STR_PAD_RIGHT);

							// Check the corresponding bits of the IP and the network
							$ip_net_bits = substr($binaryip, 0, $maskbits);
							$net_bits = substr($binarynet, 0, $maskbits);

							if ($ip_net_bits == $net_bits)
							{
								return true;
							}
						}
					}
					if (!$dots)
					{
						$ip = @inet_pton(trim($ipExpression));

						if ($ip == $myIP)
						{
							return true;
						}
					}
				}
			}
		}

		return false;
	}

	/**
	 * Is it an IPv6 IP address?
	 *
	 * @param   string   $ip  An IPv4 or IPv6 address
	 *
	 * @return  boolean  True if it's IPv6
	 */
	protected static function isIPv6($ip)
	{
		if (strstr($ip, ':'))
		{
			return true;
		}

		return false;
	}

	/**
	 * Converts inet_pton output to bits string
	 *
	 * @param   string $inet The in_addr representation of an IPv4 or IPv6 address
	 *
	 * @return  string
	 */
	protected static function inet_to_bits($inet)
	{
		if (strlen($inet) == 4)
		{
			$unpacked = unpack('A4', $inet);
		}
		else
		{
			$unpacked = unpack('A16', $inet);
		}
		$unpacked = str_split($unpacked[1]);
		$binaryip = '';

		foreach ($unpacked as $char)
		{
			$binaryip .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
		}

		return $binaryip;
	}

	/**
	 * Checks if an IPv6 address $ip is part of the IPv6 CIDR block $cidrnet
	 *
	 * @param   string  $ip       The IPv6 address to check, e.g. 21DA:00D3:0000:2F3B:02AC:00FF:FE28:9C5A
	 * @param   string  $cidrnet  The IPv6 CIDR block, e.g. 21DA:00D3:0000:2F3B::/64
	 *
	 * @return  bool
	 */
	protected static function checkIPv6CIDR($ip, $cidrnet)
	{
		$ip       = inet_pton($ip);
		$binaryip = self::inet_to_bits($ip);

		list($net, $maskbits) = explode('/',$cidrnet);

		$net         = inet_pton($net);
		$binarynet   = self::inet_to_bits($net);

		$ip_net_bits = substr($binaryip,0,$maskbits);
		$net_bits    = substr($binarynet,0,$maskbits);

		return $ip_net_bits === $net_bits;
	}
}PK��#]�5x::'system/admintools/admintools/index.htmlnu&1i�<html>
<head><title></title></head>
<body></body>
</html>
PK��#]B`��K�K%system/admintools/admintools/main.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use Akeeba\AdminTools\Admin\Helper\Storage;
use FOF30\Container\Container;
use FOF30\Utils\Ip;

defined('_JEXEC') or die;

JLoader::import('joomla.application.plugin');

// This dummy class is here to allow the class autoloader to load the main plugin file
class AtsystemAdmintoolsMain
{

}

if (!defined('FOF30_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof30/include.php'))
{
	// FOF 3.0 is not installed
	return;
}

/**
 * This class acts as a proxy to the feature classes
 *
 * @author nicholas
 *
 */
class plgSystemAdmintools extends JPlugin
{
	/** @var   Storage   Component parameters */
	protected $componentParams = null;

	/** @var   array  Maps plugin hooks (onSomethingSomething) to feature objects */
	protected $featuresPerHook = array();

	/** @var   JInput  The Joomla! application input */
	protected $input = null;

	/** @var   AtsystemUtilExceptionshandler  The security exceptions handler */
	protected $exceptionsHandler = null;

	/** @var   array  The applicable WAF Exceptions which prevent filtering from taking place */
	public $exceptions = array();

	/** @var   bool   Should I skip filtering (because of whitelisted IPs, WAF Exceptions etc) */
	public $skipFiltering = false;

	/** @var   JApplicationCms  The application we're runnign in */
	public $app = null;

	/** @var   JDatabaseDriver  The Joomla! database driver */
	public $db = null;

	/** @var   Container  The component container */
	protected $container;

	/**
	 * Initialises the System - Admin Tools plugin
	 *
	 * @param  object $subject The object to observe
	 * @param  array  $config  Configuration information
	 */
	public function __construct(&$subject, $config = array())
	{
		// Autoload the language strings
		$this->autoloadLanguage = true;

		// Call the parent constructor
		parent::__construct($subject, $config);

		$this->container = Container::getInstance('com_admintools');

		// Under Joomla 2.5 we have to explicitly load the application and the database,
		// the parent class won't do that for us.
		if (is_null($this->app))
		{
			$this->app = JFactory::getApplication();
		}

		if (is_null($this->db))
		{
			$this->db = JFactory::getDbo();
		}

		// Store a reference to the global input object
		$this->input = JFactory::getApplication()->input;

		// Load the component parameters
		$this->loadComponentParameters();

		// Work around IP issues with transparent proxies etc
		$this->workaroundIP();

		// Load the GeoIP library, if necessary
		$this->loadGeoIpProvider();

		// Preload the security exceptions handler object
		$this->loadExceptionsHandler();

		// Load the WAF Exceptions
		$this->loadWAFExceptions();

		// Load and register the plugin features
		$this->loadFeatures();
	}

	/**
	 * Log a security exception coming from a third party application. It's supposed to be used by 3PD to log security
	 * exceptions in Admin Tools' log.
	 *
	 * @param   string $reason    The blocking reason to show to the administrator. MANDATORY.
	 * @param   string $message   The message to show to the user being blocked. MANDATORY.
	 * @param   array  $extraInfo Any extra information to record to the log file (hash array).
	 * @param   bool   $autoban   OBSOLETE. Automatic IP ban can only be toggled through the Configure WAF page.
	 *
	 * @return  void
	 */
	public function onAdminToolsThirdpartyException($reason, $message, $extraInfo = array(), $autoban = false)
	{
		$this->runFeature('onAdminToolsThirdpartyException', array($reason, $message, $extraInfo = array(), $autoban = false));
	}

	/**
	 * Hooks to the onAfterInitialize system event, the first time in the Joomla! page load workflow which fires a
	 * plug-in event.
	 */
	public function onAfterInitialise()
	{
		return $this->runFeature('onAfterInitialise', array());
	}

	/**
	 * Executes right after Joomla! has finished SEF routing and is about to dispatch the request to a component
	 *
	 * @return mixed
	 */
	public function onAfterRoute()
	{
		return $this->runFeature('onAfterRoute', array());
	}

	/**
	 * Executes before Joomla! renders its content
	 *
	 * @return  mixed
	 */
	public function onBeforeRender()
	{
		// Register the late bound after render event handler, guaranteed to be the last onAfterRender plugin to execute
		$app = JFactory::getApplication();

		$app->registerEvent('onAfterRender', array($this, 'onAfterRenderLatebound'));

		return $this->runFeature('onBeforeRender', array());
	}

	/**
	 * Executes after Joomla! has rendered its content and before returning it to the browser. Last chance to modify the
	 * document!
	 *
	 * @return  mixed
	 */
	public function onAfterRender()
	{
		return $this->runFeature('onAfterRender', array());
	}

	/**
	 * This is used by Admin Tools. It is the last even to run in the onAfterRender processing chain
	 *
	 * @return  mixed
	 */
	public function onAfterRenderLatebound()
	{
		return $this->runFeature('onAfterRenderLatebound', array());
	}

	/**
	 * Executes right after Joomla! has dispatched the application to the relevant component
	 *
	 * @return  mixed
	 */
	public function onAfterDispatch()
	{
		return $this->runFeature('onAfterDispatch', array());
	}

	/**
	 * Alias for onUserLoginFailure
	 *
	 * @param JAuthenticationResponse $response
	 *
	 * @return mixed
	 *
	 * @deprecated 3.2.0
	 */
	public function onLoginFailure($response)
	{
		return $this->runFeature('onUserLoginFailure', array($response));
	}

	/**
	 * Called when a user fails to log in
	 *
	 * @param $response
	 *
	 * @return mixed
	 */
	public function onUserLoginFailure($response)
	{
		return $this->runFeature('onUserLoginFailure', array($response));
	}

	/**
	 * Called when a user is logging out
	 *
	 * @param $parameters
	 * @param $options
	 *
	 * @return mixed
	 */
	public function onUserLogout($parameters, $options)
	{
		return $this->runFeature('onUserLogout', array($parameters, $options));
	}

	/**
	 * Alias for onUserLogin
	 *
	 * @param string $user
	 * @param array  $options
	 *
	 * @return mixed
	 */
	public function onLoginUser($user, $options)
	{
		return $this->runFeature('onUserLogin', array($user, $options));
	}

	public function onUserAuthorisationFailure($authorisation)
	{
		return $this->runFeature('onUserAuthorisationFailure', array($authorisation));
	}

	public function onUserLogin($user, $options)
	{
		return $this->runFeature('onUserLogin', array($user, $options));
	}

	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		return $this->runFeature('onUserAfterSave', array($user, $isnew, $success, $msg));
	}

	public function onUserBeforeSave($olduser, $isnew, $user)
	{
		return $this->runFeature('onUserBeforeSave', array($olduser, $isnew, $user));
	}

	/**
	 * Loads the component parameters model into $this->componentParams
	 *
	 * @return  void
	 */
	protected function loadComponentParameters()
	{
		// Load the components parameters
		JLoader::import('joomla.application.component.model');

		require_once JPATH_ADMINISTRATOR . '/components/com_admintools/Helper/Storage.php';

		$this->componentParams = Storage::getInstance();
	}

	/**
	 * Work around non-transparent proxy and reverse proxy IP issues
	 *
	 * @return  void
	 */
	protected function workaroundIP()
	{
		// IP workarounds are always disabled in the Core version
		if (!defined('ADMINTOOLS_PRO'))
		{
			require_once JPATH_ADMINISTRATOR . '/components/com_admintools/version.php';
		}

		if (!ADMINTOOLS_PRO)
		{
			return;
		}

		$enableWorkarounds = $this->componentParams->getValue('ipworkarounds', -1);

		// Upgrade from older versions (default: enable IP workarounds)
		if ($enableWorkarounds == -1)
		{
			$enableWorkarounds = 1;
			$this->componentParams->setValue('ipworkarounds', 1, true);
		}

		if (!$enableWorkarounds)
		{
			return;
		}

		if (!class_exists('FOF30\\Utils\\Ip'))
		{
			return;
		}

		Ip::setAllowIpOverrides($enableWorkarounds);
		Ip::workaroundIPIssues();
	}

	/**
	 * Loads the security exception handler object, if present
	 *
	 * @return  void
	 */
	protected function loadExceptionsHandler()
	{
		if (class_exists('AtsystemUtilExceptionshandler'))
		{
			$this->exceptionsHandler = new AtsystemUtilExceptionshandler($this->params, $this->componentParams);
		}
	}

	/**
	 * Loads the Admin Tools feature classes and register their hooks with this plugin
	 *
	 * @return  void
	 */
	protected function loadFeatures()
	{
		// Load all enabled features
		$di = new DirectoryIterator(__DIR__ . '/../feature');
		$features = array();

		/** @var DirectoryIterator $fileSpec */
		foreach ($di as $fileSpec)
		{
			if ($fileSpec->isDir())
			{
				continue;
			}

			// Get the filename minus the .php extension
			$fileName = $fileSpec->getFilename();
			$fileName = substr($fileName, 0, -4);

			if (in_array($fileName, array('interface', 'abstract')))
			{
				continue;
			}

			$className = 'AtsystemFeature' . ucfirst($fileName);

			if (!class_exists($className, true))
			{
				continue;
			}

			/** @var AtsystemFeatureAbstract $o */
			$o = new $className($this->app, $this->db, $this->params, $this->componentParams, $this->input, $this->exceptionsHandler, $this->exceptions, $this->skipFiltering, $this->container, $this);

			if (!$o->isEnabled())
			{
				continue;
			}

			$features[] = array($o->getLoadOrder(), $o);
		}

		// Make sure we have some enabled features
		if (empty($features))
		{
			return;
		}

		// Sort the features by load order
		uasort($features, function ($a, $b)
		{
			if ($a[0] == $b[0])
			{
				return 0;
			}

			return ($a[0] < $b[0]) ? -1 : 1;
		});

		foreach ($features as $featureDef)
		{
			$feature = $featureDef[1];

			$className = get_class($feature);

			$methods = get_class_methods($className);

			foreach ($methods as $method)
			{
				if (substr($method, 0, 2) != 'on')
				{
					continue;
				}

				if (!isset($this->featuresPerHook[$method]))
				{
					$this->featuresPerHook[$method] = array();
				}

				$this->featuresPerHook[$method][] = $feature;
			}
		}
	}

	/**
	 * Loads the GeoIP library if it's not already loaded and the plugin is enabled
	 *
	 * @return  void
	 */
	protected function loadGeoIpProvider()
	{
		// Load the GeoIP library if it's not already loaded
		if (!class_exists('AkeebaGeoipProvider'))
		{
			if (!JPluginHelper::isEnabled('system', 'akgeoip'))
			{
				return;
			}

			if (@file_exists(JPATH_PLUGINS . '/system/akgeoip/lib/akgeoip.php'))
			{
				if (@include_once JPATH_PLUGINS . '/system/akgeoip/lib/vendor/autoload.php')
				{
					@include_once JPATH_PLUGINS . '/system/akgeoip/lib/akgeoip.php';
				}
			}
		}
	}

	/**
	 * Load the applicable WAF exceptions for this request
	 */
	protected function loadWAFExceptions()
	{
		$container = \FOF30\Container\Container::getInstance('com_admintools');
		$jConfig   = $container->platform->getConfig();
		$isSEF     = $jConfig->get('sef', 0);

		$option = $this->input->getCmd('option', '');
		$view   = $this->input->getCmd('view', '');

		// If we have SEF URLs enabled and an empty $option (SEF not yet parsed) OR we have an option that does not
		// start with com_ we need to a different kind of processing. NB! If an option in the form of com_something is
		// provided we have a non-SEF URL running on a site with SEF URLs enabled.
		if (($isSEF && empty($option)) || (!empty($option) && substr($option, 0, 4) != 'com_'))
		{
			$this->loadWAFExceptionsSEF();
		}
		else
		{
			$Itemid = $this->input->getInt('Itemid', null);

			if (!empty($Itemid))
			{
				list($option, $view) = $this->loadMenuItem($Itemid, $option, $view);
			}

			$this->loadWAFExceptionsByOption($option, $view);
		}

		if (empty($this->exceptions))
		{
			$this->exceptions = [];
		}
		else
		{
			if (empty($this->exceptions[0]))
			{
				$this->skipFiltering = true;
			}
		}
	}

	protected function loadWAFExceptionsSEF()
	{
		// Do you have a fucktasting host like the one in ticket #25473 that crashes JUri if you access it
		// onAfterIntialize because the morons unset two fundamental server variables? If you do, no exceptions for you
		if (!isset($_SERVER) || (!isset($_SERVER['HTTP_HOST']) && !isset($_SERVER['SCRIPT_NAME'])))
		{
			return;
		}

		// Get the SEF URI path
		$uriPath = JUri::getInstance()->getPath();
		$uriPath = ltrim($uriPath, '/');

		// Do I have an index.php prefix?
		if (substr($uriPath, 0, 10) == 'index.php/')
		{
			$uriPath = substr($uriPath, 10);
		}

		// Get the URI path without the language prefix
		$uriPathNoLanguage = $uriPath;

		if ($this->container->platform->isFrontend())
		{
			/** @var \JApplicationSite $app */
			$app = \JFactory::getApplication();

			if ($app->getLanguageFilter())
			{
				jimport('joomla.language.helper');
				$languages = JLanguageHelper::getLanguages('lang_code');

				foreach($languages as $lang)
				{
					$langSefCode = $lang->sef . '/';

					if (strpos($uriPath, $langSefCode) === 0)
					{
						$uriPathNoLanguage = substr($uriPath, strlen($langSefCode));
					}
				}
			}
		}

		// Load all WAF exceptions for SEF URLs
		$db = $this->db;
		$this->exceptions = array();
		$exceptions = array();
		$view = $this->input->getCmd('view', '');

		$sql = $db->getQuery(true)
				  ->select('*')
				  ->from($db->qn('#__admintools_wafexceptions'))
				  ->where('NOT(' . $db->qn('option') . ' LIKE ' . $db->q('com_%') . ')');

		$db->setQuery($sql);

		try
		{
			$exceptions = $db->loadAssocList();
		}
		catch (Exception $e)
		{
		}

		foreach ($exceptions as $exception)
		{
			if($exception['option'])
			{
				if ((strpos($uriPathNoLanguage, $exception['option']) !== 0) && (strpos($uriPath, $exception['option']) !== 0))
				{
					continue;
				}
			}

			if (!empty($exception['view']) && ($view != $exception['view']))
			{
				continue;
			}

			$this->exceptions[] = $exception['query'];
		}
	}

	/**
	 * Loads WAF Exceptions by option and view (non-SEF URLs)
	 *
	 * @param   string  $option  Component, e.g. com_something
	 * @param   string  $view    View, e.g. foobar
	 *
	 * @return  void
	 */
	protected function loadWAFExceptionsByOption($option, $view)
	{
		$db = $this->db;

		$sql = $db->getQuery(true)
				  ->select($db->qn('query'))
				  ->from($db->qn('#__admintools_wafexceptions'));

		if (empty($option))
		{
			$sql->where(
				'(' . $db->qn('option') . ' IS NULL OR ' .
				$db->qn('option') . ' = ' . $db->q('')
				. ')'
			);
		}
		else
		{
			$sql->where(
				'(' . $db->qn('option') . ' IS NULL OR ' .
				$db->qn('option') . ' = ' . $db->q('') . ' OR ' .
				$db->qn('option') . ' = ' . $db->q($option)
				. ')'
			);
		}

		if (empty($view))
		{
			$sql->where(
				'(' . $db->qn('view') . ' IS NULL OR ' .
				$db->qn('view') . ' = ' . $db->q('')
				. ')'
			);
		}
		else
		{
			$sql->where(
				'(' . $db->qn('view') . ' IS NULL OR ' .
				$db->qn('view') . ' = ' . $db->q('') . ' OR ' .
				$db->qn('view') . ' = ' . $db->q($view)
				. ')'
			);
		}

		$sql->group($db->qn('query'))
			->order($db->qn('query') . ' ASC');

		$db->setQuery($sql);

		try
		{
			$this->exceptions = $db->loadColumn();
		}
		catch (Exception $e)
		{
		}
	}

	/**
	 * Loads a menu item and returns the effective option and view
	 *
	 * @param   int     $Itemid  The menu item ID to load
	 * @param   string  $option  The currently set option
	 * @param   string  $view    The currently set view
	 *
	 * @return  array  The new option and view as array($option, $view)
	 */
	protected function loadMenuItem($Itemid, $option, $view)
	{
		// Option and view already set, they will override the Itemid
		if (!empty($option) && !empty($view))
		{
			return array($option, $view);
		}

		// Load the menu item
		$menu = JFactory::getApplication()->getMenu()->getItem($Itemid);

		// Menu item does not exist, nothign to do
		if (!is_object($menu))
		{
			return array($option, $view);
		}

		// Remove "index.php?" and parse the link
		parse_str(str_replace('index.php?', '', $menu->link), $menuquery);

		// We use the option and view from the menu item only if they are not overridden in the request
		if (empty($option))
		{
			$option = array_key_exists('option', $menuquery) ? $menuquery['option'] : $option;
		}

		if (empty($view))
		{
			$view = array_key_exists('view', $menuquery) ? $menuquery['view'] : $view;
		}

		// Return the new option and view
		return array($option, $view);
	}

	/**
	 * Execute a feature which is already loaded.
	 *
	 * @param   string  $name
	 * @param   array   $arguments
	 *
	 * @return  mixed
	 */
	public function runFeature($name, array $arguments)
	{
		if (!isset($this->featuresPerHook[$name]))
		{
			return null;
		}

		$result = null;

		foreach ($this->featuresPerHook[$name] as $plugin)
		{
			if (method_exists($plugin, $name))
			{
				// Call_user_func_array is ~3 times slower than direct method calls.
				// See the on-line PHP documentation page of call_user_func_array for more information.
				switch (count($arguments))
				{
					case 0 :
						$result = $plugin->$name();
						break;
					case 1 :
						$result = $plugin->$name($arguments[0]);
						break;
					case 2:
						$result = $plugin->$name($arguments[0], $arguments[1]);
						break;
					case 3:
						$result = $plugin->$name($arguments[0], $arguments[1], $arguments[2]);
						break;
					case 4:
						$result = $plugin->$name($arguments[0], $arguments[1], $arguments[2], $arguments[3]);
						break;
					case 5:
						$result = $plugin->$name($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]);
						break;
					default:
						// Resort to using call_user_func_array for many segments
						$result = call_user_func_array(array($plugin, $name), $arguments);
				}
			}
		}

		return $result;
	}

	/**
	 * Execute a feature which is already loaded. The feature returns the boolean AND result of all of the features'
	 * results.
	 *
	 * @param   string  $name
	 * @param   bool    $default
	 * @param   array   $arguments
	 *
	 * @return  bool
	 */
	public function runBooleanFeature($name, $default, array $arguments)
	{
		$result = $default;

		if (!isset($this->featuresPerHook[$name]))
		{
			return $result;
		}

		if (!count($this->featuresPerHook[$name]))
		{
			return $result;
		}

		$result = true;

		foreach ($this->featuresPerHook[$name] as $plugin)
		{
			if (method_exists($plugin, $name))
			{
				// Call_user_func_array is ~3 times slower than direct method calls.
				// See the on-line PHP documentation page of call_user_func_array for more information.
				switch (count($arguments))
				{
					case 0 :
						$r = $plugin->$name();
						break;
					case 1 :
						$r = $plugin->$name($arguments[0]);
						break;
					case 2:
						$r = $plugin->$name($arguments[0], $arguments[1]);
						break;
					case 3:
						$r = $plugin->$name($arguments[0], $arguments[1], $arguments[2]);
						break;
					case 4:
						$r = $plugin->$name($arguments[0], $arguments[1], $arguments[2], $arguments[3]);
						break;
					case 5:
						$r = $plugin->$name($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]);
						break;
					default:
						// Resort to using call_user_func_array for many segments
						$r = call_user_func_array(array($plugin, $name), $arguments);
				}

				$result = $result && $r;
			}
		}

		return $result;
	}
}PK��#]�Nwy^^ system/admintools/admintools.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;

// Make sure Admin Tools is installed, otherwise bail out
if (!file_exists(JPATH_ADMINISTRATOR . '/components/com_admintools'))
{
	return;
}

// PHP version check
if (defined('PHP_VERSION'))
{
	$version = PHP_VERSION;
}
elseif (function_exists('phpversion'))
{
	$version = phpversion();
}
else
{
	$version = '5.0.0'; // all bets are off!
}

if (!version_compare($version, '5.4.0', '>='))
{
	return;
}

// Why, oh why, are you people using eAccelerator? Seriously, what's wrong with you, people?!
if (function_exists('eaccelerator_info'))
{
	$isBrokenCachingEnabled = true;

	if (function_exists('ini_get') && !ini_get('eaccelerator.enable'))
	{
		$isBrokenCachingEnabled = false;
	}

	if ($isBrokenCachingEnabled)
	{
		return;
	}
}

// Include and initialise Admin Tools System Plugin autoloader
if (!defined('ATSYSTEM_AUTOLOADER'))
{
	@include_once __DIR__ . '/autoloader.php';
}

if (!defined('ATSYSTEM_AUTOLOADER') || !class_exists('AdmintoolsAutoloaderPlugin'))
{
	return;
}

AdmintoolsAutoloaderPlugin::init();

// fnmatch() doesn't exist in non-POSIX systems :(
if (!function_exists('fnmatch'))
{
	function fnmatch($pattern, $string)
	{
		return @preg_match(
			'/^' . strtr(addcslashes($pattern, '/\\.+^$(){}=!<>|'),
				array('*' => '.*', '?' => '.?')) . '$/i', $string
		);
	}
}

// This is used during testing
if (defined('JDEBUG') && JDEBUG)
{
	if (file_exists(__DIR__ . '/phonymail.php'))
	{
		require_once __DIR__ . '/phonymail.php';
	}
}

// Include the standalone FOF 3.0 Date package
if (!class_exists('FOF30\Date\Date', true))
{
	include_once JPATH_LIBRARIES . '/fof30/Date/Date.php';
}

// Import main plugin file
if (!class_exists('AtsystemAdmintoolsMain', true))
{
	return;
}PK��#]�)��system/admintools/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]h9?HH system/admintools/admintools.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5.0" type="plugin" group="system" method="upgrade">
	<name>System - Admin Tools</name>
	<author>Nicholas K. Dionysopoulos</author>
	<authorEmail>nicholas@akeebabackup.com</authorEmail>
	<authorUrl>http://www.akeebabackup.com</authorUrl>
	<copyright>Copyright (c)2010-2017 Nicholas K. Dionysopoulos</copyright>
	<license>GNU General Public License version 3, or later</license>
	<creationDate>2017-05-18</creationDate>
	<version>4.2.0</version>
	<description>
		Handles URL redirections defined in Admin Tools, fends off common attacks
		and automates session table and cache clean-up
	</description>
	<files>
		<filename plugin="admintools">admintools.php</filename>
		<filename plugin="admintools">autoloader.php</filename>
		<folder>admintools</folder>
		<folder>feature</folder>
		<folder>util</folder>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_system_admintools.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_system_admintools.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field name="language_override" type="text" default="" size="5" label="ADMINTOOLS_LANGUAGE_OVERRIDE_LBL" description="ADMINTOOLS_LANGUAGE_OVERRIDE_DESC" />
				<field name="@spacer" type="spacer" default="" label="" description="" />

				<field name="sesoptimizer" type="list" default="0" label="ADMINTOOLS_SESOPT_LBL" description="ADMINTOOLS_SESOPT_DESC">
					<option value="0">JNo</option>
					<option value="1">JYes</option>
				</field>
				<field name="sesopt_freq" type="text" default="60" size="5" label="ADMINTOOLS_SESOPT_FREQ_LBL" description="ADMINTOOLS_SESOPT_FREQ_DESC" />

				<field name="@spacer" type="spacer" default="" label="" description="" />
				<field name="sescleaner" type="list" default="0" label="ADMINTOOLS_SESCLEANER_LBL" description="ADMINTOOLS_SESCLEANER_DESC">
					<option value="0">JNo</option>
					<option value="1">JYes</option>
				</field>
				<field name="ses_freq" type="text" default="60" size="5" label="ADMINTOOLS_SES_FREQ_LBL" description="ADMINTOOLS_SES_FREQ_DESC" />

				<field name="@spacer" type="spacer" default="" label="" description="" />
				<field name="cachecleaner" type="list" default="0" label="ADMINTOOLS_CACHECLEANER_LBL" description="ADMINTOOLS_CACHECLEANER_DESC">
					<option value="0">JNo</option>
					<option value="1">JYes</option>
				</field>
				<field name="cache_freq" type="text" default="1440" size="5" label="ADMINTOOLS_CACHE_FREQ_LBL" description="ADMINTOOLS_CACHE_FREQ_DESC" />

				<field name="@spacer" type="spacer" default="" label="" description="" />
				<field name="cacheexpire" type="list" default="0" label="ADMINTOOLS_CACHECEXPIRE_LBL" description="ADMINTOOLS_CACHECEXPIRE_DESC">
					<option value="0">JNo</option>
					<option value="1">JYes</option>
				</field>
				<field name="cacheexp_freq" type="text" default="60" size="5" label="ADMINTOOLS_CACHEEXP_FREQ_LBL" description="ADMINTOOLS_CACHEEXP_FREQ_DESC" />

				<field name="@spacer" type="spacer" default="" label="" description="" />
				<field name="cleantemp" type="list" default="0" label="ADMINTOOLS_CLEANTEMP_LBL" description="ADMINTOOLS_CLEANTEMP_DESC">
					<option value="0">JNo</option>
					<option value="1">JYes</option>
				</field>
				<field name="cleantemp_freq" type="text" default="60" size="5" label="ADMINTOOLS_CLEANTEMP_FREQ_LBL" description="ADMINTOOLS_CLEANTEMP_FREQ_DESC" />

				<field name="@spacer" type="spacer" default="" label="" description="" />
				<field name="deleteinactive" type="list" default="0" label="ADMINTOOLS_DELETEINACTIVE_LBL" description="ADMINTOOLS_DELETEINACTIVE_DESC">
					<option value="0">ADMINTOOLS_DELETEINACTIVE_NONE</option>
					<option value="1">ADMINTOOLS_DELETEINACTIVE_NOTACTIVATED</option>
					<option value="2">ADMINTOOLS_DELETEINACTIVE_BLOCKED</option>
					<option value="3">ADMINTOOLS_DELETEINACTIVE_BOTH</option>
				</field>
				<field name="deleteinactive_days" type="text" default="7" size="5" label="ADMINTOOLS_DELETEINACTIVE_DAYS_LBL" description="ADMINTOOLS_DELETEINACTIVE_DAYS_DESC" />

				<field name="@spacer" type="spacer" default="" label="" description="" />
				<field name="maxlogentries" type="text" default="0" label="ADMINTOOLS_MAXLOGENTRIES_LBL" description="ADMINTOOLS_MAXLOGENTRIES_DESC" />
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��system/logrotation/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]X�/9��"system/logrotation/logrotation.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.logrotation
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;

/**
 * Joomla! Log Rotation plugin
 *
 * Rotate the log files created by Joomla core
 *
 * @since  3.9.0
 */
class PlgSystemLogrotation extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * The log check and rotation code is triggered after the page has fully rendered.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRender()
	{
		// Get the timeout as configured in plugin parameters

		/** @var \Joomla\Registry\Registry $params */
		$cache_timeout = (int) $this->params->get('cachetimeout', 30);
		$cache_timeout = 24 * 3600 * $cache_timeout;
		$logsToKeep    = (int) $this->params->get('logstokeep', 1);

		// Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if ((abs($now - $last) < $cache_timeout))
		{
			return;
		}

		// Update last run status
		$this->params->set('lastrun', $now);

		$db    = $this->db;
		$query = $db->getQuery(true)
			->update($db->qn('#__extensions'))
			->set($db->qn('params') . ' = ' . $db->q($this->params->toString('JSON')))
			->where($db->qn('type') . ' = ' . $db->q('plugin'))
			->where($db->qn('folder') . ' = ' . $db->q('system'))
			->where($db->qn('element') . ' = ' . $db->q('logrotation'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		// Get the log path
		$logPath = Path::clean($this->app->get('log_path'));

		// Invalid path, stop processing further
		if (!is_dir($logPath))
		{
			return;
		}

		$logFiles = $this->getLogFiles($logPath);

		// Sort log files by version number in reserve order
		krsort($logFiles, SORT_NUMERIC);

		foreach ($logFiles as $version => $files)
		{
			if ($version >= $logsToKeep)
			{
				// Delete files which has version greater than or equals $logsToKeep
				foreach ($files as $file)
				{
					File::delete($logPath . '/' . $file);
				}
			}
			else
			{
				// For files which has version smaller than $logsToKeep, rotate (increase version number)
				foreach ($files as $file)
				{
					$this->rotate($logPath, $file, $version);
				}
			}
		}
	}

	/**
	 * Get log files from log folder
	 *
	 * @param   string  $path  The folder to get log files
	 *
	 * @return  array   The log files in the given path grouped by version number (not rotated files has number 0)
	 *
	 * @since   3.9.0
	 */
	private function getLogFiles($path)
	{
		$logFiles = array();
		$files    = Folder::files($path, '\.php$');

		foreach ($files as $file)
		{
			$parts    = explode('.', $file);

			/*
			 * Rotated log file has this filename format [VERSION].[FILENAME].php. So if $parts has at least 3 elements
			 * and the first element is a number, we know that it's a rotated file and can get it's current version
			 */
			if (count($parts) >= 3 && is_numeric($parts[0]))
			{
				$version = (int) $parts[0];
			}
			else
			{
				$version = 0;
			}

			if (!isset($logFiles[$version]))
			{
				$logFiles[$version] = array();
			}

			$logFiles[$version][] = $file;
		}

		return $logFiles;
	}

	/**
	 * Method to rotate (increase version) of a log file
	 *
	 * @param   string  $path            Path to file to rotate
	 * @param   string  $filename        Name of file to rotate
	 * @param   int     $currentVersion  The current version number
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	private function rotate($path, $filename, $currentVersion)
	{
		if ($currentVersion === 0)
		{
			$rotatedFile = $path . '/1.' . $filename;
		}
		else
		{
			/*
			 * Rotated log file has this filename format [VERSION].[FILENAME].php. To rotate it, we just need to explode
			 * the filename into an array, increase value of first element (keep version) and implode it back to get the
			 * rotated file name
			 */
			$parts    = explode('.', $filename);
			$parts[0] = $currentVersion + 1;

			$rotatedFile = $path . '/' . implode('.', $parts);
		}

		File::move($path . '/' . $filename, $rotatedFile);
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1))
	{
		$conf = JFactory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR . '/cache' :
							$conf->get('cache_path', JPATH_SITE . '/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
PK��#]�g�##"system/logrotation/logrotation.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="system" method="upgrade">
	<name>plg_system_logrotation</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_SYSTEM_LOGROTATION_XML_DESCRIPTION</description>
	<files>
		<filename plugin="logrotation">logrotation.php</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB.plg_system_logrotation.ini</language>
		<language tag="en-GB">en-GB.plg_system_logrotation.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="cachetimeout"
					type="integer"
					label="PLG_SYSTEM_LOGROTATION_CACHETIMEOUT_LABEL"
					description="PLG_SYSTEM_LOGROTATION_CACHETIMEOUT_DESC"
					first="0"
					last="120"
					step="1"
					default="30"
					filter="int"
					validate="number"
				/>

				<field
					name="logstokeep"
					type="integer"
					label="PLG_SYSTEM_LOGROTATION_LOGSTOKEEP_LABEL"
					description="PLG_SYSTEM_LOGROTATION_LOGSTOKEEP_DESC"
					first="1"
					last="10"
					step="1"
					default="1"
					filter="int"
					validate="number"
				/>

				<field
					name="lastrun"
					type="hidden"
					default="0"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]W�ާ��:system/rsformdeletesubmissions/rsformdeletesubmissions.phpnu�[���<?php
/**
 * @package RSForm! Pro
 * @copyright (C) 2007-2019 www.rsjoomla.com
 * @license GPL, http://www.gnu.org/copyleft/gpl.html
 */

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

/**
 * RSForm! Pro Delete Submissions System Plugin
 */
class plgSystemRsformdeletesubmissions extends JPlugin
{
    public function onAfterInitialise()
    {
        if (!file_exists(JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsform.php'))
        {
            return false;
        }

        require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsform.php';

        $now        = JFactory::getDate()->toUnix();
        $config     = RSFormProConfig::getInstance();
        $last_run   = $config->get('deleteafter.last_run', 0);
        $interval   = $config->get('deleteafter.interval', 10);
        
        if ($last_run + ($interval * 60) > $now)
        {
            return false;
        }

        $config->set('deleteafter.last_run', $now);

		$db = JFactory::getDbo();
		
		$query = $db->getQuery(true)
			->select($db->qn('FormId'))
			->select($db->qn('DeleteSubmissionsAfter'))
			->from($db->qn('#__rsform_forms'))
			->where($db->qn('DeleteSubmissionsAfter') . ' > ' . $db->q(0));
		
		if ($forms = $db->setQuery($query)->loadObjectList())
		{
			foreach ($forms as $form)
			{
				$date = JFactory::getDate()->modify("-{$form->DeleteSubmissionsAfter} days")->toSql();
				// Find all Submission IDs that need to get removed
				$query->clear()
					->select($db->qn('SubmissionId'))
					->from($db->qn('#__rsform_submissions'))
					->where($db->qn('FormId') . ' = ' . $db->q($form->FormId))
					->where($db->qn('DateSubmitted') . ' < ' . $db->q($date));
				
				if ($submissions = $db->setQuery($query)->loadColumn())
				{
                    require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php';

                    RSFormProSubmissionsHelper::deleteSubmissions($submissions);
				}
			}
		}
    }

    public function onPreprocessMenuItems($context, &$items, $params = null, $enabled = true)
    {
        $user = JFactory::getUser();

        foreach ($items as $i => $item)
        {
            if ($item->element == 'com_rsform')
            {
                if (
                    ($item->title == 'COM_RSFORM_MANAGE_FORMS' && !$user->authorise('forms.manage', 'com_rsform')) ||
                    ($item->title == 'COM_RSFORM_MANAGE_SUBMISSIONS' && !$user->authorise('submissions.manage', 'com_rsform')) ||
                    ($item->title == 'COM_RSFORM_MANAGE_DIRECTORY_SUBMISSIONS' && !$user->authorise('directory.manage', 'com_rsform')) ||
                    ($item->title == 'COM_RSFORM_CONFIGURATION' && !$user->authorise('core.admin', 'com_rsform')) ||
                    ($item->title == 'COM_RSFORM_BACKUP_SCREEN' && !$user->authorise('backuprestore.manage', 'com_rsform')) ||
					($item->title == 'COM_RSFORM_RESTORE_SCREEN' && !$user->authorise('backuprestore.manage', 'com_rsform'))
                )
                {
                    unset($items[$i]);
                }
            }
        }
    }
}PK��#]�/�zz:system/rsformdeletesubmissions/rsformdeletesubmissions.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7.0" type="plugin" group="system" method="upgrade">
	<name>System - RSForm! Pro Delete Submissions</name>
	<author>RSJoomla!</author>
	<creationDate>April 2018</creationDate>
	<copyright>(C) 2007-2019 www.rsjoomla.com</copyright>
	<license>GNU General Public License</license>
	<authorEmail>support@rsjoomla.com</authorEmail>
	<authorUrl>www.rsjoomla.com</authorUrl>
	<version>1.0.0</version>
	<description><![CDATA[PLG_SYSTEM_RSFORMDELETESUBMISSIONS_DESC]]></description>

	<updateservers>
        <server type="extension" priority="1" name="System - RSForm! Pro Delete Submissions">https://www.rsjoomla.com/updates/com_rsform/Other/plg_rsformdeletesubmissions.xml</server>
    </updateservers>

	<files>
		<filename plugin="rsformdeletesubmissions">rsformdeletesubmissions.php</filename>
		<filename>index.html</filename>
	</files>
	<languages folder="language/en-GB">
		<language tag="en-GB">en-GB.plg_system_rsformdeletesubmissions.ini</language>
		<language tag="en-GB">en-GB.plg_system_rsformdeletesubmissions.sys.ini</language>
	</languages>
</extension>PK��#]�)��(system/rsformdeletesubmissions/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�#o,,)system/rsformdeletesubmissions/index.htmlnu�[���<html><body bgcolor="#FFFFFF"></body></html>PK��#](���*�*0system/atoolsjupdatecheck/atoolsjupdatecheck.phpnu&1i�<?php
/**
 * @package   AdminTools
 * @copyright Copyright (c)2010-2017 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 */

use Akeeba\AdminTools\Admin\Helper\Storage;

defined('_JEXEC') or die;

// Uncomment the following line to enable debug mode
// define('ATJUPDATEDEBUG',1);

// PHP version check
if (defined('PHP_VERSION'))
{
	$version = PHP_VERSION;
}
elseif (function_exists('phpversion'))
{
	$version = phpversion();
}
else
{
	$version = '5.0.0'; // all bets are off!
}

if (!version_compare($version, '5.3.4', 'ge'))
{
	return;
}

JLoader::import('joomla.application.plugin');

class plgSystemAtoolsjupdatecheck extends JPlugin
{
	public function onAfterRender()
	{
		// Get the timeout for Joomla! updates
		JLoader::import('joomla.application.component.helper');

		$component     = JComponentHelper::getComponent('com_installer');
		$params        = $component->params;

		$cache_timeout = $params->get('cachetimeout', 6, 'int');
		$cache_timeout = 3600 * $cache_timeout;

		// Do we need to run?
		// Store the last run timestamp inside out table
		$db = JFactory::getDbo();

		$query = $db->getQuery(true)
			->select($db->qn('value'))
			->from($db->qn('#__admintools_storage'))
			->where($db->qn('key') . ' = ' . $db->q('atoolsjupdatecheck_lastrun'));

		$last = (int)$db->setQuery($query)->loadResult();
		$now  = time();

		if (!defined('ATJUPDATEDEBUG') && (abs($now - $last) < $cache_timeout))
		{
			return;
		}

		// Update last run status
		// If I have the time of the last run, I can update, otherwise insert
		if ($last)
		{
			$query = $db->getQuery(true)
				->update($db->qn('#__admintools_storage'))
				->set($db->qn('value') . ' = ' . $db->q($now))
				->where($db->qn('key') . ' = ' . $db->q('atoolsjupdatecheck_lastrun'));
		}
		else
		{
			$query = $db->getQuery(true)
				->insert($db->qn('#__admintools_storage'))
				->columns(array($db->qn('key'), $db->qn('value')))
				->values($db->q('atoolsjupdatecheck_lastrun') . ', ' . $db->q($now));
		}

		try
		{
			$result = $db->setQuery($query)->execute();
		}
		catch (Exception $exc)
		{
			$result = false;
		}

		if (!$result)
		{
			return;
		}

		// This is the extension ID for Joomla! itself
		$eid = 700;

		// Get any available updates
		$updater = JUpdater::getInstance();
		$results = $updater->findUpdates(array($eid), $cache_timeout);

		if (!$results)
		{
			return;
		}

		require_once JPATH_ADMINISTRATOR . '/components/com_installer/models/update.php';

		$model = JModelLegacy::getInstance('Update', 'InstallerModel');

		$model->setState('filter.extension_id', $eid);
		$updates = $model->getItems();

		if (empty($updates))
		{
			return;
		}

		$update = array_pop($updates);

		// Check the version. It must be different than the current version.
		if (version_compare($update->version, JVERSION, 'eq'))
		{
			return;
		}

		// If we're here, we have updates. Let's create an OTP.
		$uri  = JUri::base();
		$uri  = rtrim($uri, '/');

		$uri .= (substr($uri, -13) != 'administrator') ? '/administrator/' : '/';

		$link = 'index.php?option=com_joomlaupdate';

		$superAdmins     = array();
		$superAdminEmail = $this->params->get('email', '');

		if (!empty($superAdminEmail))
		{
			$superAdmins = $this->_getSuperAdministrators($superAdminEmail);
		}

		if (empty($superAdmins))
		{
			$superAdmins = $this->_getSuperAdministrators();
		}

		if (empty($superAdmins))
		{
			return;
		}

		$this->loadLanguage();
		$email_subject = <<<ENDSUBJECT
THIS EMAIL IS SENT FROM YOUR SITE "[SITENAME]" - Update available
ENDSUBJECT;


			$autoLoginReminder = <<< ALREND
Visiting this link will require you to enter your login credentials (typically
your username and password) into your site's administrator login page in order
to initiate the update process. If you are not sure about the legitimacy of
this email message we strongly recommend you to visit your site's
administrator page manually, log in, and check for the availability of updates
yourself.

ALREND;

		$email_body = <<<ENDBODY
This email IS NOT sent by Joomla.org or Akeeba Ltd. It is sent automatically
by your own site, [SITENAME]

================================================================================
UPDATE INFORMATION
================================================================================

Your site has determined that there is an updated version of Joomla!
available for download.

Joomla! version currently installed:        [CURVERSION]
Joomla! version available for installation: [NEWVERSION]

This email is sent to you by your site to remind you of this fact. The authors
of Joomla! (Open Source Matters) or Admin Tools (Akeeba Ltd) will not contact
you about available updates of Joomla!.

================================================================================
UPDATE INSTRUCTIONS
================================================================================

To install the update on [SITENAME] please click the following link. (If the URL
is not a link, simply copy & paste it to your browser).

Update link: [LINK]

$autoLoginReminder

================================================================================
WHY AM I RECEIVING THIS EMAIL?
================================================================================

This email has been automatically sent by a plugin you, or the person who built
or manages your site, has installed and explicitly activated. This plugin looks
for updated versions of Joomla! and sends an email notification to all Super
Users. You will receive several similar emails from your site, up to 6 times
per day, until you either update the software or disable these emails.

To disable these emails, please unpublish the 'System - Joomla! Update Email'
plugin in the Plugin Manager on your site.

If you do not understand what this means, please do not contact the authors of
Joomla! or Admin Tools. They are NOT sending you this email and they cannot
help you. Instead, please contact the person who built or manages your site.

If you are the person who built or manages your website, please note that you
activated the update email notification feature during Admin Tools' first run,
by clicking on a check box with a clear explanation of how this feature works
printed under it.

================================================================================
WHO SENT ME THIS EMAIL?
================================================================================

This email is sent to you by your own site, [SITENAME]

ENDBODY;

		$newVersion = $update->version;

		$jVersion = new JVersion;
		$currentVersion = $jVersion->getShortVersion();

		$jconfig = JFactory::getConfig();
		$sitename = $jconfig->get('sitename');

		$substitutions = array(
			'[NEWVERSION]' => $newVersion,
			'[CURVERSION]' => $currentVersion,
			'[SITENAME]'   => $sitename
		);

		// If Admin Tools Professional is installed, fetch the administrator secret key as well
		$adminpw   = '';
		$helperFile = JPATH_ROOT . '/administrator/components/com_admintools/Helper/Storage.php';

		if (@file_exists($helperFile))
		{
			include_once $helperFile;

			$model   = Storage::getInstance();
			$adminpw = $model->getValue('adminpw', '');
		}

		foreach ($superAdmins as $sa)
		{
			$emaillink = $uri . $link;

			if (!empty($adminpw))
			{
				$emaillink .= '&' . urlencode($adminpw);
			}

			$substitutions['[LINK]'] = $emaillink;

			foreach ($substitutions as $k => $v)
			{
				$email_subject = str_replace($k, $v, $email_subject);
				$email_body = str_replace($k, $v, $email_body);
			}

			try
			{
				$mailer   = JFactory::getMailer();
				$mailfrom = $jconfig->get('mailfrom');
				$fromname = $jconfig->get('fromname');

				// This line is required because SpamAssassin is BROKEN
				$mailer->Priority = 3;

				$mailer->setSender(array($mailfrom, $fromname));

				if (empty($sa->email))
				{
					throw new RuntimeException('This Super User has no email. Say what?!', 500);
				}

				if ($mailer->addRecipient($sa->email) === false)
				{
					throw new RuntimeException('What do you know, the Super User email is wrong.', 500);
				}

				$mailer->setSubject($email_subject);
				$mailer->setBody($email_body);
				$mailer->Send();
			}
			catch (Exception $e)
			{
				// Joomla! 3.5 and later throw an exception when crap happens instead of suppressing it and returning false
			}
		}
	}

	/**
	 * Returns the Super Users email information. If you provide a comma separated $email list
	 * we will check that these emails do belong to Super Users and that they have not blocked
	 * system emails.
	 *
	 * @param   null|string  $email  A list of Super Users to email
	 *
	 * @return  array  The list of Super User emails
	 */
	private function _getSuperAdministrators($email = null)
	{
		// Get a reference to the database object
		$db = JFactory::getDbo();

		// Convert the email list to an array
		if (!empty($email))
		{
			$temp = explode(',', $email);
			$emails = array();

			foreach ($temp as $entry)
			{
				$entry = trim($entry);
				$emails[] = $db->q($entry);
			}

			$emails = array_unique($emails);
		}
		else
		{
			$emails = array();
		}

		// Get a list of groups which have Super User privileges
		$ret = array();

		try
		{
			$query = $db->getQuery(true)
				->select($db->qn('rules'))
				->from($db->qn('#__assets'))
				->where($db->qn('parent_id') . ' = ' . $db->q(0));
			$db->setQuery($query, 0, 1);
			$rulesJSON	 = $db->loadResult();
			$rules		 = json_decode($rulesJSON, true);

			$rawGroups = $rules['core.admin'];
			$groups = array();

			if (empty($rawGroups))
			{
				return $ret;
			}

			foreach ($rawGroups as $g => $enabled)
			{
				if ($enabled)
				{
					$groups[] = $db->q($g);
				}
			}

			if (empty($groups))
			{
				return $ret;
			}
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		// Get the user IDs of users belonging to the SA groups
		try
		{
			$query = $db->getQuery(true)
				->select($db->qn('user_id'))
				->from($db->qn('#__user_usergroup_map'))
				->where($db->qn('group_id') . ' IN(' . implode(',', $groups) . ')' );
			$db->setQuery($query);
			$rawUserIDs = $db->loadColumn(0);

			if (empty($rawUserIDs))
			{
				return $ret;
			}

			$userIDs = array();

			foreach ($rawUserIDs as $id)
			{
				$userIDs[] = $db->q($id);
			}
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		// Get the user information for the Super Administrator users
		try
		{
			$query = $db->getQuery(true)
				->select(array(
					$db->qn('id'),
					$db->qn('username'),
					$db->qn('email'),
				))->from($db->qn('#__users'))
				->where($db->qn('id') . ' IN(' . implode(',', $userIDs) . ')')
				->where($db->qn('sendEmail') . ' = ' . $db->q('1'));

			if (!empty($emails))
			{
				$query->where($db->qn('email') . 'IN(' . implode(',', $emails) . ')');
			}

			$db->setQuery($query);
			$ret = $db->loadObjectList();
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		return $ret;
	}
}PK��#]��7��0system/atoolsjupdatecheck/atoolsjupdatecheck.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5.0" type="plugin" group="system" method="upgrade">
	<name>System - Admin Tools Joomla! Update Email</name>
	<author>Nicholas K. Dionysopoulos</author>
	<authorEmail>nicholas@dionysopoulos.me</authorEmail>
	<authorUrl>http://www.akeebabackup.com</authorUrl>
	<copyright>Copyright (c)2010-2017 Nicholas K. Dionysopoulos</copyright>
	<license>GNU General Public License version 3, or later</license>
	<creationDate>2011-05-26</creationDate>
	<version>1.0</version>
	<description>PLG_ATOOLSJUPDATECHECK_DESCRIPTION</description>
	<files>
		<filename plugin="atoolsjupdatecheck">atoolsjupdatecheck.php</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_system_atoolsjupdatecheck.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_system_atoolsjupdatecheck.sys.ini</language>
	</languages>
	<params>
		<param name="language_override" type="text" default="" size="5"
			   label="PLG_ATOOLSJUPDATECHECK_LANGUAGE_OVERRIDE_LBL"
			   description="PLG_ATOOLSJUPDATECHECK_LANGUAGE_OVERRIDE_DESC"/>
	</params>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field name="email" type="text" default="" size="40" label="PLG_ATOOLSJUPDATECHECK_EMAIL_LBL"
					   description="PLG_ATOOLSJUPDATECHECK_EMAIL_DESC"/>
				<field name="lastrun" type="hidden" default="0" size="15"/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��#system/atoolsjupdatecheck/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]~���system/log/log.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.log
 *
 * @copyright   (C) 2007 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! System Logging Plugin.
 *
 * @since  1.5
 */
class PlgSystemLog extends JPlugin
{
	/**
	 * Called if user fails to be logged in.
	 *
	 * @param   array  $response  Array of response data.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onUserLoginFailure($response)
	{
		$errorlog = array();

		switch ($response['status'])
		{
			case JAuthentication::STATUS_SUCCESS:
				$errorlog['status']  = $response['type'] . ' CANCELED: ';
				$errorlog['comment'] = $response['error_message'];
				break;

			case JAuthentication::STATUS_FAILURE:
				$errorlog['status']  = $response['type'] . ' FAILURE: ';

				if ($this->params->get('log_username', 0))
				{
					$errorlog['comment'] = $response['error_message'] . ' ("' . $response['username'] . '")';
				}
				else
				{
					$errorlog['comment'] = $response['error_message'];
				}
				break;

			default:
				$errorlog['status']  = $response['type'] . ' UNKNOWN ERROR: ';
				$errorlog['comment'] = $response['error_message'];
				break;
		}

		JLog::addLogger(array(), JLog::INFO);

		try
		{
			JLog::add($errorlog['comment'], JLog::INFO, $errorlog['status']);
		}
		catch (Exception $e)
		{
			// If the log file is unwriteable during login then we should not go to the error page
			return;
		}
	}
}
PK��#]�$K��system/log/log.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_log</name>
	<author>Joomla! Project</author>
	<creationDate>April 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_LOG_XML_DESCRIPTION</description>
	<files>
		<filename plugin="log">log.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_log.ini</language>
		<language tag="en-GB">en-GB.plg_system_log.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="log_username"
					type="radio"
					label="PLG_SYSTEM_LOG_FIELD_LOG_USERNAME_LABEL"
					description="PLG_SYSTEM_LOG_FIELD_LOG_USERNAME_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��system/log/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]n*mf  system/sef/sef.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_sef</name>
	<author>Joomla! Project</author>
	<creationDate>December 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEF_XML_DESCRIPTION</description>
	<files>
		<filename plugin="sef">sef.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_sef.ini</language>
		<language tag="en-GB">en-GB.plg_system_sef.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="domain"
					type="url"
					label="PLG_SEF_DOMAIN_LABEL"
					description="PLG_SEF_DOMAIN_DESCRIPTION"
					hint="https://www.example.com"
					filter="url"
					validate="url"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]?>� ��system/sef/sef.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.sef
 *
 * @copyright   (C) 2007 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! SEF Plugin.
 *
 * @since  1.5
 */
class PlgSystemSef extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.5
	 */
	protected $app;

	/**
	 * Add the canonical uri to the head.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	public function onAfterDispatch()
	{
		$doc = $this->app->getDocument();

		if (!$this->app->isClient('site') || $doc->getType() !== 'html')
		{
			return;
		}

		$sefDomain = $this->params->get('domain', false);

		// Don't add a canonical html tag if no alternative domain has added in SEF plugin domain field.
		if (empty($sefDomain))
		{
			return;
		}

		// Check if a canonical html tag already exists (for instance, added by a component).
		$canonical = '';

		foreach ($doc->_links as $linkUrl => $link)
		{
			if (isset($link['relation']) && $link['relation'] === 'canonical')
			{
				$canonical = $linkUrl;
				break;
			}
		}

		// If a canonical html tag already exists get the canonical and change it to use the SEF plugin domain field.
		if (!empty($canonical))
		{
			// Remove current canonical link.
			unset($doc->_links[$canonical]);

			// Set the current canonical link but use the SEF system plugin domain field.
			$canonical = $sefDomain . JUri::getInstance($canonical)->toString(array('path', 'query', 'fragment'));
		}
		// If a canonical html doesn't exists already add a canonical html tag using the SEF plugin domain field.
		else
		{
			$canonical = $sefDomain . JUri::getInstance()->toString(array('path', 'query', 'fragment'));
		}

		// Add the canonical link.
		$doc->addHeadLink(htmlspecialchars($canonical), 'canonical');
	}

	/**
	 * Convert the site URL to fit to the HTTP request.
	 *
	 * @return  void
	 */
	public function onAfterRender()
	{
		if (!$this->app->isClient('site'))
		{
			return;
		}

		// Replace src links.
		$base   = JUri::base(true) . '/';
		$buffer = $this->app->getBody();

		// For feeds we need to search for the URL with domain.
		$prefix = $this->app->getDocument()->getType() === 'feed' ? JUri::root() : '';

		// Replace index.php URI by SEF URI.
		if (strpos($buffer, 'href="' . $prefix . 'index.php?') !== false)
		{
			preg_match_all('#href="' . $prefix . 'index.php\?([^"]+)"#m', $buffer, $matches);

			foreach ($matches[1] as $urlQueryString)
			{
				$buffer = str_replace(
					'href="' . $prefix . 'index.php?' . $urlQueryString . '"',
					'href="' . trim($prefix, '/') . JRoute::_('index.php?' . $urlQueryString) . '"',
					$buffer
				);
			}

			$this->checkBuffer($buffer);
		}

		// Check for all unknown protocols (a protocol must contain at least one alphanumeric character followed by a ":").
		$protocols  = '[a-zA-Z0-9\-]+:';
		$attributes = array('href=', 'src=', 'poster=');

		foreach ($attributes as $attribute)
		{
			if (strpos($buffer, $attribute) !== false)
			{
				$regex  = '#\s' . $attribute . '"(?!/|' . $protocols . '|\#|\')([^"]*)"#m';
				$buffer = preg_replace($regex, ' ' . $attribute . '"' . $base . '$1"', $buffer);
				$this->checkBuffer($buffer);
			}
		}

		if (strpos($buffer, 'srcset=') !== false)
		{
			$regex = '#\s+srcset="([^"]+)"#m';

			$buffer = preg_replace_callback(
				$regex,
				function ($match) use ($base, $protocols)
				{
					preg_match_all('#(?:[^\s]+)\s*(?:[\d\.]+[wx])?(?:\,\s*)?#i', $match[1], $matches);

					foreach ($matches[0] as &$src)
					{
						$src = preg_replace('#^(?!/|' . $protocols . '|\#|\')(.+)#', $base . '$1', $src);
					}

					return ' srcset="' . implode($matches[0]) . '"';
				},
				$buffer
			);

			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in javascript window open events.
		if (strpos($buffer, 'window.open(') !== false)
		{
			$regex  = '#onclick="window.open\(\'(?!/|' . $protocols . '|\#)([^/]+[^\']*?\')#m';
			$buffer = preg_replace($regex, 'onclick="window.open(\'' . $base . '$1', $buffer);
			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in onmouseover and onmouseout attributes.
		$attributes = array('onmouseover=', 'onmouseout=');

		foreach ($attributes as $attribute)
		{
			if (strpos($buffer, $attribute) !== false)
			{
				$regex  = '#' . $attribute . '"this.src=([\']+)(?!/|' . $protocols . '|\#|\')([^"]+)"#m';
				$buffer = preg_replace($regex, $attribute . '"this.src=$1' . $base . '$2"', $buffer);
				$this->checkBuffer($buffer);
			}
		}

		// Replace all unknown protocols in CSS background image.
		if (strpos($buffer, 'style=') !== false)
		{
			$regex_url  = '\s*url\s*\(([\'\"]|\&\#0?3[49];)?(?!/|\&\#0?3[49];|' . $protocols . '|\#)([^\)\'\"]+)([\'\"]|\&\#0?3[49];)?\)';
			$regex  = '#style=\s*([\'\"])(.*):' . $regex_url . '#m';
			$buffer = preg_replace($regex, 'style=$1$2: url($3' . $base . '$4$5)', $buffer);
			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in OBJECT param tag.
		if (strpos($buffer, '<param') !== false)
		{
			// OBJECT <param name="xx", value="yy"> -- fix it only inside the <param> tag.
			$regex  = '#(<param\s+)name\s*=\s*"(movie|src|url)"[^>]\s*value\s*=\s*"(?!/|' . $protocols . '|\#|\')([^"]*)"#m';
			$buffer = preg_replace($regex, '$1name="$2" value="' . $base . '$3"', $buffer);
			$this->checkBuffer($buffer);

			// OBJECT <param value="xx", name="yy"> -- fix it only inside the <param> tag.
			$regex  = '#(<param\s+[^>]*)value\s*=\s*"(?!/|' . $protocols . '|\#|\')([^"]*)"\s*name\s*=\s*"(movie|src|url)"#m';
			$buffer = preg_replace($regex, '<param value="' . $base . '$2" name="$3"', $buffer);
			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in OBJECT tag.
		if (strpos($buffer, '<object') !== false)
		{
			$regex  = '#(<object\s+[^>]*)data\s*=\s*"(?!/|' . $protocols . '|\#|\')([^"]*)"#m';
			$buffer = preg_replace($regex, '$1data="' . $base . '$2"', $buffer);
			$this->checkBuffer($buffer);
		}

		// Use the replaced HTML body.
		$this->app->setBody($buffer);
	}

	/**
	 * Check the buffer.
	 *
	 * @param   string  $buffer  Buffer to be checked.
	 *
	 * @return  void
	 */
	private function checkBuffer($buffer)
	{
		if ($buffer === null)
		{
			switch (preg_last_error())
			{
				case PREG_BACKTRACK_LIMIT_ERROR:
					$message = 'PHP regular expression limit reached (pcre.backtrack_limit)';
					break;
				case PREG_RECURSION_LIMIT_ERROR:
					$message = 'PHP regular expression limit reached (pcre.recursion_limit)';
					break;
				case PREG_BAD_UTF8_ERROR:
					$message = 'Bad UTF8 passed to PCRE function';
					break;
				default:
					$message = 'Unknown PCRE error calling PCRE function';
			}

			throw new RuntimeException($message);
		}
	}

	/**
	 * Replace the matched tags.
	 *
	 * @param   array  &$matches  An array of matches (see preg_match_all).
	 *
	 * @return  string
	 *
	 * @deprecated  4.0  No replacement.
	 */
	protected static function route(&$matches)
	{
		JLog::add(__METHOD__ . ' is deprecated, no replacement.', JLog::WARNING, 'deprecated');

		$url   = $matches[1];
		$url   = str_replace('&amp;', '&', $url);
		$route = JRoute::_('index.php?' . $url);

		return 'href="' . $route;
	}
}
PK��#]�)��system/sef/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��system/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��system/stats/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�+Nbbsystem/stats/stats.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin" group="system" method="upgrade">
	<name>plg_system_stats</name>
	<author>Joomla! Project</author>
	<creationDate>November 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.5.0</version>
	<description>PLG_SYSTEM_STATS_XML_DESCRIPTION</description>
	<files>
		<folder>field</folder>
		<folder>layouts</folder>
		<filename plugin="stats">stats.php</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_system_stats.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_system_stats.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="data"
					type="plgsystemstats.data"
					label=""
				/>

				<field
					name="unique_id"
					type="plgsystemstats.uniqueid"
					label="PLG_SYSTEM_STATS_UNIQUE_ID_LABEL"
					description="PLG_SYSTEM_STATS_UNIQUE_ID_DESC"
					size="10"
				/>

				<field
					name="interval"
					type="number"
					label="PLG_SYSTEM_STATS_INTERVAL_LABEL"
					description="PLG_SYSTEM_STATS_INTERVAL_DESC"
					filter="integer"
					default="12"
				/>

				<field
					name="mode"
					type="list"
					label="PLG_SYSTEM_STATS_MODE_LABEL"
					description="PLG_SYSTEM_STATS_MODE_DESC"
					default="1"
					>
					<option value="1">PLG_SYSTEM_STATS_MODE_OPTION_ALWAYS_SEND</option>
					<option value="2">PLG_SYSTEM_STATS_MODE_OPTION_ON_DEMAND</option>
					<option value="3">PLG_SYSTEM_STATS_MODE_OPTION_NEVER_SEND</option>
				</field>

				<field
					name="lastrun"
					type="hidden"
					default="0"
					size="15"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]vc1��1�1system/stats/stats.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

// Uncomment the following line to enable debug mode for testing purposes. Note: statistics will be sent on every page load
// define('PLG_SYSTEM_STATS_DEBUG', 1);

/**
 * Statistics system plugin. This sends anonymous data back to the Joomla! Project about the
 * PHP, SQL, Joomla and OS versions
 *
 * @since  3.5
 */
class PlgSystemStats extends JPlugin
{
	/**
	 * Indicates sending statistics is always allowed.
	 *
	 * @var    integer
	 * @since  3.5
	 */
	const MODE_ALLOW_ALWAYS = 1;

	/**
	 * Indicates sending statistics is only allowed one time.
	 *
	 * @var    integer
	 * @since  3.5
	 */
	const MODE_ALLOW_ONCE = 2;

	/**
	 * Indicates sending statistics is never allowed.
	 *
	 * @var    integer
	 * @since  3.5
	 */
	const MODE_ALLOW_NEVER = 3;

	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.5
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.5
	 */
	protected $db;

	/**
	 * URL to send the statistics.
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $serverUrl = 'https://developer.joomla.org/stats/submit';

	/**
	 * Unique identifier for this site
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $uniqueId;

	/**
	 * Listener for the `onAfterInitialise` event
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	public function onAfterInitialise()
	{
		if (!$this->app->isClient('administrator') || !$this->isAllowedUser())
		{
			return;
		}

		if (!$this->isDebugEnabled() && !$this->isUpdateRequired())
		{
			return;
		}

		if (JUri::getInstance()->getVar('tmpl') === 'component')
		{
			return;
		}

		// Load plugin language files only when needed (ex: they are not needed in site client).
		$this->loadLanguage();

		JHtml::_('jquery.framework');
		JHtml::_('script', 'plg_system_stats/stats.js', array('version' => 'auto', 'relative' => true));
	}

	/**
	 * User selected to always send data
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params or sending the data.
	 */
	public function onAjaxSendAlways()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
		}

		$this->params->set('mode', static::MODE_ALLOW_ALWAYS);

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings', 500);
		}

		$this->sendStats();

		echo json_encode(array('sent' => 1));
	}

	/**
	 * User selected to never send data.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params.
	 */
	public function onAjaxSendNever()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
		}

		$this->params->set('mode', static::MODE_ALLOW_NEVER);

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings', 500);
		}

		echo json_encode(array('sent' => 0));
	}

	/**
	 * User selected to send data once.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params or sending the data.
	 */
	public function onAjaxSendOnce()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
		}

		$this->params->set('mode', static::MODE_ALLOW_ONCE);

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings', 500);
		}

		$this->sendStats();

		echo json_encode(array('sent' => 1));
	}

	/**
	 * Send the stats to the server.
	 * On first load | on demand mode it will show a message asking users to select mode.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params or sending the data.
	 */
	public function onAjaxSendStats()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
		}

		// User has not selected the mode. Show message.
		if ((int) $this->params->get('mode') !== static::MODE_ALLOW_ALWAYS)
		{
			$data = array(
				'sent' => 0,
				'html' => $this->getRenderer('message')->render($this->getLayoutData())
			);

			echo json_encode($data);

			return;
		}

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings', 500);
		}

		$this->sendStats();

		echo json_encode(array('sent' => 1));
	}

	/**
	 * Get the data through events
	 *
	 * @param   string  $context  Context where this will be called from
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function onGetStatsData($context)
	{
		return $this->getStatsData();
	}

	/**
	 * Debug a layout of this plugin
	 *
	 * @param   string  $layoutId  Layout identifier
	 * @param   array   $data      Optional data for the layout
	 *
	 * @return  string
	 *
	 * @since   3.5
	 */
	public function debug($layoutId, $data = array())
	{
		$data = array_merge($this->getLayoutData(), $data);

		return $this->getRenderer($layoutId)->debug($data);
	}

	/**
	 * Get the data for the layout
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutData()
	{
		return array(
			'plugin'       => $this,
			'pluginParams' => $this->params,
			'statsData'    => $this->getStatsData()
		);
	}

	/**
	 * Get the layout paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutPaths()
	{
		$template = JFactory::getApplication()->getTemplate();

		return array(
			JPATH_ADMINISTRATOR . '/templates/' . $template . '/html/layouts/plugins/' . $this->_type . '/' . $this->_name,
			__DIR__ . '/layouts',
		);
	}

	/**
	 * Get the plugin renderer
	 *
	 * @param   string  $layoutId  Layout identifier
	 *
	 * @return  JLayout
	 *
	 * @since   3.5
	 */
	protected function getRenderer($layoutId = 'default')
	{
		$renderer = new JLayoutFile($layoutId);

		$renderer->setIncludePaths($this->getLayoutPaths());

		return $renderer;
	}

	/**
	 * Get the data that will be sent to the stats server.
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	private function getStatsData()
	{
		$data = array(
			'unique_id'   => $this->getUniqueId(),
			'php_version' => PHP_VERSION,
			'db_type'     => $this->db->name,
			'db_version'  => $this->db->getVersion(),
			'cms_version' => JVERSION,
			'server_os'   => php_uname('s') . ' ' . php_uname('r')
		);

		// Check if we have a MariaDB version string and extract the proper version from it
		if (preg_match('/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i', $data['db_version'], $versionParts))
		{
			$data['db_version'] = $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch'];
		}

		return $data;
	}

	/**
	 * Get the unique id. Generates one if none is set.
	 *
	 * @return  integer
	 *
	 * @since   3.5
	 */
	private function getUniqueId()
	{
		if (null === $this->uniqueId)
		{
			$this->uniqueId = $this->params->get('unique_id', hash('sha1', JUserHelper::genRandomPassword(28) . time()));
		}

		return $this->uniqueId;
	}

	/**
	 * Check if current user is allowed to send the data
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isAllowedUser()
	{
		return JFactory::getUser()->authorise('core.admin');
	}

	/**
	 * Check if the debug is enabled
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isDebugEnabled()
	{
		return defined('PLG_SYSTEM_STATS_DEBUG');
	}

	/**
	 * Check if last_run + interval > now
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isUpdateRequired()
	{
		$last     = (int) $this->params->get('lastrun', 0);
		$interval = (int) $this->params->get('interval', 12);
		$mode     = (int) $this->params->get('mode', 0);

		if ($mode === static::MODE_ALLOW_NEVER)
		{
			return false;
		}

		// Never updated or debug enabled
		if (!$last || $this->isDebugEnabled())
		{
			return true;
		}

		return (abs(time() - $last) > $interval * 3600);
	}

	/**
	 * Check valid AJAX request
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isAjaxRequest()
	{
		return strtolower($this->app->input->server->get('HTTP_X_REQUESTED_WITH', '')) === 'xmlhttprequest';
	}

	/**
	 * Render a layout of this plugin
	 *
	 * @param   string  $layoutId  Layout identifier
	 * @param   array   $data      Optional data for the layout
	 *
	 * @return  string
	 *
	 * @since   3.5
	 */
	public function render($layoutId, $data = array())
	{
		$data = array_merge($this->getLayoutData(), $data);

		return $this->getRenderer($layoutId)->render($data);
	}

	/**
	 * Save the plugin parameters
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function saveParams()
	{
		// Update params
		$this->params->set('lastrun', time());
		$this->params->set('unique_id', $this->getUniqueId());
		$interval = (int) $this->params->get('interval', 12);
		$this->params->set('interval', $interval ?: 12);

		$query = $this->db->getQuery(true)
				->update($this->db->quoteName('#__extensions'))
				->set($this->db->quoteName('params') . ' = ' . $this->db->quote($this->params->toString('JSON')))
				->where($this->db->quoteName('type') . ' = ' . $this->db->quote('plugin'))
				->where($this->db->quoteName('folder') . ' = ' . $this->db->quote('system'))
				->where($this->db->quoteName('element') . ' = ' . $this->db->quote('stats'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race condition
			$this->db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue execution
			return false;
		}

		try
		{
			// Update the plugin parameters
			$result = $this->db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$this->db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$this->db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		return $result;
	}

	/**
	 * Send the stats to the stats server
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 *
	 * @throws  RuntimeException  If there is an error sending the data.
	 */
	private function sendStats()
	{
		try
		{
			// Don't let the request take longer than 2 seconds to avoid page timeout issues
			$response = JHttpFactory::getHttp()->post($this->serverUrl, $this->getStatsData(), null, 2);
		}
		catch (UnexpectedValueException $e)
		{
			// There was an error sending stats. Should we do anything?
			throw new RuntimeException('Could not send site statistics to remote server: ' . $e->getMessage(), 500);
		}
		catch (RuntimeException $e)
		{
			// There was an error connecting to the server or in the post request
			throw new RuntimeException('Could not connect to statistics server: ' . $e->getMessage(), 500);
		}
		catch (Exception $e)
		{
			// An unexpected error in processing; don't let this failure kill the site
			throw new RuntimeException('Unexpected error connecting to statistics server: ' . $e->getMessage(), 500);
		}

		if ($response->code !== 200)
		{
			$data = json_decode($response->body);

			throw new RuntimeException('Could not send site statistics to remote server: ' . $data->message, $response->code);
		}

		return true;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1))
	{
		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR . '/cache' : $this->app->get('cache_path', JPATH_SITE . '/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
PK��#]֙Q system/stats/layouts/message.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var  PlgSystemStats             $plugin        Plugin rendering this layout
 * @var  \Joomla\Registry\Registry  $pluginParams  Plugin parameters
 * @var  array                      $statsData     Array containing the data that will be sent to the stats server
 */
?>
<div class="alert alert-info js-pstats-alert" style="display:none;">
	<button data-dismiss="alert" class="close" type="button">×</button>
	<h2><?php echo JText::_('PLG_SYSTEM_STATS_LABEL_MESSAGE_TITLE'); ?></h2>
	<p>
		<?php echo JText::_('PLG_SYSTEM_STATS_MSG_JOOMLA_WANTS_TO_SEND_DATA'); ?>
		<a href="#" class="js-pstats-btn-details alert-link"><?php echo JText::_('PLG_SYSTEM_STATS_MSG_WHAT_DATA_WILL_BE_SENT'); ?></a>
	</p>
	<?php
		echo $plugin->render('stats', compact('statsData'));
	?>
	<p><?php echo JText::_('PLG_SYSTEM_STATS_MSG_ALLOW_SENDING_DATA'); ?></p>
	<p class="actions">
		<a href="#" class="btn js-pstats-btn-allow-always"><?php echo JText::_('PLG_SYSTEM_STATS_BTN_SEND_ALWAYS'); ?></a>
		<a href="#" class="btn js-pstats-btn-allow-once"><?php echo JText::_('PLG_SYSTEM_STATS_BTN_SEND_NOW'); ?></a>
		<a href="#" class="btn js-pstats-btn-allow-never"><?php echo JText::_('PLG_SYSTEM_STATS_BTN_NEVER_SEND'); ?></a>
	</p>
</div>
PK��#]_�mlffsystem/stats/layouts/stats.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var  array  $statsData  Array containing the data that will be sent to the stats server
 */

$versionFields = array('php_version', 'db_version', 'cms_version');
?>
<dl class="dl-horizontal js-pstats-data-details"  style="display:none;">
	<?php foreach ($statsData as $key => $value) : ?>
		<dt><?php echo JText::_('PLG_SYSTEM_STATS_LABEL_' . strtoupper($key)); ?></dt>
		<dd><?php echo in_array($key, $versionFields) ? (preg_match('/\d+(?:\.\d+)+/', $value, $matches) ? $matches[0] : $value) : $value; ?></dd>
	<?php endforeach; ?>
</dl>
PK��#]oT=		'system/stats/layouts/field/uniqueid.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete    Autocomplete attribute for the field.
 * @var   boolean  $autofocus       Is autofocus enabled?
 * @var   string   $class           Classes for the input.
 * @var   string   $description     Description of the field.
 * @var   boolean  $disabled        Is this field disabled?
 * @var   string   $group           Group the field belongs to. <fields> section in form XML.
 * @var   boolean  $hidden          Is this field hidden in the form?
 * @var   string   $hint            Placeholder for the field.
 * @var   string   $id              DOM id of the field.
 * @var   string   $label           Label of the field.
 * @var   string   $labelclass      Classes to apply to the label.
 * @var   boolean  $multiple        Does this field support multiple values?
 * @var   string   $name            Name of the input field.
 * @var   string   $onchange        Onchange attribute for the field.
 * @var   string   $onclick         Onclick attribute for the field.
 * @var   string   $pattern         Pattern (Reg Ex) of value of the form field.
 * @var   boolean  $readonly        Is this field read only?
 * @var   boolean  $repeat          Allows extensions to duplicate elements.
 * @var   boolean  $required        Is this field required?
 * @var   integer  $size            Size attribute of the input.
 * @var   boolean  $spellcheck      Spellcheck state for the form field.
 * @var   string   $validate        Validation rules to apply.
 * @var   string   $value           Value attribute of the field.
 * @var   array    $options         Options available for this field.
 */
?>
<input type="hidden" name="<?php echo $name; ?>" id="<?php echo $id; ?>" value="<?php echo htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); ?>" />
<a class="btn" onclick="document.getElementById('<?php echo $id; ?>').value='';Joomla.submitbutton('plugin.apply');">
	<span class="icon-refresh"></span> <?php echo JText::_('PLG_SYSTEM_STATS_RESET_UNIQUE_ID'); ?>
</a>PK��#]�e����#system/stats/layouts/field/data.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete    Autocomplete attribute for the field.
 * @var   boolean  $autofocus       Is autofocus enabled?
 * @var   string   $class           Classes for the input.
 * @var   string   $description     Description of the field.
 * @var   boolean  $disabled        Is this field disabled?
 * @var   string   $group           Group the field belongs to. <fields> section in form XML.
 * @var   boolean  $hidden          Is this field hidden in the form?
 * @var   string   $hint            Placeholder for the field.
 * @var   string   $id              DOM id of the field.
 * @var   string   $label           Label of the field.
 * @var   string   $labelclass      Classes to apply to the label.
 * @var   boolean  $multiple        Does this field support multiple values?
 * @var   string   $name            Name of the input field.
 * @var   string   $onchange        Onchange attribute for the field.
 * @var   string   $onclick         Onclick attribute for the field.
 * @var   string   $pattern         Pattern (Reg Ex) of value of the form field.
 * @var   boolean  $readonly        Is this field read only?
 * @var   boolean  $repeat          Allows extensions to duplicate elements.
 * @var   boolean  $required        Is this field required?
 * @var   integer  $size            Size attribute of the input.
 * @var   boolean  $spellcheck      Spellcheck state for the form field.
 * @var   string   $validate        Validation rules to apply.
 * @var   string   $value           Value attribute of the field.
 * @var   array    $options         Options available for this field.
 * @var   array    $statsData       Statistics that will be sent to the stats server
 */

JHtml::_('jquery.framework');
?>
<a href="#" onclick="jQuery(this).next().toggle(200); return false;"><?php echo JText::_('PLG_SYSTEM_STATS_MSG_WHAT_DATA_WILL_BE_SENT'); ?></a>
<?php
echo $field->render('stats', compact('statsData'));
PK��#]G!E���system/stats/field/data.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PlgSystemStatsFormFieldBase', __DIR__ . '/base.php');

/**
 * Unique ID Field class for the Stats Plugin.
 *
 * @since  3.5
 */
class PlgSystemStatsFormFieldData extends PlgSystemStatsFormFieldBase
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $type = 'Data';

	/**
	 * Name of the layout being used to render the field
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $layout = 'field.data';

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutData()
	{
		$data       = parent::getLayoutData();

		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('system', 'stats');

		$result = $dispatcher->trigger('onGetStatsData', array('stats.field.data'));

		$data['statsData'] = $result ? reset($result) : array();

		return $data;
	}
}
PK��#]�V���system/stats/field/base.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Base field for the Stats Plugin.
 *
 * @since  3.5
 */
abstract class PlgSystemStatsFormFieldBase extends JFormField
{
	/**
	 * Get the layouts paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutPaths()
	{
		$template = JFactory::getApplication()->getTemplate();

		return array(
			JPATH_ADMINISTRATOR . '/templates/' . $template . '/html/layouts/plugins/system/stats',
			dirname(__DIR__) . '/layouts',
			JPATH_SITE . '/layouts'
		);
	}
}
PK��#]EN8��system/stats/field/uniqueid.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PlgSystemStatsFormFieldBase', __DIR__ . '/base.php');

/**
 * Unique ID Field class for the Stats Plugin.
 *
 * @since  3.5
 */
class PlgSystemStatsFormFieldUniqueid extends PlgSystemStatsFormFieldBase
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $type = 'Uniqueid';

	/**
	 * Name of the layout being used to render the field
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $layout = 'field.uniqueid';
}
PK��#]a6�system/cache/cache.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_cache</name>
	<author>Joomla! Project</author>
	<creationDate>February 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CACHE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="cache">cache.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_cache.ini</language>
		<language tag="en-GB">en-GB.plg_system_cache.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="browsercache"
					type="radio"
					label="PLG_CACHE_FIELD_BROWSERCACHE_LABEL"
					description="PLG_CACHE_FIELD_BROWSERCACHE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="exclude_menu_items"
					type="menuitem"
					label="PLG_CACHE_FIELD_EXCLUDE_MENU_ITEMS_LABEL"
					description="PLG_CACHE_FIELD_EXCLUDE_MENU_ITEMS_DESC"
					multiple="multiple"
					filter="int_array"
				/>

			</fieldset>
			<fieldset name="advanced">
				<field
					name="exclude"
					type="textarea"
					label="PLG_CACHE_FIELD_EXCLUDE_LABEL"
					description="PLG_CACHE_FIELD_EXCLUDE_DESC"
					class="input-xxlarge"
					rows="15"
					filter="raw"
				/>

			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�~�ccsystem/cache/cache.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.cache
 *
 * @copyright   (C) 2007 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! Page Cache Plugin.
 *
 * @since  1.5
 */
class PlgSystemCache extends JPlugin
{
	/**
	 * Cache instance.
	 *
	 * @var    JCache
	 * @since  1.5
	 */
	public $_cache;

	/**
	 * Cache key
	 *
	 * @var    string
	 * @since  3.0
	 */
	public $_cache_key;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.8.0
	 */
	protected $app;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   1.5
	 */
	public function __construct(& $subject, $config)
	{
		parent::__construct($subject, $config);

		// Get the application if not done by JPlugin.
		if (!isset($this->app))
		{
			$this->app = JFactory::getApplication();
		}

		// Set the cache options.
		$options = array(
			'defaultgroup' => 'page',
			'browsercache' => $this->params->get('browsercache', 0),
			'caching'      => false,
		);

		// Instantiate cache with previous options and create the cache key identifier.
		$this->_cache     = JCache::getInstance('page', $options);
		$this->_cache_key = JUri::getInstance()->toString();
	}

	/**
	 * Get a cache key for the current page based on the url and possible other factors.
	 *
	 * @return  string
	 *
	 * @since   3.7
	 */
	protected function getCacheKey()
	{
		static $key;

		if (!$key)
		{
			JPluginHelper::importPlugin('pagecache');

			$parts = JEventDispatcher::getInstance()->trigger('onPageCacheGetKey');
			$parts[] = JUri::getInstance()->toString();

			$key = md5(serialize($parts));
		}

		return $key;
	}

	/**
	 * After Initialise Event.
	 * Checks if URL exists in cache, if so dumps it directly and closes.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onAfterInitialise()
	{
		if ($this->app->isClient('administrator') || $this->app->get('offline', '0') || $this->app->getMessageQueue())
		{
			return;
		}

		// If any pagecache plugins return false for onPageCacheSetCaching, do not use the cache.
		JPluginHelper::importPlugin('pagecache');

		$results = JEventDispatcher::getInstance()->trigger('onPageCacheSetCaching');
		$caching = !in_array(false, $results, true);

		if ($caching && JFactory::getUser()->guest && $this->app->input->getMethod() === 'GET')
		{
			$this->_cache->setCaching(true);
		}

		$data = $this->_cache->get($this->getCacheKey());

		// If page exist in cache, show cached page.
		if ($data !== false)
		{
			// Set HTML page from cache.
			$this->app->setBody($data);

			// Dumps HTML page.
			echo $this->app->toString((bool) $this->app->get('gzip'));

			// Mark afterCache in debug and run debug onAfterRespond events.
			// e.g., show Joomla Debug Console if debug is active.
			if (JDEBUG)
			{
				JProfiler::getInstance('Application')->mark('afterCache');
				JEventDispatcher::getInstance()->trigger('onAfterRespond');
			}

			// Closes the application.
			$this->app->close();
		}
	}

	/**
	 * After Render Event.
	 * Verify if current page is not excluded from cache.
	 *
	 * @return   void
	 *
	 * @since   3.9.12
	 */
	public function onAfterRender()
	{
		if ($this->_cache->getCaching() === false)
		{
			return;
		}

		// We need to check if user is guest again here, because auto-login plugins have not been fired before the first aid check.
		// Page is excluded if excluded in plugin settings.
		if (!JFactory::getUser()->guest || $this->app->getMessageQueue() || $this->isExcluded() === true)
		{
			$this->_cache->setCaching(false);

			return;
		}

		// Disable compression before caching the page.
		$this->app->set('gzip', false);
	}

	/**
	 * After Respond Event.
	 * Stores page in cache.
	 *
	 * @return   void
	 *
	 * @since   1.5
	 */
	public function onAfterRespond()
	{
		if ($this->_cache->getCaching() === false)
		{
			return;
		}

		// Saves current page in cache.
		$this->_cache->store($this->app->getBody(), $this->getCacheKey());
	}

	/**
	 * Check if the page is excluded from the cache or not.
	 *
	 * @return   boolean  True if the page is excluded else false
	 *
	 * @since    3.5
	 */
	protected function isExcluded()
	{
		// Check if menu items have been excluded.
		if ($exclusions = $this->params->get('exclude_menu_items', array()))
		{
			// Get the current menu item.
			$active = $this->app->getMenu()->getActive();

			if ($active && $active->id && in_array((int) $active->id, (array) $exclusions))
			{
				return true;
			}
		}

		// Check if regular expressions are being used.
		if ($exclusions = $this->params->get('exclude', ''))
		{
			// Normalize line endings.
			$exclusions = str_replace(array("\r\n", "\r"), "\n", $exclusions);

			// Split them.
			$exclusions = explode("\n", $exclusions);

			// Gets internal URI.
			$internal_uri	= '/index.php?' . JUri::getInstance()->buildQuery($this->app->getRouter()->getVars());

			// Loop through each pattern.
			if ($exclusions)
			{
				foreach ($exclusions as $exclusion)
				{
					// Make sure the exclusion has some content
					if ($exclusion !== '')
					{
						// Test both external and internal URI
						if (preg_match('#' . $exclusion . '#i', $this->_cache_key . ' ' . $internal_uri, $match))
						{
							return true;
						}
					}
				}
			}
		}

		// If any pagecache plugins return true for onPageCacheIsExcluded, exclude.
		JPluginHelper::importPlugin('pagecache');

		$results = JEventDispatcher::getInstance()->trigger('onPageCacheIsExcluded');

		return in_array(true, $results, true);
	}
}
PK��#]�)��system/cache/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]r��88#system/plugin_googlemap2/index.htmlnu�[���<html>

<body bgcolor="#FFFFFF">

</body>

</html>PK��#]q!����4system/plugin_googlemap2/plugin_googlemap2_proxy.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2_proxy.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2011 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

// No protection of Joomla because this php program may be called directly to deliver content
// defined( '_JEXEC' ) or die( 'Restricted access' );

$debug = urldecode($_GET['debug']);
if ($debug!="1")
	@ob_start();
	
header('content-type:text/xml;');

if (!isset($HTTP_RAW_POST_DATA)){
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
}
$post_data = $HTTP_RAW_POST_DATA;
$header[] = "Content-type: text/xml";
$header[] = "Content-length: ".strlen($post_data);

$url = urldecode($_GET['url']);
$url = "http://".$url;
	
$ok = false;

if (ini_get('allow_url_fopen'))
	if (($response = file_get_contents($url)))
		$ok = true;

if (!$ok) {
	$ch = curl_init( $url );

	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	if( !ini_get('safe_mode')&&!ini_get('open_basedir') )
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		
	curl_setopt($ch, CURLOPT_TIMEOUT, 80);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
	curl_setopt($ch, CURLOPT_FAILONERROR, 0);
	curl_setopt($ch, CURLOPT_VERBOSE, 1);

	if ( strlen($post_data)>0 ){
		curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
	}
	
	$response = curl_exec($ch);    
	if (curl_errno($ch)) {
		print curl_error($ch);
	} else {
		curl_close($ch);
		$ok = true;
	}
}

if (!$ok) {
	$url = urldecode($_GET['url']);

    // Do it the safe mode way for local files
	$pattern = "/(www.)?".$_SERVER["HTTP_HOST"]."/i";
	if (preg_match($pattern, $url)!=0) {
		$url = $_SERVER["DOCUMENT_ROOT"].preg_replace($pattern, "", $url);
	
		if (ini_get('allow_url_fopen'))
			if (($response = file_get_contents($url)))
				$ok = true;
		
		if (!$ok) {
			$ch = curl_init( $url );
		
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
			curl_setopt($ch, CURLOPT_TIMEOUT, 80);
			curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
			curl_setopt($ch, CURLOPT_FAILONERROR, 0);
			curl_setopt($ch, CURLOPT_VERBOSE, 1);
			curl_setopt($ch, CURLOPT_COOKIEFILE, 1);
			
			if ( strlen($post_data)>0 ){
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
			}
			
			$response = curl_exec($ch);    
			if (curl_errno($ch)) {
				print curl_error($ch);
			} else {
				curl_close($ch);
				$ok = true;
			}
		}
	}
}

if ($ok) {
	while (@ob_end_clean());
}

print $response;

?> PK��#]�F�=h=h5system/plugin_googlemap2/plugin_googlemap2_helper.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2_helper.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2011 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

defined( '_JEXEC' ) or die( 'Restricted access' );

if (!defined('_CMN_JAVASCRIPT')) define('_CMN_JAVASCRIPT', "<b>JavaScript must be enabled in order for you to use Google Maps.</b> <br/>However, it seems JavaScript is either disabled or not supported by your browser. <br/>To view Google Maps, enable JavaScript by changing your browser options, and then try again.");

class plgSystemPlugin_googlemap2_helper
{
	var $jversion;
	var $params;
	var $regex;
	var $document;
	var $brackets;
	var $debug_plugin;
	var $debug_text;
	var $protocol;
	var $googlewebsite;
	var $urlsetting;
	var $googlekey;
	var $language;
	var $langtype;
	var $iso;
	var $no_javascript;
	var $pagebreak;
	var	$google_API_version;
	var $mapcss;
	var	$timeinterval;
	var	$googleindexing;
	var	$langanim;
	var	$first_google;
	var	$first_googlemaps;
	var	$first_mootools;
	var	$first_modalbox;
	var	$first_localsearch;
	var $first_googleearth;
	var	$first_kmlrenderer;
	var	$first_kmlelabel;
	var	$first_svcontrol;
	var	$first_animdir;
	var	$first_arcgis;
	var	$first_panoramiolayer;
	var $initparams;
	var $clientgeotype;
	var $event;
	var $_text;
	var	$_langanim;
	var	$_client_geo;
	var $_inline_coords;
	var $_inline_tocoords;
	var $_kmlsbwidthorig;
	var $_lbxwidthorig;
	
	/**
	 * Constructor
	 *
	 * @access      protected
	 * @since       1.0
	 */
	 // Can we use _construct or should we use init?
	 //	function init() {
	public function __construct($jversion, $params, $regex, $document, $brackets)
	{
		// The params of the plugin
		$this->jversion = $jversion;
		$this->params = $params;
		$this->regex = $regex;
		$this->document = $document;
		$this->brackets = $brackets;
		// Set debug
		$this->debug_plugin = $this->params->get( 'debug', '0' );
		$this->debug_text = '';
		// Get ID
		$this->id = intval( JRequest::getVar('id', null) );	
		$this->id = explode(":", $this->id);
		$this->id = $this->id[0];
		// What is the url of website without / at the end
		$this->url = preg_replace('/\/$/', '', JURI::base());
		$this->_debug_log("url base(): ".$this->url);			
		$this->base = JURI::base(true);
		$this->_debug_log("url base(true): ".$this->base);			
		// Protocol not working with maps.google.com only with enterprise account
		if ($_SERVER['SERVER_PORT'] == 443)
			$this->protocol = "https://";
		else
			$this->protocol = "http://";
		$this->_debug_log("Protocol: ".$this->protocol);
		// Get language
		$this->langtype = $this->params->get( 'langtype', '' );
		$this->lang = JFactory::getLanguage();
		// Load the language files for Joomla 1.5. In Joomla 1.6 it is done in the construct of the plugin
		if (substr($this->jversion,0,3)=="1.5")
			$this->lang->load("plg_system_plugin_googlemap2", JPATH_SITE."/administrator", $this->lang->getTag(), true);
		$this->language = $this->_getlang();
		$this->no_javascript = JText::_( 'CMN_JAVASCRIPT', _CMN_JAVASCRIPT);
		// Get region
		$this->region = $this->params->get( 'region', '' );
		// Define encoding
		$this->iso = "utf-8";
		// Get params
		$this->googlewebsite = $this->params->get( 'googlewebsite', 'maps.google.com' );
		$this->_debug_log("googlewebsite: ".$this->googlewebsite);
		$this->urlsetting = $this->params->get( 'urlsetting', 'http_host' );
		$this->_debug_log("urlsetting: ".$this->urlsetting);
		if ($this->urlsetting=='mosconfig')
			$this->urlsetting = $this->url;
		else 
			$this->urlsetting = $_SERVER['HTTP_HOST'];
		$this->google_API_version = $this->params->get( 'Google_API_version', '2.x' );
		$this->googleindexing = $this->params->get( 'googleindexing', '1' );
		$this->mapcss = $this->params->get( 'mapcss', '' );
		$this->timeinterval = $this->params->get( 'timeinterval', '500' );
		$this->clientgeotype = $this->params->get( 'clientgeotype', '0' );
		$this->langanim = $this->params->get( 'langanim', 'en;The requested panorama could not be displayed|Could not generate a route for the current start and end addresses|Street View coverage is not available for this route|You have reached your destination|miles|miles|ft|kilometers|kilometer|meters|In|You will reach your destination|Stop|Drive|Press Drive to follow your route|Route|Speed|Fast|Medium|Slow' );
		// Get key
		$this->googlekey = $this->_get_API_key();
		// Pagebreak regular expression
		$this->pagebreak = '/<hr\s(title=".*"\s)?class="system-pagebreak"(\stitle=".*")?\s\/>/si';
		// load scripts once
		$this->first_google=true;
		$this->first_googlemaps=true;
		$this->first_mootools=true;
		$this->first_modalbox=true;
		$this->first_localsearch=true;
		$this->first_googleearth=true;
		$this->first_kmlrenderer=true;
		$this->first_kmlelabel=true;
		$this->first_svcontrol=true;
		$this->first_animdir= true;
		$this->first_arcgis=true;
		$this->first_panoramiolayer = true;
		$this->_debug_log("brackets: ".$this->brackets);
		// Get params
		$this->initparams = (object) null;
		$this->_getInitialParams();
	}	
	
	function process($match, $params, &$text, $counter, $event) {
		$startmem = round($this->_memory_get_usage()/1024);
		$this->_debug_log("Memory Usage Start (_process): " . $startmem . " KB");
		$this->_text = &$text;
		$this->event = $event;
		
		// Parameters can get the default from the plugin if not empty or from the administrator part of the plugin
		$this->_mp = clone $this->initparams;

		// Language initial value
		$this->_mp->lang = $this->language;
		
		// Next parameters can be set as default out of the administrtor module or stay empty and the plugin-code decides the default. 
		$this->_mp->zoomtype = $this->params->get( 'zoomType', '' );
		$this->_mp->mapType = strtolower($this->params->get( 'mapType', '' )); 

		// Default global process parameters
		$this->_client_geo = 0;
		//track if coordinates different from config
		$this->_inline_coords = 0;
		$this->_inline_tocoords = 0;
		$this->_mp->geocoded = 0;

		// default empty and should be filled as a parameter with the plugin out of the content item
		$this->_mp->tolat='';
		$this->_mp->tolon='';
		$this->_mp->toaddress='';
		$this->_mp->description='';
		$this->_mp->tooltip='';
		$this->_mp->kml = array();
		$this->_mp->kmlsb = array();
		$this->_mp->layer = array();
		$this->_mp->lookat = array();
		$this->_mp->camera = array();
		$this->_mp->msid='';
		$this->_mp->searchtext='';
		$this->_mp->latitude='';
		$this->_mp->longitude='';
		$this->_mp->waypoints = array();

		// Give the map a random name so it won't interfere with another map
		$this->_mp->mapnm = $this->id."_".$this->_randomkeys(5)."_".$counter;
		
		// Match the field details to build the html
		$fields = explode("|", $params);

		foreach($fields as $value) {
			$value = trim($value, " \xC2\xA0\n\t\r\0\x0B");
			$values = explode("=",$value, 2);
			$values[0] = trim(strtolower($values[0]), " \xC2\xA0\n\t\r\0\x0B");
			$values[0] = preg_replace(array('/\r/','/\n/','/\<.*?\b[^>]*>/si'), '', $values[0]);
			$values=preg_replace("/^'/", '', $values);
			$values=preg_replace("/'$/", '', $values);
			$values=preg_replace("/^&#0{0,2}39;/",'',$values);
			$values=preg_replace("/&#0{0,2}39;$/",'',$values);
//			echo "<br/>".$values[0]." = ".$values[1];
				
			if (count($values)>1) {
				$values[1] = trim($values[1], " \xC2\xA0\n\t\r\0\x0B");

				if($values[0]=='debug'){
					$this->debug_plugin=$values[1];
				}else if($values[0]=='gmv'){
					$this->google_API_version = $values[1];
				}else if($values[0]=='lat'&&$values[1]!=''){
					$this->_mp->latitude=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='lon'&&$values[1]!=''){
					$this->_mp->longitude=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='centerlat'){
					$this->_mp->centerlat=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='centerlon'){
					$this->_mp->centerlon=$this->_remove_html_tags($values[1]);
					$this->_inline_coords = 1;
				}else if($values[0]=='tolat'){
					$this->_mp->tolat=$this->_remove_html_tags($values[1]);
					$this->_inline_tocoords = 1;
				}else if($values[0]=='tolon'){
					$this->_mp->tolon=$this->_remove_html_tags($values[1]);
					$this->_inline_tocoords = 1;
				}else if($values[0]=='text'){
					$this->_mp->description=html_entity_decode(html_entity_decode(trim($values[1])));
					if(!$this->_is_utf8($this->_mp->description)) 
						$this->_mp->description = utf8_encode($this->_mp->description);
					if (substr($this->google_API_version,0,1)=='2')
						$this->_mp->description=str_replace("\"","\\\"", $this->_mp->description);
					$this->_mp->description=str_replace("&#0{0,2}39;","'", $this->_mp->description);
				}else if($values[0]=='tooltip'){
					$this->_mp->tooltip=html_entity_decode(html_entity_decode(trim($values[1])));
					$this->_mp->tooltip=str_replace("&amp;","&", $this->_mp->tooltip);
					if(!$this->_is_utf8($this->_mp->tooltip)) 
						$this->_mp->tooltip= utf8_encode($this->_mp->tooltip);
				}else if($values[0]=='maptype'){
					$this->_mp->mapType=strtolower($values[1]);
				}else if ($values[0]=='waypoint'){
					$this->_mp->waypoints[0] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/waypoint\([0-9]+\)/", $values[0])){
					$this->_mp->waypoints[$this->_get_index($values[0], '(')] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/waypoint\[[0-9]+\]/", $values[0])){
					$this->_mp->waypoints[$this->_get_index($values[0], '[')] = $values[1];
				}else if($values[0]=='kml'){
					$this->_mp->kml[0]=$this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/kml\([0-9]+\)/", $values[0])){
					$this->_mp->kml[$this->_get_index($values[0], '(')] = $this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/kml\[[0-9]+\]/", $values[0])){
					$this->_mp->kml[$this->_get_index($values[0], '[')] = $this->_remove_html_tags($values[1]);
				}else if($values[0]=='kmlsb'){
					$this->_mp->kmlsb[0]=$this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/kmlsb\([0-9]+\)/", $values[0])){
					$this->_mp->kmlsb[$this->_get_index($values[0], '(')] = $this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/kmlsb\[[0-9]+\]/", $values[0])){
					$this->_mp->kmlsb[$this->_get_index($values[0], '[')] = $this->_remove_html_tags($values[1]);
				}else if($values[0]=='layer'){
					$this->_mp->layer[0]=$this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/layer\([0-9]+\)/", $values[0])){
					$this->_mp->layer[$this->_get_index($values[0], '(')] = $this->_remove_html_tags($values[1]);
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/layer\[[0-9]+\]/", $values[0])){
					$this->_mp->layer[$this->_get_index($values[0], '[')] = $this->_remove_html_tags($values[1]);
				}else if($values[0]=='lookat'){
					$this->_mp->lookat[0]=$values[1];
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/lookat\([0-9]+\)/", $values[0])){
					$this->_mp->lookat[$this->_get_index($values[0], '(')] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/lookat\[[0-9]+\]/", $values[0])){
					$this->_mp->lookat[$this->_get_index($values[0], '[')] = $values[1];
				}else if($values[0]=='camera'){
					$this->_mp->camera[0]=$values[1];
				}else if(($this->brackets=='both'||$this->brackets=='[')&&preg_match("/camera\([0-9]+\)/", $values[0])){
					$this->_mp->camera[$this->_get_index($values[0], '(')] = $values[1];
				}else if(($this->brackets=='both'||$this->brackets=='{')&&preg_match("/camera\[[0-9]+\]/", $values[0])){
					$this->_mp->camera[$this->_get_index($values[0], '[')] = $values[1];
				}else if($values[0]=='tilelayer'){
					$this->_mp->tilelayer=$this->_remove_html_tags($values[1]);
				}else {
					// other parameters
					if ($values[0]!='')
						$this->_mp->$values[0]=$values[1];
				}
			}
		}
		
		// Search for geo parameters inside the text
		//$this->_findgeoparam();
		
		//Translate parameters
		$this->_mp->erraddr = $this->_translate($this->_mp->erraddr, $this->_mp->lang);
		$this->_mp->txtaddr = $this->_translate($this->_mp->txtaddr, $this->_mp->lang);
		$this->_mp->txtaddr = str_replace(array("\r\n", "\r", "\n"), '', $this->_mp->txtaddr );
		$this->_mp->txtgetdir = $this->_translate($this->_mp->txtgetdir, $this->_mp->lang);
		$this->_mp->txtfrom = $this->_translate($this->_mp->txtfrom, $this->_mp->lang);
		$this->_mp->txtto = $this->_translate($this->_mp->txtto, $this->_mp->lang);
		$this->_mp->txtdiraddr = $this->_translate($this->_mp->txtdiraddr, $this->_mp->lang);
		$this->_mp->txtdir = $this->_translate($this->_mp->txtdir, $this->_mp->lang);
		$this->_mp->txtlightbox = $this->_translate(html_entity_decode($this->_mp->txtlightbox), $this->_mp->lang);
		$this->_mp->txt_driving = $this->_translate($this->_mp->txt_driving, $this->_mp->lang);
		$this->_mp->txt_avhighways = $this->_translate($this->_mp->txt_avhighways, $this->_mp->lang);
		$this->_mp->txt_walking = $this->_translate($this->_mp->txt_walking, $this->_mp->lang);
		$this->_mp->txt_optimize = $this->_translate($this->_mp->txt_optimize, $this->_mp->lang);
		$this->_mp->txt_alternatives = $this->_translate($this->_mp->txt_alternatives, $this->_mp->lang);
		$this->_langanim = $this->_translate($this->langanim, $this->_mp->lang);
		$this->_langanim = explode("|", $this->_langanim);

		$this->_debug_log("clientgeotype: ".$this->clientgeotype);
		
		// Latitude only when no coordinates are specified and no address
		if(!empty($this->_mp->latitudeid)) {
			// Get information
			$url = "http://www.google.de/latitude/apps/badge/api?user=".$this->_mp->latitudeid."&type=kml";
			unset($this->_mp->latitudeid);
			$getpage = $this->_getURL($url);
			if ($getpage!='') {
				$expr = '/xmlns/';
				$getpage = preg_replace($expr, 'id', $getpage);
				$xml = new SimpleXMLElement($getpage);
				$coords = "";
				foreach($xml->xpath('//coordinates') as $coordinates) {
					$coords = $coordinates;
					break;
				}
				if ($coords!='') {
					$this->_debug_log("Coordinates: ".join(", ", explode(",", $coords)));
					list ($this->_mp->longitude, $this->_mp->latitude) = explode(",", $coords);
					$this->_inline_coords = 1;
					
					if ($this->_mp->centerlat==''&&$this->_mp->centerlon=='') {
						$this->_mp->zoom = 19 + $this->_mp->corzoom;
					}
					
					// Get icon
					if ($this->_mp->icon=='') {
						foreach($xml->xpath('//Icon/href') as $href) {
							$this->_mp->icon = (string) $href;
							break;
						}
						if ($this->_mp->icon!=""&&$this->_mp->iconwidth==""&&$this->_mp->iconheight=="") {
							$this->_mp->iconwidth = "32";
							$this->_mp->iconheight = "32";
						}
						if ($this->_mp->icon!=""&&$this->_mp->iconanchorx==""&&$this->_mp->iconanchory=="") {
							$this->_mp->iconanchorx = "16";
							$this->_mp->iconanchory = "32";
						}
					}
					// show description -> add to text
					if ($this->_mp->latitudedesc=="1") {
						foreach($xml->xpath('//description') as $descr) {
							$desc = $descr;
							break;
						}
						$desc=html_entity_decode(html_entity_decode(trim($desc)));
						$desc=str_replace("\"","\\\"", $desc);
						$desc=str_replace("&#0{0,2}39;","'", $desc);
						
						$this->_mp->description .= "<p class='latitude'>".str_replace(' http://www.google.com/latitude/apps/badge', '', $desc)."</p>";
					}
					// show coordinates -> add to text
					if ($this->_mp->latitudecoord=="1") {
						$this->_mp->description .= "<table class=latitudetable><tr><td>Latitude</td><td>".$this->_mp->latitude."</td></tr><tr><td>Longitude</td><td>".$this->_mp->longitude."</td></tr></table>";
					}
				} else
					$this->_debug_log("Latitude coordinates: null");
			} else
				$this->_debug_log("Latitude totally wrong!");
			unset($url, $getpage, $expr, $xml, $coord, $coordinates, $descr, $desc);
		}

		if ($this->_mp->twittername!="") {
			$url = $this->base."/plugins/system/plugin_googlemap2_twitter_kml.php?";
			$url .= "twittername=".urlencode($this->_mp->twittername);
			$url .= "&twittertweets=".urlencode($this->_mp->twittertweets);
			$url .= "&twittericon=".urlencode($this->_mp->twittericon);
			$url .= "&twitterline=".urlencode($this->_mp->twitterline);
			$url .= "&twitterlinewidth=".urlencode($this->_mp->twitterlinewidth);
			$url .= "&twitterstartloc=".urlencode($this->_mp->twitterstartloc);
			
			$this->_mp->kml[] = $url;
			unset($url, $this->_mp->twittername, $this->_mp->twittertweets, $this->_mp->twittericon, $this->_mp->twitterline, $this->_mp->twitterlinewidth, $this->_mp->twitterstartloc);
		}

		if($this->_inline_coords == 0 && !empty($this->_mp->address))	{
			if ($this->clientgeotype=="local")
				$coord = "";
			else
				$coord = $this->get_geo($this->_mp->address);
				
			if ($coord=='') {
				$this->_client_geo = 1;
			} else {
				list ($this->_mp->longitude, $this->_mp->latitude, $altitude) = explode(",", $coord);
				$this->_inline_coords = 1;
				$this->_mp->geocoded = 1;
			}
		}

		if($this->_inline_tocoords == 0 && !empty($this->_mp->toaddress))	{
			if ($this->clientgeotype=="local")
				$tocoord = "";
			else
				$tocoord = $this->get_geo($this->_mp->toaddress);
			if ($tocoord=='') {
				$client_togeo = 1;
			} else {
				list ($this->_mp->tolon, $this->_mp->tolat, $altitude) = explode(",", $tocoord);
				$this->_inline_tocoords = 1;
			}
		}

		if (is_numeric($this->_mp->svwidth)) 
			$this->_mp->svwidth .= "px";
			
		if (is_numeric($this->_mp->svheight))
			$this->_mp->svheight.= "px";

		if (is_numeric($this->_mp->kmlsbwidth)) {
			$this->_kmlsbwidthorig = $this->_mp->kmlsbwidth;
			$this->_mp->kmlsbwidth .= "px";
		} else 
			$this->_kmlsbwidthorig = 0;
			
		$this->_lbxwidthorig = $this->_mp->lbxwidth;
		
		if (is_numeric($this->_mp->lbxwidth))
			$this->_mp->lbxwidth .= "px";
		
		if (is_numeric($this->_mp->lbxheight))
			$this->_mp->lbxheight .= "px";
			
		if (is_numeric($this->_mp->width))
			$this->_mp->width .= "px";
			
		if (is_numeric($this->_mp->height))
			$this->_mp->height .= "px";

		if (!is_numeric($this->_mp->panomax))
			$this->_mp->panomax= "50";
			
		if ($this->_mp->msid!=''&&count($this->_mp->kml)==0) {
			$this->_mp->kml[0]=$this->protocol.$this->googlewebsite.'/maps/ms?';
			if ($this->_mp->lang!='')
				$this->_mp->kml[0] .= "hl=".$this->_mp->lang."&amp;";
			$this->_mp->kml[0].='ie='.$this->iso.'&amp;msa=0&amp;msid='.$this->_mp->msid.'&amp;output=kml';
			$this->_debug_log("- msid: ".$this->_mp->kml[0]);
		}

		// Get the code to be added to the text
		if (substr($this->google_API_version,0,1)=='2')
			list ($code, $lbcode) = $this->_processMapv2();
		else
			list ($code, $lbcode) = $this->_processMapv3();
		
		// Get memory before adding code to text
		$endmem = round($this->_memory_get_usage()/1024);
		$diffmem = $endmem-$startmem;
		$this->_debug_log("Memory Usage End: " . $endmem . " KB (".$diffmem." KB)");

		// Add code to text
		$code = "\n<!-- Plugin Google Maps version 2.18 by Mike Reumer ".(($this->debug_text!='')?$this->debug_text."\n":"")."-->".$code;

		// Clean up debug text for next _process
		$this->debug_text = '';
		
		// Depending of show place the code at end of page or on the {mosmap} position		
		if ($this->_mp->show==0) {
			$offset = strpos($this->_text, $match);
			$this->_text = preg_replace($this->regex, $lbcode, $this->_text, 1);
			// If pagebreak add code before pagebreak
			preg_match($this->pagebreak, $this->_text, $m, PREG_OFFSET_CAPTURE, $offset);
			if (count($m)>0)
				$offsetpagebreak = $m[0][1];
			else
				$offsetpagebreak = 0;
			if ($offsetpagebreak!=0) 
				$this->_text = substr($this->_text, 0, $offsetpagebreak).$code.substr($this->_text, $offsetpagebreak);
			else
				$this->_text .= $code;
		} else
			$this->_text = preg_replace($this->regex, $code, $this->_text, 1);

		// Clean up generated variables
		unset($startmem, $endmem, $diffmem, $offset, $lbcode, $m, $offsetpagebreak, $code);
		
		return true;
	}
	
	function _processMapv2() {
		// Variables of process
		$code='';
		$lbcode='';
		
		if ($this->_mp->googlebar=='1'||$this->_mp->localsearch=='1') {
			$searchoption = array();

			switch ($this->_mp->searchlist) {
			case "suppress":
				$searchoption[] ="resultList : G_GOOGLEBAR_RESULT_LIST_SUPPRESS";
				break;
			
			case "inline":
				$searchoption[] ="resultList : G_GOOGLEBAR_RESULT_LIST_INLINE";
				break;

			case "div":
				$searchoption[] ="resultList : document.getElementById('searchresult".$this->_mp->mapnm."')";
				break;

			default:
				if(empty($this->_mp->searchlist))
					$searchoption[] ="resultList : G_GOOGLEBAR_RESULT_LIST_INLINE";
				else {
					$searchoption[] ="resultList : document.getElementById('".$this->_mp->searchlist."')";
					$extsearchresult= true;
				}
				break;
			}
			
			switch ($this->_mp->searchtarget) {
			case "_self":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_SELF";
				break;
			
			case "_blank":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_BLANK";
				break;

			case "_top":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_TOP";
				break;

			case "_parent":
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_PARENT";
				break;

			default:
				$searchoption[] ="linkTarget : G_GOOGLEBAR_LINK_TARGET_BLANK";
				break;
			}
			
			if ($this->_mp->searchzoompan=="1")
				$searchoption[] ="suppressInitialResultSelection : false
								  , suppressZoomToBounds : false";
			else

				$searchoption[] ="suppressInitialResultSelection : true
								  , suppressZoomToBounds : true";
								  
			$searchoptions = implode(', ', $searchoption);
		} else 
			$searchoptions = "";

		if ($this->_mp->icon!='') {
			$code .= "\n<img src='".$this->_mp->icon."' style='display:none' alt='icon' />";
			if ($this->_mp->iconshadow!='')
				$code .= "\n<img src='".$this->_mp->iconshadow."' style='display:none' alt='icon shadow' />";
			if ($this->_mp->icontransparent!='')
				$code .= "\n<img src='".$this->_mp->icontransparent."' style='display:none' alt='icon transparent' />";
		} 
		
		if ($this->_mp->sv!='none'&&$this->_mp->animdir=='0') {
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-0.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-1.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-2.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-3.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-4.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-5.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-6.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-7.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-8.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-9.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-10.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-11.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-12.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-13.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-14.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-15.png' style='display:none' alt='streetview icon' />";
			$code .= "\n<img src='".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man-pick.png' style='display:none' alt='streetview icon' />";
		}
		// Generate the map position prior to any Google Scripts so that these can parse the code
		$code.= "<!-- fail nicely if the browser has no Javascript -->
				<noscript><blockquote class='warning'><p>".$this->no_javascript."</p></blockquote></noscript>";			

		if ($this->_mp->align!='none')
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none; text-align:".$this->_mp->align."\">";
		else
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none;\">";

		if ($this->_mp->lightbox=='1') {
			$lboptions = array();
			if ($this->_mp->lbxzoom!="")
				$lboptions[] = "zoom : ".$this->_mp->lbxzoom;
			if ($this->_mp->lbxcenterlat!=""&&$this->_mp->lbxcenterlon!="")
				$lboptions[] = "mapcenter : \"".$this->_mp->lbxcenterlat." ".$this->_mp->lbxcenterlon."\"";
				
			$this->_lbxwidthorig = (is_numeric($this->_lbxwidthorig)?(($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right")?$this->_lbxwidthorig+$this->_kmlsbwidthorig+5:$this->_lbxwidthorig)."px":$this->_lbxwidthorig);
			$lbname = (($this->_mp->gotoaddr=='1'||(($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))||$this->_mp->animdir!='0'||$this->_mp->sv=='top'||$this->_mp->sv=='bottom'||$this->_mp->searchlist=='div'||$this->_mp->dir=='5'||($this->_mp->formaddress==1&&$this->_mp->animdir==0))?"lightbox":"googlemap");
			
			if ($this->_mp->show==1) {
				$code.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", map".$this->_mp->mapnm.", {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."'>";
			} else {
				$lbcode.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", map".$this->_mp->mapnm.", {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."' style='display:none'>";
			}
		}

		if ($this->_mp->gotoaddr=='1')	{
			$code.="<form name=\"gotoaddress".$this->_mp->mapnm."\" class=\"gotoaddress\" onSubmit=\"javascript:gotoAddress".$this->_mp->mapnm."();return false;\">";
			$code.="	<input id=\"txtAddress".$this->_mp->mapnm."\" name=\"txtAddress".$this->_mp->mapnm."\" type=\"text\" size=\"25\" value=\"\">";
			$code.="	<input name=\"goto\" type=\"button\" class=\"button\" onClick=\"gotoAddress".$this->_mp->mapnm."();return false;\" value=\"Goto\">";
			$code.="</form>";
		}
		
		if ($this->_mp->formaddress==1&&$this->_mp->animdir==0) {
			$code.="<form id='directionform".$this->_mp->mapnm."' action='".$this->protocol.$this->googlewebsite."/maps' method='get' target='_blank' onsubmit='DirectionMarkersubmit".$this->_mp->mapnm."(this);return false;' class='mapdirform'>";
			$code.=$this->_mp->txtdir;
			$code.=(($this->_mp->txtfrom=='')?"":"<br />").$this->_mp->txtfrom."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='saddr' id='saddr' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."' />";
			$code.=(($this->_mp->txtto=='')?"":"<br />").$this->_mp->txtto."<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='daddr' id='daddr' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."' />";

			if ($this->_mp->txt_driving!=''||$this->_mp->dirtype=="D")
				$code.="<br/><input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"");
			if ($this->_mp->txt_avhighways!=''||$this->_mp->dirtype=="1")
				$code.="<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"");
			if ($this->_mp->txt_transit!=''||$this->_mp->dirtype=="R")
				$code.="<input ".(($this->_mp->txt_transit=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='r' ".(($this->_mp->dirtype=="R")?"checked='checked'":"")." />".$this->_mp->txt_transit.(($this->_mp->txt_transit!='')?"&nbsp;":"");
			if ($this->_mp->txt_bicycle!=''||$this->_mp->dirtype=="B")
				$code.="<input ".(($this->_mp->txt_bicycle=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='b' ".(($this->_mp->dirtype=="B")?"checked='checked'":"")." />".$this->_mp->txt_bicycle.(($this->_mp->txt_bicycle!='')?"&nbsp;":"");
			if ($this->_mp->txt_walking!=''||$this->_mp->dirtype=="W")
				$code.="<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"");
			$code.="<input value='".$this->_mp->txtgetdir."' class='button' type='submit' style='margin-top: 2px;'>";

			if ($this->_mp->dir=='2')
				$code.= "<input type='hidden' name='pw' value='2'/>";

			if ($this->_mp->lang!='') 
				$code.= "<input type='hidden' name='hl' value='".$this->_mp->lang."'/>";
			$code.="</form>";
		}
		
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<table style=\"width:100%;border-spacing:0px;\">
					<tr>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="left")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\" class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<td>";
			
		if ($this->_mp->sv=='top'||($this->_mp->animdir!='0'&&$this->_mp->animdir!='3')) {
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";

			if ($this->_mp->animdir!='0') {
				$code.="<div id='status".$this->_mp->mapnm."' class='status' style='top: -".floor($this->_mp->svheight/2)."px'><b>Loading</b></div><div id='instruction".$this->_mp->mapnm."' class='instruction'></div></div><div id='progressBorder".$this->_mp->mapnm."' class='progressBorder'><div id='progressBar".$this->_mp->mapnm."' class='progressBar'></div></div>";
				$code.= "<div class='animforms'>";
				$code.= "<div class='animbuttonforms'><input type='button' value='Drive' id='stopgo".$this->_mp->mapnm."'  onclick='route".$this->_mp->mapnm.".startDriving()'  disabled='disabled' /></div>";

				if ($this->_mp->formspeed==1)
					$code.= "<div class='animformspeed'>
								<div class='animlabel'>".((array_key_exists(16, $this->_langanim))?$this->_langanim[16]:"Drive")."</div>
								<select id='speed".$this->_mp->mapnm."' onchange='route".$this->_mp->mapnm.".setSpeed()'>
									<option value='0'>".((array_key_exists(17, $this->_langanim))?$this->_langanim[17]:"Fast")."</option>
									<option value='1' selected='selected'>".((array_key_exists(18, $this->_langanim))?$this->_langanim[18]:"Normal")."</option>
									<option value='2'>".((array_key_exists(19, $this->_langanim))?$this->_langanim[19]:"Slow")."</option>
								</select>
							</div>";

				if ($this->_mp->formdirtype==1)
					$code.= "<div class='animformdirtype'>
								<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"")."<br />
							</div>";

				if ($this->_mp->formaddress==1)
					$code.= "<div class='animformaddress'>
								".(($this->_mp->txtfrom=='')?"":"<div class='animlabel'>".$this->_mp->txtfrom."</div>")."
								<div class='animinput'><input id='from".$this->_mp->mapnm."' ".(($this->_mp->txtfrom=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."'/></div>
								<div style='clear: both;'></div>
								".(($this->_mp->txtto=='')?"":"<div class='animlabel'>".$this->_mp->txtto."</div>")."
								<div class='animinput'><input id='to".$this->_mp->mapnm."' ".(($this->_mp->txtto=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."'/></div>
							</div>
							<div class='animbuttons'>
								<input type='button' value='".((array_key_exists(15, $this->_langanim))?$this->_langanim[15]:"Route")."' class='animroute' onclick='route".$this->_mp->mapnm.".generateRoute()' />
							</div>
							";
			}
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
		}

		if (($this->_mp->animdir=='2'||$this->_mp->animdir=='3')&&$this->_mp->showdir!='0') {
			$code.="<table style=\"width:".$this->_mp->width.";\"><tr>";
			$code.="<td style='width:50%;'><div id=\"googlemap".$this->_mp->mapnm."\" ".((!empty($this->_mp->mapclass))?"class=\"".$this->_mp->mapclass."\"" :"class=\"map\"")." style=\"" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:100%; height:".$this->_mp->height.";".(($this->_mp->show==0&&$this->_mp->lightbox==0)?"display:none;":"").(((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&$this->_mp->kmlsidebar=="right")||$this->_mp->animdir=='2')?"float:left;":"")."\"></div></td>";
			$code.= "<td style='width:50%;'><div id=\"dirsidebar".$this->_mp->mapnm."\" class='directions' style='float:left;width:100%;height: ".$this->_mp->height.";overflow:auto; '></div></td>";				
			$code.="</tr></table>";
		} else {
			$code.="<div id=\"googlemap".$this->_mp->mapnm."\" ".((!empty($this->_mp->mapclass))?"class=\"".$this->_mp->mapclass."\"" :"class=\"map\"")." style=\"" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->width."; height:".$this->_mp->height.";".(($this->_mp->show==0&&$this->_mp->lightbox==0)?"display:none;":"").(((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&$this->_mp->kmlsidebar=="right")||$this->_mp->animdir=='2')?"float:left;":"")."\"></div>";
		}
					
		if ($this->_mp->sv=='bottom'||$this->_mp->animdir=="3") {
			if ($this->_mp->animdir=='3') {
				$code.="<div id='progressBorder".$this->_mp->mapnm."' class='progressBorder'><div id='progressBar".$this->_mp->mapnm."' class='progressBar'></div></div>";
				$code.= "<div class='animforms'>";
				$code.= "<div class='animbuttonforms'><input type='button' value='Drive' id='stopgo".$this->_mp->mapnm."'  onclick='route".$this->_mp->mapnm.".startDriving()'  disabled='disabled' /></div>";


				if ($this->_mp->formspeed==1)
					$code.= "<div class='animformspeed'>
								<div class='animlabel'>".((array_key_exists(16, $this->_langanim))?$this->_langanim[16]:"Drive")."</div>
								<select id='speed".$this->_mp->mapnm."' onchange='route".$this->_mp->mapnm.".setSpeed()'>
									<option value='0'>".((array_key_exists(17, $this->_langanim))?$this->_langanim[17]:"Fast")."</option>
									<option value='1' selected='selected'>".((array_key_exists(18, $this->_langanim))?$this->_langanim[18]:"Normal")."</option>
									<option value='2'>".((array_key_exists(19, $this->_langanim))?$this->_langanim[19]:"Slow")."</option>
								</select>
							</div>";

				if ($this->_mp->formdirtype==1)
					$code.= "<div class='animformdirtype'>
								<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"")."<br />
								<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg".$this->_mp->mapnm."' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"")."<br />
							</div>";

				if ($this->_mp->formaddress==1)
					$code.= "<div class='animformaddress'>
								".(($this->_mp->txtfrom=='')?"":"<div class='animlabel'>".$this->_mp->txtfrom."</div>")."
								<div class='animinput'><input id='from".$this->_mp->mapnm."' ".(($this->_mp->txtfrom=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."'/></div>
								<div style='clear: both;'></div>
								".(($this->_mp->txtto=='')?"":"<div class='animlabel'>".$this->_mp->txtto."</div>")."
								<div class='animinput'><input id='to".$this->_mp->mapnm."' ".(($this->_mp->txtto=='')?"type='hidden' ":"")." size='30' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."'/></div>
							</div>
							<div class='animbuttons'>
								<input type='button' value='".((array_key_exists(15, $this->_langanim))?$this->_langanim[15]:"Route")."' class='animroute' onclick='route".$this->_mp->mapnm.".generateRoute()' />
							</div>
							";
			}
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";
			if ($this->_mp->animdir!='0')
				$code.="<div id='status".$this->_mp->mapnm."' class='status' style='top: -".floor($this->_mp->svheight/2)."px'><b>Loading</b></div><div id='instruction".$this->_mp->mapnm."' class='instruction'></div></div>";
		}

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</td>";
		
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="right")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\"  class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";
			
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</tr>
					</table>";

		if ($this->_mp->searchlist=='div')
			$code.="<div id=\"searchresult".$this->_mp->mapnm."\"></div>";

		if ($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right")
			$code.="<div style=\"clear: both;\"></div>";
		
		if (((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->address)||($this->_mp->dir=='5'))&&($this->_mp->animdir!='2'||($this->_mp->animdir=='2'&&$this->_mp->showdir=='0')))
			$code.= "<div id=\"dirsidebar".$this->_mp->mapnm."\" class='directions' ".(($this->_mp->showdir=='0')?"style='display:none'":"")."></div>";

		if ($this->_mp->lightbox=='1')
			$code .= "</div>";

		// Close of mapbody div
		$code.="</div>";

		// Only add the scripts and css once
		if($this->first_google) {
			$url = $this->protocol.$this->googlewebsite."/maps?file=api&amp;v=".$this->google_API_version."&amp;oe=".$this->iso;				
			if ($this->_mp->lang!='') 
				$url .= "&amp;hl=".$this->_mp->lang;

			$url .= "&amp;key=".$this->googlekey;
			$url .= "&amp;sensor=false";
			$url .= "&amp;indexing=".(($this->googleindexing)?"true":"false");
			
			$this->_addscript($url);
			if ($this->mapcss!='') {
				$url = $this->base."/media/plugin_googlemap2/site/googlemaps/googlemaps.css.php";
				$this->_addstylesheet($url);
			}
			$this->first_google=false;
		}

		if (($this->_mp->loadmootools=="1"||$this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->effect!="none"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_mootools) {
			if ($this->event!='onAfterRender') {
				if (substr($this->jversion,0,3)=='1.5')
					JHTML::_('behavior.mootools');
				else
					JHtml::_('behavior.framework',false);				
			} else {
				if (substr($this->jversion,0,3)=='1.5')
					$url = $this->base."/plugins/system/mtupgrade/mootools.js";
				else {
					$mooconfig = JFactory::getConfig();
		            $moodebug = $mooconfig->get('debug');
			        $moouncompressed   = $moodebug ? '-uncompressed' : '';
					$url = $this->base."/media/system/js/mootools-core".$moouncompressed.".js";
					unset($mooconfig, $moodebug, $moouncompressed);
				}
				$this->_addscript($url);
			}
			$this->first_mootools = false;
		}

		if (($this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_modalbox)	{
			if (substr($this->jversion,0,3)=='1.5')
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/modalbox1.2hack.js");
			else
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/moodalbox1.3hack.js");
			
			$this->_addstylesheet($this->base."/media/plugin_googlemap2/site/moodalbox/css/moodalbox.css");
			$this->first_modalbox = false;
		}

		if (($this->_mp->localsearch=="1"||$this->_client_geo==1)&&$this->first_localsearch) {
			$this->_addscript($this->protocol."www.google.com/uds/api?file=uds.js&amp;v=1.0&amp;key=".$this->googlekey);
			$this->_addscript($this->protocol."www.google.com/uds/solutions/localsearch/gmlocalsearch.js".((!empty($this->_mp->adsense))?"?adsense=".$this->_mp->adsense:"").((!empty($this->_mp->channel)&&!empty($this->_mp->adsense))?"&amp;channel=".$this->_mp->channel:""));
			$style = "@import url('".$this->protocol."www.google.com/uds/css/gsearch.css');\n@import url('".$this->protocol."www.google.com/uds/solutions/localsearch/gmlocalsearch.css');";
			$this->_addstyledeclaration($style);
			$this->first_localsearch = false;
		}
		
		if ($this->first_kmlelabel&&(($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")||($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!=""))) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/elabel/elabel.js");
			$this->first_kmlelabel = false;
		}
		
		if (($this->_mp->kmlrenderer=='geoxml'||count($this->_mp->kmlsb)!=0)&&$this->first_kmlrenderer) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/geoxml/geoxml.js");
			$this->first_kmlrenderer = false;
		}
		
		if ($this->_mp->zoomtype=='3D-largeSV'&&$this->first_svcontrol) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/StreetViewControl/StreetViewControl.js");
			$this->first_svcontrol = false;
		}

		if ($this->_mp->animdir!='0'&&$this->first_animdir) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/directions/directions.js");
			$this->_addstylesheet($this->base."/media/plugin_googlemap2/site/directions/directions.css");
			$this->first_animdir = false;
		}
		
		if ($this->_mp->kmlrenderer=='arcgis'&&$this->first_arcgis) {
			$this->_addscript($this->protocol."serverapi.arcgisonline.com/jsapi/gmaps/?v=1.4");
			$this->first_arcgis = false;
		}

		if ($this->_mp->panotype!='none'&&$this->first_panoramiolayer) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/panoramiolayer/panoramiolayer.js");
			$this->first_panoramiolayer = false;
		}

		$code.="<script type='text/javascript'>/*<![CDATA[*/\n";
		if ($this->debug_plugin=="1")
			$code.="function VersionControl(opt_no_style){
					  this.noStyle = opt_no_style;
					};
					VersionControl.prototype = new GControl();
					VersionControl.prototype.initialize = function(map) {
					  var display = document.createElement('div');
					  map.getContainer().appendChild(display);
					  display.innerHTML = '2.'+G_API_VERSION;
					  display.className = 'api-version-display';
					  if(!this.noStyle){
						display.style.fontFamily = 'Arial, sans-serif';
						display.style.fontSize = '11px';
					  }
					  this.htmlElement = display;
					  return display;
					};
					VersionControl.prototype.getDefaultPosition = function() {
					  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(3, 38));
					};
				";

		// Globale map variable linked to the div
		$code.="var tst".$this->_mp->mapnm."=document.getElementById('googlemap".$this->_mp->mapnm."');
		var tstint".$this->_mp->mapnm.";
		var map".$this->_mp->mapnm.";
		var mySlidemap".$this->_mp->mapnm.";
		var overviewmap".$this->_mp->mapnm.";
		var overmap".$this->_mp->mapnm.";
		var xml".$this->_mp->mapnm.";
		var imageovl".$this->_mp->mapnm.";
		var directions".$this->_mp->mapnm.";
		";
		
		if ($this->_mp->proxy=="1") {
			if (substr($this->jversion,0,3)=="1.5")
				$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2_proxy.php?';";
			else
				$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2/plugin_googlemap2_proxy.php?';";
		}

		if ($this->_mp->traffic=='1') 
			$code.="\nvar trafficInfo".$this->_mp->mapnm.";";
		if ($this->_mp->localsearch=='1') 
			$code.="\nvar localsearch".$this->_mp->mapnm.";";
		if ($this->_mp->adsmanager=='1') 
			$code.="\nvar adsmanager".$this->_mp->mapnm.";";
		if ($this->_mp->kmlrenderer=='geoxml'||count($this->_mp->kmlsb)!=0) {
			$code.="\nvar exml".$this->_mp->mapnm.";";

			$code.="\ntop.publishdirectory = '".$this->base."/media/plugin_googlemap2/site/geoxml/';";
		}
		if (count($this->_mp->lookat)>0||count($this->_mp->camera)>0||$this->_mp->tilelayer!=''||$this->_mp->mapType=='earth'||$this->_mp->showearthmaptype=="1")
			$code.="\nvar geplugin".$this->_mp->mapnm.";";

		if ($this->_mp->panotype!='none')
			$code.="\nvar panoLayer".$this->_mp->mapnm.";";

		if ($this->_mp->icon!='') {
			$code.="\nmarkericon".$this->_mp->mapnm." = new GIcon(G_DEFAULT_ICON);";
			$code.="\nmarkericon".$this->_mp->mapnm.".image = '".$this->_mp->icon."';";
			if ($this->_mp->iconwidth!=''&&$this->_mp->iconheight!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".iconSize = new GSize(".$this->_mp->iconwidth.", ".$this->_mp->iconheight.");";
			if ($this->_mp->iconshadow !='') {
				$code.="\nmarkericon".$this->_mp->mapnm.".shadow = '".$this->_mp->iconshadow."';";

				if ($this->_mp->iconshadowwidth!=''&&$this->_mp->iconshadowheight!='') 
					$code.="\nmarkericon".$this->_mp->mapnm.".shadowSize = new GSize(".$this->_mp->iconshadowwidth.", ".$this->_mp->iconshadowheight.");";
			}
			if ($this->_mp->iconanchorx!=''&&$this->_mp->iconanchory!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".iconAnchor = new GPoint(".$this->_mp->iconanchorx.", ".$this->_mp->iconanchory.");";
			if ($this->_mp->iconinfoanchorx!=''&&$this->_mp->iconinfoanchory!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".infoWindowAnchor = new GPoint(".$this->_mp->iconinfoanchorx.", ".$this->_mp->iconinfoanchory.");";
			if ($this->_mp->icontransparent!='') 			
				$code.="\nmarkericon".$this->_mp->mapnm.".transparent = '".$this->_mp->icontransparent."';";
			if ($this->_mp->iconimagemap!='')
				$code.="\nmarkericon".$this->_mp->mapnm.".imageMap = [".$this->_mp->iconimagemap."];";
		}
		
		if ($this->_mp->sv!='none'||$this->_mp->animdir!='0') {
			$code.="\nvar svclient".$this->_mp->mapnm.";
					var svmarker".$this->_mp->mapnm.";
					var svlastpoint".$this->_mp->mapnm.";
					var svpanorama".$this->_mp->mapnm.";
					";
			if ($this->_mp->svautorotate=="1")
				$code.="\nvar timer".$this->_mp->mapnm." = null;
						var svfocus".$this->_mp->mapnm." = false;
						var panobj".$this->_mp->mapnm.";
					";
		}

		if ($this->_mp->animdir!='0')				
			$code.="\nvar route".$this->_mp->mapnm.";
					";
		
		if ($this->_mp->sv!='none'&&$this->_mp->animdir=='0') {
			$code.="\nvar guyIcon".$this->_mp->mapnm." = new GIcon(G_DEFAULT_ICON);
					guyIcon".$this->_mp->mapnm.".image = '".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-0.png';
					guyIcon".$this->_mp->mapnm.".transparent = '".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man-pick.png';
					guyIcon".$this->_mp->mapnm.".imageMap = [26,13, 30,14, 32,28, 27,28, 28,36, 18,35, 18,27, 16,26, 16,20, 16,14, 19,13, 22,8];
					guyIcon".$this->_mp->mapnm.".iconSize = new GSize(49, 52);
					guyIcon".$this->_mp->mapnm.".iconAnchor = new GPoint(25, 35);
					guyIcon".$this->_mp->mapnm.".infoWindowAnchor = new GPoint(25, 5);
					";
		}
		if ($this->_mp->tilelayer!="") {
			$code.="\nvar tilelayer".$this->_mp->mapnm.";
					var mercator".$this->_mp->mapnm.";
					var copyright".$this->_mp->mapnm.";
					";
		}

		if ( array_key_exists('HTTP_USER_AGENT',$_SERVER) && strpos(" ".$_SERVER['HTTP_USER_AGENT'], 'Opera') ) {
			$code.="var _mSvgForced = true;
					var _mSvgEnabled = true; ";
		}

		if($this->_mp->zoomwheel=='1') {
			$code.="function CancelEvent".$this->_mp->mapnm."(event) { 
						var e = event; 
						if (typeof e.preventDefault == 'function') e.preventDefault(); 
							if (typeof e.stopPropagation == 'function') e.stopPropagation(); 

						if (window.event) { 
							window.event.cancelBubble = true; // for IE 
							window.event.returnValue = false; // for IE 
						} 
					}
				";
		}
		
		$code.="\nfunction resetposition".$this->_mp->mapnm."() {
			map".$this->_mp->mapnm.".returnToSavedPosition();
		}";

		if ($this->_mp->gotoaddr=='1') {
			$code.="function gotoAddress".$this->_mp->mapnm."() {
						var address = document.getElementById('txtAddress".$this->_mp->mapnm."').value;

						if (address.length > 0) {
							var geocoder = new GClientGeocoder();
							geocoder.setViewport(map".$this->_mp->mapnm.".getBounds());

							geocoder.getLatLng(address,
							function(point) {
								if (!point) {
									var erraddr = '{$this->_mp->erraddr}';
									erraddr = erraddr.replace(/##/, address);
								  alert(erraddr);
								} else {
								  var txtaddr = '{$this->_mp->txtaddr}';
								  txtaddr = txtaddr.replace(/##/, address);
								  map".$this->_mp->mapnm.".setCenter(point".(($this->_mp->gotoaddrzoom!=0)?",".$this->_mp->gotoaddrzoom:"").");
								  map".$this->_mp->mapnm.".openInfoWindowHtml(point,txtaddr);
								  setTimeout('map".$this->_mp->mapnm.".closeInfoWindow();', 5000);
								}
							  });
						  }
						  return false;
						  
					}";
		}
		
		if (($this->_mp->dir!='0')||((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->toaddress))&&$this->_mp->animdir=='0') {
			$code .="function handleErrors".$this->_mp->mapnm."(){
						var dirsidebar".$this->_mp->mapnm." = document.getElementById('dirsidebar".$this->_mp->mapnm."');
						var newelem = document.createElement('p');
						if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_UNKNOWN_ADDRESS)
							newelem.innerHTML = 'No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_SERVER_ERROR)
							newelem.innerHTML = 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_MISSING_QUERY)
							 newelem.innerHTML = 'The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						//   else if (directions".$this->_mp->mapnm.".getStatus().code == G_UNAVAILABLE_ADDRESS)  <--- Doc bug... this is either not defined, or Doc is wrong
						//     newelem.innerHTML = 'The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						   else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_BAD_KEY)
							 newelem.innerHTML = 'The given key is either invalid or does not match the domain for which it was given.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						
						   else if (directions".$this->_mp->mapnm.".getStatus().code == G_GEO_BAD_REQUEST)
							 newelem.innerHTML = 'A directions request could not be successfully parsed.<br />Error code: ' + directions".$this->_mp->mapnm.".getStatus().code;
						   else newelem.innerHTML = 'An unknown error occurred.';
						dirsidebar".$this->_mp->mapnm.".appendChild(newelem); 
					}
						";
			}
			
		if ($this->_mp->dir!='0'&&$this->_mp->animdir=='0') {
			$code.="\nDirectionMarkersubmit".$this->_mp->mapnm." = function( formObj ){
						if(formObj.dir&&formObj.dir[1].checked ){
							tmp = formObj.daddr.value;
							formObj.daddr.value = formObj.saddr.value;
							formObj.saddr.value = tmp;
						}";
			if ($this->_mp->dir=='1')
				$code.="\nformObj.submit();";
			elseif ($this->_mp->dir=='2')
				$code.="\nformObj.submit();";
			elseif ($this->_mp->dir=='3')
				$code.="\nfor (var i=0; i < formObj.dirflg.length; i++) {
						   if (formObj.dirflg[i].checked) {
							  var dirflg= formObj.dirflg[i].value;
							  break;
						   }
						}
						MOOdalBox.open('".$this->protocol.$this->googlewebsite."/maps?dir=to&dirflg='+dirflg+'&saddr='+formObj.saddr.value+'&hl=en&daddr='+formObj.daddr.value+'".(($this->_mp->lang!='')?"&amp;hl=".$this->_mp->lang:"")."&pw=2', '".$this->_mp->lbxcaption."', '".$this->_mp->lbxwidth." ".$this->_mp->lbxheight."', null, 16);";
			elseif ($this->_mp->dir=='5') 
					$code .= "\nfor (var i=0; i < formObj.dirflg.length; i++) {
								   if (formObj.dirflg[i].checked) {
									  var dirflg= formObj.dirflg[i].value;
									  break;
								   }
								}
								var dirsidebar".$this->_mp->mapnm." = document.getElementById('dirsidebar".$this->_mp->mapnm."');
								if (directions".$this->_mp->mapnm.") {
									directions".$this->_mp->mapnm.".clear();
									if ( dirsidebar".$this->_mp->mapnm.".hasChildNodes() )
										{
											while ( dirsidebar".$this->_mp->mapnm.".childNodes.length >= 1 )
											{
												dirsidebar".$this->_mp->mapnm.".removeChild( dirsidebar".$this->_mp->mapnm.".firstChild );       
											} 
										}
								} else {
									directions".$this->_mp->mapnm." = new GDirections(map".$this->_mp->mapnm.", dirsidebar".$this->_mp->mapnm.");
									GEvent.addListener(directions".$this->_mp->mapnm.", 'error', handleErrors".$this->_mp->mapnm.");
								}
								options = Array();
								if (dirflg=='w')
									options.travelMode = G_TRAVEL_MODE_WALKING;
								if (dirflg=='h')
									options.avoidHighways = true;
								directions".$this->_mp->mapnm.".load('from: '+formObj.saddr.value+' to: '+formObj.daddr.value, options);
							";
			else
				$code.="\nfor (var i=0; i < formObj.dirflg.length; i++) {
						   if (formObj.dirflg[i].checked) {
							  var dirflg= formObj.dirflg[i].value;
							  break;
						   }
						}
						MOOdalBox.open('".$this->protocol.$this->googlewebsite."/maps?dir=to&dirflg='+dirflg+'&saddr='+formObj.saddr.value+'&hl=en&daddr='+formObj.daddr.value+'".(($this->_mp->lang!='')?"&amp;hl=".$this->_mp->lang:"")."', '".$this->_mp->lbxcaption."', '".$this->_mp->lbxwidth." ".$this->_mp->lbxheight."', null, 16);";
				
			$code.="\nif(formObj.dir&&formObj.dir[1].checked )
						setTimeout('DirectionRevert".$this->_mp->mapnm."()',100);
					};";
			
			$code.="\nDirectionRevert".$this->_mp->mapnm." = function(){
						formObj = document.getElementById('directionform".$this->_mp->mapnm."');
						tmp = formObj.daddr.value;
						formObj.daddr.value = formObj.saddr.value;
						formObj.saddr.value = tmp;
					};";
		}
		
		// Function for overview
		if(!$this->_mp->overview==0) {
			$code.="\nfunction checkOverview".$this->_mp->mapnm."() {
						for (var i in overviewmap".$this->_mp->mapnm.") {
							if (overviewmap".$this->_mp->mapnm."[i].setMapType) {
								overmap".$this->_mp->mapnm." = overviewmap".$this->_mp->mapnm."[i];
								break;
							}
						}						
						if (overmap".$this->_mp->mapnm.") {
					";
						  
			if($this->_mp->overview==2)

			{
				$code.="\n		overviewmap".$this->_mp->mapnm.".hide(true);";
			}

			switch ($this->_mp->mapType) {
			case "satellite":
			
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_SATELLITE_MAP);";
				break;
			
			case "hybrid":
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_HYBRID_MAP);";
				break;

			case "terrain":
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_PHYSICAL_MAP);";
				break;
			
			case "earth":
				break;

			default:
				$code.="\n		overmap".$this->_mp->mapnm.".setMapType(G_NORMAL_MAP);";
				break;
			}
			
			if ($this->_mp->ovzoom!="") {
				$code.="\n		setTimeout('overmap".$this->_mp->mapnm.".setCenter(map".$this->_mp->mapnm.".getCenter(), map".$this->_mp->mapnm.".getZoom()+".$this->_mp->ovzoom.")', 100);";
				$code.="\n		GEvent.addListener(map".$this->_mp->mapnm.",'move',function() {
var c = Math.min(Math.max(0, map".$this->_mp->mapnm.".getZoom()+".$this->_mp->ovzoom."), 19);
overmap".$this->_mp->mapnm.".setCenter(map".$this->_mp->mapnm.".getCenter(), c);
});";
				$code.="\n		GEvent.addListener(map".$this->_mp->mapnm.",'moveend',function() {
var c = Math.min(Math.max(0, map".$this->_mp->mapnm.".getZoom()+".$this->_mp->ovzoom."), 19);
overmap".$this->_mp->mapnm.".setCenter(map".$this->_mp->mapnm.".getCenter(), c);

});";
			}
			$code.= "\n	} else {
						  setTimeout('checkOverview".$this->_mp->mapnm."()',100);
						}
					  }";
		}
		
		$code.="\nfunction initearth".$this->_mp->mapnm."(geplugin) {
			if (!geplugin".$this->_mp->mapnm.")
				geplugin".$this->_mp->mapnm." = geplugin;
			if (geplugin".$this->_mp->mapnm."&&map".$this->_mp->mapnm.".getCurrentMapType() == G_SATELLITE_3D_MAP) {";

		// Add layers
		if ($this->_mp->earthborders=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_BORDERS, true);";
		if ($this->_mp->earthbuildings=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_BUILDINGS, true);";
		else
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_BUILDINGS, false);";
		if ($this->_mp->earthroads=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_ROADS, true);";
		if ($this->_mp->earthterrain=="1")
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_TERRAIN, true);";
		else
			$code.="\n	geplugin".$this->_mp->mapnm.".getLayerRoot().enableLayerById(geplugin".$this->_mp->mapnm.".LAYER_TERRAIN, false);";
			
		if ($this->_mp->tilelayer) {
			$code.="\n	var url = '".$this->_mp->tilelayer."';
			var newurl = url+'/doc.kml';
			var link = geplugin".$this->_mp->mapnm.".createLink('');
			link.setHref(newurl);
			var networkLink = geplugin".$this->_mp->mapnm.".createNetworkLink('');
			networkLink.set(link, false, false);
			geplugin".$this->_mp->mapnm.".getFeatures().appendChild(networkLink);";
		}
		
		if (count($this->_mp->lookat)>0||count($this->_mp->camera)>0)
			$code.="\n	setTimeout('setearth".$this->_mp->mapnm."()', ".$this->_mp->earthtimeout.");";
			
		$code.="\n}
				}";
				
		if (count($this->_mp->lookat)>0||count($this->_mp->camera)>0) {
			$la = false;
			$cam = false;
			$code.="\nfunction setearth".$this->_mp->mapnm."() {
						var lookat = geplugin".$this->_mp->mapnm.".getView().copyAsLookAt(geplugin".$this->_mp->mapnm.".ALTITUDE_RELATIVE_TO_GROUND);
						var camera = geplugin".$this->_mp->mapnm.".getView().copyAsCamera(geplugin".$this->_mp->mapnm.".ALTITUDE_RELATIVE_TO_GROUND);";
			if (count($this->_mp->lookat)>0) {
				$values = explode(',', $this->_mp->lookat[0]);
				if (count($values)>0&&$values[0]!='') { // Latitude
					$code.="\nlookat.setLatitude(".$values[0].");";
					$la = true;
				}
				if (count($values)>1&&$values[1]!='') { // Longitude
					$code.="\nlookat.setLongitude(".$values[1].");";
					$la = true;
				}
				if (count($values)>2&&$values[2]!='') { // Range
					$code.="\nlookat.setRange(".$values[2].");";
					$la = true;
				}
				if (count($values)>3&&$values[3]!='') { // tilt
					$code.="\nlookat.setTilt(".$values[3].");";
					$la = true;
				}
				if (count($values)>4&&$values[4]!='') { // setHeading
					$code.="\nlookat.setHeading(".$values[4].");";
					$la = true;
				}
				if (count($values)>5&&$values[5]!='') { // altitude
					$code.="\nlookat.setAltitude(".$values[5].");";
					$la = true;
				}
				if (count($values)>6&&$values[6]!='') {// flyspeed
					if ($values[6]=='teleport')
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(geplugin".$this->_mp->mapnm.".SPEED_TELEPORT);";
					else
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(".$values[6].");";
				}
			}
			
			if (count($this->_mp->camera)>0) {
				$values = explode(',', $this->_mp->camera[0]);
				if (count($values)>0&&$values[0]!='') { // Latitude
					$code.="\ncamera.setLatitude(".$values[0].");";
					$cam = true;

				}
				if (count($values)>1&&$values[1]!='') { // Longitude
					$code.="\ncamera.setLongitude(".$values[1].");";
					$cam = true;
				}
				if (count($values)>2&&$values[2]!='') { // tilt
					$code.="\ncamera.setTilt(".$values[2].");";
					$cam = true;
				}
				if (count($values)>3&&$values[3]!='') { // heading
					$code.="\ncamera.setHeading(".$values[3].");";
					$cam = true;
				}
				if (count($values)>4&&$values[4]!='') { // altitude
					$code.="\ncamera.setAltitude(".$values[4].");";
					$cam = true;
				}
				if (count($values)>5&&$values[5]!='') { // roll
					$code.="\ncamera.setRoll(".$values[5].");";
					$cam = true;
				}
				if (count($values)>6&&$values[6]!='') {// flyspeed
					if ($values[6]=='teleport')
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(geplugin".$this->_mp->mapnm.".SPEED_TELEPORT);";
					else
						$code.="\ngeplugin".$this->_mp->mapnm.".getOptions().setFlyToSpeed(".$values[6].");";
				}
			}
					
			if ($la)
				$code.="\n	geplugin".$this->_mp->mapnm.".getView().setAbstractView(lookat);";
			if ($cam)
				$code.="\n	geplugin".$this->_mp->mapnm.".getView().setAbstractView(camera);";
				
			$code.="\n}";
		}

		if ($this->_mp->kmlrenderer=='arcgis') {
			$code .="\nfunction dynmapcallback".$this->_mp->mapnm."(mapservicelayer) {
						  map".$this->_mp->mapnm.".addOverlay(mapservicelayer);
							}";	
		}
		
		if ($this->_mp->kmlrenderer=='google') {
			$code .= "\nfunction savePositionKML".$this->_mp->mapnm."() {
							ok = true;
							for (x=0;x<xml".$this->_mp->mapnm.".length;x++) {
								if (!xml".$this->_mp->mapnm."[x].hasLoaded())
									ok = false;
							}
							if (ok)
								map".$this->_mp->mapnm.".savePosition();
							else
								setTimeout('savePositionKML".$this->_mp->mapnm."()',100);
						}
					";
		}
		
			
		// Functions to watch if the map has changed
		$code.="\nfunction checkMap".$this->_mp->mapnm."()
		{
			if (tst".$this->_mp->mapnm.") {
			";
			
		if ($this->_mp->show!=0)
			$code.="\n			if (tst".$this->_mp->mapnm.".offsetWidth != tst".$this->_mp->mapnm.".getAttribute(\"oldValue\"))
					{
						tst".$this->_mp->mapnm.".setAttribute(\"oldValue\",tst".$this->_mp->mapnm.".offsetWidth);
						if (tst".$this->_mp->mapnm.".offsetWidth > 0) {
					";

		$code.="\n				if (tst".$this->_mp->mapnm.".getAttribute(\"refreshMap\")==0)

							clearInterval(tstint".$this->_mp->mapnm.");";
		if ($this->_mp->effect !='none') 
			$code .="\n					mySlidemap".$this->_mp->mapnm." = new Fx.Slide('googlemap".$this->_mp->mapnm."',{duration: 1500, mode: '".$this->_mp->effect."'});
							mySlidemap".$this->_mp->mapnm.".hide();
							mySlidemap".$this->_mp->mapnm.".slideIn();";

		$code .="\n					getMap".$this->_mp->mapnm."();
							tst".$this->_mp->mapnm.".setAttribute(\"refreshMap\", 1);";
		if ($this->_mp->show!=0)
			$code .="\n				} 
					}";
		$code .="\n	}
		}
		";

		if ($this->_mp->sv!="none"&&$this->_mp->animdir=='0') {
			$code .="\nfunction onYawChange".$this->_mp->mapnm."(newYaw) {
						var GUY_NUM_ICONS = 16;
						var GUY_ANGULAR_RES = 360/GUY_NUM_ICONS;
						if (newYaw < 0) {
							newYaw += 360;
						}
						var guyImageNum = Math.round(newYaw/GUY_ANGULAR_RES) % GUY_NUM_ICONS;
						var guyImageUrl = '".$this->base."/media/plugin_googlemap2/site/StreetViewControl/images/man_arrow-' + guyImageNum + '.png';
						svmarker".$this->_mp->mapnm.".setImage(guyImageUrl);
					}

					function onNewLocation".$this->_mp->mapnm."(point) {
						// Get the original x + y coordinates
						svmarker".$this->_mp->mapnm.".setLatLng(point.latlng);
						map".$this->_mp->mapnm.".panTo(point.latlng);
						svlastpoint".$this->_mp->mapnm." = point.latlng;";
			if ($this->_mp->svautorotate=="1")		
				$code .="\nspiralstart".$this->_mp->mapnm."();
";
						
			$code .="\n}

					function onDragEnd".$this->_mp->mapnm."() {
						var latlng = svmarker".$this->_mp->mapnm.".getLatLng();
						if (svpanorama".$this->_mp->mapnm.") {
							svclient".$this->_mp->mapnm.".getNearestPanorama(latlng, svonResponse".$this->_mp->mapnm.");
						}
					}

					function svonResponse".$this->_mp->mapnm."(response) {
						if (response.code != 200) {
							svmarker".$this->_mp->mapnm.".setLatLng(svlastpoint".$this->_mp->mapnm.");
							map".$this->_mp->mapnm.".setCenter(svlastpoint".$this->_mp->mapnm.");
						} else {
							var latlng = new GLatLng(response.Location.lat, response.Location.lng);

							svmarker".$this->_mp->mapnm.".setLatLng(latlng);
							svlastpoint".$this->_mp->mapnm." = latlng;
							svpanorama".$this->_mp->mapnm.".setLocationAndPOV(latlng, null);
						}
					}
					";

			if ($this->_mp->svautorotate=="1")		
				$code .="\nfunction spiral".$this->_mp->mapnm."() {
							var pov=svpanorama".$this->_mp->mapnm.".getPOV();
							svpanorama".$this->_mp->mapnm.".panTo({yaw:pov.yaw+2, pitch:pov.pitch, zoom:pov.zoom});
						}
						function svmouseover".$this->_mp->mapnm." () {
							svfocus".$this->_mp->mapnm." = true;
							spiralstop".$this->_mp->mapnm."();
						}
						function svmouseout".$this->_mp->mapnm." () {
							svfocus".$this->_mp->mapnm." = false;
							spiralstart".$this->_mp->mapnm."();
						}
						function spiralstop".$this->_mp->mapnm."() {
							if (timer".$this->_mp->mapnm.") {
								clearInterval(timer".$this->_mp->mapnm.");
								timer".$this->_mp->mapnm." = null;
							}
						}
						function spiralstart".$this->_mp->mapnm."() {
							if (!svfocus".$this->_mp->mapnm.") {
								if (timer".$this->_mp->mapnm.")
									spiralstop".$this->_mp->mapnm."();
								timer".$this->_mp->mapnm." = window.setInterval(spiral".$this->_mp->mapnm.", 200);
							}
						}
				";
		}

		// Function for displaying the map and marker
		$code.="\nfunction getMap".$this->_mp->mapnm."(){";
	
		if ($this->_mp->show!=0)
			$code.="\n	if (tst".$this->_mp->mapnm.".offsetWidth > 0) {";
		
		$code.="\n	map".$this->_mp->mapnm." = new GMap2(document.getElementById('googlemap".$this->_mp->mapnm."')".(($this->_mp->googlebar=='1'&&!empty($searchoptions))?", { googleBarOptions: {".$searchoptions." } }":"").");
				map".$this->_mp->mapnm.".getContainer().style.overflow='hidden';
				";
		
		if ($this->_mp->sv!="none"||$this->_mp->animdir!='0')
			$code.="\nsvclient".$this->_mp->mapnm." = new GStreetviewClient();";
			
		if($this->_mp->keyboard=='1'&&$this->_mp->controltype=='user')
		{
			$code.="\nnew GKeyboardHandler(map".$this->_mp->mapnm.");
			";
		} 
		if($this->_mp->dragging=="0")
			$code.="\nmap".$this->_mp->mapnm.".disableDragging();";
	
		if ($this->_mp->shownormalmaptype=="0")
			$code.="\nmap".$this->_mp->mapnm.".removeMapType(G_NORMAL_MAP);";
		if ($this->_mp->showsatellitemaptype=="0")
			$code.="\nmap".$this->_mp->mapnm.".removeMapType(G_SATELLITE_MAP);";
		if ($this->_mp->showhybridmaptype=="0")
			$code.="\nmap".$this->_mp->mapnm.".removeMapType(G_HYBRID_MAP);";
		if ($this->_mp->showterrainmaptype=="1")
			$code.="\nmap".$this->_mp->mapnm.".addMapType(G_PHYSICAL_MAP);";
		if ($this->_mp->showearthmaptype=="1") {
			$code.="\nmap".$this->_mp->mapnm.".addMapType(G_SATELLITE_3D_MAP);";
			$code.="\nGEvent.addListener(map".$this->_mp->mapnm.", 'maptypechanged', function() {
										if (map".$this->_mp->mapnm.".getCurrentMapType() == G_SATELLITE_3D_MAP)
											setTimeout('map".$this->_mp->mapnm.".getEarthInstance(initearth".$this->_mp->mapnm.")',100);
						 });
						";			
		}
	
		if(!$this->_mp->overview==0)
		{
			$code.="\noverviewmap".$this->_mp->mapnm." = new GOverviewMapControl();";

			$code.="\nmap".$this->_mp->mapnm.".addControl(overviewmap".$this->_mp->mapnm.", new GControlPosition(G_ANCHOR_BOTTOM_RIGHT));";
			$code.="setTimeout('checkOverview".$this->_mp->mapnm."()',100);";
	
		} elseif (!$this->_mp->overview==0) {
			$code.="\noverviewmap".$this->_mp->mapnm." = new GOverviewMapControl();";
			$code.="\nmap".$this->_mp->mapnm.".addControl(overviewmap".$this->_mp->mapnm.", new GControlPosition(G_ANCHOR_BOTTOM_RIGHT));";
			
			if($this->_mp->overview==2)
			{
				$code.="\noverviewmap".$this->_mp->mapnm.".hide(true);";
			}
		}
	
		if($this->_mp->navlabel == 1)
			$code.="\nmap".$this->_mp->mapnm.".addControl(new GNavLabelControl(), new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(7, 30)));";
	
		if($this->_client_geo == 1) {
			if ($this->clientgeotype=="local") {
				$code.="\nvar localSearch = new GlocalSearch();";
				$replace = array("\n", "\r", "&lt;br/&gt;", "&lt;br /&gt;", "&lt;br&gt;");
				$addr = str_replace($replace, '', $this->_mp->address);
	
				$code.="\nvar address = \"".$addr."\";";
				$code.="\nlocalSearch.setSearchCompleteCallback(null,	function() {
						if (localSearch.results[0]) {
							var resultLat = localSearch.results[0].lat;
							var resultLng = localSearch.results[0].lng;
							var point = new GLatLng(resultLat,resultLng);
						} else 
						";
				if ($this->_mp->latitude !=''&&$this->_mp->longitude!='')
					$code.="var point = new GLatLng( {$this->_mp->latitude}, {$this->_mp->longitude});";
				else
					$code.="var point = new GLatLng( {$this->_mp->deflatitude}, {$this->_mp->deflongitude});";
			} else {
				$code.="var geocoder = new GClientGeocoder();";
				$replace = array("\n", "\r", "&lt;br/&gt;", "&lt;br /&gt;", "&lt;br&gt;");
				$addr = str_replace($replace, '', $this->_mp->address);
	
				$code.="var address = \"".$addr."\";";
				$code.="geocoder.getLatLng(address, function(point) {
							if (!point)";
							
				if ($this->_mp->latitude !=''&&$this->_mp->longitude!='')
					$code.="var point = new GLatLng( {$this->_mp->latitude}, {$this->_mp->longitude});";
				else
					$code.="var point = new GLatLng( {$this->_mp->deflatitude}, {$this->_mp->deflongitude});";
			}
		} else { 
			if ($this->_mp->latitude !=''&&$this->_mp->longitude!='')
				$code.="\nvar point = new GLatLng( {$this->_mp->latitude}, {$this->_mp->longitude});";
			else
				$code.="\nvar point = new GLatLng( {$this->_mp->deflatitude}, {$this->_mp->deflongitude});";
		}
		if (!empty($this->_mp->centerlat)&&!empty($this->_mp->centerlon))
			$code.="\nvar centerpoint = new GLatLng( {$this->_mp->centerlat}, {$this->_mp->centerlon});";
		else
			$code.="\nvar centerpoint = point;";
	
		if ($this->_inline_coords == 0 && count($this->_mp->kml)>0)
			$code.="map".$this->_mp->mapnm.".setCenter(new GLatLng(0, 0), 0);
			";					
		else
			$code.="map".$this->_mp->mapnm.".setCenter(centerpoint, ".$this->_mp->zoom.");
			";					
			
		if ($this->_mp->controltype=='user') {
			switch ($this->_mp->zoomtype) {
				case "Large":
					$code.="map".$this->_mp->mapnm.".addControl(new GLargeMapControl());";

					break;
				case "Small":
					$code.="map".$this->_mp->mapnm.".addControl(new GSmallMapControl());";
					break;
				case "3D-large":
					$code.="map".$this->_mp->mapnm.".addControl(new GLargeMapControl3D());";
					if ($this->_mp->rotation)
						$code.="map".$this->_mp->mapnm.".enableRotation();";
					break;
				case "3D-largeSV":
					$code.="map".$this->_mp->mapnm.".addControl(new StreetViewControl());";
					if ($this->_mp->rotation)
						$code.="map".$this->_mp->mapnm.".enableRotation();";
					break;
				case "3D-small":
					$code.="map".$this->_mp->mapnm.".addControl(new GSmallZoomControl3D());";
					if ($this->_mp->rotation)
						$code.="map".$this->_mp->mapnm.".enableRotation();";
					break;
				default:
					break;
			}
			
			switch ($this->_mp->showmaptype) {
				case "0":
					break;
				case "1":
					$code.="map".$this->_mp->mapnm.".addControl(new GMapTypeControl());";
					break;
				case "2":
					$code.="map".$this->_mp->mapnm.".addControl(new GHierarchicalMapTypeControl());";
					break;
				case "3":
					$code.="map".$this->_mp->mapnm.".addControl(new GMenuMapTypeControl());";
					break;
			} 
	
			if ($this->_mp->showscale==1)
				$code.="map".$this->_mp->mapnm.".addControl(new GScaleControl());";
		} else {
			$code.="map".$this->_mp->mapnm.".setUIToDefault();";
			if ($this->_mp->rotation)
				$code.="map".$this->_mp->mapnm.".enableRotation();";
		}
			
		if (count($this->_mp->kml)>0) {
			if ($this->_mp->kmlrenderer=="google") {
				$code .= "xml".$this->_mp->mapnm." = [];";
				$kmz= false;
				foreach ($this->_mp->kml as $idx => $val) {
					$code .= "var kmlurl = '".$this->_make_absolute($this->_mp->kml[$idx])."';";
					$code .= "kmlurl = kmlurl.replace(/&amp;/g, String.fromCharCode(38));";
					$code .= "\nxml".$this->_mp->mapnm."[".$idx."] = new GGeoXml(kmlurl);";
					$code .= "\nmap".$this->_mp->mapnm.".addOverlay(xml".$this->_mp->mapnm."[".$idx."]);";
					if (strpos($this->_mp->kml[$idx], '.kmz')!=0)
						$kmz = true;
				}
				if ($kmz) {
					$code .= "\n   GEvent.addListener(map".$this->_mp->mapnm.", 'infowindowopen', function() {
						var divs = map".$this->_mp->mapnm.".getContainer().getElementsByTagName('div');
						for (var n = 0 ; n < divs.length ; ++n) {
							if (divs[n].id == 'iw_kml') {
								var imgs = divs[n].getElementsByTagName('img');
								for (var j = 0 ; j < imgs.length ; ++j) {
									var index = imgs[j].src.indexOf('/mapsatt');
									if (index != -1)
										imgs[j].src = 'http://maps.google.com' + imgs[j].src.substr(index);
								}
							}
						}
					}
					);";
				}
				if ($this->_inline_coords==0) {
					
					$code .= "\nGEvent.addListener(xml".$this->_mp->mapnm."[0], 'load', function() {
								if (xml".$this->_mp->mapnm."[0].loadedCorrectly()) {";
					$code .= "\nxml".$this->_mp->mapnm."[0].gotoDefaultViewport(map".$this->_mp->mapnm.");";
					if ($this->_mp->corzoom!='0')
						$code .= "\nmap".$this->_mp->mapnm.".setZoom(map".$this->_mp->mapnm.".getZoom()+".$this->_mp->corzoom.");";
					$code .= "\nsavePositionKML".$this->_mp->mapnm."();"; 
					$code .= "\n}
							});";
				}
				if (count($this->_mp->kmlsb)!=0) {
					$this->_mp->kmlrenderer = 'geoxml';
					$this->_mp->kml=$this->_mp->kmlsb;
				}
			}
			
			if ($this->_mp->kmlrenderer=="arcgis") {
				$code .= "var xml = [];";
				foreach ($this->_mp->kml as $idx => $val) {
					$code .= "var kmlurl = '".$this->_make_absolute($this->_mp->kml[$idx])."';";
					$code .= "\nkmlurl = kmlurl.replace(/&amp;/g, String.fromCharCode(38));";
					$code .= "\nxml[".$idx."] = new esri.arcgis.gmaps.DynamicMapServiceLayer(kmlurl, null, 0.75, dynmapcallback".$this->_mp->mapnm.");";
				}
			}
			
			if ($this->_mp->kmlrenderer=="geoxml") {
				$code .= "\nvar kml".$this->_mp->mapnm." = [];";
				foreach ($this->_mp->kml as $idx => $val) {
					$code .= "\nvar kmlurl = '".(($this->_mp->proxy=='1')?$this->_make_absolute($this->_mp->kml[$idx]):$this->_mp->kml[$idx])."';";
					$code .= "\nkmlurl = escape(kmlurl.replace(/&amp;/g, String.fromCharCode(38)));";
					$code .= "\nkml".$this->_mp->mapnm.".push(kmlurl);";
				}
				$xmloptions = array();
				if ($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right") {
					$xmloptions[] = "sidebarid: 'kmlsidebar".$this->_mp->mapnm."'";
				} else {
					if ($this->_mp->kmlsidebar!="none")
						$xmloptions[] = "sidebarid: '".$this->_mp->kmlsidebar."'";
				}
				if ($this->_mp->kmlmessshow=='1')
					$xmloptions[] = "messshow: true";
				
				if ($this->_inline_coords==1)
					$xmloptions[] = "nozoom: true";
	
				if ($this->_mp->dir!='0')
					$xmloptions[] = "directions: true";
					
				if ($this->_mp->kmlfoldersopen!='0')
					$xmloptions[] = "allfoldersopen: true";
					
				if ($this->_mp->kmlhide!='0')
					$xmloptions[] = "hideall: true";

				if ($this->_mp->kmlscale!='0')
					$xmloptions[] = "scale: true";

				if ($this->_mp->kmlopenmethod!='0')
					$xmloptions[] = "iwmethod: '".$this->_mp->kmlopenmethod."'";
				
				if ($this->_mp->kmlsbsort=='asc') {
					$xmloptions[] = "sortbyname: 'asc'";
				}elseif ($this->_mp->kmlsbsort=='desc') {
					$xmloptions[] = "sortbyname: 'desc'";
				} else 	
					$xmloptions[] = "sortbyname: 'none'";
	
				if ($this->_mp->kmlclickablemarkers!='1')
					$xmloptions[] = "clickablemarkers: false";
					
				if ($this->_mp->kmlzoommarkers!='0')
					$xmloptions[] = "zoommarkers: '".$this->_mp->kmlzoommarkers."'";

				if ($this->_mp->kmlopendivmarkers!='')
					$xmloptions[] = "opendivmarkers: '".$this->_mp->kmlopendivmarkers."'";

				if ($this->_mp->kmlcontentlinkmarkers!='0')
					$xmloptions[] = "contentlinkmarkers: true";

				if ($this->_mp->kmllinkablemarkers!='0')
					$xmloptions[] = "linkablemarkers: true";

				if ($this->_mp->kmllinktarget!='')
					$xmloptions[] = "linktarget: '".$this->_mp->kmllinktarget."'";

				if ($this->_mp->kmllinkmethod!='')
					$xmloptions[] = "linkmethod: '".$this->_mp->kmllinkmethod."'";

				if (($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")) {
					$xmloptions[] = "polylabelopacity: '".$this->_mp->kmlpolylabel."'";
					$xmloptions[] = "polylabelclass: '".$this->_mp->kmlpolylabelclass."'";
				}
				if (($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!="")) {
					$xmloptions[] = "pointlabelopacity: '".$this->_mp->kmlmarkerlabel."'";
					$xmloptions[] = "pointlabelclass: '".$this->_mp->kmlmarkerlabelclass."'";
				}
				if ($this->_mp->icon!='')
					$xmloptions[] ="baseicon : markericon".$this->_mp->mapnm;
	
				if ($this->_mp->maxcluster!=''&&$this->_mp->gridsize!='') {
					$clusteroptions = array();
					if ($this->_mp->maxcluster!='')
						$clusteroptions[] ="maxVisibleMarkers : ".$this->_mp->maxcluster;
					if ($this->_mp->gridsize!='')
						$clusteroptions[] ="gridSize : ".$this->_mp->gridsize;
					if ($this->_mp->minmarkerscluster!='')
						$clusteroptions[] ="minMarkersPerCluster : ".$this->_mp->minmarkerscluster;
					if ($this->_mp->maxlinesinfocluster!='')
						$clusteroptions[] ="maxLinesPerInfoBox : ".$this->_mp->maxlinesinfocluster;
					if ($this->_mp->clusterinfowindow!='')
						$clusteroptions[] ="ClusterInfoWindow : '".$this->_mp->clusterinfowindow."'" ;
					if ($this->_mp->clusterzoom!='')
						$clusteroptions[] ="ClusterZoom : '".$this->_mp->clusterzoom."'" ;
					if ($this->_mp->clustermarkerzoom!='')
						$clusteroptions[] ="ClusterMarkerZoom : ".$this->_mp->clustermarkerzoom;
					if ($this->_mp->icon!='')
						$clusteroptions[] ="Icon : markericon".$this->_mp->mapnm;
	
					$xmloptions[] = "clustering : {".implode(",",$clusteroptions)."}";
				}
				
				$xmloptions[] = "titlestyle: ' '";
					
				$code .= "\nexml".$this->_mp->mapnm." = new GeoXml(\"exml".$this->_mp->mapnm."\", map".$this->_mp->mapnm.", kml".$this->_mp->mapnm.", {".implode(",",$xmloptions)."});";
				$code .= "\nexml".$this->_mp->mapnm.".parse(); ";
				if ($this->_inline_coords==0&&$this->_mp->corzoom!='0')
					$code .= "\nsetTimeout('map".$this->_mp->mapnm.".setZoom(map".$this->_mp->mapnm.".getZoom()+".$this->_mp->corzoom.")', 750);";
			}
		}
	
		if ($this->_mp->traffic=='1') {
			$code .= "\ntrafficInfo".$this->_mp->mapnm." = new GTrafficOverlay();";
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(trafficInfo".$this->_mp->mapnm.");";
		}
	
		if ($this->_mp->panoramio!="none") {
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('com.panoramio.".$this->_mp->panoramio."'));";
		}
		if ($this->_mp->panotype!="none") {
			$code .= "\n  var options = {
							order: '".$this->_mp->panoorder."',
							set: '".$this->_mp->panotype."', 
							to: '".$this->_mp->panomax."' };
						panoLayer".$this->_mp->mapnm." = new PanoramioLayer(map".$this->_mp->mapnm.", options);
						panoLayer".$this->_mp->mapnm.".enable();";
		}
		
		if ($this->_mp->youtube!="none") {
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('com.youtube.".$this->_mp->youtube."'));";
		}
	
		if ($this->_mp->wiki!="none") {
			$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('org.wikipedia.".$this->_mp->wiki."'));";
		}
		
		if (count($this->_mp->layer)>0) {
			foreach ($this->_mp->layer as $lay) {
				$code .= "\nmap".$this->_mp->mapnm.".addOverlay(new GLayer('".$lay."'));";
			}
		}
		
		if ($this->_mp->localsearch=='1') {
			$code .= "localsearch".$this->_mp->mapnm." = new google.maps.LocalSearch(".((!empty($searchoptions))?"{ ".$searchoptions." }":"").");";
			$code .= "map".$this->_mp->mapnm.".addControl(localsearch".$this->_mp->mapnm.", new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10,20)));";
			if (!empty($this->_mp->searchtext))
				$code .= "localsearch".$this->_mp->mapnm.".execute('".$this->_mp->searchtext."');";
		}
		
		if ($this->_mp->googlebar=='1') {
			$code .= "map".$this->_mp->mapnm.".enableGoogleBar();";
		}
	
		if ($this->_mp->adsmanager=='1') {
			$code .= "adsmanager".$this->_mp->mapnm." = new GAdsManager(map".$this->_mp->mapnm.", ".((!empty($this->_mp->adsense))?"'".$this->_mp->adsense."'":"''").", { style: 'adunit', maxAdsOnMap: ".$this->_mp->maxads.((!empty($this->_mp->searchtext))?", keywords: '".$this->_mp->searchtext."'":"").((!empty($this->_mp->channel)&&!empty($this->_mp->adsense))?", channel: '".$this->_mp->channel."'":"").(($this->_mp->localsearch=='1')?", position: new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(20,20))":"")."}); ";
			$code .= "adsmanager".$this->_mp->mapnm.".enable();";
		}
	
		if ($this->debug_plugin=="1")
			$code.="map".$this->_mp->mapnm.".addControl(new VersionControl());";
	
		if (((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->toaddress))&&$this->_mp->animdir=='0'&&$this->_mp->formaddress!='1') {
			// Route
			$xmloptions = array();
			if ($this->_mp->dirtype=='W')
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_WALKING";
			else
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_DRIVING";
			
			if ($this->_mp->avoidhighways=='1')
				$xmloptions[] = "avoidHighways : true";
			else
				$xmloptions[] = "avoidHighways : false";
			
			$code .= "var dirsidebar".$this->_mp->mapnm." = document.getElementById('dirsidebar".$this->_mp->mapnm."');";
			$code .= "if (directions".$this->_mp->mapnm.") {
							directions".$this->_mp->mapnm.".clear();
							if ( dirsidebar".$this->_mp->mapnm.".hasChildNodes() )
							{
								while ( dirsidebar".$this->_mp->mapnm.".childNodes.length >= 1 )
								{
									dirsidebar".$this->_mp->mapnm.".removeChild( dirsidebar".$this->_mp->mapnm.".firstChild );
								} 
							}
					} else {
							directions".$this->_mp->mapnm." = new GDirections(map".$this->_mp->mapnm.", dirsidebar".$this->_mp->mapnm.");
							GEvent.addListener(directions".$this->_mp->mapnm.", 'error', handleErrors".$this->_mp->mapnm.");
						}
				";
				
			if (is_array($this->_mp->waypoints)&&count($this->_mp->waypoints)>0) {
				if ($this->_mp->address!="")
					array_unshift($this->_mp->waypoints, $this->_mp->address);
				else if ($lat !=""&&$lon!="")
					array_unshift($this->_mp->waypoints, $lat.", ".$lon);
				
				if ($this->_mp->toaddress!="")
					array_push($this->_mp->waypoints, $this->_mp->toaddress);
				else if ($this->_mp->tolat!=""&&$this->_mp->tolon!="")
					array_push($this->_mp->waypoints, $this->_mp->tolat.", ".$this->_mp->tolon);
				
				$wpstring="";
				foreach ($this->_mp->waypoints as $wp) {
					if ($wpstring!="")
						$wpstring.= ", ";
					$wpstring .= "'".$wp."'";
				}
				$code.="\ndirections".$this->_mp->mapnm.".loadFromWaypoints([".$wpstring."], {".implode(",",$xmloptions)."});";
			} else
				$code.="\ndirections".$this->_mp->mapnm.".load('from: ".(($this->_mp->address!="")?$this->_mp->address:(($this->_mp->latitude!='')?$this->_mp->latitude:$this->_mp->deflatitude).", ".(($this->_mp->longitude!='')?$this->_mp->longitude:$this->_mp->deflongitude))." to: ".(($this->_mp->toaddress!="")?$this->_mp->toaddress:$this->_mp->tolat.", ".$this->_mp->tolon)."', {".implode(",",$xmloptions)."});";
		}
		
		switch (strtolower($this->_mp->mapType)) {
		case "satellite":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_SATELLITE_MAP);";
			break;
		
		case "hybrid":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_HYBRID_MAP);";
			break;
	
		case "terrain":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_PHYSICAL_MAP);";
			break;
	
		case "earth":
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_SATELLITE_3D_MAP);";
			$code.="\nmap".$this->_mp->mapnm.".getEarthInstance(initearth".$this->_mp->mapnm.");";
			break;
		
		default:
			$code.="\nmap".$this->_mp->mapnm.".setMapType(G_NORMAL_MAP);";
			break;
		}
		
		$code .="\nvar mt = map".$this->_mp->mapnm.".getMapTypes();
		for (var i=0; i<mt.length; i++) {
			mt[i].getMinimumResolution = function() {return ".$this->_mp->minzoom.";};
			mt[i].getMaximumResolution = function() {return ".$this->_mp->maxzoom.";};
		}";
	
		if($this->_mp->zoomnew=='1'&&$this->_mp->controltype=='user')
		{
			$code.="
			map".$this->_mp->mapnm.".enableContinuousZoom();
			map".$this->_mp->mapnm.".enableDoubleClickZoom();
			";
		} else {
			$code.="
			map".$this->_mp->mapnm.".disableContinuousZoom();
			map".$this->_mp->mapnm.".disableDoubleClickZoom();
			";
		}
	
		if($this->_mp->zoomwheel=='1'&&$this->_mp->controltype=='user')
		{
			$code.="map".$this->_mp->mapnm.".enableScrollWheelZoom();
			";
		} 
	
		if (($this->_inline_coords == 0 && count($this->_mp->kml)==0) // No inline coordinates and no kml => standard configuration
			||($this->_mp->latitude !=''&&$this->_mp->longitude!=''&&!($this->_mp->geocoded==1&&$this->_mp->toaddress!=''&&$this->_mp->description==''))) { // Inline coordinates and text is not empty
			$options = '';
			
			if ($this->_mp->tooltip!='') 
				$options .= (($options!='')?', ':'')."title:\"".$this->_mp->tooltip."\"";
			if ($this->_mp->icon!='')
				$options .= (($options!='')?', ':'')."icon:markericon".$this->_mp->mapnm;
			
			$code.="var marker".$this->_mp->mapnm." = new GMarker(point".(($options!='')?', {'.$options.'}':'').");";
			
			$code.="map".$this->_mp->mapnm.".addOverlay(marker".$this->_mp->mapnm.");
			";
	
			if ($this->_mp->description!=''||$this->_mp->dir!='0') {
				// convert $this->_mp->description to maybe tabs?
				// Check <tab> tag
				$reg='/(<tab\s*?(title=\\\?"(.*?)\\\?")?>)(.*?)(<\/tab>)/si';
				$c=preg_match_all($reg,$this->_mp->description,$m);
	
				// if <tab> then make array of $this->_mp->description
				if ($c>0) {
					$this->_mp->description= array();
					for ($z=0;$z<$c;$z++) {
						// transform attribute title to title of tab
						$this->_mp->description[$z]->title = htmlspecialchars_decode($m[3][$z], ENT_NOQUOTES);
						$this->_mp->description[$z]->text = htmlspecialchars_decode($m[4][$z], ENT_NOQUOTES);
					}
				}
				if ($this->_mp->dir!='0') {
					$dirform="<form id='directionform".$this->_mp->mapnm."' action='".$this->protocol.$this->googlewebsite."/maps' method='get' target='_blank' onsubmit='DirectionMarkersubmit".$this->_mp->mapnm."(this);return false;' class='mapdirform'>";
					
					$dirform.=$this->_mp->txtdir."<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='radio' ")." ".(($this->_mp->dirdefault=='0')?"checked='checked'":"")." name='dir' value='to'>".(($this->_mp->txtto!='')?$this->_mp->txtto."&nbsp;":"")."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='radio' ").(($this->_mp->dirdefault=='1')?"checked='checked'":"")." name='dir' value='from'>".(($this->_mp->txtfrom!='')?$this->_mp->txtfrom:"");
					$dirform.="<br />".$this->_mp->txtdiraddr."<input type='text' class='inputbox' size='20' name='saddr' id='saddr' value='' /><br />";
	
					if ($this->_mp->txt_driving!=''||$this->_mp->dirtype=="D")
							$dirform.="<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"");
					if ($this->_mp->txt_avhighways!=''||$this->_mp->dirtype=="1")
						$dirform.="<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"");
					if ($this->_mp->txt_walking!=''||$this->_mp->dirtype=="W")
						$dirform.="<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"");
					if ($this->_mp->txt_driving!=''||$this->_mp->txt_avhighways!=''||$this->_mp->txt_walking!='')
						$dirform.="<br />";	
					$dirform.="<input value='".$this->_mp->txtgetdir."' class='button' type='submit' style='margin-top: 2px;'>";
					
					if ($this->_mp->dir=='2')
						$dirform.= "<input type='hidden' name='pw' value='2'/>";
	
					if ($this->_mp->lang!='') 
						$dirform.= "<input type='hidden' name='hl' value='".$this->_mp->lang."'/>";
	
					if (!empty($this->_mp->address))
						$dirform.="<input type='hidden' name='daddr' value='".$this->_mp->address."'/></form>";
					else
						$dirform.="<input type='hidden' name='daddr' value='".(($this->_mp->latitude!='')?$this->_mp->latitude:$this->_mp->deflatitude).", ".(($this->_mp->longitude!='')?$this->_mp->longitude:$this->_mp->deflongitude)."'/></form>";
					
					// Add form before div or at the end of the html.
					if (is_array($this->_mp->description)) {
						$this->_mp->description[$z+1]->title = $this->_mp->txtdir;
						$this->_mp->description[$z+1]->text = htmlspecialchars_decode($dirform, ENT_NOQUOTES);
					} else {
						$pat="/&lt;\/div&gt;$/";
						if (preg_match($pat, $this->_mp->description))
							$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
						else {
							$pat="/<\/div>$/";
							if (preg_match($pat, $this->_mp->description))
								$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
							else
								$this->_mp->description.=$dirform;
						}
					}
				}
				
				if (!is_array($this->_mp->description))
					$this->_mp->description = htmlspecialchars_decode($this->_mp->description, ENT_NOQUOTES);
	
				// If marker 
				if ($this->_mp->marker==1) {
					if (is_array($this->_mp->description)) {
						$code .= "marker".$this->_mp->mapnm.".openInfoWindowTabsHtml([";
						$first = true;
						foreach ($this->_mp->description as $tab) {
							if ($first) 
								$first = false;
							else 
								$code.=",  ";
								
							$code.= "new GInfoWindowTab(\"".$tab->title."\", \"".$tab->text."\")";
						}
						
						$code .= "]);";  
						
					} else
						$code.="marker".$this->_mp->mapnm.".openInfoWindowHtml(\"".$this->_mp->description."\");"; 
				}
				
				$code.="GEvent.addListener(marker".$this->_mp->mapnm.", 'click', function() {
						marker".$this->_mp->mapnm;
				if (is_array($this->_mp->description)) {
					$code .=".openInfoWindowTabsHtml([";
					$first = true;
					foreach ($this->_mp->description as $tab) {
						if ($first) 
							$first = false;
						else 
							$code.=",  ";
							
						$code.= "new GInfoWindowTab(\"".$tab->title."\", \"".$tab->text."\")";
					}
					
					$code .= "]);";  
					
				} else
					$code.=".openInfoWindowHtml(\"".$this->_mp->description."\");";
					
				$code.="});
				";
			}
		}
		
		if ($this->_mp->imageurl!='') {
			$code .= "imageovl".$this->_mp->mapnm." = new GScreenOverlay('{$this->_mp->imageurl}',
									new GScreenPoint({$this->_mp->imagex}, {$this->_mp->imagey}, '{$this->_mp->imagexyunits}', '{$this->_mp->imagexyunits}'),  // screenXY
									new GScreenPoint({$this->_mp->imageanchorx}, {$this->_mp->imageanchory}, '{$this->_mp->imageanchorunits}', '{$this->_mp->imageanchorunits}'),  // overlayXY
									new GScreenSize({$this->_mp->imagewidth}, {$this->_mp->imageheight})  // size on screen
								);
						map".$this->_mp->mapnm.".addOverlay(imageovl".$this->_mp->mapnm.");
				";
		}
		if ($this->_mp->animdir=='0'&&($this->_mp->sv=='top'||$this->_mp->sv=='bottom'||($this->_mp->sv!='none'&&$this->_mp->sv!='top'&&$this->_mp->sv!='bottom'))) {
			if ($this->_mp->sv!='none'&&$this->_mp->sv!='top'&&$this->_mp->sv!='bottom')
				$code.="\npanobj".$this->_mp->mapnm." = document.getElementById('".$this->_mp->sv."');
						";
			else
				$code.="\npanobj".$this->_mp->mapnm." = document.getElementById('svpanorama".$this->_mp->mapnm."');
						";
			$this->_mp->svopt = "";
			if ($this->_mp->svyaw!='0')
				$this->_mp->svopt .= "yaw:".$this->_mp->svyaw;
			if ($this->_mp->svpitch!='0')
				$this->_mp->svopt .= (($this->_mp->svopt=="")?"":", ")."pitch:".$this->_mp->svpitch;
			if ($this->_mp->svzoom!='')
				$this->_mp->svopt .= (($this->_mp->svopt=="")?"":", ")."zoom:".$this->_mp->svzoom;
				
			$code.="\nsvpanorama".$this->_mp->mapnm." = new GStreetviewPanorama(panobj".$this->_mp->mapnm.");
					svlastpoint".$this->_mp->mapnm." = map".$this->_mp->mapnm.".getCenter();
					svpanorama".$this->_mp->mapnm.".setLocationAndPOV(svlastpoint".$this->_mp->mapnm.", ".(($this->_mp->svopt!='')?"{".$this->_mp->svopt."}":'null').");
					svmarker".$this->_mp->mapnm." = new GMarker(svlastpoint".$this->_mp->mapnm.", {icon: guyIcon".$this->_mp->mapnm." , draggable: true});
					map".$this->_mp->mapnm.".addOverlay(svmarker".$this->_mp->mapnm.");
					GEvent.addListener(svmarker".$this->_mp->mapnm.", 'dragend', onDragEnd".$this->_mp->mapnm.");
					GEvent.addListener(svpanorama".$this->_mp->mapnm.", 'initialized', onNewLocation".$this->_mp->mapnm.");
					GEvent.addListener(svpanorama".$this->_mp->mapnm.", 'yawchanged', onYawChange".$this->_mp->mapnm."); 
					";
			if ($this->_mp->svautorotate=="1")		
				$code.="\npanobj".$this->_mp->mapnm.".addEventListener('mouseover', svmouseover".$this->_mp->mapnm.", true);
					panobj".$this->_mp->mapnm.".addEventListener('mouseout', svmouseout".$this->_mp->mapnm.", true);
					";
		}
	
		if ($this->_mp->animdir!="0") {
			$xmloptions = array();
			$xmloptions[] = "preserveViewport: false";
			$xmloptions[] = "getSteps: true";
			
			if ($this->_mp->dirtype=='W')
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_WALKING";
			else
				$xmloptions[] = "travelMode : G_TRAVEL_MODE_DRIVING";
			
			if ($this->_mp->avoidhighways=='1')
				$xmloptions[] = "avoidHighways : true";
			else
				$xmloptions[] = "avoidHighways : false";
				
			$opts = array();
			if ($this->_mp->animspeed!=1)
				$opts[] = "Speed : ".$this->_mp->animspeed;
			if ($this->_mp->animautostart!=0)
				$opts[] = "AutoStart : true";
			if ($this->_mp->animunit!='')
				$opts[] = "Unit : '".$this->_mp->animunit."'";
	//					$opts[] = "zoomlevel : ".$this->_mp->zoom;
			if ($this->_mp->dirtype=='W')
				$opts[] = "travelMode : G_TRAVEL_MODE_WALKING";
			else
				$opts[] = "travelMode : G_TRAVEL_MODE_DRIVING";
			
			if ($this->_mp->avoidhighways=='1')
				$opts[] = "avoidHighways : true";
			else
				$opts[] = "avoidHighways : false";
	
			$code.="\nvar panobj = document.getElementById('svpanorama".$this->_mp->mapnm."');
					svpanorama".$this->_mp->mapnm." = new GStreetviewPanorama(panobj);
					directions".$this->_mp->mapnm." = new GDirections(map".$this->_mp->mapnm.");
					";
	
			$lang = "";
			foreach ($this->_langanim as $al) {
				$lang.=(($lang=='')?"":",")."'".$al."'";
			}
			
			$code.="\nopts = {".implode(",",$opts)."};
					lang = [".$lang."];
					";
			$code .="\nroute".$this->_mp->mapnm." = new Directionsobj('route".$this->_mp->mapnm."', map".$this->_mp->mapnm.", '".$this->_mp->mapnm."', svpanorama".$this->_mp->mapnm.", svclient".$this->_mp->mapnm.", directions".$this->_mp->mapnm.", centerpoint, opts, lang);";
			
			if (is_array($this->_mp->waypoints)&&count($this->_mp->waypoints)>0) {
				if ($this->_mp->address!="")
					array_unshift($this->_mp->waypoints, $this->_mp->address);
				if ($this->_mp->toaddress!="")

					array_push($this->_mp->waypoints, $this->_mp->toaddress);
				$wpstring="";
				foreach ($this->_mp->waypoints as $wp) {
					if ($wpstring!="")
						$wpstring.= ", ";
					$wpstring .= "'".$wp."'";
				}
				$code.="\ndirections".$this->_mp->mapnm.".loadFromWaypoints([".$wpstring."], {".implode(",",$xmloptions)."});";
			} else
				$code.="\ndirections".$this->_mp->mapnm.".load('from: ".$this->_mp->address." to: ".$this->_mp->toaddress."', {".implode(",",$xmloptions)."});";
		}
		
		if ($this->_mp->tilelayer!="") {
			$this->_mp->tilebounds=explode(",", $this->_mp->tilebounds);
			if (count($this->_mp->tilebounds)==4) {
				$code .="\nvar tileopts = {};";				
				if ($this->_mp->tilemethod!='maptiler') { 
					$this->_mp->tilemethod = str_replace('[', '{', $this->_mp->tilemethod);
					$this->_mp->tilemethod = str_replace(']', '}', $this->_mp->tilemethod);
					$this->_mp->tilemethod = str_replace('&amp;', '&', $this->_mp->tilemethod);
					$code .="\ntileopts.tileUrlTemplate = '".$this->_make_absolute($this->_mp->tilemethod)."';";
				}
				
				$code .="\ncopyright".$this->_mp->mapnm." = new GCopyrightCollection('');";
				$code .="copyright".$this->_mp->mapnm.".addCopyright(new GCopyright('', new GLatLngBounds(new GLatLng(".$this->_mp->tilebounds[0].", ".$this->_mp->tilebounds[1]."), new GLatLng(".$this->_mp->tilebounds[2].", ".$this->_mp->tilebounds[3].")), ".$this->_mp->tileminzoom.",''));";				
				$code .="\ntilelayer".$this->_mp->mapnm." = new GTileLayer(copyright".$this->_mp->mapnm.", ".$this->_mp->tileminzoom.", ".$this->_mp->tilemaxzoom.", tileopts);";
				
				$code .="\ntilelayer".$this->_mp->mapnm.".isPng = function() { return true;};
				tilelayer".$this->_mp->mapnm.".getOpacity = function() { return ".$this->_mp->tileopacity."; };";
				if ($this->_mp->tilemethod=='maptiler') {
					$code .="\nmercator".$this->_mp->mapnm." = new GMercatorProjection(".($this->_mp->tilemaxzoom+1).");
					tilelayer".$this->_mp->mapnm.".getTileUrl = function(tile,zoom) {
						if ((zoom < ".$this->_mp->tileminzoom.") || (zoom > ".$this->_mp->tilemaxzoom.")) {
							return '".$this->_make_absolute($this->_mp->tilelayer)."/none.png';
						} 
						var ymax = 1 << zoom;
						var y = ymax - tile.y -1;
						var tileBounds = new GLatLngBounds(
							mercator".$this->_mp->mapnm.".fromPixelToLatLng( new GPoint( (tile.x)*256, (tile.y+1)*256 ) , zoom ),
							mercator".$this->_mp->mapnm.".fromPixelToLatLng( new GPoint( (tile.x+1)*256, (tile.y)*256 ) , zoom )
						);
						if (tileBounds".$this->_mp->mapnm.".intersects(tileBounds)) {
							return '".$this->_make_absolute($this->_mp->tilelayer)."/'+zoom+'/'+tile.x+'/'+y+'.png';
						} else {
							return '".$this->_make_absolute($this->_mp->tilelayer)."/none.png';
						}
					};
					tileBounds".$this->_mp->mapnm." = new GLatLngBounds(new GLatLng(".$this->_mp->tilebounds[0].", ".$this->_mp->tilebounds[1]."), new GLatLng(".$this->_mp->tilebounds[2].", ".$this->_mp->tilebounds[3]."));";
				}

				$code .="\nvar overlay".$this->_mp->mapnm." = new GTileLayerOverlay( tilelayer".$this->_mp->mapnm.", {zPriority:0 } );
				map".$this->_mp->mapnm.".addOverlay(overlay".$this->_mp->mapnm.");";
			}
		}
		
		if($this->_mp->zoomwheel=='1')
		{
			$code.="GEvent.addDomListener(tst".$this->_mp->mapnm.", 'DOMMouseScroll', CancelEvent".$this->_mp->mapnm.");
					GEvent.addDomListener(tst".$this->_mp->mapnm.", 'mousewheel', CancelEvent".$this->_mp->mapnm.");
				";
		}
	
		/* remove link in google logo. Do not use
		$code.= "\nvar func".$this->_mp->mapnm." = function () {";
		$code.= "\n	var test_div = document.getElementById('googlemap".$this->_mp->mapnm."');";
		$code.= "\n	var test_obj = test_div.childNodes[1];";
		$code.= "\n	test_obj = test_obj.getElementsByTagName('a');";
		$code.= "\n	if (test_obj&&test_obj.length>0)";
		$code.= "\n		test_obj[0].href = '".$this->protocol.$this->googlewebsite."';";
		$code.= "\n};";
		$code.= "\nsetTimeout(func".$this->_mp->mapnm.", 1500);";
		*/
		
		/* remove copyright, terms and mapdata. Do not use 					
		$code.= "test_div = document.getElementById('googlemap".$this->_mp->mapnm."');";
		$code.= "test_obj = test_div.childNodes[1].style.display='none';";
		$code.= "test_obj = test_div.childNodes[2].style.display='none';";
		*/
	
		if($this->_client_geo == 1) {
			if ($this->clientgeotype=="local")
				$code.="	});
					localSearch.execute(address);";
			else
				$code.="		       
							  });";
		}
	
		// End of script voor showing the map 
		if ($this->_mp->show!=0)
			$code.="\n	}";
			
		$code.="\n}
		/*]]>*/</script>
		";
		
		// Call the Maps through timeout to render in IE also
		// Set an event for watching the changing of the map so it can refresh itself
		$code.= "<script type=\"text/javascript\">/*<![CDATA[*/
				if (GBrowserIsCompatible()) {
					obj = document.getElementById('mapbody".$this->_mp->mapnm."');
					obj.style.display = 'block';
					window.onunload=function(){window.onunload;GUnload()};
					tst".$this->_mp->mapnm.".setAttribute(\"oldValue\",0);
					tst".$this->_mp->mapnm.".setAttribute(\"refreshMap\",0);
					";
		
		if ($this->_mp->loadmootools=='1') {
		$code.= "if (window.MooTools==null)
					tstint".$this->_mp->mapnm."=setInterval(\"checkMap".$this->_mp->mapnm."()\",".$this->timeinterval.");
				else
					window.addEvent('domready', function() {
							tstint".$this->_mp->mapnm."=setInterval('checkMap".$this->_mp->mapnm."()', ".$this->timeinterval.");
						});
				";
		} else {
			$code.= "tstint".$this->_mp->mapnm."=setInterval(\"checkMap".$this->_mp->mapnm."()\",".$this->timeinterval.");
					";
		}
		
		$code.= "}
		/*]]>*/</script>
		";
	
		// Clean up variables except generated code and memory variables
		unset($fields, $value, $values, $coord, $tocoord, $client_togeo, $searchoption, $lboptions, $url, $la, $cam, $replace, $addr, $idx, $val, $xmloptions, $clusteroptions, $wpstring, $wp, $options, $reg, $c, $z, $dirform, $first, $opts, $al, $kmz);
		
		return array($code, $lbcode);
	}
	
	function _findgeoparam() {
		// Find latitude, longitude or address inside the text
		// Later tolat, tolon or toaddress
	
		$reg='/<td\b[^>]*><strong>Latitude:<\/strong>(.*?)<\/td>/si';
		$c=preg_match_all($reg,$this->_text,$m);
		if ($c>0) {
			$this->_mp->latitude=$this->_remove_html_tags($m[1][0]);
			$this->_inline_coords = 1;
		}
			
		$reg='/<td\b[^>]*><strong>Longitude:<\/strong>(.*?)<\/td>/si';
		$c=preg_match_all($reg,$this->_text,$m);
		if ($c>0) {
			$this->_mp->longitude=$this->_remove_html_tags($m[1][0]);
			$this->_inline_coords = 1;
		}

		$reg='/<td\b[^>]*><strong>City:<\/strong>(.*?)<\/td>/si';
		$c=preg_match_all($reg,$this->_text,$m);
		if ($c>0)
			$this->_mp->address = $m[1][0];
	}
	
	function _processMapv3() {
		// Variables of process
		$code='';
		$lbcode='';
		
		//Detect browsers for special changes
		$iphone = strpos($_SERVER['HTTP_USER_AGENT']," iPhone");
		$android = strpos($_SERVER['HTTP_USER_AGENT'],"Android");
		$ipod = strpos($_SERVER['HTTP_USER_AGENT']," iPod");
//		Setting width and height is not correct because in mobile browser it's a wesbite rendering and width 100% or height 100% i snot supported.
//		if($iphone || $android || $ipod) {
//			$this->_mp->width = '100%';
//			$this->_mp->height = '100%';
//		}
		
		// Iphone or Ipod add special meta tag
//		if($iphone || $ipod) {
//			$this->document->setMetaData("viewport", "initial-scale=1.0, user-scalable=no");
//		}
		
		// No inline coordinates and no kml => standard configuration show marker based on defaults
		if ($this->_inline_coords == 0 && $this->_client_geo != 1 && count($this->_mp->kml)==0) { 
			$this->_mp->latitude = $this->_mp->deflatitude;
			$this->_mp->longitude = $this->_mp->deflongitude;
		}
		
		if (is_array($this->_mp->waypoints)) {
			$waypoints = array();
			foreach ($this->_mp->waypoints as $wp) {
				array_push($waypoints, $wp);
			}
			$this->_mp->waypoints = $waypoints;
			unset($waypoints);
		}

		if ($this->_mp->styledmap)
			$this->_styledmap = $this->_mp->styledmap;
		else
			$this->_styledmap = "null";
		
		unset($this->_mp->styledmap);
		
		$this->_processMapv3_scripts();
		
		list ($code, $lbcode) = $this->_processMapv3_template();
		
		$this->_processMapv3_markers();
		$this->_processMapv3_kml();
		$this->_processMapv3_tiles();
		$code .= $this->_processMapv3_icons();
		$this->_processMapv3_streetview();
	
		$code.="\n<script type='text/javascript'>/*<![CDATA[*/";
		
		if ($this->_mp->kmlrenderer=='geoxml') {
			if ($this->_mp->proxy=="1") {
				if (substr($this->jversion,0,3)=="1.5")
					$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2_proxy.php?';";
				else
					$code .= "\nvar proxy = '".$this->base."/plugins/system/plugin_googlemap2/plugin_googlemap2_proxy.php?';";
			}
			$code.="\ntop.publishdirectory = '".$this->base."/media/plugin_googlemap2/site/geoxml/';";
		}

		$code.= "\nvar mapconfig".$this->_mp->mapnm." = ".$this->json_encode($this->_mp).";";
		$code.= "\nvar mapstyled".$this->_mp->mapnm." = ".$this->_styledmap.";";
		$code.= "\nvar googlemap".$this->_mp->mapnm." = new GoogleMaps('".$this->_mp->mapnm."', mapconfig".$this->_mp->mapnm.", mapstyled".$this->_mp->mapnm.");";
		$code.= "\n/*]]>*/</script>";
		
		return array($code, $lbcode);
	}
	
	function json_encode($a=false)
	{
		if (!function_exists('json_encode')) {
			if (is_null($a)) return 'null';
			if ($a === false) return 'false';
			if ($a === true) return 'true';
			if (is_scalar($a))
			{
			  if (is_float($a))
			  {
				// Always use "." for floats.
				return floatval(str_replace(",", ".", strval($a)));
			  }
			
			  if (is_string($a))
			  {
				static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
				return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"';

			  }
			  else
				return $a;
			}
			$isList = true;
			for ($i = 0, reset($a); $i < count($a); $i++, next($a))
			{
			  if (key($a) !== $i)
			  {
				$isList = false;
				break;
			  }
			}
			$result = array();
			if ($isList)
			{
			  foreach ($a as $v) $result[] = $this->json_encode($v);
			  return '[' . join(",", $result) . ']';
			}
			else
			{
			  foreach ($a as $k => $v) $result[] = $this->json_encode($k).':'.$this->json_encode($v);
			  return '{' . join(",", $result) . '}';
			}
		} else
			return json_encode($a);
	}
	
	function _processMapv3_scripts() {
		// Only add the scripts and css once
		//Load mootools first because it's necessary for the extra functions like lightbox or effects
		// For effects we need to load mootools-more/framework true too
		if (($this->_mp->loadmootools=="1"&&$this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->effect!="none"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_mootools) {
			if ($this->event!='onAfterRender') {
				if (substr($this->jversion,0,3)=='1.5')
					JHTML::_('behavior.mootools');
				else
					JHtml::_('behavior.framework',(($this->_mp->effect!="none")?true:false));				
			} else {
				if (substr($this->jversion,0,3)=='1.5') {
					$url = $this->base."/plugins/system/mtupgrade/mootools.js";
					$this->_addscript($url);
				} else {
					$mooconfig = JFactory::getConfig();
		            $moodebug = $mooconfig->get('debug');
			        $moouncompressed   = $moodebug ? '-uncompressed' : '';
					$url = $this->base."/media/system/js/mootools-core".$moouncompressed.".js";
					$this->_addscript($url);
					if ($this->_mp->effect!="none") {
						$url = $this->base."/media/system/js/mootools-more".$moouncompressed.".js";
						$this->_addscript($url);
					}
					unset($mooconfig, $moodebug, $moouncompressed);
				}
			}
			$this->first_mootools = false;
		}
		
		if($this->first_google) {
			if ($this->protocol=='http://')
				$url = $this->protocol.$this->googlewebsite."/maps/api/js?v=".$this->google_API_version;
			else {
				$url = 'maps.googleapis.com';
				$url = $this->protocol.$url."/maps/api/js?v=".$this->google_API_version;
			}
			
			if ($this->googlekey!="")
				$url .= "&amp;key=".$this->googlekey;

			if ($this->_mp->lang!='') 
				$url .= "&amp;language=".$this->_mp->lang;
			if ($this->region!='') 
				$url .= "&amp;region=".$this->region;

			$library = array();
			if ($this->_mp->autocompl!='none')
				$library[]='places';
			if ($this->_mp->weather=='1'||$this->_mp->weathercloud=='1')
				$library[]='weather';				

			if (count($library)>0)
				$url .= "&amp;libraries=".implode(',', $library);
				
			$url .= "&amp;sensor=false";
			
			$this->_addscript($url);
			$this->first_google=false;
		}
		
		if ($this->_mp->mapType=='earth'||$this->_mp->showearthmaptype=="1") {
			$this->_addscript($this->protocol."www.google.com/jsapi?key=".$this->googlekey);
			$this->_addscript($this->protocol."www.google.com/uds/?file=earth&amp;v=1");
			$this->_addscript($this->base."/media/plugin_googlemap2/site/googleearthv3/googleearth.js");
			$this->first_googleearth = false;
		}
		
		if($this->first_googlemaps) {
			$url = $this->base."/media/plugin_googlemap2/site/googlemaps/googlemapsv3.js";
			$this->_addscript($url);
			if ($this->mapcss!='') {
				$url = $this->base."/media/plugin_googlemap2/site/googlemaps/googlemaps.css.php";
				$this->_addstylesheet($url);
			}
			$this->first_googlemaps=false;
		}		
		
		if ($this->first_kmlelabel&&(($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")||($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!=""))) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/elabel/elabel_v3.js");
			$this->first_kmlelabel = false;
		}

		if (($this->_mp->kmlrenderer=='geoxml'||count($this->_mp->kmlsb)!=0)&&$this->first_kmlrenderer) {
			$this->_addscript($this->base."/media/plugin_googlemap2/site/geoxmlv3/geoxmlv3.js");
			$this->first_kmlrenderer = false;
		}

		if (($this->_mp->kmllightbox=="1"||$this->_mp->lightbox=="1"||$this->_mp->dir=="3"||$this->_mp->dir=="4"||strpos($this->_mp->description, "MOOdalBox"))&&$this->first_modalbox)	{
			if (substr($this->jversion,0,3)=='1.5')
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/modalbox1.2hackv3.js");
			else
				$this->_addscript($this->base."/media/plugin_googlemap2/site/moodalbox/js/moodalbox1.3hackv3.js");
			
			$this->_addstylesheet($this->base."/media/plugin_googlemap2/site/moodalbox/css/moodalbox.css");
			$this->first_modalbox = false;
		}
		
		if (($this->_mp->localsearch=="1"||$this->_mp->clientgeotype=='local')&&$this->first_localsearch) {
			$this->_addscript($this->protocol."www.google.com/uds/api?file=uds.js&amp;v=1.0&amp;key=".$this->googlekey);
			$style = "@import url('".$this->protocol."www.google.com/uds/css/gsearch.css');\n@import url('".$this->protocol."www.google.com/uds/solutions/localsearch/gmlocalsearch.css');";
			$this->_addstyledeclaration($style);
			$this->first_localsearch = false;
		}
		
		// Clean up variables except generated code and memory variables
		unset($url,$library);
	}
	
	function _processMapv3_markers() {
		$this->_mp->descr = ($this->_mp->description!='')?'1':'0';
		if ($this->_mp->description!=''||$this->_mp->dir!='0') {
			if ($this->_mp->dir!='0')
				$dirform =$this->_processMapv3_templatedirform('Marker');
			else
				$dirform = "";

			// Where to add dirform? tab or add the end of description?
			if (is_array($this->_mp->description)) {
				$this->_mp->description[$z+1]->title = $this->_mp->txtdir;
				$this->_mp->description[$z+1]->text = htmlspecialchars_decode($dirform, ENT_NOQUOTES);
			} else {
				$pat="/&lt;\/div&gt;$/";
				if (preg_match($pat, $this->_mp->description))
					$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
				else {
					$pat="/<\/div>$/";
					if (preg_match($pat, $this->_mp->description))
						$this->_mp->description = preg_replace($pat, $dirform."</div>", $this->_mp->description);
					else
						$this->_mp->description.=$dirform;
				}
			}

			
			if (!is_array($this->_mp->description))
				$this->_mp->description = htmlspecialchars_decode($this->_mp->description, ENT_NOQUOTES);
				
			// Encrypt description
			$this->_mp->description = htmlentities($this->_mp->description, ENT_QUOTES, "UTF-8");
		}
		$this->_mp->tooltip =  htmlentities($this->_mp->tooltip, ENT_QUOTES, "UTF-8");
	}
	
	function _processMapv3_tiles () {
		if ($this->_mp->tilelayer!="") {
			$this->_mp->tilebounds=explode(",", $this->_mp->tilebounds);
			if (count($this->_mp->tilebounds)==4) {
				$checkboundtiles = "if (googlemap".$this->_mp->mapnm.".checkboundTilelayer(coord, zoom)) {";
			} else {
				$checkboundtiles = "";
				unset($this->_mp->tilebounds);
			}
	
			if ($this->_mp->tilemethod!='maptiler') { 
				$this->_mp->tilemethod = str_replace('[', '{', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace(']', '}', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('&amp;', '&', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{x}', '"+coord.x+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{X}', '"+coord.x+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{y}', '"+coord.y+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{Y}', '"+coord.y+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{z}', '"+zoom+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = str_replace('{Z}', '"+zoom+"', $this->_mp->tilemethod);
				$this->_mp->tilemethod = "function(coord, zoom) {".$checkboundtiles." return \"".$this->_mp->tilemethod."\";} }";
			} else {
				$this->_mp->tilemethod = "function(coord, zoom) {".$checkboundtiles." var ymax = 1 << zoom; var y = ymax - coord.y -1; return '".$this->_make_absolute($this->_mp->tilelayer)."/'+zoom+'/'+coord.x+'/'+y+'.png';} }";
			}
			
			unset($checkboundtiles);
		}
	}
	
	function _processMapv3_icons () {
		$code = "";
		if ($this->_mp->icon!='') {
			$code .= "\n<img src='".$this->_mp->icon."' style='display:none' alt='icon' />";
			if ($this->_mp->iconshadow!='')
				$code .= "\n<img src='".$this->_mp->iconshadow."' style='display:none' alt='icon shadow' />";
		
			// icon
			$icon = new stdClass();
			$icon->name = "A";
			$icon->imageurl = $this->_mp->icon;
			$icon->iconwidth = $this->_mp->iconwidth;
			$icon->iconheight = $this->_mp->iconheight;
			$icon->iconshadow = $this->_mp->iconshadow;
			$icon->iconshadowwidth = $this->_mp->iconshadowwidth;
			$icon->iconshadowheight = $this->_mp->iconshadowheight;
			$icon->iconanchorx = $this->_mp->iconanchorx;
			$icon->iconanchory = $this->_mp->iconanchory;
			if ($this->_mp->iconimagemap!="")
				$icon->iconimagemap = $this->_mp->iconimagemap;
			else
				$icon->iconimagemap = 	"13,0,15,1,16,2,17,3,18,4,18,5,19,6,19,7,19,8,19,9,19,10,19,11,19,12,19,13,18,14,18,15,17,16,16,17,15,18,14,19,14,20,13,21,13,22,12,23,12,24,12,25,12,26,11,27,11,28,11,29,11,30,11,31,11,32,11,33,8,33,8,32,8,31,8,30,8,29,8,28,8,27,8,26,7,25,7,24,7,23,6,22,6,21,5,20,5,19,4,18,3,17,2,16,1,15,1,14,0,13,0,12,0,11,0,10,0,9,0,8,0,7,0,6,1,5,1,4,2,3,3,2,4,1,6,0,13,0";
	
			$this->_mp->markericon = array($icon);
			$this->_mp->icontype ="A";
		} else
			$this->_mp->icontype ="";

		unset($icon, $this->_mp->icon, $this->_mp->iconwidth, $this->_mp->iconheight, $this->_mp->iconshadow, $this->_mp->iconshadowwidth, $this->_mp->iconshadowheight, $this->_mp->iconanchorx, $this->_mp->iconanchory, $this->_mp->iconimagemap, $this->_mp->iconshadowanchorx, $this->_mp->iconshadowanchory, $this->_mp->iconshadowanchorx, $this->_mp->iconshadowanchory, $this->_mp->iconinfoanchorx, $this->_mp->iconinfoanchory, $this->_mp->icontransparent);
		
		return $code;
	}
	
	function _processMapv3_streetview() {
		if ($this->_mp->sv!='none'&&$this->_mp->animdir=='0') {
			if ($this->_mp->sv=='top'||$this->_mp->sv=='bottom')
				$this->_mp->sv = "svpanorama".$this->_mp->mapnm;
				
			$this->_mp->svopt = new stdClass();
			if ($this->_mp->svyaw!='0')
				$this->_mp->svopt->heading = (int) $this->_mp->svyaw;
			else
				$this->_mp->svopt->heading = 0;
			if ($this->_mp->svpitch!='0')
				$this->_mp->svopt->pitch = (int) $this->_mp->svpitch;
			else
				$this->_mp->svopt->pitch = 0;
			if ($this->_mp->svzoom!='')
				$this->_mp->svopt->zoom = (int) $this->_mp->svzoom;
			else
				$this->_mp->svopt->zoom = 1;
				
			if ($this->_mp->svaddress=='0')
				$this->_mp->svaddress = false;
			else
				$this->_mp->svaddress = true;
		}		
		
		unset($this->_mp->svyaw,$this->_mp->svpitch,$this->_mp->svzoom);
	}

	function _processMapv3_kml() {
		// Change kml url if proxy is used
		if ($this->_mp->proxy=='1') {
			foreach ($this->_mp->kml as $idx=>$val) {
				$this->_mp->kml[$idx] = $this->_make_absolute($val);
			}
		}

		// Rename parameter so they can be used by geoxml
		$this->_mp->geoxmloptions = new stdClass();
		
		// Set the style of the title of placemark to empty
		$this->_mp->geoxmloptions->titlestyle = ' ';
		
		if ($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right") {
			$this->_mp->geoxmloptions->sidebarid = 'kmlsidebar'.$this->_mp->mapnm;
		} else {
			if ($this->_mp->kmlsidebar!="none")
				$this->_mp->geoxmloptions->sidebarid = $this->_mp->kmlsidebar;
		}
		
		if ($this->_mp->kmlmessshow=='0') {
			$this->_mp->geoxmloptions->veryquiet = true;
			$this->_mp->geoxmloptions->quiet = true;
		}
	
		if ($this->_inline_coords==1)
			$this->_mp->geoxmloptions->nozoom = true;

		if ($this->_mp->dir!='0')
			$this->_mp->geoxmloptions->directions = true;
			
		if ($this->_mp->kmlfoldersopen!='0')
			$this->_mp->geoxmloptions->allfoldersopen = true;
			
		if ($this->_mp->kmlhide!='0')
			$this->_mp->geoxmloptions->hideall = true;

		if ($this->_mp->kmlscale!='0')
			$this->_mp->geoxmloptions->scale=  true;

		if ($this->_mp->kmlopenmethod!='0')
			$this->_mp->geoxmloptions->iwmethod = $this->_mp->kmlopenmethod;
		
		if ($this->_mp->kmlsbsort=='asc') {
			$this->_mp->geoxmloptions->sortbyname = 'asc';
		}elseif ($this->_mp->kmlsbsort=='desc') {
			$this->_mp->geoxmloptions->sortbyname= 'desc';
		} else 	
			$this->_mp->geoxmloptions->sortbyname = null;

		if ($this->_mp->kmlclickablemarkers!='1') {
			$this->_mp->geoxmloptions->clickablemarkers = false;
			$this->_mp->geoxmloptions->clickablelines = false;
			$this->_mp->geoxmloptions->dohilite = false;
		}
			
		if ($this->_mp->kmlzoommarkers!='0')
			$this->_mp->geoxmloptions->zoommarkers = $this->_mp->kmlzoommarkers;

		if ($this->_mp->kmlopendivmarkers!='')
			$this->_mp->geoxmloptions->opendivmarkers = $this->_mp->kmlopendivmarkers;

		if ($this->_mp->kmlcontentlinkmarkers!='0')
			$this->_mp->geoxmloptions->extcontentmarkers = true;

		if ($this->_mp->kmllinkablemarkers!='0')
			$this->_mp->geoxmloptions->contentlinkmarkers = true;

		if ($this->_mp->kmllinktarget!='')
			$this->_mp->geoxmloptions->linktarget = $this->_mp->kmllinktarget;

		if ($this->_mp->kmllinkmethod!='')
			$this->_mp->geoxmloptions->linkmethod = $this->_mp->kmllinkmethod;

		if (($this->_mp->kmlpolylabel!=""&&$this->_mp->kmlpolylabelclass!="")) {
			$this->_mp->geoxmloptions->polylabelopacity = $this->_mp->kmlpolylabel;
			$this->_mp->geoxmloptions->polylabelclass = $this->_mp->kmlpolylabelclass;
		}
		if (($this->_mp->kmlmarkerlabel!=""&&$this->_mp->kmlmarkerlabelclass!="")) {
			$this->_mp->geoxmloptions->pointlabelopacity = $this->_mp->kmlmarkerlabel;
			$this->_mp->geoxmloptions->pointlabelclass = $this->_mp->kmlmarkerlabelclass;
		}
		if ($this->_mp->icon!='')
			$this->_mp->geoxmloptions->baseicon = "A";

		if ($this->_mp->maxcluster!=''&&$this->_mp->gridsize!='') {
			$clusteroptions = array();
			if ($this->_mp->maxcluster!='')
				$clusteroptions[] ="maxVisibleMarkers : ".$this->_mp->maxcluster;
			if ($this->_mp->gridsize!='')
				$clusteroptions[] ="gridSize : ".$this->_mp->gridsize;
			if ($this->_mp->minmarkerscluster!='')
				$clusteroptions[] ="minMarkersPerCluster : ".$this->_mp->minmarkerscluster;
			if ($this->_mp->maxlinesinfocluster!='')
				$clusteroptions[] ="maxLinesPerInfoBox : ".$this->_mp->maxlinesinfocluster;
			if ($this->_mp->clusterinfowindow!='')
				$clusteroptions[] ="ClusterInfoWindow : '".$this->_mp->clusterinfowindow."'" ;
			if ($this->_mp->clusterzoom!='')
				$clusteroptions[] ="ClusterZoom : '".$this->_mp->clusterzoom."'" ;
			if ($this->_mp->clustermarkerzoom!='')
				$clusteroptions[] ="ClusterMarkerZoom : ".$this->_mp->clustermarkerzoom;
			if ($this->_mp->icon!='')
				$clusteroptions[] ="Icon : markericon".$this->_mp->mapnm;

			$this->_mp->geoxmloptions->clustering = $clusteroptions;
		}
		
		unset($this->_mp->kmlmessshow, $this->_mp->kmlfoldersopen, $this->_mp->kmlhide, $this->_mp->kmlscale, $this->_mp->kmlopenmethod, $this->_mp->kmlsbsort, $this->_mp->kmlsbsort, $this->_mp->kmlclickablemarkers, $this->_mp->kmlzoommarkers, $this->_mp->kmlopendivmarkers, $this->_mp->kmlcontentlinkmarkers, $this->_mp->kmllinkablemarkers, $this->_mp->kmllinktarget, $this->_mp->kmllinkmethod, $this->_mp->kmlpolylabel, $this->_mp->kmlpolylabelclass, $this->_mp->kmlmarkerlabel, $this->_mp->kmlmarkerlabelclass, $this->_mp->maxcluster, $this->_mp->gridsize, $this->_mp->maxcluster, $this->_mp->minmarkerscluster, $this->_mp->maxlinesinfocluster, $this->_mp->clusterinfowindow, $this->_mp->clusterzoom, $this->_mp->clustermarkerzoom, $clusteroptions, $idx, $val);
	}
	
	function _processMapv3_template() {
		$code = "";
		$lbcode = "";

		$code.= "<!-- fail nicely if the browser has no Javascript -->
				<noscript><blockquote class='warning'><p>".$this->no_javascript."</p></blockquote></noscript>";			

		if ($this->_mp->align!='none')
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none; text-align:".$this->_mp->align."\">";
		else
			$code.="<div id='mapbody".$this->_mp->mapnm."' style=\"display: none;\">";
			
		if ($this->_mp->lightbox=='1') {
			$lboptions = array();
			if ($this->_mp->lbxzoom!="")
				$lboptions[] = "zoom : ".$this->_mp->lbxzoom;
			if ($this->_mp->lbxcenterlat!=""&&$this->_mp->lbxcenterlon!="")
				$lboptions[] = "mapcenter : \"".$this->_mp->lbxcenterlat." ".$this->_mp->lbxcenterlon."\"";
				
			$this->_lbxwidthorig = (is_numeric($this->_lbxwidthorig)?(($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right")?$this->_lbxwidthorig+$this->_kmlsbwidthorig+5:$this->_lbxwidthorig)."px":$this->_lbxwidthorig);
			$lbname = (($this->_mp->gotoaddr=='1'||(($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))||$this->_mp->animdir!='0'||$this->_mp->sv=='top'||$this->_mp->sv=='bottom'||$this->_mp->searchlist=='div'||$this->_mp->dir=='5'||($this->_mp->formaddress==1&&$this->_mp->animdir==0))?"lightbox":"googlemap");
			
			if ($this->_mp->show==1) {
				$code.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", googlemap".$this->_mp->mapnm.".map, {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."' class='maplightbox' ".(($this->_mp->align!='none')?"style='text-align:".$this->_mp->align."'":"").">";
			} else {
				$lbcode.="<a href='javascript:void(0)' onclick='javascript:MOOdalBox.open(\"".$lbname.$this->_mp->mapnm."\", \"".$this->_mp->lbxcaption."\", \"".$this->_lbxwidthorig." ".$this->_mp->lbxheight."\", googlemap".$this->_mp->mapnm.".map, {".implode(",",$lboptions)."});return false;' class='lightboxlink'>".html_entity_decode($this->_mp->txtlightbox)."</a>";
				$code .= "<div id='lightbox".$this->_mp->mapnm."' class='maplightbox' style='display:none;".(($this->_mp->align!='none')?"text-align:".$this->_mp->align.";":"")."'>";
			}
		}
		
		if ($this->_mp->gotoaddr=='1')	{
			$code.="<form id=\"gotoaddress".$this->_mp->mapnm."\" class=\"gotoaddress\" onSubmit=\"javascript:googlemap".$this->_mp->mapnm.".gotoAddress();return false;\">";
			$code.="	<input id=\"txtAddress".$this->_mp->mapnm."\" name=\"txtAddress".$this->_mp->mapnm."\" type=\"text\" size=\"25\" value=\"\">";
			$code.="	<input name=\"goto\" type=\"button\" class=\"button\" onClick=\"javascript:googlemap".$this->_mp->mapnm.".gotoAddress();return false;\" value=\"Goto\">";
			$code.="</form>";
		}

		if ($this->_mp->latitudeform=='1')	{
			$code.="<form id=\"latitudeform".$this->_mp->mapnm."\" class=\"latitudefrom\" onSubmit=\"javascript:googlemap".$this->_mp->mapnm.".showLatitude();return false;\">";
			$code.="	<input id=\"latitudeid".$this->_mp->mapnm."\" name=\"latitudeid".$this->_mp->mapnm."\" type=\"text\" size=\"25\" value=\"\">";
			$code.="	<input name=\"show\" type=\"button\" class=\"button\" onClick=\"javascript:googlemap".$this->_mp->mapnm.".showLatitude();return false;\" value=\"Show latitude location\">";
			$code.="</form>";
		}

		if ($this->_mp->formaddress==1)
			$code.=$this->_processMapv3_templatedirform('Form');
			
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<table style=\"width:100%;border-spacing:0px;\">
					<tr>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="left")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\" class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="<td>";
			
		if ($this->_mp->sv=='top'||($this->_mp->animdir!='0'&&$this->_mp->animdir!='3')) {
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
		}
			
		$code.="<div id=\"googlemap".$this->_mp->mapnm."\" ".((!empty($this->_mp->mapclass))?"class=\"".$this->_mp->mapclass."\"" :"class=\"map\"")." style=\"" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->width."; height:".$this->_mp->height.";".(($this->_mp->show==0&&$this->_mp->lightbox==0)?"display:none;":"").(((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0))&&$this->_mp->kmlsidebar=="right")||$this->_mp->animdir=='2')?"float:left;":"")."\"></div>";

		if ($this->_mp->sv=='bottom'||$this->_mp->animdir=="3") {
			$code.="<div style=\"clear: both;\"></div>";
			$code.="</div>";
			$code.="<div id='svpanel".$this->_mp->mapnm."' class='svPanel' style='" . ($this->_mp->align != 'none' ? ($this->_mp->align == 'center' || $this->_mp->align == 'left' ? 'margin-right: auto; ' : '') . ($this->_mp->align == 'center' || $this->_mp->align == 'right' ? 'margin-left: auto; ' : '') : '') . "width:".$this->_mp->svwidth."; height:".$this->_mp->svheight."'><div id='svpanorama".$this->_mp->mapnm."' class='streetview' style='width:".$this->_mp->svwidth."; height:".$this->_mp->svheight.(($this->_mp->kmlsidebar=="right")?"float:left;":"").";'></div>";
		}

		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</td>";
		
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&$this->_mp->kmlsidebar=="right")
			$code.="<td style=\"width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";vertical-align:top;\"><div id=\"kmlsidebar".$this->_mp->mapnm."\"  class=\"kmlsidebar\" style=\"align:left;width:".$this->_mp->kmlsbwidth.";height:".$this->_mp->height.";overflow:auto;\"></div></td>";
			
		if ((($this->_mp->kmlrenderer=="google"&&count($this->_mp->kmlsb)!=0)||($this->_mp->kmlrenderer=="geoxml"&&(count($this->_mp->kml)!=0||count($this->_mp->kmlsb)!=0)))&&($this->_mp->kmlsidebar=="left"||$this->_mp->kmlsidebar=="right"))
			$code.="</tr>
					</table>";

		if (((!empty($this->_mp->tolat)&&!empty($this->_mp->tolon))||!empty($this->_mp->address)||($this->_mp->dir=='5'))&&($this->_mp->animdir!='2'||($this->_mp->animdir=='2'&&$this->_mp->showdir=='0')))
			$code.= "<div id=\"dirsidebar".$this->_mp->mapnm."\" class='directions' ".(($this->_mp->showdir=='0')?"style='display:none'":"")."></div>";

		if ($this->_mp->lightbox=='1')
			$code .= "</div>";

		// Close of mapbody div
		$code.="</div>";
		
		return array($code, $lbcode);
	}
	
	function _processMapv3_templatedirform($type) {
		$dirform="";
		$dirform="<form id='directionform".$this->_mp->mapnm."' action='".$this->protocol.$this->googlewebsite."/maps' method='get' target='_blank' onsubmit='javascript:googlemap".$this->_mp->mapnm.".DirectionMarkersubmit(this);return false;' class='mapdirform'>";
		
		$dirform.=$this->_mp->txtdir;
		
		if ($type=='Marker') {
			$dirform.="<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='radio' ")." ".(($this->_mp->dirdefault=='0')?"checked='checked'":"")." name='dir' value='to'>".(($this->_mp->txtto!='')?$this->_mp->txtto."&nbsp;":"")."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='radio' ").(($this->_mp->dirdefault=='1')?"checked='checked'":"")." name='dir' value='from'>".(($this->_mp->txtfrom!='')?$this->_mp->txtfrom:"");
			$dirform.="<br />".$this->_mp->txtdiraddr."<input type='text' class='inputbox' size='20' name='saddr' id='saddr' value='' />";
			
			if (!empty($this->_mp->address))
				$dirform.="<input type='hidden' name='daddr' value='".$this->_mp->address."'/>";
			else
				$dirform.="<input type='hidden' name='daddr' value='".(($this->_mp->latitude!='')?$this->_mp->latitude:$this->_mp->deflatitude).", ".(($this->_mp->longitude!='')?$this->_mp->longitude:$this->_mp->deflongitude)."'/>";
		}
		
		if ($type=='Form') {
			$dirform.=(($this->_mp->txtfrom=='')?"":"<br />").$this->_mp->txtfrom."<input ".(($this->_mp->txtfrom=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='saddr' id='saddr' value='".(($this->_mp->formdir=='1')?$this->_mp->address:(($this->_mp->formdir=='2')?$this->_mp->toaddress:""))."' />";

			$dirform.=(($this->_mp->txtto=='')?"":"<br />").$this->_mp->txtto."<input ".(($this->_mp->txtto=='')?"type='hidden' ":"type='text'")." class='inputbox' size='20' name='daddr' id='daddr' value='".(($this->_mp->formdir=='1')?$this->_mp->toaddress:(($this->_mp->formdir=='2')?$this->_mp->address:""))."' />";
		}
		
		if ($this->_mp->txt_driving!=''||$this->_mp->txt_avhighways!=''||$this->_mp->txt_walking!='')
			$dirform.="<br />";	

		if ($this->_mp->txt_driving!=''||$this->_mp->dirtype=="D")
			$dirform.="<input ".(($this->_mp->txt_driving=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='' ".(($this->_mp->dirtype=="D")?"checked='checked'":"")." />".$this->_mp->txt_driving.(($this->_mp->txt_driving!='')?"&nbsp;":"");
		if ($this->_mp->txt_avhighways!=''||$this->_mp->dirtype=="1")
			$dirform.="<input ".(($this->_mp->txt_avhighways=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='h' ".(($this->_mp->avoidhighways=='1')?"checked='checked'":"")." />".$this->_mp->txt_avhighways.(($this->_mp->txt_avhighways!='')?"&nbsp;":"");
		if ($this->_mp->txt_transit!=''||$this->_mp->dirtype=="R")
			$dirform.="<input ".(($this->_mp->txt_transit=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='r' ".(($this->_mp->dirtype=="R")?"checked='checked'":"")." />".$this->_mp->txt_transit.(($this->_mp->txt_transit!='')?"&nbsp;":"");
		if ($this->_mp->txt_bicycle!=''||$this->_mp->dirtype=="B")
			$dirform.="<input ".(($this->_mp->txt_bicycle=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='b' ".(($this->_mp->dirtype=="B")?"checked='checked'":"")." />".$this->_mp->txt_bicycle.(($this->_mp->txt_bicycle!='')?"&nbsp;":"");
		if ($this->_mp->txt_walking!=''||$this->_mp->dirtype=="W")
			$dirform.="<input ".(($this->_mp->txt_walking=='')?"type='hidden' ":"type='radio' ")."class='radio' name='dirflg' value='w' ".(($this->_mp->dirtype=="W")?"checked='checked'":"")." />".$this->_mp->txt_walking.(($this->_mp->txt_walking!='')?"&nbsp;":"");
			
		$dirform.=(($this->_mp->txt_optimize!='')?"<br/>":"")."<input ".(($this->_mp->txt_optimize=='')?"type='hidden' ":"type='checkbox' ")."class='checkbox' name='diroptimize' value='1' ".(($this->_mp->diroptimize=='1')?"checked='checked'":"")." />".$this->_mp->txt_optimize;
		$dirform.=(($this->_mp->txt_alternatives!='')?"<br/>":"")."<input ".(($this->_mp->txt_alternatives=='')?"type='hidden' ":"type='checkbox' ")."class='checkbox' name='diralternatives' value='1' ".(($this->_mp->diralternatives=='1')?"checked='checked'":"")." />".$this->_mp->txt_alternatives;
			
		$dirform.="<br/><input value='".$this->_mp->txtgetdir."' class='button' type='submit' style='margin-top: 2px;'>";
		
		if ($this->_mp->dir=='2')
			$dirform.= "<input type='hidden' name='pw' value='2'/>";

		if ($this->_mp->lang!='') 
			$dirform.= "<input type='hidden' name='hl' value='".$this->_mp->lang."'/>";

		$dirform.="</form>";

		return $dirform;
	}
	
	function _getInitialParams() {
		if (substr($this->jversion,0,3)=="1.5")
			$filename = JPATH_SITE."/plugins/system/plugin_googlemap2.xml";
		else
			$filename = JPATH_SITE."/plugins/system/plugin_googlemap2/plugin_googlemap2.xml";

		if ($xml = simplexml_load_file($filename)) {
			if (substr($this->jversion,0,3)=="1.5")
				$root =& $xml;
			else if (isset($xml->config[0]->fields[0]))
				$root = $xml->config[0]->fields[0];
			else
				$root =& $xml;
		
			foreach ($root->children() as $params) {
				foreach($params->children() as $param) {
					if ($param->attributes()->export=='1') {
						$name = $param->attributes()->name;
						if ($name=='lat') {
							$this->initparams->deflatitude = $this->params->get($name, $param->attributes()->default);
						} elseif ($name=='lon') {
							$this->initparams->deflongitude = $this->params->get($name, $param->attributes()->default);
						} elseif (substr($name,0,3)=='txt') {
							$nm = strtolower($name);
							$this->initparams->$nm = $this->params->get($name, '');
						} else {
							$nm = strtolower($name);
							$this->initparams->$nm = (string) $this->params->get($name, $param->attributes()->default);
						}
					}
				}
			}
		}
		
		// Clean up generated variables
		unset($filename, $xml, $root, $params, $param, $name, $nm);
	}
	
	function _getURL($url) {
		$ok = false;
		$getpage = "";
		if (ini_get('allow_url_fopen')) { 
			if (file_exists($url)) {
				$getpage = file_get_contents($url);
				$ok = true;
			}
		} 
		
		if (!$ok) { 
			$this->_debug_log("URI couldn't be opened probably ALLOW_URL_FOPEN off");
			if (function_exists('curl_init')) {
				$this->_debug_log("curl_init does exists");
				$ch = curl_init();
				$timeout = 5; // set to zero for no timeout
				curl_setopt ($ch, CURLOPT_URL, $url);
				curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
				curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
				$getpage = curl_exec($ch);
				curl_close($ch);
			} else
				$this->_debug_log("curl_init doesn't exists");
		}
		$this->_debug_log("Returned page: ".htmlentities($getpage));
		
		// Clean up generated variables
		unset($ok, $ch, $timeout);
		
		return $getpage;
	}

	function get_geo($address)
	{
		$this->_debug_log("get_geo(".$address.")");
	
		$coords = '';
		$getpage='';
		$replace = array("\n", "\r", "&lt;br/&gt;", "&lt;br /&gt;", "&lt;br&gt;", "<br>", "<br />", "<br/>");
		$address = str_replace($replace, '', $address);

		// Convert address to utf-8 encoding
		if (function_exists('mb_detect_encoding')) {
			$enc = mb_detect_encoding($address);
			if (!empty($enc))
				$address = mb_convert_encoding($address, "utf-8", $enc);
			else
				$address = mb_convert_encoding($address, "utf-8");
		}

		$this->_debug_log("Address: ".$address);
		
		$uri = $this->protocol.$this->googlewebsite."/maps/geo?q=".urlencode($address)."&output=xml&key=".$this->googlekey;
		$this->_debug_log("get_geo(".$uri.")");
		$getpage = $this->_getURL($uri);

		if (function_exists('mb_detect_encoding')) {
			$enc = mb_detect_encoding($getpage);
			if (!empty($enc))
				$getpage = mb_convert_encoding($getpage, "utf-8", $enc);
		}

		if ($getpage <>'') {
			$expr = '/xmlns/';
			$getpage = preg_replace($expr, 'id', $getpage);
			$xml = new SimpleXMLElement($getpage);
			foreach($xml->xpath('//coordinates') as $coordinates) {
				$coords = $coordinates;
				break;
			}
			if ($coords=='') {
				$this->_debug_log("Coordinates: null");
			} else
				$this->_debug_log("Coordinates: ".join(", ", explode(",", $coords)));
		} else
			$this->_debug_log("get_geo totally wrong end!");
	
		// Clean up variables
		unset($coord, $getpage, $replace, $enc, $uri, $ok, $ch, $timeout, $expr, $xml, $coordinates);
		
		return $coords;
	}
	
	function _debug_log($text)
	{
		if ($this->debug_plugin =='1')
			$this->debug_text .= "\n// ".$text." (".round($this->_memory_get_usage()/1024)." KB)";
	
		return;
	}
	
	function _get_index($string)
	{
		if ($this->brackets=='{') {
			$string = preg_replace("/^(.*?)\[/", '', $string);
			$string = preg_replace("/\](.*?)$/", '', $string);
			
		} else {
			$string = preg_replace("/^.*\(/", '', $string);
			$string = preg_replace("/\).*$/", '', $string);
		}
		
		return $string;
	}
	
    function _memory_get_usage()
    {
		if ( function_exists( 'memory_get_usage' ) )
			return memory_get_usage(); 
		else
			return 0;
    }

	function _get_API_key () {
		$url = trim($this->urlsetting);
		$replace = array('http://', 'https://');
		$url = str_replace($replace, '', $url);


		$url = (($this->protocol=='https://')?$this->protocol:'').$url;
		$this->_debug_log("url: ".$url);
		$key = '';
		$multikey = trim($this->params->get( 'Google_Multi_API_key', '' ));
		if ($multikey!='') {
			$this->_debug_log("multikey: ".$multikey);
			$replace = array("\n", "\r", "<br/>", "<br />", "<br>");
			$sites = preg_split("/[\n\r]+/", $multikey);
			foreach($sites as $site)
			{
				$values = explode(";",$site, 2);
				if (count($values)>1) {
					$values[0] = trim(str_replace($replace, '', $values[0]));
					$values[1] = str_replace($replace, '', $values[1]);
					$this->_debug_log("values[0]: ".$values[0]);
					$this->_debug_log("values[1]: ".$values[1]);
					if ($url==$values[0])
					{
						$key = trim($values[1]);
						break;
					}
				}
			}
		}
		if ($key=='')
			$key = trim($this->params->get( 'Google_API_key', '' ));

		// Clean up variables
		unset($url, $replace, $multikey, $sites, $site, $values);
		$this->_debug_log("key: ".$key);
		return $key;
	}
	
	function _randomkeys($length)
	{
		$key = "";
		$pattern = "1234567890abcdefghijklmnopqrstuvwxyz";
		for($i=0;$i<$length;$i++)
		{
			$key .= $pattern{rand(0,35)};
		}
		
		// Clean up variables
		unset($i, $pattern);
		return $key;
	}

	function _translate($orgtext, $lang) {
		$langtexts = preg_split("/[\n\r]+/", $orgtext);
		$text = "";

		if (is_array($langtexts)) {
			$replace = array("\n", "\r", "<br/>", "<br />", "<br>");
			$firsttext = "";
			foreach($langtexts as $langtext) {
				$values = explode(";",$langtext, 2);
				if (count($values)>1) {
					$values[0] = trim(str_replace($replace, '', $values[0]));
					if ($firsttext == "")
						$firsttext = $values[1];
						
					if (trim($lang)==$values[0])
					{
						$text = $values[1];
						break;
					}
				}
			}
			// Not found
			if ($text=="")
				$text = $firsttext;
		}	
		
		if ($text=="")
			$text = $orgtext;
	
		$text = htmlspecialchars_decode($text, ENT_NOQUOTES);
	
		// Clean up variables
		unset($langtexts, $replace, $langtext, $values);
		return $text;
	}
	
	function _getlang() {
		$this->_debug_log("langtype: ".$this->langtype);

		if ($this->langtype == 'site') {
			$lang = $this->lang->getTag();
			$this->_debug_log("Joomla lang: ".$lang);
			// Chinese and portugal use full iso code to indicate language
			if (!($lang=='zh'||$lang=='pt')) {
				$locale_parts = explode('-', $this->lang->getTag());
				$lang = $locale_parts[0];
			}
			$this->_debug_log("site lang: ".$lang);
		} else if ($this->langtype == 'config') {
			$lang = $this->params->get( 'lang', '' );
			$this->_debug_log("config lang: ".$lang);
		} else if ($this->langtype == 'joomfish'&&isset($_COOKIE['jfcookie'])) {
			$lang = $_COOKIE['jfcookie']['lang']; 
			$this->_debug_log("Joomfish lang: ".$lang);
		} else {
			$lang = '';
			$this->_debug_log("No language: ".$lang);
		} 
		
		// Clean up variables
		unset($locale_parts);
		return $lang;
	}
	
	function _remove_html_tags($text) {
		$reg[] = "/<span[^>]*?>/si";
		$repl[] = '';
		$reg[] = "/<\/span>/si";
		$repl[] = '';
		$text = preg_replace( $reg, $repl, $text );
		
		// Clean up variables
		unset($reg, $repl);
		return $text;
	}
	
	function _make_absolute($link) {
		if(substr($link,0, 7)!='http://'&&substr($link,0, 7)!='https://') {
			if(substr($link,0,1)=='/') {
				return $this->url.$link;
			} else {
				return $this->url.'/'.$link;
			}
		}
		return $link;
	}
	
	function _addscript($url) {
		// The method depends on event type. onAfterRender is complex and others are simple based on framework
		if ($this->event!='onAfterRender')
			$this->document->addScript($url);
		else {
			// Get header
			$reg = "/(<HEAD[^>]*>)(.*?)(<\/HEAD>)(.*)/si";
			$count = preg_match_all($reg,$this->_text,$html);	
			if ($count>0) {
				$head=$html[2][0];
			} else {
				$head='';
			}
			// clean browser if statements
			$reg = "/<!--\[if(.*?)<!\[endif\]-->/si";
			$head = preg_replace($reg, '', $head);

			// define scripts regex
			$reg = '/<script.*src=[\'\"](.*?)[\'\"][^>]*[^<]*(<\/script>)?/i';
			$found = false;
			
			$count = preg_match_all($reg,$head,$scripts,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);	

			if ($count>0)
				foreach ($scripts[1] as $script) {
					if ($script[0]==$url) {
						$found = true;
						break;
					}
				}
				
			if (!$found) {
				$script = "\n<script type='text/javascript' src='".$url."'></script>\n";
				if ($count==0) {
					// No scripts then just add it before </head>
					$this->_text = preg_replace("/<head(| .*?)>(.*?)<\/head>/is", "<head$1>$2".$script."</head>", $this->_text);
				} else {
					//add script after the last script
					// position last script and add length
					$pos = strpos($this->_text, trim($scripts[0][$count-1][0]))+strlen(trim($scripts[0][$count-1][0]));
					$this->_text = substr($this->_text,0, $pos).$script.substr($this->_text,$pos);
				}
			}
			
			// Clean up variables
			unset($reg, $count, $head, $found, $scripts, $script, $pos);
		}
	}
	
	function _addstylesheet($url) {
		// The method depends on event type. onAfterRender is complex and others are simple based on framework
		if ($this->event!='onAfterRender')
			$this->document->addStyleSheet($url);
		else {
			// Get header
			$reg = "/(<HEAD[^>]*>)(.*?)(<\/HEAD>)(.*)/si";
			$count = preg_match_all($reg,$this->_text,$html);	
			if ($count>0) {
				$head=$html[2][0];
			} else {
				$head='';
			}
			
			// clean browser if statements
			$reg = "/<!--\[if(.*?)<!\[endif\]-->/si";
			$head = preg_replace($reg, '', $head);

			// define scripts regex
			$reg = '/<link.*href=[\'\"](.*?)[\'\"][^>]*[^<]*(<\/link>)?/i';
			$found = false;
			
			$count = preg_match_all($reg,$head,$styles,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);	
			if ($count>0)
				foreach ($styles[1] as $style) {
					if ($style[0]==$url) {
						$found = true;
						break;
					}
				}
				
			if (!$found) {
				$style = "\n<link href='".$url."' rel='stylesheet' type='text/css' />\n";
				if ($count==0) {
					// No styles then just add it before </head>
					$this->_text = preg_replace("/<head(| .*?)>(.*?)<\/head>/is", "<head$1>$2".$style."</head>", $this->_text);
				} else {
					//add style after the last style
					// position last style and add length
					$pos = strpos($this->_text, trim($styles[0][$count-1][0]))+strlen(trim($styles[0][$count-1][0]));
					$this->_text = substr($this->_text,0, $pos).$style.substr($this->_text,$pos);
				}
			}
			
			// Clean up variables
			unset($reg, $count, $head, $found, $styles, $style, $pos);
		}
	}
	function _addstyledeclaration($source) {
		// The method depends on event type. onAfterRender is complex and others are simple based on framework
		if ($this->event!='onAfterRender')
			$this->document->addStyleDeclaration($source);
		else {
			// Get header
			$reg = "/(<HEAD[^>]*>)(.*?)(<\/HEAD>)(.*)/si";
			$count = preg_match_all($reg,$this->_text,$html);	
			if ($count>0) {
				$head=$html[2][0];
			} else {
				$head='';
			}
			
			// clean browser if statements
			$reg = "/<!--\[if(.*?)<!\[endif\]-->/si";
			$head = preg_replace($reg, '', $head);

			// define scripts regex
			$reg = '/<style[^>]*>(.*?)<\/style>/si';
			$found = false;
			
			$count = preg_match_all($reg,$head,$styles,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);	
			if ($count>0)
				foreach ($styles[1] as $style) {
					if ($style[0]==$source) {
						$found = true;
						break;
					}
				}
				
			if (!$found) {
				$source = "\n<style type='text/css'>\n".$source."\n</style>\n";
				if ($count==0) {
					// No styles then just add it before </head>
					$this->_text = preg_replace("/<head(| .*?)>(.*?)<\/head>/is", "<head$1>$2".$source."</head>", $this->_text);
				} else {
					//add style after the last style
					// position last style and add length
					$pos = strpos($this->_text, trim($styles[0][$count-1][0]))+strlen(trim($styles[0][$count-1][0]));
					$this->_text = substr($this->_text,0, $pos).$source.substr($this->_text,$pos);
				}
			}
			
			// Clean up variables
			unset($reg, $count, $head, $found, $styles, $style, $pos);
		}
	}
	

	function _is_utf8($string) { // v1.01
	//	define('_is_utf8_split',5000);
	//	if (strlen($string) > _is_utf8_split) {
		if (strlen($string) > 5000) {
			// Based on: http://mobile-website.mobi/php-utf8-vs-iso-8859-1-59
			for ($i=0,$s=_is_utf8_split,$j=ceil(strlen($string)/_is_utf8_split);$i < $j;$i++,$s+=_is_utf8_split) {

				if (is_utf8(substr($string,$s,_is_utf8_split)))
					return true;
			}
			return false;
		} else {
			// From http://w3.org/International/questions/qa-forms-utf-8.html
			return preg_match('%^(?:
					[\x09\x0A\x0D\x20-\x7E]            # ASCII
				| [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
				|  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
				| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
				|  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
				|  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
				| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
				|  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
			)*$%xs', $string);
		}
	} 
}

?>PK��#]�)��"system/plugin_googlemap2/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��d�5�5.system/plugin_googlemap2/plugin_googlemap2.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2011 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.plugin.plugin' );
jimport( 'joomla.html.parameter' ); 

class plgSystemPlugin_googlemap2 extends JPlugin
{
	var $config;
	var $subject;
	var $jversion;
	var $params;
	var $regex;
	var $document;
	var $doctype;
	var $published;
	var $plugincode;
	var $brackets;
	var $countmatch;
	var $event;
	var $helper;
	
	/**
	 * Constructor
	 *
	 * @access      protected
	 * @param       object  $subject The object to observe
	 * @param       array   $config  An array that holds the plugin configuration
	 * @since       1.0
	 */
	public function __construct( &$subject, $config )
	{
		parent::__construct( $subject, $config );
		$this->event = 'construct';
		// Do some extra initialisation in this constructor if required
		$this->subject = $subject;
		$this->config = $config;
		// Version of Joomla
		$this->jversion = JVERSION;
		// In Joomla 1.5 get the parameters in Joomla 1.6 and higher the plugin already has them
		if (substr($this->jversion,0,3)=="1.5") {
			$plugin = JPluginHelper::getPlugin('system', 'plugin_googlemap2');
			$this->params = new JParameter( $plugin->params);
		}
		// Load the language files for the plugin for Joomla 1.6 and higher
		if (substr($this->jversion,0,3)!="1.5")
			$this->loadLanguage();
		// Check if the params are defined and set so the initial defaults can be removed.
		$this->_restore_permanent_defaults();
		// Set document and doctype to null. Can only be retrievedwhen events are triggered. otherwise the language of the site magically changes.
		$this->document = NULL;
		$this->doctype = NULL;
		// Get params
		$this->publ = $this->params->get( 'publ', 1 );
		$this->plugincode = $this->params->get( 'plugincode', 'mosmap' );
		$this->brackets = $this->params->get( 'brackets', '{' );
		// define the regular expression for the bot
		if ($this->brackets=="both") {
			$this->regex="/(<p\b[^>]*>\s*)?(\{|\[)".$this->plugincode.".*?(([a-z0-9A-Z]+((\{|\[)[0-9]+(\}|\]))?='[^']+'.*?\|?.*?)*)(\}|\])(\s*<\/p>)?/msi";
			$this->countmatch = 3;
		} elseif ($this->brackets=="[") {
			$this->regex="/(<p\b[^>]*>\s*)?\[".$this->plugincode.".*?(([a-z0-9A-Z]+(\{[0-9]+\})?='[^']+'.*?\|?.*?)*)\](\s*<\/p>)?/msi";
			$this->countmatch = 2;
		} else {
			$this->regex="/(<p\b[^>]*>\s*)?\{".$this->plugincode.".*?(([a-z0-9A-Z]+(\[[0-9]+\])?='[^']+'.*?\|?.*?)*)\}(\s*<\/p>)?/msi";
			$this->countmatch = 2;
		}
		// The helper class
		$this->helper = null;

		// Clean up variables
		unset($plugin, $option, $view, $task, $layout);
	}
	
	/**
	 * Do something onAfterInitialise 
	 */
	public function onAfterInitialise()
	{
		$this->event = 'onAfterInitialise';
	}
	
	/**
	 * onPrepareContent is rename in Joomla 1.6 to onContentPrepare
	 */
	public function onContentPrepare($context, &$article, &$params, $limitstart=0)
	{
		$this->event = 'onContentPrepare';
		
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// Check if fields exists. If article and text does not exists then stop
		if (isset($article)&&isset($article->text))
			$text = &$article->text;
		else
			return true;
			
		if (isset($article)&&isset($article->introtext))
			$introtext = &$article->introtext;
		else
			$introtext = "";
			
		// check whether plugin has been unpublished
		// PDF or feed can't show maps so remove it
		if ( !$this->publ ||($this->doctype=='pdf'||$this->doctype=='feed') ) {
			$text = preg_replace( $this->regex, '', $text );
			$introtext = preg_replace( $this->regex, '', $introtext );
			unset($app, $text, $introtext);
			return true;
		}
		
		// perform the replacement in a normal way, but this has the disadvantage that other plugins
		// can't add information to the mosmap, other later added content is not checked and modules can't be checked
		// $this->_replace( $text );	
		// $this->_replace( $introtext );
		
		// Clean up variables
		unset($app, $text, $introtext);
	}
	
	/**
	 * onPrepareContent is for Joomla 1.5
	 */
	public function onPrepareContent(&$article)
	{
		$this->event = 'onPrepareContent';
	
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// Check if fields exists. If article and text does not exists then stop
		if (isset($article)&&isset($article->text))
			$text = &$article->text;
		else
			return true;
			
		if (isset($article)&&isset($article->introtext))
			$introtext = &$article->introtext;
		else
			$introtext = "";
			
		// check whether plugin has been unpublished
		// PDF or feed can't show maps so remove it
		if ( !$this->publ ||($this->doctype=='pdf'||$this->doctype=='feed') ) {
			$text = preg_replace( $this->regex, '', $text );
			$introtext = preg_replace( $this->regex, '', $introtext );
			unset($app, $text, $introtext);
			return true;
		}
		
		// perform the replacement in a normal way, but this has the disadvantage that other plugins
		// can't add information to the mosmap, other later added content is not checked and modules can't be checked
		//$this->_replace( $text );	
		//$this->_replace( $introtext );	
		
		// Clean up variables
		unset($app, $text, $introtext);
	}
	
	/**
	 * Do something onAfterRoute 
	 */
	public function onAfterRoute()
	{
		$this->event = 'onAfterRoute';
	}
	
	/**
	 * Do something onAfterDispatch 
	 */
	public function onAfterDispatch()
	{
		$this->event = 'onAfterDispatch';
		
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// FEED
		if ($this->doctype=='feed'&&isset($this->document->items)) {
			foreach($this->document->items as $item) {
				$text = &$item->description;
				$text = preg_replace( $this->regex, '', $text );
			}
			// Clean up variables
			unset($app, $item, $text);
			return true;
		}
		
		// PDF can't show maps so remove it
		if ($this->doctype=='pdf') {
			$text = $this->document->getBuffer("component");
			$text = preg_replace( $this->regex, '', $text );
			$this->document->setBuffer($text, "component"); 
			// Clean up variables
			unset($app, $item, $text);
			return true;
		}
		
		// In other components or leftovers
		$text = $this->document->getBuffer("component");
		if (strlen($text)>0) {
			
			// check whether plugin has been unpublished
			if ( !$this->publ )
				$text = preg_replace( $this->regex, '', $text );
			else
				$this->_replace($text);			
			$this->document->setBuffer($text, "component"); 
		}
		
		// Clean up variables
		unset($app, $item, $text);
	}
	
	/**
	 * Do something onAfterRender 
	 */
	public function onAfterRender()
	{
		$this->event = 'onAfterRender';
		
		$app = JFactory::getApplication();
		if($app->isAdmin()) {
			return;
		}
		
		// get document types
		$this->_getdoc();

		// Get the rendered body text
		$text = JResponse::getBody();
		
		// check whether plugin has been unpublished
		if ( !$this->publ ) {
			$text = preg_replace( $this->regex, '', $text );
			// Clean up variables
			unset($app, $text);
			return true;
		}
		
		// PDF or feed can't show maps so remove it
		if ($this->doctype=='pdf'||$this->doctype=='feed') {
			$text = preg_replace( $this->regex, '', $text );
			// Clean up variables
			unset($app, $text);
			return true;
		}
		
		// perform the replacement
		$this->_replace( $text );
		
		// Set the body text with the replaced result
        JResponse::setBody($text);

		// Clean up variables
		unset($app, $text);
	}
	
	function _getdoc() {
		if ($this->document==NULL) {
			$this->document = JFactory::getDocument();
			$this->doctype = $this->document->getType();
		}
	}
	
	function _replace(&$text) {
		$matches = array();
		$text=preg_replace("/&#0{0,2}39;/",'\'',$text);
		preg_match_all($this->regex,$text,$matches,PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER);
//		print_r($matches);
		// Remove plugincode that are in head of the page
		$matches = $this->_checkhead($text, $matches);
		// Remove plugincode that are in the editor and textarea
		$matches = $this->_checkeditorarea($text, $matches);
		$cnt = count($matches[0]);
//		print_r($matches);
		if ($cnt>0) {
			if ($this->helper==null) {
				if (substr($this->jversion,0,3)=="1.5")
					$filename = JPATH_SITE."/plugins/system/plugin_googlemap2_helper.php";
				else
					$filename = JPATH_SITE."/plugins/system/plugin_googlemap2/plugin_googlemap2_helper.php";
				
				include_once($filename);
				$this->helper = new plgSystemPlugin_googlemap2_helper($this->jversion, $this->params, $this->regex, $this->document, $this->brackets);
			}
			// Process the found {mosmap} codes
			for($counter = 0; $counter < $cnt; $counter++) {
				// Very strange the first match is the plugin code??
				$this->helper->process($matches[0][$counter][0], $matches[$this->countmatch][$counter][0], $text, $counter, $this->event);
			}
		}
		
		// Clean up variables
		unset($matches, $cnt, $counter, $content, $filename);
	}
	
	function _checkhead($text, $plgmatches) {
		$result = array(array(),array(),array(),array());
		$cnt = count($plgmatches[0]);
		// Get head location
		$end = stripos($text, '</head>');
		// check if match plugin is the head
		for($counter = 0; $counter < $cnt; $counter++) {
			if (!($plgmatches[0][$counter][1] > 0 &&$plgmatches[0][$counter][1]< $end)) {
					$result[0][] = $plgmatches[0][$counter];
					$result[1][] = $plgmatches[1][$counter];
					$result[2][] = $plgmatches[2][$counter];
					$result[3][] = $plgmatches[3][$counter];
			}
		}

		return $result;
	}
	
	function _checkeditorarea($text, $plgmatches) {
		$edmatches = array_merge($this->_getEditorPositions($text), $this->_getTextAreaPositions($text));
		$result = array(array(),array(),array(),array());
		if (count($edmatches)>0) {
			$cnt = count($plgmatches[0]);
			// check if match plugin is in match editor
			for($counter = 0; $counter < $cnt; $counter++) {
				$oke = true;
				foreach ($edmatches as $ed) {
					if ($plgmatches[0][$counter][1] > $ed['start']&&$plgmatches[0][$counter][1]< $ed['end'])
						$oke= false;
				}
				if ($oke) {
					$result[0][] = $plgmatches[0][$counter];
					$result[1][] = $plgmatches[1][$counter];
					$result[2][] = $plgmatches[2][$counter];
					$result[3][] = $plgmatches[3][$counter];
				}
			}
		} else
			$result = $plgmatches;
			
		// Clean up variables
		unset($edmatches, $cnt, $counter, $ed);
		
		return $result;
	}
	
	function _getEditorPositions($strBody) {
		if (substr($this->jversion,0,3)=="1.5"||substr($this->jversion,0,3)=="1.6"||$this->jversion=="1.7.0"||$this->jversion=="1.7.1"||$this->jversion=="1.7.2")
			preg_match_all("/<!-- Start Editor -->(.*)<!-- End Editor -->/Ums", $strBody, $strEditor, PREG_PATTERN_ORDER);
		else
			preg_match_all("/<div class=\"edit item-page\">(.*)<\/form>\n<\/div>/Ums", $strBody, $strEditor, PREG_PATTERN_ORDER);

		$intOffset = 0;
		$intIndex = 0;
		$intEditorPositions = array();

		foreach($strEditor[0] as $strFullEditor) {
			$intEditorPositions[$intIndex] = array('start' => (strpos($strBody, $strFullEditor, $intOffset)), 'end' => (strpos($strBody, $strFullEditor, $intOffset) + strlen($strFullEditor)));
			$intOffset += strlen($strFullEditor);
			$intIndex++;
		}
		
		// Clean up variables
		unset($strEditor, $intOffset, $strFullEditor, $intIndex);
		
		return $intEditorPositions;
	}
	
	function _getTextAreaPositions($strBody) {
		preg_match_all("/<textarea\b[^>]*>(.*)<\/textarea>/Ums", $strBody, $strTextArea, PREG_PATTERN_ORDER);

		$intOffset = 0;
		$intIndex = 0;
		$intTextAreaPositions = array();

		foreach($strTextArea[0] as $strFullTextArea) {
			$intTextAreaPositions[$intIndex] = array('start' => (strpos($strBody, $strFullTextArea, $intOffset)), 'end' => (strpos($strBody, $strFullTextArea, $intOffset) + strlen($strFullTextArea)));
			$intOffset += strlen($strFullTextArea);
			$intIndex++;
		}
		
		// Clean up variables
		unset($strTextArea, $intOffset, $strFullTextArea, $intIndex);
		
		return $intTextAreaPositions;
	}
	
	function _restore_permanent_defaults() {
		$app = JFactory::getApplication();
		if($app->isSite()) {
			return;
		}
		if ($this->params->get( 'publ', '' )!='') {
			jimport('joomla.filesystem.file');
			
			if (substr($this->jversion,0,3)=="1.5")
				$dir = JPATH_SITE."/plugins/system/";
			else
				$dir = JPATH_SITE."/plugins/system/plugin_googlemap2/";
			
			if (file_exists($dir.'plugin_googlemap2.perm')) {
				if (JFile::move ($dir.'plugin_googlemap2.xml', $dir.'plugin_googlemap2.init')) {
					if (JFile::move ($dir.'plugin_googlemap2.perm', $dir.'plugin_googlemap2.xml'))
						JFile::delete($dir.'plugin_googlemap2.init');
					else
						JFile::move ($dir.'plugin_googlemap2.init', $dir.'plugin_googlemap2.xml');
				}
			}
		}
	}
}

?>PK��#]�y5	5	.system/plugin_googlemap2/plugin_googlemap2.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="1.6.0" type="plugin" group="system" method="upgrade">
	<name>Google Maps</name>
	<author>Mike Reumer</author>
	<creationDate>June 2012</creationDate>
	<copyright>(C) 2012 Reumer</copyright>
	<license>http://www.gnu.org/copyleft/gpl.html GNU/GPL</license>
	<authorEmail>tech@reumer.net</authorEmail>
	<authorUrl>tech.reumer.net</authorUrl>
	<version>2.18</version>
	<description>PLUGIN_GOOGLE_MAPS_INSTALLATION</description>
	<files>
		<filename plugin="plugin_googlemap2">plugin_googlemap2.php</filename>
		<filename>plugin_googlemap2_helper.php</filename>
		<filename>plugin_googlemap2_proxy.php</filename>
		<filename>plugin_googlemap2_twitter_kml.php</filename>
		<filename>gpl.txt</filename>
		<filename>index.html</filename>
	</files>
	<media folder="media" destination="plugin_googlemap2">
		<folder>site</folder>
		<filename>index.html</filename>	
    </media>
	<languages>
	   <language tag="en-GB">language/en-GB.plg_system_plugin_googlemap2.ini</language>
	   <language tag="en-GB">language/en-GB.plg_system_plugin_googlemap2.sys.ini</language>
	   <language tag="it-IT">language/it-IT.plg_system_plugin_googlemap2.ini</language>
	   <language tag="it-IT">language/it-IT.plg_system_plugin_googlemap2.sys.ini</language>
	   <language tag="es-ES">language/es-ES.plg_system_plugin_googlemap2.ini</language>
	   <language tag="es-ES">language/es-ES.plg_system_plugin_googlemap2.sys.ini</language>
	   <language tag="fr-FR">language/fr-FR.plg_system_plugin_googlemap2.ini</language>
	   <language tag="fr-FR">language/fr-FR.plg_system_plugin_googlemap2.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="GOOGLEMAP_BASIC">
				<field name="publ" type="radio" size="1" default="1" export='0' label="Published" description="GOOGLEMAP_TT_CONFIG_PUBLISHED">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="debug" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_DEBUG" description="GOOGLEMAPS_TT_MAPS_DEBUG">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="plugincode" type="text" size= "40" default="mosmap" export='0' label="GOOGLEMAPS_PLUGINCODE" description="GOOGLEMAPS_TT_PLUGINCODE" />
				<field name="brackets" type="radio" size= "1" default="{" export='0' label="GOOGLEMAPS_BRACKETS" description="GOOGLEMAPS_TT_BRACKETS">
					<option value="{">{}</option>
					<option value="[">[]</option>
					<option value="both">GOOGLEMAPS_BRACKETS_BOTH</option>
				</field>
				<field name="Google_API_version" type="text" size= "5" default="3.x" export='0' label="GOOGLEMAPS_GOOGLEAPIVERSION" description="GOOGLEMAPS_TT_GOOGLEAPIVERSION" />
				<field name="show" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAP_SHOW" description="GOOGLEMAPS_TT_MAP_SHOW">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="mapclass" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAP_CLASS" description="GOOGLEMAPS_TT_MAP_CLASS" />
				<field name="mapcss" type="textarea" rows="3" cols="40" default="/* For img in the map remove borders, shadow, no margin and no max-width&#13;*/&#13;.map img {&#13;    border: 0px;&#13;    box-shadow: 0px;&#13;    margin: 0px;&#13;    max-width: none !important;&#13;}&#13;&#13;/* Make sure the directions are below the map&#13;*/&#13;.directions {&#13;    clear: left;&#13;}&#13;&#13;/* Solve problems in chrome with the show of the direction steps in full width&#13;*/&#13;.adp-placemark {&#13;    width : 100%&#13;}" export='0' label="GOOGLEMAPS_MAPS_CSS" description="GOOGLEMAPS_TT_MAPS_CSS" />
				<field name="loadmootools" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_LOADWITHMOOTOOLS" description="GOOGLEMAPS_TT_LOADWITHMOOTOOLS">
					<option value="1">GOOGLEMAPS_LOADWITHMOOTOOLSMOOTOOLS</option>
					<option value="0">GOOGLEMAPS_LOADWITHMOOTOOLSTIMEINTERVAL</option>
				</field>
				<field name="timeinterval" type="text" size= "4" default="500" export='0' label="GOOGLEMAPS_TIMEINTERVAL" description="GOOGLEMAPS_TT_TIMEINTERVAL" />
				<field name="Google_API_key" type="text" size="60" maxsize="255" default="" export='0' label="GOOGLEMAPS_API_KEY" description="GOOGLEMAPS_TT_API_KEY" />
				<field name="Google_Multi_API_key" type="textarea" rows="5" cols="40" default="" export='0' label="GOOGLEMAPS_MULTI_API_KEY" description="GOOGLEMAPS_TT_MULTI_API_KEY" />
				<field name="urlsetting" type="radio" size= "1" default="http_host" export='0' label="GOOGLEMAPS_URLWEBSITE" description="GOOGLEMAPS_TT_URLWEBSITE">
					<option value="Joomla">GOOGLEMAPS_URLWEBSITE_JOOMLA</option>
					<option value="http_host">HTTP_HOST</option>
				</field>
				<field name="googlewebsite" type="list" size= "1" default="maps.google.com" export='1' label="GOOGLEMAPS_GOOGLEWEBSITE" description="GOOGLEMAPS_TT_GOOGLEWEBSITE">
					<option value='maps.google.com'>United States - www.google.com (Default)</option>
					<option value='maps.google.com'>United States - maps.google.com</option>
					<option value='maps.google.com.af'>Afghanistan - maps.google.com.af</option>
					<option value='maps.google.as'>American Samoa - maps.google.as</option>
					<option value='maps.google.ad'>Andorra - maps.google.ad</option>
					<option value='maps.google.it.ao'>Angola - maps.google.it.ao</option>
					<option value='maps.google.com.ai'>Anguilla - maps.google.com.ai</option>
					<option value='maps.google.com.ar'>Argentina - maps.google.com.ar</option>
					<option value='maps.google.am'>Armenia - maps.google.am</option>
					<option value='maps.google.com.au'>Australia - maps.google.com.au</option>
					<option value='maps.google.at'>Austria - maps.google.at</option>
					<option value='maps.google.az'>Azerbaijan - maps.google.az</option>
					<option value='maps.google.bs'>Bahamas - maps.google.bs</option>
					<option value='maps.google.com.bh'>Bahrain - maps.google.com.bh</option>
					<option value='maps.google.com.bd'>Bangladesh - maps.google.com.bd</option>
					<option value='maps.google.by'>Belarus - maps.google.by</option>
					<option value='maps.google.be'>Belgium - maps.google.be</option>
					<option value='maps.google.com.bz'>Belize - maps.google.com.bz</option>
					<option value='maps.google.com.bo'>Bolivia - maps.google.com.bo</option>
					<option value='maps.google.ba'>Bosnia and Herzegovina - maps.google.ba</option>
					<option value='maps.google.co.bw'>Botswana - maps.google.co.bw</option>
					<option value='maps.google.com.br'>Brazil - maps.google.com.br</option>
					<option value='maps.google.vg'>British Virgin Islands - maps.google.vg</option>
					<option value='maps.google.com.bn'>Brunei - maps.google.com.bn</option>
					<option value='maps.google.bg'>Bulgaria - maps.google.bg</option>
					<option value='maps.google.bi'>Burundi - maps.google.bi</option>
					<option value='maps.google.kh'>Cambodia - maps.google.kh</option>
					<option value='maps.google.ca'>Canada - maps.google.ca</option>
					<option value='maps.google.cl'>Chile - maps.google.cl</option>
					<option value='maps.google.cn'>China - maps.google.cn</option>
					<option value='maps.google.com.co'>Colombia - maps.google.com.co</option>
					<option value='maps.google.co.ck'>Cook Islands - maps.google.co.ck</option>
					<option value='maps.google.co.cr'>Costa Rica - maps.google.co.cr</option>
					<option value='maps.google.ci'>Côte d\'Ivoire - maps.google.ci</option>
					<option value='maps.google.hr'>Croatia - maps.google.hr</option>
					<option value='maps.google.com.cu'>Cuba - maps.google.com.cu</option>
					<option value='maps.google.cz'>Czech Republic - maps.google.cz</option>
					<option value='maps.google.cd'>Dem. Rep. of the Congo - maps.google.cd</option>
					<option value='maps.google.dk'>Denmark - maps.google.dk</option>
					<option value='maps.google.dj'>Djibouti - maps.google.dj</option>
					<option value='maps.google.dm'>Dominica - maps.google.dm</option>
					<option value='maps.google.com.do'>Dominican Republic - maps.google.com.do</option>
					<option value='maps.google.com.ec'>Ecuador - maps.google.com.ec</option>
					<option value='maps.google.com.eg'>Egypt - maps.google.com.eg</option>
					<option value='maps.google.com.sv'>El Salvador - maps.google.com.sv</option>
					<option value='maps.google.ee'>Estonia - maps.google.ee</option>
					<option value='maps.google.com.et'>Ethiopia - maps.google.com.et</option>
					<option value='maps.google.fm'>Fed. States of Micronesia - maps.google.fm</option>
					<option value='maps.google.com.fj'>Fiji - maps.google.com.fj</option>
					<option value='maps.google.fi'>Finland - maps.google.fi</option>
					<option value='maps.google.fr'>France - maps.google.fr</option>
					<option value='maps.google.gm'>Gambia - maps.google.gm</option>
					<option value='maps.google.ge'>Georgia - maps.google.ge</option>
					<option value='maps.google.de'>Germany - maps.google.de</option>
					<option value='maps.google.com.gh'>Ghana - maps.google.com.gh</option>
					<option value='maps.google.com.gi'>Gibraltar - maps.google.com.gi</option>
					<option value='maps.google.gr'>Greece - maps.google.gr</option>
					<option value='maps.google.gl'>Greenland - maps.google.gl</option>
					<option value='maps.google.gp'>Guadeloupe - maps.google.gp</option>
					<option value='maps.google.com.gt'>Guatemala - maps.google.com.gt</option>
					<option value='maps.google.gg'>Guernsey - maps.google.gg</option>
					<option value='maps.google.com.gy'>Guyana - maps.google.com.gy</option>
					<option value='maps.google.ht'>Haiti - maps.google.ht</option>
					<option value='maps.google.hn'>Honduras - maps.google.hn</option>
					<option value='maps.google.com.hk'>Hong Kong - maps.google.com.hk</option>
					<option value='maps.google.hu'>Hungary - maps.google.hu</option>
					<option value='maps.google.is'>Iceland - maps.google.is</option>
					<option value='maps.google.co.in'>India - maps.google.co.in</option>
					<option value='maps.google.co.id'>Indonesia - maps.google.co.id</option>
					<option value='maps.google.ie'>Ireland - maps.google.ie</option>
					<option value='maps.google.im'>Isle of Man - maps.google.im</option>
					<option value='maps.google.co.il'>Israel - maps.google.co.il</option>
					<option value='maps.google.it'>Italy - maps.google.it</option>
					<option value='maps.google.com.jm'>Jamaica - maps.google.com.jm</option>
					<option value='maps.google.co.jp'>Japan - maps.google.co.jp</option>
					<option value='maps.google.je'>Jersey - maps.google.je</option>
					<option value='maps.google.jo'>Jordan - maps.google.jo</option>
					<option value='maps.google.kg'>Kazakhstan - maps.google.kg</option>
					<option value='maps.google.kz'>Kazakhstan - maps.google.kz</option>
					<option value='maps.google.co.ke'>Kenya - maps.google.co.ke</option>
					<option value='maps.google.ki'>Kiribati - maps.google.ki</option>
					<option value='maps.google.la'>Laos - maps.google.la</option>
					<option value='maps.google.lv'>Latvia - maps.google.lv</option>
					<option value='maps.google.co.ls'>Lesotho - maps.google.co.ls</option>
					<option value='maps.google.com.ly'>Libya - maps.google.com.ly</option>
					<option value='maps.google.li'>Liechtenstein - maps.google.li</option>
					<option value='maps.google.lt'>Lithuania - maps.google.lt</option>
					<option value='maps.google.lu'>Luxembourg - maps.google.lu</option>
					<option value='maps.google.mw'>Malawi - maps.google.mw</option>
					<option value='maps.google.com.my'>Malaysia - maps.google.com.my</option>
					<option value='maps.google.mv'>Maldives - maps.google.mv</option>
					<option value='maps.google.mt'>Malta - maps.google.mt</option>
					<option value='maps.google.mu'>Mauritus - maps.google.mu</option>
					<option value='maps.google.com.mx'>Mexico - maps.google.com.mx</option>
					<option value='maps.google.md'>Moldova - maps.google.md</option>
					<option value='maps.google.mn'>Mongolia - maps.google.mn</option>
					<option value='maps.google.ms'>Montserrat - maps.google.ms</option>
					<option value='maps.google.co.ma'>Morocco - maps.google.co.ma</option>
					<option value='maps.google.com.na'>Namibia - maps.google.com.na</option>
					<option value='maps.google.nr'>Nauru - maps.google.nr</option>
					<option value='maps.google.com.np'>Nepal - maps.google.com.np</option>
					<option value='maps.google.nl'>Netherlands - maps.google.nl</option>
					<option value='maps.google.co.nz'>New Zealand - maps.google.co.nz</option>
					<option value='maps.google.com.ni'>Nicaragua - maps.google.com.ni</option>
					<option value='maps.google.com.ng'>Nigeria - maps.google.com.ng</option>
					<option value='maps.google.nu'>Niue - maps.google.nu</option>
					<option value='maps.google.com.nf'>Norfolk Island - maps.google.com.nf</option>
					<option value='maps.google.no'>Norway - maps.google.no</option>
					<option value='maps.google.com.om'>Oman - maps.google.com.om</option>
					<option value='maps.google.com.pk'>Pakistan - maps.google.com.pk</option>
					<option value='maps.google.com.pa'>Panama - maps.google.com.pa</option>
					<option value='maps.google.com.py'>Parguay - maps.google.com.py</option>
					<option value='maps.google.com.pe'>Peru - maps.google.com.pe</option>
					<option value='maps.google.com.ph'>Philippines - maps.google.com.ph</option>
					<option value='maps.google.pn'>Pitcairn Islands - maps.google.pn</option>
					<option value='maps.google.pl'>Poland - maps.google.pl</option>
					<option value='maps.google.pt'>Portugal - maps.google.pt</option>
					<option value='maps.google.com.pr'>Puerto Rico - maps.google.com.pr</option>
					<option value='maps.google.com.qa'>Qatar - maps.google.com.qa</option>
					<option value='maps.google.cg'>Rep. of the Congo - maps.google.cg</option>
					<option value='maps.google.ru'>Russia - maps.google.ru</option>
					<option value='maps.google.rw'>Rwanda - maps.google.rw</option>
					<option value='maps.google.sh'>Saint Helena - maps.google.sh</option>
					<option value='maps.google.com.vc'>Saint Vincent and the Grenadines - maps.google.com.vc</option>
					<option value='maps.google.ws'>Samoa - maps.google.ws</option>
					<option value='maps.google.st'>Sao Tome and Principe - maps.google.st</option>
					<option value='maps.google.com.sa'>Saudi Arabia - maps.google.com.sa</option>
					<option value='maps.google.sn'>Senegal - maps.google.sn</option>
					<option value='maps.google.rs'>Serbia - maps.google.rs</option>
					<option value='maps.google.sc'>Seychelles - maps.google.sc</option>
					<option value='maps.google.com.sg'>Singapore - maps.google.com.sg</option>
					<option value='maps.google.com.sb'>Solomon Islands - maps.google.com.sb</option>
					<option value='maps.google.co.za'>South Africa - maps.google.co.za</option>
					<option value='maps.google.co.kr'>South Korea - maps.google.co.kr</option>
					<option value='maps.google.lk'>Sri Lanka - maps.google.lk</option>
					<option value='maps.google.com.tj'>Tajikistan - maps.google.com.tj</option>
					<option value='maps.google.co.th'>Thailand - maps.google.co.th</option>
					<option value='maps.google.tl'>Timor Leste - maps.google.tl</option>
					<option value='maps.google.tk'>Tokelau - maps.google.tk</option>
					<option value='maps.google.to'>Tonga - maps.google.to</option>
					<option value='maps.google.tt'>Trinidad and Tobago - maps.google.tt</option>
					<option value='maps.google.tm'>Turkmenistan - maps.google.tm</option>
					<option value='maps.google.co.vi'>U.S. Virgin Islands - maps.google.co.vi</option>
					<option value='maps.google.co.ug'>Uganda - maps.google.co.ug</option>
					<option value='maps.google.ae'>United Arab Emirates - maps.google.ae</option>
					<option value='maps.google.com.uy'>Uruguay - maps.google.com.uy</option>
					<option value='maps.google.co.uz'>Uzbekistan - maps.google.co.uz</option>
					<option value='maps.google.vu'>Vanuatu - maps.google.vu</option>
					<option value='maps.google.co.ve'>Venzuela - maps.google.co.ve</option>
					<option value='maps.google.com.vn'>Vietnam - maps.google.com.vn</option>
					<option value='maps.google.co.zm'>Zambia - maps.google.co.zm</option>
					<option value='maps.google.co.zw'>Zimbabwe - maps.google.co.zw</option>
					<option value='maps.google.ch'>Switzerland - maps.google.ch</option>
					<option value='maps.google.es'>Spain - maps.google.es</option>
					<option value='maps.google.se'>Sweden - maps.google.se</option>
					<option value='maps.google.tw'>Taiwan - maps.google.tw</option>
					<option value='maps.google.co.uk'>United Kingdom - maps.google.co.uk</option>
				</field>
				<field name="googleindexing" type="radio" size= "1" default="1" export='0' label="GOOGLEMAPS_INDEXING" description="GOOGLEMAPS_TT_INDEXING">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="styledmap" type="textarea" rows="5" cols="40" default="" export='1' label="GOOGLEMAPS_MAPS_STYLEDMAP" description="GOOGLEMAPS_TT_MAPS_STYLEDMAP" />
				<field name="align" type="list" size= "4" default="center" export='1' label="GOOGLEMAPS_MAPS_ALIGN" description="GOOGLEMAPS_TT_MAPS_ALIGN">
					<option value="left">GOOGLEMAPS_MAPS_ALIGNLEFT</option>
					<option value="center">GOOGLEMAPS_MAPS_ALIGNCENTER</option>
					<option value="right">GOOGLEMAPS_MAPS_ALIGNRIGHT</option>
					<option value="none">GOOGLEMAPS_MAPS_ALIGNNONE</option>
				</field>
				<field name="langtype" type="list" size="1" default="site" export='0' label="GOOGLEMAPS_LANGUAGE_OPTION" description="GOOGLEMAPS_TT_LANGUAGE_OPTION">
					<option value="site">GOOGLEMAPS_LANGTYPE_SITE</option>
					<option value="joomfish">GOOGLEMAPS_LANGTYPE_JOOMFISH</option>
					<option value="user">GOOGLEMAPS_LANGTYPE_USER</option>
					<option value="config">GOOGLEMAPS_LANGTYPE_CONFIG</option>
				</field>
				<field name="lang" type="text" size= "5" default="" export='0' label="GOOGLEMAPS_LANGUAGE" description="GOOGLEMAPS_TT_LANGUAGE" />
				<field name="width" type="text" size= "10" default="500" export='1' label="GOOGLEMAPS_MAPS_WIDTH" description="GOOGLEMAPS_TT_MAPS_WIDTH" />
				<field name="height" type="text" size= "10" default="400" export='1' label="GOOGLEMAPS_MAPS_HEIGHT" description="GOOGLEMAPS_TT_MAPS_HEIGHT" />
				<field name="effect" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_EFFECT" description="GOOGLEMAPS_TT_MAPS_EFFECT">
					<option value="none">GOOGLEMAPS_MAPS_EFFECTNONE</option>
					<option value="horizontal">GOOGLEMAPS_MAPS_EFFECTHORZ</option>
					<option value="vertical">GOOGLEMAPS_MAPS_EFFECTVERT</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_LOCATION">
				<field name="lat" type="text" size= "15" default="52.075581" export='1' label="GOOGLEMAPS_MAPS_LAT" description="GOOGLEMAPS_TT_MAPS_LAT" />
				<field name="lon" type="text" size= "15" default="4.541513" export='1' label="GOOGLEMAPS_MAPS_LNG" description="GOOGLEMAPS_TT_MAPS_LNG" />
				<field name="centerlat" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_CENTERLAT" description="GOOGLEMAPS_TT_MAPS_CENTERLAT" />
				<field name="centerlon" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_CENTERLNG" description="GOOGLEMAPS_TT_MAPS_CENTERLNG" />
				<field name="address" type="text" size= "80" default="" export='1' label="GOOGLEMAPS_MAPS_ADRESS" description="GOOGLEMAPS_TT_MAPS_ADRESS" />
				<field name="latitudeid" type="text" size= "30" default="" export='1' label="GOOGLEMAPS_MAPS_LATITUDEID" description="GOOGLEMAPS_TT_MAPS_LATITUDEID" />
				<field name="latitudedesc" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_LATITUDEDESC" description="GOOGLEMAPS_TT_MAPS_LATITUDEDESC">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>		
				<field name="latitudecoord" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_LATITUDECOORD" description="GOOGLEMAPS_TT_MAPS_LATITUDECOORD">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="latitudeform" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_LATITUDEFORM" description="GOOGLEMAPS_TT_MAPS_LATITUDEFORM">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_CONTROL">
				<field name="controltype" type="radio" size= "5" default="UI" export='1' label="GOOGLEMAPS_MAPS_CONTROLTYPE" description="GOOGLEMAPS_TT_MAPS_CONTROLTYPE">
					<option value="UI">GOOGLEMAPS_MAPS_CONTROLTYPEAUTOMATIC</option>
					<option value="user">GOOGLEMAPS_MAPS_CONTROLTYPEUSER</option>
				</field>
				<field name="zoomType" type="radio" size= "10" default="3D-large" export='1' label="GOOGLEMAPS_MAPS_MAPCONTROL" description="GOOGLEMAPS_TT_MAPS_MAPCONTROL">
					<option value="Large">GOOGLEMAPS_MAPS_MAPCONTROLLARGE</option>
					<option value="Small">GOOGLEMAPS_MAPS_MAPCONTROLSMALL</option>
					<option value="3D-large">GOOGLEMAPS_MAPS_MAPCONTROL3DLARGE</option>
					<option value="3D-largeSV">GOOGLEMAPS_MAPS_MAPCONTROL3DLARGESV</option>
					<option value="3D-small">GOOGLEMAPS_MAPS_MAPCONTROL3DSMALL</option>
					<option value="None">GOOGLEMAPS_MAPS_MAPCONTROLNONE</option>
				</field>
				<field name="svcontrol" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SVCONTROL" description="GOOGLEMAPS_TT_MAPS_SVCONTROL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>		
				<field name="zoom" type="list" size= "1" default="10" export='1' label="GOOGLEMAPS_MAPS_ZOOM" description="GOOGLEMAPS_TT_MAPS_ZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="corzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_CORZOOM" description="GOOGLEMAPS_TT_MAPS_CORZOOM">
					<option value="10">+10</option>
					<option value="9">+9</option>
					<option value="8">+8</option>
					<option value="7">+7</option>
					<option value="6">+6</option>
					<option value="5">+5</option>
					<option value="4">+4</option>
					<option value="3">+3</option>
					<option value="2">+2</option>
					<option value="1">+1</option>
					<option value="0">0</option>
					<option value="-1">-1</option>
					<option value="-2">-2</option>
					<option value="-3">-3</option>
					<option value="-4">-4</option>
					<option value="-5">-5</option>
					<option value="-6">-6</option>
					<option value="-7">-7</option>
					<option value="-8">-8</option>
					<option value="-9">-9</option>
					<option value="-10">-10</option>
				</field>
				<field name="minzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_MINZOOM" description="GOOGLEMAPS_TT_MAPS_MINZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="maxzoom" type="list" size= "1" default="19" export='1' label="GOOGLEMAPS_MAPS_MAXZOOM" description="GOOGLEMAPS_TT_MAPS_MAXZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="rotation" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_ROTATION" description="GOOGLEMAPS_TT_MAPS_ROTATION">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>		
				<field name="zoomnew" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ZOOMNEW" description="GOOGLEMAPS_TT_MAPS_ZOOMNEW">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="zoomWheel" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_MOUSEWHEEL" description="GOOGLEMAPS_TT_MAPS_MOUSEWHEEL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="keyboard" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KEYBOARD" description="GOOGLEMAPS_TT_MAPS_KEYBOARD">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="mapType" type="radio" size= "9" default="Normal" export='1' label="GOOGLEMAPS_MAPS_MAPTYPE" description="GOOGLEMAPS_TT_MAPS_MAPTYPE">
					<option value="Normal">GOOGLEMAPS_MAPS_MAPTYPENORMAL</option>
					<option value="Satellite">GOOGLEMAPS_MAPS_MAPTYPESATELLITE</option>
					<option value="Hybrid">GOOGLEMAPS_MAPS_MAPTYPEHYBRID</option>
					<option value="Terrain">GOOGLEMAPS_MAPS_MAPTYPETERRAIN</option>
					<option value="Earth">GOOGLEMAPS_MAPS_MAPTYPEEARTH</option>
				</field>
				<field name="showmaptype" type="radio" size= "1" export='1' default="1" label="GOOGLEMAPS_MAPS_SHOWMAPTYPE" description="GOOGLEMAPS_TT_MAPS_SHOWMAPTYPE">
					<option value="0">GOOGLEMAPS_MAPS_SHOWMAPTYPENONE</option>
					<option value="1">GOOGLEMAPS_MAPS_SHOWMAPTYPEHORZMENU</option>
					<option value="2">GOOGLEMAPS_MAPS_SHOWMAPTYPEHIERMENU</option>
					<option value="3">GOOGLEMAPS_MAPS_SHOWMAPTYPEVERTMENU</option>
				</field>
				<field name="showNormalMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWNORMAL" description="GOOGLEMAPS_MAPS_TT_SHOWNORMAL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showSatelliteMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWSATELLITE" description="GOOGLEMAPS_MAPS_TT_SHOWSATELLITE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showHybridMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWHYBRID" description="GOOGLEMAPS_MAPS_TT_SHOWHYBRID">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showTerrainMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWTERRAIN" description="GOOGLEMAPS_MAPS_TT_SHOWTERRAIN">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showEarthMaptype" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWEARTH" description="GOOGLEMAPS_MAPS_TT_SHOWEARTH">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="showscale" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_SCALE" description="GOOGLEMAPS_TT_MAPS_SCALE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="overview" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_OVERVIEW" description="GOOGLEMAPS_TT_MAPS_OVERVIEW">
					<option value="0">GOOGLEMAPS_MAPS_OVERVIEWDISABLED</option>
					<option value="1">GOOGLEMAPS_MAPS_OVERVIEWENABLED</option>
					<option value="2">GOOGLEMAPS_MAPS_OVERVIEWENABLEDCLOSED</option>
				</field>
				<field name="ovzoom" type="list" size= "1" default="-3" export='1' label="GOOGLEMAPS_MAPS_OVZOOM" description="GOOGLEMAPS_TT_MAPS_OVZOOM">
					<option value="10">+10</option>
					<option value="9">+9</option>
					<option value="8">+8</option>
					<option value="7">+7</option>
					<option value="6">+6</option>
					<option value="5">+5</option>
					<option value="4">+4</option>
					<option value="3">+3</option>
					<option value="2">+2</option>
					<option value="1">+1</option>
					<option value="">0</option>
					<option value="-1">-1</option>
					<option value="-2">-2</option>
					<option value="-3">-3</option>
					<option value="-4">-4</option>
					<option value="-5">-5</option>
					<option value="-6">-6</option>
					<option value="-7">-7</option>
					<option value="-8">-8</option>
					<option value="-9">-9</option>
					<option value="-10">-10</option>
				</field>
				<field name="navlabel" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_NAVLABEL" description="GOOGLEMAPS_TT_MAPS_NAVLABEL">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="dragging" type="radio" size="1" default="1" export='1' label="GOOGLEMAPS_MAPS_DRAGGING" description="GOOGLEMAPS_TT_MAPS_DRAGGING">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="marker" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_INFOWINDOW" description="GOOGLEMAPS_MAPS_TT_INFOWINDOW">
				<option value="1">GOOGLEMAPS_MAPS_INFOWINDOWOPEN</option>
				<option value="0">GOOGLEMAPS_MAPS_INFOWINDOWCLOSED</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_ICON">
				<field name="icon" type="text" size="40" maxsize="255" default="" export='1' label="GOOGLEMAPS_ICONS_IMAGE" description="GOOGLEMAPS_TT_ICONS_IMAGE" />
				<field name="iconwidth" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_WIDTH" description="GOOGLEMAPS_TT_ICONS_WIDTH" />
				<field name="iconheight" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_HEIGHT" description="GOOGLEMAPS_TT_ICONS_HEIGHT" />
				<field name="iconanchorx" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_ANCHORX" description="GOOGLEMAPS_TT_ICONS_ANCHORX" />
				<field name="iconanchory" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_ANCHORY" description="GOOGLEMAPS_TT_ICONS_ANCHORY" />
				<field name="iconshadow" type="text" size="60" maxsize="255" default="" export='1' label="GOOGLEMAPS_ICONS_SHADOW" description="GOOGLEMAPS_TT_ICONS_SHADOW" />
				<field name="iconshadowwidth" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_SHADOWWIDTH" description="GOOGLEMAPS_TT_ICONS_SHADOWWIDTH" />
				<field name="iconshadowheight" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_SHADOWHEIGHT" description="GOOGLEMAPS_TT_ICONS_SHADOWHEIGHT" />
				<field name="iconinfoanchorx" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_INFOANCHORX" description="GOOGLEMAPS_TT_ICONS_INFOANCHORX" />
				<field name="iconinfoanchory" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_ICONS_INFOANCHORY" description="GOOGLEMAPS_TT_ICONS_INFOANCHORY" />
				<field name="icontransparent" type="text" size="60" maxsize="255" default="" export='1' label="GOOGLEMAPS_ICONS_TRANSPARENT" description="GOOGLEMAPS_TT_ICONS_TRANSPARENT" />
				<field name="iconimagemap" type="textarea" rows="5" cols="60" default="" export='1' label="GOOGLEMAPS_ICONS_IMAGEMAP" description="GOOGLEMAPS_TT_ICONS_IMAGEMAP" />
			</fieldset>
			<fieldset name="GOOGLEMAP_LAYERS">
				<field name="traffic" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_TRAFFIC" description="GOOGLEMAPS_TT_MAPS_TRAFIC">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="transit" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_TRANSIT" description="GOOGLEMAPS_TT_MAPS_TRANSIT">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="bicycle" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_BICYCLE" description="GOOGLEMAPS_TT_MAPS_BICYCLE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="panoramio" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_PANORAMIO" description="GOOGLEMAPS_TT_MAPS_PANORAMIO">
					<option value="none">GOOGLEMAPS_MAPS_PANORAMIONO</option>
					<option value="all">GOOGLEMAPS_MAPS_PANORAMIOALL</option>
					<option value="popular">GOOGLEMAPS_MAPS_PANORAMIOPOPULAR</option>
				</field>
				<field name="panotype" type="text" size="8" default="none" export='1' label="GOOGLEMAPS_MAPS_PANORAMIOTYPE" description="GOOGLEMAPS_TT_MAPS_PANORAMIOTYPE" />
				<field name="panoorder" type="radio" size= "1" default="popularity" export='1' label="GOOGLEMAPS_MAPS_PANORAMIOORDER" description="GOOGLEMAPS_TT_MAPS_PANORAMIOORDER">
					  <option value="popularity">GOOGLEMAPS_MAPS_PANORAMIOORDERPOPULARITY</option>
					  <option value="upload_date">GOOGLEMAPS_MAPS_PANORAMIOORDERUPLOADDATE</option>
				</field>
				<field name="panomax" type="text" size="3" default="50" export='1' label="GOOGLEMAPS_MAPS_PANORAMIOMAX" description="GOOGLEMAPS_TT_MAPS_PANORAMIOMAX" />
				<field name="youtube" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_YOUTUBE" description="GOOGLEMAPS_TT_MAPS_YOUTUBE">
					<option value="all">Yes</option>
					<option value="none">No</option>
				</field>
				<field name="wiki" type="text" size= "8" default="none" export='1' label="GOOGLEMAPS_MAPS_WIKI" description="GOOGLEMAPS_TT_MAPS_WIKI" />
				<field name="adsmanager" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ADS" description="GOOGLEMAPS_TT_MAPS_ADS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="maxads" type="text" size="3" default="3" export='1' label="GOOGLEMAPS_MAPS_ADSMAX" description="GOOGLEMAPS_TT_MAPS_ADSMAX" />
				<field name="localsearch" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_LOCALSEARCH" description="GOOGLEMAPS_TT_MAPS_LOCALSEARCH">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="adsense" type="text" size="40" default="" export='1' label="GOOGLEMAPS_ADSENSE" description="GOOGLEMAPS_TT_ADSENSE" />
				<field name="channel" type="text" size="40" default="" export='1' label="GOOGLEMAPS_MAPS_ADSENSECHANNEL" description="GOOGLEMAPS_TT_MAPS_ADSENSECHANNEL" />
				<field name="googlebar" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_GOOGLEBAR" description="GOOGLEMAPS_TT_MAPS_GOOGLEBAR">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="searchlist" type="text" size="40" default="inline" export='1' label="GOOGLEMAPS_MAPS_SEARCHLISTTYPE" description="GOOGLEMAPS_TT_MAPS_SEARCHLISTTYPE" />
				<field name="searchtarget" type="radio" size= "7" default="_blank" export='1' label="GOOGLEMAPS_MAPS_SEARCHLINKTARGET" description="GOOGLEMAPS_TT_MAPS_SEARCHLINKTARGET">
					<option value="_blank">GOOGLEMAPS_MAPS_SEARCHLINKTARGETBLANK</option>
					<option value="_self">GOOGLEMAPS_MAPS_SEARCHLINKTARGETSELF</option>
					<option value="_top">GOOGLEMAPS_MAPS_SEARCHLINKTARGETTOP</option>
					<option value="_parent">GOOGLEMAPS_MAPS_SEARCHLINKTARGETPARENT</option>
				</field>
				<field name="searchzoompan" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SEARCHZOOM" description="GOOGLEMAPS_TT_MAPS_SEARCHZOOM">
				<option value="1">GOOGLEMAPS_MAPS_SEARCHZOOMPANZOOM</option>
				<option value="0">GOOGLEMAPS_MAPS_SEARCHZOOMNOZOOM</option>
				</field>
				<field name="weather" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_WEATHER" description="GOOGLEMAPS_TT_MAPS_WEATHER">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="weathercloud" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_WEATHERCLOUD" description="GOOGLEMAPS_TT_MAPS_WEATHERCLOUD">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="weatherinfo" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_WEATHERINFO" description="GOOGLEMAPS_TT_MAPS_WEATHERINFO">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="weathertempunit" type="radio" size= "1" default="celsius" export='1' label="GOOGLEMAPS_MAPS_WEATHERTEMPUNIT" description="GOOGLEMAPS_TT_MAPS_WEATHERTEMPUNIT">
					<option value="celsius">GOOGLEMAPS_MAPS_WEATHERCELSIUS</option>
					<option value="fahrenheit">GOOGLEMAPS_MAPS_WEATHERFAHRENHEIT</option>
				</field>
				<field name="weatherwindunit" type="radio" size= "1" default="km" export='1' label="GOOGLEMAPS_MAPS_WEATHERWINDUNIT" description="GOOGLEMAPS_TT_MAPS_WEATHERWINDUNIT">
					<option value="km">GOOGLEMAPS_MAPS_WEATHERKM</option>
					<option value="m">GOOGLEMAPS_MAPS_WEATHERM</option>
					<option value="miles">GOOGLEMAPS_MAPS_WEATHERMILES</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_DIRECTIONS">
				<field name="dir" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIR" description="GOOGLEMAPS_TT_MAPS_DIR">
					<option value="0">GOOGLEMAPS_MAPS_DIRNONE</option>
					<option value="1">GOOGLEMAPS_MAPS_DIREXTERNALGOOGLE</option>
					<option value="2">GOOGLEMAPS_MAPS_DIREXTERNALDIR</option>
					<option value="3">GOOGLEMAPS_MAPS_DIRLIGHTBOX</option>
					<option value="4">GOOGLEMAPS_MAPS_DIRLIGHTBOXGOOGLE</option>
					<option value="5">GOOGLEMAPS_MAPS_DIRONMAP</option>
				</field>
				<field name="dirtype" type="radio" size= "1" default="D" export='1' label="GOOGLEMAPS_MAPS_DIRTYPE" description="GOOGLEMAPS_TT_MAPS_DIRTYPE">
					<option value="D">GOOGLEMAPS_MAPS_DIRTYPEDRIVING</option>
					<option value="W">GOOGLEMAPS_MAPS_DIRTYPEWALKING</option>
					<option value="B">GOOGLEMAPS_MAPS_DIRTYPEBICYCLE</option>
					<option value="R">GOOGLEMAPS_MAPS_DIRTYPETRANSIT</option>
				</field>
				<field name="avoidhighways" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_AVOIDHIGHWAYS" description="GOOGLEMAPS_TT_MAPS_AVOIDHIGHWAYS">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="diroptimize" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIROPTIMIZE" description="GOOGLEMAPS_TT_MAPS_DIROPTIMIZE">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="diralternatives" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIRALTERNATIVES" description="GOOGLEMAPS_TT_MAPS_DIRALTERNATIVES">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="showdir" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWDIR" description="GOOGLEMAPS_TT_MAPS_SHOWDIR">
				<option value="0">No</option>
				<option value="1">Yes</option>
				</field>
				<field name="animdir" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ANIMDIR" description="GOOGLEMAPS_TT_MAPS_ANIMDIR">
				  <option value="0">No</option>
				  <option value="1">GOOGLEMAPS_MAPS_ANIMDIRTOP</option>
				  <option value="2">GOOGLEMAPS_MAPS_ANIMDIRBOTTOM</option>
				</field>
				<field name="animspeed" type="text" size="3" default="1" export='1' label="GOOGLEMAPS_MAPS_ANIMSPEED" description="GOOGLEMAPS_TT_MAPS_ANIMSPEED" />
				<field name="animautostart" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ANIMAUTOSTART" description="GOOGLEMAPS_TT_MAPS_ANIMAUTOSTART">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="animunit" type="radio" size="1" default="kilometers" export='1' label="GOOGLEMAPS_MAPS_ANIMUNIT" description="GOOGLEMAPS_TT_MAPS_ANIMUNIT">
					<option value="kilometers">GOOGLEMAPS_TT_MAPS_ANIMUNITKILOMETERS</option>
					<option value="miles">GOOGLEMAPS_TT_MAPS_ANIMUNITMILES</option>
				</field>
				<field name="formspeed" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_FORMSPEED" description="GOOGLEMAPS_TT_MAPS_FORMSPEED">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="formdirtype" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_DIRSHOWTYPE" description="GOOGLEMAPS_TT_MAPS_DIRSHOWTYPE">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>		
				<field name="formaddress" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_FORMADDRESS" description="GOOGLEMAPS_TT_MAPS_FORMADDRESS">
					<option value="0">No</option>
					<option value="1">Yes</option>
				</field>
				<field name="formdir" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_FORMDIR" description="GOOGLEMAPS_TT_MAPS_FORMDIR">
					<option value="0">GOOGLEMAPS_MAPS_FORMDIRNO</option>
					<option value="1">GOOGLEMAPS_MAPS_FORMDIRFROM</option>
					<option value="2">GOOGLEMAPS_MAPS_FORMDIRTO</option>
				</field>
				<field name="autocompl" type="radio" size= "1" default="both" export='1' label="GOOGLEMAPS_MAPS_AUTOCOMPL" description="GOOGLEMAPS_TT_MAPS_AUTOCOMPL">
					<option value="none">GOOGLEMAPS_MAPS_AUTOCOMPL_NONE</option>
					<option value="establishment">GOOGLEMAPS_MAPS_AUTOCOMPL_ESTABL</option>
					<option value="geocode">GOOGLEMAPS_MAPS_AUTOCOMPL_GEOCODE</option>
					<option value="both">GOOGLEMAPS_MAPS_AUTOCOMPL_BOTH</option>
				</field>
				<field name="langanim" type="textarea" filter="raw" rows="3" cols="40" default="en;The requested panorama could not be displayed|Could not generate a route for the current start and end addresses|Street View coverage is not available for this route|You have reached your destination|miles|miles|ft|kilometers|kilometer|meters|In|You will reach your destination|Stop|Drive|Press Drive to follow your route|Route|Speed|Fast|Medium|Slow" export='0' label="GOOGLEMAPS_MAPS_LANGANIM" description="GOOGLEMAPS_TT_MAPS_LANGANIM" />
				<field name="txtdir" type="textarea" filter="raw" rows="3" cols="40" default="Directions: " export='1' label="GOOGLEMAPS_MAPS_TITLEDIR" description="GOOGLEMAPS_TT_MAPS_TITLEDIR" />
				<field name="txtgetdir" type="textarea" filter="raw" rows="3" cols="40" default="Get Directions" export='1' label="GOOGLEMAPS_MAPS_BUTTONDIR" description="GOOGLEMAPS_TT_MAPS_BUTTONDIR" />
				<field name="txtfrom" type="textarea" filter="raw" rows="3" cols="40" default="" export='1' label="GOOGLEMAPS_MAPS_TXTFROMDIR" description="GOOGLEMAPS_TT_MAPS_TXTFROMDIR" />
				<field name="txtto" type="textarea" filter="raw" rows="3" cols="40" default="" export='1' label="GOOGLEMAPS_MAPS_TXTTODIR" description="GOOGLEMAPS_TT_MAPS_TXTTODIR" />
				<field name="txtdiraddr" type="textarea" filter="raw" rows="3" cols="40" default="Address: " export='1' label="GOOGLEMAPS_MAPS_TXTLABELADDR" description="GOOGLEMAPS_TT_MAPS_TXTLABELADDR" />
				<field name="txt_driving" type="textarea" filter="raw" rows="3" cols="40" default="" value="Driving" export='1' label="GOOGLEMAPS_MAPS_TXTLABELDRIVING" description="GOOGLEMAPS_TT_MAPS_TXTLABELDRIVING" />
				<field name="txt_avhighways" type="textarea" filter="raw" rows="3" cols="40" default="" value="Avoid highways" export='1' label="GOOGLEMAPS_MAPS_TXTAVOIDHIGHWAYS" description="GOOGLEMAPS_TT_MAPS_TXTAVOIDHIGHWAYS" />
				<field name="txt_walking" type="textarea" filter="raw" rows="3" cols="40" default="" value="Walking" export='1' label="GOOGLEMAPS_MAPS_TXTWALKING" description="GOOGLEMAPS_TT_MAPS_TXTWALKING" />
				<field name="txt_bicycle" type="textarea" rows="3" cols="40" default="" value="Bicycle" export='1' label="GOOGLEMAPS_MAPS_TXTBICYCLE" description="GOOGLEMAPS_TT_MAPS_TXTBICYCLE" />
				<field name="txt_transit" type="textarea" rows="3" cols="40" default="" value="Transit" export='1' label="GOOGLEMAPS_MAPS_TXTTRANSIT" description="GOOGLEMAPS_TT_MAPS_TXTTRANSIT" />
				<field name="txt_optimize" type="textarea" rows="3" cols="40" default="" value="Optimize route" export='1' label="GOOGLEMAPS_MAPS_TXTOPTIMIZE" description="GOOGLEMAPS_TT_MAPS_TXTOPTIMIZE" />
				<field name="txt_alternatives" type="textarea" rows="3" cols="40" default="" value="Route alternatives" export='1' label="GOOGLEMAPS_MAPS_TXTALTERNATIVES" description="GOOGLEMAPS_TT_MAPS_TXTALTERNATIVES" />
				<field name="dirdefault" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_FROMTODEFAULT" description="GOOGLEMAPS_TT_MAPS_FROMTODEFAULT">
				<option value="0">GOOGLEMAPS_MAPS_FROMTODEFAULTTO</option>
				<option value="1">GOOGLEMAPS_MAPS_FROMTODEFAULTFROM</option>
				</field>
				<field name="gotoaddr" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_GOTOADDR" description="GOOGLEMAPS_TT_MAPS_GOTOADDR">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="gotoaddrzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_GOTOADDRZOOM" description="GOOGLEMAPS_TT_MAPS_GOTOADDRZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="txtaddr" type="textarea" filter="raw" rows="3" cols="40" default="Address: ##" export='1' label="GOOGLEMAPS_MAPS_TXTADDRESSINFOWINDOW" description="GOOGLEMAPS_TT_MAPS_TXTADDRESSINFOWINDOW" />
				<field name="erraddr" type="textarea" filter="raw" rows="3" cols="40" default="Address ## not found!" export='1' label="GOOGLEMAPS_MAPS_ADDRERRTXT" description="GOOGLEMAPS_TT_MAPS_ADDRERRTXT" />
				<field name="clientgeotype" type="radio" size= "1" default="google" export='1' label="GOOGLEMAPS_MAPS_GEOTYPE" description="GOOGLEMAPS_TT_MAPS_GEOTYPE">
					<option value="google">GOOGLEMAPS_MAPS_GEOTYPE_GOOGLE</option>
					<option value="local">GOOGLEMAPS_MAPS_GEOTYPE_LOCAL</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_LIGHTBOX">
				<field name="lightbox" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_LIGHTBOX" description="GOOGLEMAPS_TT_MAPS_LIGHTBOX">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="txtlightbox" type="textarea" filter="raw" rows="3" cols="40" default="Open lightbox" export='1' label="GOOGLEMAPS_MAPS_TXTLIGHTBOX" description="GOOGLEMAPS_TT_MAPS_TXTLIGHTBOX" />
				<field name="lbxcaption" type="text" size="40" default="" export='1' label="GOOGLEMAPS_MAPS_LBXCAPTION" description="GOOGLEMAPS_TT_MAPS_LBXCAPTION" />
				<field name="lbxwidth" type="text" size= "10" default="500" export='1' label="GOOGLEMAPS_MAPS_LBWIDTH" description="GOOGLEMAPS_TT_MAPS_LBWIDTH" />
				<field name="lbxheight" type="text" size= "10" default="700" export='1' label="GOOGLEMAPS_MAPS_LBHEIGHT" description="GOOGLEMAPS_TT_MAPS_LBHEIGHT" />
				<field name="lbxcenterlat" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_LBXCENTERLAT" description="GOOGLEMAPS_TT_MAPS_LBXCENTERLAT" />
				<field name="lbxcenterlon" type="text" size= "15" default="" export='1' label="GOOGLEMAPS_MAPS_LBXCENTERLNG" description="GOOGLEMAPS_TT_MAPS_LBXCENTERLNG" />
				<field name="lbxzoom" type="list" size= "1" default="" export='1' label="GOOGLEMAPS_MAPS_LBXZOOM" description="GOOGLEMAPS_TT_MAPS_LBXZOOM">
					<option value="">GOOGLEMAPS_MAPS_LBXZOOMFROMMAP</option>
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_STREETVIEW">
				<field name="sv" type="text" size="40" default="none" export='1' label="GOOGLEMAPS_MAPS_SV" description="GOOGLEMAPS_TT_MAPS_SV" />
				<field name="svwidth" type="text" size= "10" default="100%" export='1' label="GOOGLEMAPS_MAPS_SVWIDTH" description="GOOGLEMAPS_TT_MAPS_SVWIDTH" />
				<field name="svheight" type="text" size= "10" default="300" export='1' label="GOOGLEMAPS_MAPS_SVHEIGHT" description="GOOGLEMAPS_TT_MAPS_SVHEIGHT" />
				<field name="svyaw" type="text" size= "10" default="0" export='1' label="GOOGLEMAPS_MAPS_SVYAW" description="GOOGLEMAPS_TT_MAPS_SVYAW" />
				<field name="svpitch" type="text" size= "10" default="0" export='1' label="GOOGLEMAPS_MAPS_SVPITCH" description="GOOGLEMAPS_TT_MAPS_SVPITCH" />
				<field name="svzoom" type="text" size= "10" default="" export='1' label="GOOGLEMAPS_MAPS_SVZOOM" description="GOOGLEMAPS_TT_MAPS_SVZOOM" />
				<field name="svautorotate" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_SVAUTOROTATE" description="GOOGLEMAPS_TT_MAPS_SVAUTOROTATE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="svaddress" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SVADDRESS" description="GOOGLEMAPS_TT_MAPS_SVADDRESS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_EARTH">
				<field name="earthtimeout" type="text" size= "4" default="100" export='1' label="GOOGLEMAPS_MAPS_EARTHTIMEOUT" description="GOOGLEMAPS_TT_MAPS_EARTHTIMEOUT" />
				<field name="earthborders" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_EARTHBORDERS" description="GOOGLEMAPS_TT_MAPS_EARTHBORDERS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="earthbuildings" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_EARTHBUILDINGS" description="GOOGLEMAPS_TT_MAPS_EARTHBUILDINGS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="earthroads" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_EARTHROADS" description="GOOGLEMAPS_TT_MAPS_EARTHROADS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="earthterrain" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_EARTHTERRAIN" description="GOOGLEMAPS_TT_MAPS_EARTHTERRAIN">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_KML">
				<field name="kmlrenderer" type="list" size= "3" default="google" export='1' label="GOOGLEMAPS_MAPS_KMLRENDERER" description="GOOGLEMAPS_TT_MAPS_KMLRENDERER">
					<option value="google">GOOGLEMAPS_MAPS_KMLRENDERERGOOGLE</option>
					<option value="geoxml">GOOGLEMAPS_MAPS_KMLRENDERERGEOXML</option>
					<option value="arcgis">GOOGLEMAPS_MAPS_KMLRENDERERARCGIS</option>
				</field>
				<field name="kmlsidebar" type="text" size="40" default="none" export='1' label="GOOGLEMAPS_MAPS_KMLSIDEBAR" description="GOOGLEMAPS_TT_MAPS_KMLSIDEBAR" />
				<field name="kmlsbwidth" type="text" size= "10" default="200" export='1' label="GOOGLEMAPS_MAPS_KMLSIDEBARWIDTH" description="GOOGLEMAPS_TT_MAPS_KMLSIDEBARWIDTH" />
				<field name="kmlfoldersopen" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLFOLDERSOPEN" description="GOOGLEMAPS_TT_MAPS_KMLFOLDERSOPEN">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlhide" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLHIDE" description="GOOGLEMAPS_TT_MAPS_KMLHIDE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlscale" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLSCALE" description="GOOGLEMAPS_TT_MAPS_KMLSCALE">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlopenmethod" type="radio" size="1" default="click" export='1' label="GOOGLEMAPS_MAPS_KMLINFOEVENT" description="GOOGLEMAPS_TT_MAPS_KMLINFOEVENT">
					<option value="click">GOOGLEMAPS_MAPS_KMLINFOEVENTCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_KMLINFOEVENTDOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_KMLINFOEVENTMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_KMLINFOEVENTMOUSEDOWN</option>
				</field>
				<field name="kmlsbsort" type="radio" size= "1" default="none" export='1' label="GOOGLEMAPS_MAPS_KMLSORTSIDEBAR" description="GOOGLEMAPS_TT_MAPS_KMLSORTSIDEBAR">
					<option value="none">GOOGLEMAPS_MAPS_KMLSORTSIDEBARNONE</option>
					<option value="asc">GOOGLEMAPS_MAPS_KMLSORTSIDEBARASC</option>
					<option value="desc">GOOGLEMAPS_MAPS_KMLSORTSIDEBARDESC</option>
				</field>
				<field name="kmllightbox" type="radio" size="1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLLIGHTBOX" description="GOOGLEMAPS_TT_MAPS_KMLLIGHTBOX">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlmessshow" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLSHOWMESS" description="GOOGLEMAPS_TT_MAPS_KMLSHOWMESS">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlclickablemarkers" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_SHOWKMLINFO" description="GOOGLEMAPS_TT_MAPS_SHOWKMLINFO">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmlzoommarkers" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_ZOOMMARKERS" description="GOOGLEMAPS_TT_MAPS_ZOOMMARKERS">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
				<field name="kmlopendivmarkers" type="text" size= "30" default="" export='1' label="GOOGLEMAPS_MAPS_SHOWINFOINDIV" description="GOOGLEMAPS_TT_MAPS_SHOWINFOINDIV" />
				<field name="kmlcontentlinkmarkers" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLSHOWEXTCONTENT" description="GOOGLEMAPS_TT_MAPS_KMLSHOWEXTCONTENT">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmllinkablemarkers" type="radio" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_KMLMARKERLINK" description="GOOGLEMAPS_TT_MAPS_KMLMARKERLINK">
					<option value="1">Yes</option>
					<option value="0">No</option>
				</field>
				<field name="kmllinktarget" type="radio" size= "1" default="_self" export='1' label="GOOGLEMAPS_MAPS_KMLLINKTARGET" description="GOOGLEMAPS_TT_MAPS_KMLLINKTARGET">
					<option value="_self">GOOGLEMAPS_MAPS_KMLLINKTARGETOWNWINTAB</option>
					<option value="_blank">GOOGLEMAPS_MAPS_KMLLINKTARGETNEWWINTAB</option>
				</field>
				<field name="kmllinkmethod" type="radio" size="1" default="dblclick" export='1' label="GOOGLEMAPS_MAPS_KMLMARKERLINKMETHOD" description="GOOGLEMAPS_TT_MAPS_KMLMARKERLINKMETHOD">
					<option value="click">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODDOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_KMLMARKERLINKMETHODMOUSEDOWN</option>
				</field>
				<field name="kmlmarkerlabel" type="text" size= "3" default="100" export='1' label="GOOGLEMAPS_MAPS_LABELOPACITYMARKER" description="GOOGLEMAPS_TT_MAPS_LABELOPACITYMARKER" />
				<field name="kmlmarkerlabelclass" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAPS_LABELCLASSMARKER" description="GOOGLEMAPS_TT_MAPS_LABELCLASSMARKER" />
				<field name="kmlpolylabel" type="text" size= "3" default="100" export='1' label="GOOGLEMAPS_MAPS_LABELOPACITYPOLYGON" description="GOOGLEMAPS_TT_MAPS_LABELOPACITYPOLYGON" />
				<field name="kmlpolylabelclass" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAPS_LABELCLASSPOLYGON" description="GOOGLEMAPS_TT_MAPS_LABELCLASSPOLYGON" />
				<field name="proxy" type="radio" size= "1" default="1" export='1' label="GOOGLEMAPS_MAPS_KMLPROXY" description="GOOGLEMAPS_TT_MAPS_KMLPROXY">
				<option value="1">Yes</option>
				<option value="0">No</option>
				</field>
				<field name="maxcluster" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERMAXMARKERS" description="GOOGLEMAPS_TT_MAPS_CLUSTERMAXMARKERS" />
				<field name="gridsize" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERGRIDSIZE" description="GOOGLEMAPS_TT_MAPS_CLUSTERGRIDSIZE" />
				<field name="minmarkerscluster" type="text" size= "2" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERMINMARKERS" description="GOOGLEMAPS_TT_MAPS_CLUSTERMINMARKERS" />
				<field name="maxlinesinfocluster" type="text" size= "4" default="" export='1' label="GOOGLEMAPS_MAPS_CLUSTERINFOMAXLINES" description="GOOGLEMAPS_TT_MAPS_CLUSTERINFOMAXLINES" />
				<field name="clusterinfowindow" type="radio" size="1" default="click" export='1' label="GOOGLEMAPS_MAPS_CLUSTERINFOMETHOD" description="GOOGLEMAPS_TT_MAPS_CLUSTERINFOMETHOD">
					<option value="click">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODDOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_CLUSTERINFOMETHODMOUSEDOWN</option>
				</field>
				<field name="clusterzoom" type="radio" size="1" default="dblclick" export='1' label="GOOGLEMAPS_MAPS_CLUSTERZOOMINTO" description="GOOGLEMAPS_TT_MAPS_CLUSTERZOOMINTO">
					<option value="click">GOOGLEMAPS_MAPS_CLUSTERZOOMINTOCLICK</option>
					<option value="dblclick">GOOGLEMAPS_MAPS_CLUSTERZOOMINTODOUBLECLICK</option>
					<option value="mouseover">GOOGLEMAPS_MAPS_CLUSTERZOOMINTOMOUSEOVER</option>
					<option value="mousedown">GOOGLEMAPS_MAPS_CLUSTERZOOMINTOMOUSEDOWN</option>
				</field>
				<field name="clustermarkerzoom" type="list" size= "1" default="16" export='1' label="GOOGLEMAPS_MAPS_CLUSTERMARKERZOOM" description="GOOGLEMAPS_TT_MAPS_CLUSTERMARKERZOOM">
					<option value="19">19</option>
					<option value="18">18</option>
					<option value="17">17</option>
					<option value="16">16</option>
					<option value="15">15</option>
					<option value="14">14</option>
					<option value="13">13</option>
					<option value="12">12</option>
					<option value="11">11</option>
					<option value="10">10</option>
					<option value="9">9</option>
					<option value="8">8</option>
					<option value="7">7</option>
					<option value="6">6</option>
					<option value="5">5</option>
					<option value="4">4</option>
					<option value="3">3</option>
					<option value="2">2</option>
					<option value="1">1</option>
					<option value="0">0</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_CUSTOMTILE">
				<field name="tilelayer" type="text" size= "80" default="" export='1' label="GOOGLEMAPS_MAPS_TILELAYER" description="GOOGLEMAPS_TT_MAPS_TILELAYER" />
				<field name="tilemethod" type="text" size= "80" default="" export='1' label="GOOGLEMAPS_MAPS_TILEMETHOD" description="GOOGLEMAPS_TT_MAPS_TILEMETHOD" />
				<field name="tileopacity" type="text" size= "4" default="1" export='1' label="GOOGLEMAPS_MAPS_TILEOPACITY" description="GOOGLEMAPS_TT_MAPS_TILEOPACITY" />
				<field name="tilebounds" type="text" size= "40" default="" export='1' label="GOOGLEMAPS_MAPS_TILEBOUNDS" description="GOOGLEMAPS_TT_MAPS_TILEBOUNDS" />
				<field name="tileminzoom" type="list" size= "1" default="0" export='1' label="GOOGLEMAPS_MAPS_TILEMINZOOM" description="GOOGLEMAPS_TT_MAPS_TILEMINZOOM">
				  <option value="19">19</option>
				  <option value="18">18</option>
				  <option value="17">17</option>
				  <option value="16">16</option>
				  <option value="15">15</option>
				  <option value="14">14</option>
				  <option value="13">13</option>
				  <option value="12">12</option>
				  <option value="11">11</option>
				  <option value="10">10</option>
				  <option value="9">9</option>
				  <option value="8">8</option>
				  <option value="7">7</option>
				  <option value="6">6</option>
				  <option value="5">5</option>
				  <option value="4">4</option>
				  <option value="3">3</option>
				  <option value="2">2</option>
				  <option value="1">1</option>
				  <option value="0">0</option>
				</field>
				<field name="tilemaxzoom" type="list" size= "1" default="19" export='1' label="GOOGLEMAPS_MAPS_TILEMAXZOOM" description="GOOGLEMAPS_TT_MAPS_TILEMAXZOOM">
				  <option value="19">19</option>
				  <option value="18">18</option>
				  <option value="17">17</option>
				  <option value="16">16</option>
				  <option value="15">15</option>
				  <option value="14">14</option>
				  <option value="13">13</option>
				  <option value="12">12</option>
				  <option value="11">11</option>
				  <option value="10">10</option>
				  <option value="9">9</option>
				  <option value="8">8</option>
				  <option value="7">7</option>
				  <option value="6">6</option>
				  <option value="5">5</option>
				  <option value="4">4</option>
				  <option value="3">3</option>
				  <option value="2">2</option>
				  <option value="1">1</option>
				  <option value="0">0</option>
				</field>
			</fieldset>
			<fieldset name="GOOGLEMAP_IMAGEOVERLAY">
				<field name="imageurl" type="text" size="40" maxsize="255" default="" export='1' label="GOOGLEMAPS_IMAGE_IMAGE_URL" description="GOOGLEMAPS_TT_IMAGE_URL" />
				<field name="imagex" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_X" description="GOOGLEMAPS_TT_IMAGE_X" />
				<field name="imagey" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_Y" description="GOOGLEMAPS_TT_IMAGE_Y" />
				<field name="imagexyunits" type="radio" size= "8" default="pixels" export='1' label="GOOGLEMAPS_IMAGE_XYUNITS" description="GOOGLEMAPS_TT_IMAGE_XYUNITS">
					<option value="fraction">GOOGLEMAPS_IMAGE_UNITFRACTION</option>
					<option value="pixels">GOOGLEMAPS_IMAGE_UNITPIXELS</option>
				</field>		
				<field name="imagewidth" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_WIDTH" description="GOOGLEMAPS_TT_IMAGE_WIDTH" />
				<field name="imageheight" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_HEIGHT" description="GOOGLEMAPS_TT_IMAGE_HEIGHT" />
				<field name="imageanchorx" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_ANCHORX" description="GOOGLEMAPS_TT_IMAGE_ANCHORX" />
				<field name="imageanchory" type="text" size= "3" default="" export='1' label="GOOGLEMAPS_IMAGE_ANCHORY" description="GOOGLEMAPS_TT_IMAGE_ANCHORY" />
				<field name="imageanchorunits" type="radio" size= "8" default="pixels" export='1' label="GOOGLEMAPS_IMAGE_ANCHORUNITS" description="GOOGLEMAPS_TT_IMAGE_ANCHORUNITS">
					<option value="fraction">GOOGLEMAPS_IMAGE_UNITFRACTION</option>
					<option value="pixels">GOOGLEMAPS_IMAGE_UNITPIXELS</option>
				</field>		
			</fieldset>
			<fieldset name="GOOGLEMAP_TWITTER">
				<field name="twittername" type="text" size= "60" default="" export='1' label="GOOGLEMAPS_TWITTER_NAME" description="GOOGLEMAPS_TT_TWITTER_NAME" />
				<field name="twittertweets" type="text" size= "3" default="15" export='1' label="GOOGLEMAPS_TWITTER_TWEETS" description="GOOGLEMAPS_TT_TWITTER_TWEETS" />
				<field name="twittericon" type="text" size= "255" default="/media/plugin_googlemap2/site/Twitter/twitter_map_icon.png" export='1' label="GOOGLEMAPS_TWITTER_ICON" description="GOOGLEMAPS_TT_TWITTER_ICON" />
				<field name="twitterline" type="text" size= "10" default="#ff0000ff" export='1' label="GOOGLEMAPS_TWITTER_LINE" description="GOOGLEMAPS_TT_TWITTER_LINE" />
				<field name="twitterlinewidth" type="text" size= "2" default="4" export='1' label="GOOGLEMAPS_TWITTER_LINEWIDTH" description="GOOGLEMAPS_TT_TWITTER_LINEWIDTH" />
				<field name="twitterstartloc" type="text" size= "30" default="0,0,0" export='1' label="GOOGLEMAPS_TWITTER_STARTLOC" description="GOOGLEMAPS_TT_TWITTER_STARTLOC" />
			</fieldset>
		</fields>
	</config>
	<updateservers>
		<server type="extension" priority="1" name="Plugin Googlemap Update Site">http://tech.reumer.net/update/plugin_googlemap2/extension.xml</server>
	</updateservers>	
</extension>PK��#]|�wfK�K� system/plugin_googlemap2/gpl.txtnu�[���                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
PK��#]�
�O.O.:system/plugin_googlemap2/plugin_googlemap2_twitter_kml.phpnu�[���<?php
/*------------------------------------------------------------------------
# plugin_googlemap2_twitter.php - Google Maps plugin
# ------------------------------------------------------------------------
# author    Mike Reumer
# copyright Copyright (C) 2012 tech.reumer.net. All Rights Reserved.
# @license - http://www.gnu.org/copyleft/gpl.html GNU/GPL
# Websites: http://tech.reumer.net
# Technical Support: http://tech.reumer.net/Contact-Us/Mike-Reumer.html 
# Documentation: http://tech.reumer.net/Google-Maps/Documentation-of-plugin-Googlemap/
--------------------------------------------------------------------------*/

@define('_JEXEC', 1);
if (!defined('DS'))
	@define( 'DS', DIRECTORY_SEPARATOR );

// Fix magic quotes.
@ini_set('magic_quotes_runtime', 0);
 
// Maximise error reporting.
//@ini_set('zend.ze1_compatibility_mode', '0');
//error_reporting(E_ALL);
//@ini_set('display_errors', 1);
 
/*
 * Ensure that required path constants are defined.
 */
if (!defined('JPATH_BASE'))
{
	$path = dirname(__FILE__);
	// Joomla 1.6.x/1.7.x/2.5.x
	$path = str_replace('/plugins/system/plugin_googlemap2', '', $path);
	$path = str_replace('\plugins\system\plugin_googlemap2', '', $path);
	// Joomla 1.5.x
	$path = str_replace('/plugins/system', '', $path);
	$path = str_replace('\plugins\system', '', $path);
	
	define('JPATH_BASE', $path);
}

require_once ( JPATH_BASE.'/includes/defines.php' );
 
if (!file_exists(JPATH_LIBRARIES . '/import.legacy.php')) {
	// Joomla 1.5
	require_once ( JPATH_BASE.'/includes/framework.php' );
	/* To use Joomla's Database Class */
	require_once ( JPATH_BASE.'/libraries/joomla/factory.php' );
	$mainframe =& JFactory::getApplication('site');
	$mainframe->initialise();
	$user =& JFactory::getUser();
	$session =& JFactory::getSession();
} else {
	// Joomla 1.6.x/1.7.x/2.5.x
	/**
	 * Import the platform. This file is usually in JPATH_LIBRARIES 
	 */
	require_once JPATH_BASE . '/configuration.php';
	require_once JPATH_LIBRARIES . '/import.legacy.php';
}
 
class Twitter {
	private $user = null;
	private $tweets = null;
	
	function __construct($user) {
		$this->user = $user;
	}
	
	function getUserTimeLine($count = 19, $retweets=0) {
		$ch = curl_init();

		curl_setopt($ch, CURLOPT_URL, 'http://api.twitter.com/1/statuses/user_timeline.json?screen_name='.$this->user.'&count='.$count.'&&include_rts='.$retweets);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$data = curl_exec($ch);
		curl_close($ch);
		
		$this->tweets = json_decode($data);
		
		if (is_object($this->tweets)&&isset($this->tweets->errors))
			$this->tweets = array();
		
		if (count($this->tweets)==0)
			$this->tweets = array();
		
		return $this->tweets;
	}
	
	function getProfile() {
		$profile = array();

		if(!empty($this->tweets)&&!isset($this->tweets->errors)) {
			$profile = $this->tweets[0]->user;
		}
		
		return $profile;
	}
	
	function timeSince($date) {
		$datetime = strtotime($date);
		$offset = time() - $datetime;
		
		$units = array(
			'second' => 1,
			'minute' => 60,
			'hour' => 3600,
			'day' => 86400,
			'month' => 2629743,
			'year' => 31556926);
		
		foreach($units as $unit => $value) {
			if($offset >= $value) {
				$result = floor($offset / $value);
				
				if(!in_array($unit, array('month','year'))) {
					if($result > 1) {
						$unit .= 's';
					}
					
					$timeAgo = 'About'.' '.$result.' '.$unit.' '.'Ago';
				} else {
					return date('j M Y', $datetime);
				}
			}
		}
		
		return $timeAgo;
	}
	
	function parseText($text) {
		// url
		$text = preg_replace( "/(([[:alnum:]]+:\/\/)|www\.)([^[:space:]]*)([[:alnum:]#?\/&=])/i", "<a href=\"\\1\\3\\4\" target=\"_blank\">\\1\\3\\4</a>", ' '.$text);
		$text = str_replace('href="www.', 'href="http://www.', $text);
		// mailto
		$text = preg_replace( "/(([a-z0-9_]|\\-|\\.)+@([^[:space:]]*)([[:alnum:]-]))/i", "<a href=\"mailto:\\1\">\\1</a>", $text);
		// user
		$text = preg_replace( "/ +@([a-z0-9_]*) ?/i", " <a href=\"http://twitter.com/\\1\" target=\"_blank\">@\\1</a> ", $text);
		// argument
		$text = preg_replace( "/ +#([a-z0-9_]*) ?/i", " <a href=\"http://twitter.com/search?q=%23\\1\" target=\"_blank\">#\\1</a> ", $text);
		// truncates long url
		$text = preg_replace("/>(([[:alnum:]]+:\/\/)|www\.)([^[:space:]]{30,40})([^[:space:]]*)([^[:space:]]{10,20})([[:alnum:]#?\/&=])</", ">\\3...\\5\\6<", $text);
		
		return trim($text);
	}

}

class plugin_googlemap2_twitter_kml
{
		/**
		 * Display the application.
		 */
		function doExecute(){
			// Get config
			$plugin = JPluginHelper::getPlugin('system', 'plugin_googlemap2');
			
			$jversion = JVERSION;
			// In Joomla 1.5 get the parameters in Joomla 1.6 and higher the plugin already has them, but need to be rendered with JRegistry
			if (substr($jversion,0,3)=="1.5")
				$params = new JParameter($plugin->params);
			else {
				$params = new JRegistry();
				$params->loadString($plugin->params);
			}
			
			// Get params
			$twittername = urldecode(JRequest::getVar('twittername', ''));
			if ($twittername=="")
				$twittername = $params->get('twittername', '');
				
			$twittertweets = urldecode(JRequest::getVar('twittertweets', ''));
			if ($twittertweets=="")
				$twittertweets = $params->get('twittertweets', '15');
				
			$line = urldecode(JRequest::getVar('twitterline', ''));
			if ($line=="")
				$line = $params->get('twitterline', '#ff0000ff');
				
			$twitterlinewidth = urldecode(JRequest::getVar('twitterlinewidth', ''));
			if ($twitterlinewidth=="")
				$twitterlinewidth = $params->get('twitterlinewidth', '5');

			$twitterstartloc = urldecode(JRequest::getVar('twitterstartloc', ''));
			if ($twitterstartloc=="")
				$twitterstartloc = $params->get('twitterstartloc', '5');
				
			$twitter = new Twitter(ltrim(rtrim($twittername)));
			$tweets = $twitter->getUserTimeLine(ltrim(rtrim($twittertweets)), 1);
			$profile = $twitter->getProfile();
			
			// Start KML file, create parent node
			$dom = new DOMDocument('1.0','UTF-8');
			
			//Create the root KML element and append it to the Document
			$node = $dom->createElementNS('http://earth.google.com/kml/2.1','kml');
			$parNode = $dom->appendChild($node);
			
			//Create a Folder element and append it to the KML element
			$docnode = $dom->createElement('Document');
			$parNode = $parNode->appendChild($docnode);
			
			$twitterStyleNode = $dom->createElement('Style');
			$twitterStyleNode->setAttribute('id', 'tweetStyle');
			$twitterIconstyleNode = $dom->createElement('IconStyle');
			$twitterIconstyleNode->setAttribute('id', 'tweetIcon');
			$twitterIconNode = $dom->createElement('Icon');
			$twitterHref = $dom->createElement('href', $params->get('twittericon', ''));
			
			$twitterIconNode->appendChild($twitterHref);
			$twitterIconstyleNode->appendChild($twitterIconNode);
			$twitterStyleNode->appendChild($twitterIconstyleNode);
			$docnode->appendChild($twitterStyleNode);

			if ($line!='') {
				// Create a line of travelling
				$twitterStyleNode = $dom->createElement('Style');
				$twitterStyleNode->setAttribute('id', 'lineStyle');
				$twitterLinestyleNode = $dom->createElement('LineStyle');
				$twitterColorNode = $dom->createElement('color', ltrim(rtrim($line)));
				$twitterLinestyleNode->appendChild($twitterColorNode);
				$twitterWidthNode = $dom->createElement('width', ltrim(rtrim($twitterlinewidth)));
				$twitterLinestyleNode->appendChild($twitterWidthNode);
				$twitterStyleNode->appendChild($twitterLinestyleNode);
				$docnode->appendChild($twitterStyleNode);
			}
			
			//Create a Folder element and append it to the KML element
			$fnode = $dom->createElement('Folder');
			$folderNode = $parNode->appendChild($fnode);
			$nameNode = $dom->createElement('name', 'Tweets '.$twittername);
			$folderNode->appendChild($nameNode);
			
			$tweets = array_reverse($tweets);
			$prev_location = explode(',', $twitterstartloc);
			// swap lat and long values. In kml is it different first long then lat
			$lat = $prev_location[0];
			$prev_location[0] = $prev_location[1];
			$prev_location[1] = $lat;
			
			foreach($tweets as $tweet) {
				if ($tweet->coordinates=="")
					$tweet->coordinates->coordinates = $prev_location;
				else
					$prev_location = $tweet->coordinates->coordinates;
			}
			$tweets = array_reverse($tweets);

			foreach($tweets as $tweet) {
				//Create a Placemark and append it to the document

				$node = $dom->createElement('Placemark');
				$placeNode = $folderNode->appendChild($node);
				
				//Create an id attribute and assign it the value of id column
				$placeNode->setAttribute('id','tweet_'.$tweet->id_str);
				
				//Create name, description, and address elements and assign them the values of 
				//the name, type, and address columns from the results
				
				$nameNode = $dom->createElement('name', date('d m Y g:i:s', strtotime($tweet->created_at)));
				$placeNode->appendChild($nameNode);
				
				$styleUrl = $dom->createElement('styleUrl', '#tweetStyle');
				$placeNode->appendChild($styleUrl);
				
				$descText  = "";
				$descText .="<a href='http://www.twitter.com/".$profile->screen_name."' target='_blank' title='Follow us'><h4 class='tw_user'><img src='".$profile->profile_image_url."' alt='".$profile->name."' />".$profile->name."</h4></a>";
				
				$descText .= "<span class='tw_text'>".$twitter->parseText($tweet->text)."</span>";
				$descText .="<br/><span class='tw_date'>".$twitter->timeSince($tweet->created_at)."</span>";
				
				$descNode = $dom->createElement('description', '');
				$cdataNode = $dom->createCDATASection($descText);
				$descNode->appendChild($cdataNode);
				$placeNode->appendChild($descNode);
				
				$pointNode = $dom->createElement('Point');
				$placeNode->appendChild($pointNode);
			
				$coor_pointNode = $dom->createElement('coordinates',implode(",",$tweet->coordinates->coordinates));
				$pointNode->appendChild($coor_pointNode);
			}
			
			if ($line!=''&&count($tweets)>0) {
				// Create a line of travelling
				
				//Create a Placemark and append it to the document
				$node = $dom->createElement('Placemark');
				$placeNode = $folderNode->appendChild($node);
				
				//Create an id attribute and assign it the value of id column
				$placeNode->setAttribute('id','tweetline');
				
				//Create name, description, and address elements and assign them the values of 
				//the name, type, and address columns from the results
				
				$nameNode = $dom->createElement('name','');
				$placeNode->appendChild($nameNode);
				
				$styleUrl = $dom->createElement('styleUrl', '#lineStyle');
				$placeNode->appendChild($styleUrl);

				//Create a LineString element
				$lineNode = $dom->createElement('LineString');
				$placeNode->appendChild($lineNode);
				$exnode = $dom->createElement('extrude', '1');
				$lineNode->appendChild($exnode);
				$almodenode =$dom->createElement('altitudeMode','relativeToGround');
				$lineNode->appendChild($almodenode);
				
				$coordinates = "";
				
				foreach($tweets as $tweet) {
					$coordinates .= " ".implode(",",$tweet->coordinates->coordinates);
				}
				//Create a coordinates element and give it the value of the lng and lat columns from the results
				$coorNode = $dom->createElement('coordinates',$coordinates);
				$lineNode->appendChild($coorNode);
			}
			
			$kmlOutput = $dom->saveXML();
			
			//assign the KML headers. 
			header('Content-type: application/vnd.google-earth.kml+xml');
			echo $kmlOutput;
 		}
}
// Instantiate the application.
$web = new plugin_googlemap2_twitter_kml;
 
// Run the application
$web->doExecute();

?>PK��#]|��� system/backuponupdate/script.phpnu�[���<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

use FOF40\InstallScript\Plugin;

defined('_JEXEC') || die;

// Load FOF if not already loaded
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
	throw new RuntimeException('This extension requires FOF 4.');
}

class plgSystemBackuponupdateInstallerScript extends Plugin
{
}
PK��#]�)��system/backuponupdate/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��"�(�((system/backuponupdate/backuponupdate.phpnu�[���<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die();

use FOF40\Container\Container;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Uri\Uri;

// Old PHP version detected. EJECT! EJECT! EJECT!
if (!version_compare(PHP_VERSION, '7.2.0', '>='))
{
	return;
}

// Make sure Akeeba Backup is installed
if (!file_exists(JPATH_ADMINISTRATOR . '/components/com_akeeba'))
{
	return;
}

// Load FOF if not already loaded
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
	return;
}

/*
 * Hopefully, if we are still here, the site is running on at least PHP5. This means that
 * including the Akeeba Backup factory class will not throw a White Screen of Death, locking
 * the administrator out of the back-end.
 */

// Make sure Akeeba Backup is installed, or quit
$akeeba_installed = @file_exists(JPATH_ADMINISTRATOR . '/components/com_akeeba/BackupEngine/Factory.php');

if (!$akeeba_installed)
{
	return;
}

// Make sure Akeeba Backup is enabled
if (!ComponentHelper::isEnabled('com_akeeba'))
{
	return;
}

class plgSystemBackuponupdate extends CMSPlugin
{
	/** @var \Joomla\CMS\Application\AdministratorApplication */
	public $app;

	private $isEnabled;

	/**
	 * Constructor
	 *
	 * @param   object  $subject  The object to observe
	 * @param   array   $config   An array that holds the plugin configuration
	 *
	 * @since   3.8.0
	 */
	public function __construct(&$subject, $config)
	{
		/**
		 * I know that this piece of code cannot possibly be executed since I have already returned BEFORE declaring
		 * the class when eAccelerator is detected. However, eAccelerator is a GINORMOUS, STINKY PILE OF BULL CRAP. The
		 * stupid thing will return above BUT it will also declare the class EVEN THOUGH according to how PHP works
		 * this part of the code should be unreachable o_O Therefore I have to define this constant and exit the
		 * constructor when we have already determined that this class MUST NOT be defined. Because screw you
		 * eAccelerator, that's why.
		 */
		if (defined('AKEEBA_EACCELERATOR_IS_SO_BORKED_IT_DOES_NOT_EVEN_RETURN'))
		{
			return;
		}

		parent::__construct($subject, $config);
	}

	/**
	 * Runs on application initialization. Implements the functionality of this plugin.
	 *
	 * @return  void
	 * @since   3.8.0
	 */
	public function onAfterInitialise()
	{
		// Make sure this is the back-end
		try
		{
			$app = Factory::getApplication();
		}
		catch (Exception $e)
		{
			return;
		}

		if (!$app->isClient('administrator'))
		{
			return;
		}

		// Make sure we are enabled
		if (!$this->isEnabled())
		{
			return;
		}

		// Make sure a user is logged in
		$user = JFactory::getUser();

		if (!is_object($user) || $user->guest)
		{
			return;
		}

		// Make sure the user is a Super User
		if (!$user->authorise('core.admin'))
		{
			return;
		}

		// Handle the flag toggle through AJAX
		$ji          = Factory::getApplication()->input;
		$toggleParam = $ji->getCmd('_akeeba_backup_on_update_toggle');

		if ($toggleParam && ($toggleParam == Factory::getSession()->getToken()))
		{
			$this->toggleBoUFlag();

			$uri = Uri::getInstance();
			$uri->delVar('_akeeba_backup_on_update_toggle');

			$this->app->redirect($uri->toString());

			return;
		}

		// Get the input variables
		$component = $ji->getCmd('option', '');
		$task      = $ji->getCmd('task', '');
		$backedup  = ((int) $ji->getInt('is_backed_up', 0)) === 1;

		// Conditionally display the Backup on Update message
		$this->conditionallyEnqueueMessage($component, $task);

		// Make sure we are active
		if ($this->getBoUFlag() != 1)
		{
			return;
		}

		// Perform a redirection on Joomla! Update download or install task, unless we have already backed up the site
		$redirectCondition = ($component == 'com_joomlaupdate') && ($task == 'update.install') && !$backedup;

		if ($redirectCondition)
		{
			// Get the backup profile ID
			$profileId = (int) $this->params->get('profileid', 1);

			if ($profileId <= 0)
			{
				$profileId = 1;
			}

			// Get the description override
			$this->loadLanguage();
			$description = $this->preprocessDescription($this->params->get(
				'description',
				Text::_('PLG_SYSTEM_BACKUPONUPDATE_DEFAULT_DESCRIPTION')
			));

			$jtoken = Factory::getSession()->getFormToken();

			// Get the return URL
			$returnUri = new Uri(Uri::base() . 'index.php');
			$params    = [
				'option'       => 'com_joomlaupdate',
				'task'         => 'update.install',
				'is_backed_up' => 1,
				$jtoken        => 1,
			];
			array_walk($params, function ($value, $key) use (&$returnUri) {
				$returnUri->setVar($key, $value);
			});

			// Get the redirect URL
			$redirectUri = new Uri(Uri::base() . 'index.php');
			$params      = [
				'option'      => 'com_akeeba',
				'view'        => 'Backup',
				'autostart'   => 1,
				'returnurl'   => base64_encode($returnUri->toString()),
				'description' => urlencode($description),
				'profileid'   => $profileId,
				$jtoken       => 1,
			];
			array_walk($params, function ($value, $key) use (&$redirectUri) {
				$redirectUri->setVar($key, $value);
			});

			// Perform the redirection
			$app->redirect($redirectUri->toString());
		}
	}

	/**
	 * Load a plugin layout file. These files can be overridden with standard Joomla! template overrides.
	 *
	 * @param   string  $layout  The layout file to load
	 * @param   array   $params  An array passed verbatim to the layout file as the `$params` variable
	 *
	 * @return  string  The rendered contents of the file
	 *
	 * @since   5.4.1
	 */
	private function loadTemplate($layout, array $params = []): string
	{
		$file = PluginHelper::getLayoutPath('system', 'backuponupdate', $layout);

		ob_start();

		require_once $file;

		$ret = ob_get_clean();

		return $ret;
	}

	/**
	 * Get the Backup on Update flag
	 *
	 * @return  int
	 * @since   5.5.0
	 */
	private function getBoUFlag(): int
	{
		$container = Container::getInstance('com_akeeba', ['tempInstance' => 1]);

		return (int) $container->platform->getSessionVar('active', 1, 'plg_system_backuponupdate');
	}

	/**
	 * Toggle the Backup on Update flag
	 *
	 * @return  void
	 * @since   5.5.0
	 */
	private function toggleBoUFlag(): void
	{
		$container = Container::getInstance('com_akeeba', ['tempInstance' => 1]);
		$status    = 1 - $this->getBoUFlag();

		$container->platform->setSessionVar('active', $status, 'plg_system_backuponupdate');
	}

	/**
	 * Should this plugin be enabled at all?
	 *
	 * @return  bool
	 * @since   7.0.0
	 */
	private function isEnabled(): bool
	{
		if (!is_null($this->isEnabled))
		{
			return $this->isEnabled;
		}

		$this->isEnabled = false;

		if (!version_compare(PHP_VERSION, '7.2.0', '>='))
		{
			return false;
		}

		// Make sure Akeeba Backup is installed
		if (!file_exists(JPATH_ADMINISTRATOR . '/components/com_akeeba'))
		{
			return false;
		}

		// Is Akeeba Backup enabled?
		try
		{
			$db    = Factory::getDbo();
			$query = $db->getQuery(true)
				->select($db->qn('enabled'))
				->from($db->qn('#__extensions'))
				->where($db->qn('element') . ' = ' . $db->q('com_akeeba'))
				->where($db->qn('type') . ' = ' . $db->q('component'));
			$db->setQuery($query);
			$enabled         = $db->loadResult();
			$this->isEnabled = is_null($enabled) ? false : ((bool) $enabled);
		}
		catch (Exception $e)
		{
			$this->isEnabled = false;
		}

		return $this->isEnabled;
	}

	/**
	 * Returns the version number of the latest Joomla release.
	 *
	 * It will return the string "(???)" if no Joomla update is being listed
	 *
	 * @return  string
	 * @since   7.0.0
	 */
	private function getLatestJoomlaVersion(): string
	{
		$latestVersion = '(???)';

		// Get the extension ID for Joomla! itself (the files_joomla pseudo-extension)
		try
		{
			$db    = Factory::getDbo();
			$query = $db->getQuery(true)
				->select($db->qn('extension_id'))
				->from($db->qn('#__extensions'))
				->where($db->qn('name') . ' = ' . $db->q('files_joomla'));

			$jEid = $db->setQuery($query)->loadResult();
		}
		catch (Exception $e)
		{
			$jEid = 700;
		}

		if (is_null($jEid) || ($jEid <= 0))
		{
			$jEid = 700;
		}

		// Fetch the Joomla update information from the database.
		try
		{
			$db           = Factory::getDbo();
			$query        = $db->getQuery(true)
				->select('*')
				->from($db->quoteName('#__updates'))
				->where($db->quoteName('extension_id') . ' = ' . $db->quote($jEid));
			$updateObject = $db->setQuery($query)->loadObject();
		}
		catch (Exception $e)
		{
			return $latestVersion;
		}

		if (is_null($updateObject))
		{
			return $latestVersion;
		}

		return $updateObject->version ?? $latestVersion;
	}

	/**
	 * Pre
	 *
	 * @param $description
	 *
	 * @return string|string[]
	 */
	private function preprocessDescription(string $description): string
	{
		$replacements = [
			'[VERSION_FROM]' => JVERSION,
			'[VERSION_TO]'   => $this->getLatestJoomlaVersion(),
		];

		return str_replace(array_keys($replacements), array_values($replacements), $description);
	}

	private function conditionallyEnqueueMessage(string $component, string $task): void
	{
		// Only show the message in Joomla! Update's main view
		if (($component !== 'com_joomlaupdate') || (!empty($task) && (strpos($task, 'update.') === 0)))
		{
			return;
		}

		$this->loadLanguage('plg_system_backuponupdate');

		$willBackup  = $this->getBoUFlag() === 1;
		$infoType    = version_compare(JVERSION, '3.999.999', 'gt') ? 'success' : 'info';
		$messageType = $willBackup ? $infoType : 'warning';

		$uri = Uri::getInstance();
		$uri->setVar('_akeeba_backup_on_update_toggle', $this->app->getSession()->getToken());

		$message =
			'<h3>' .
			Text::_('PLG_SYSTEM_BACKUPONUPDATE_LBL_TITLE') .
			'</h3>' .
			'<p>' .
			Text::_('PLG_SYSTEM_BACKUPONUPDATE_LBL_CONTENT_' . ($willBackup ? 'ACTIVE' : 'INACTIVE')) .
			'</p>' .
			sprintf(
				'<p><a href="%s" class="btn btn-%s">%s</a></p>',
				$uri->toString(),
				$willBackup ? 'danger' : 'primary',
				Text::_('PLG_SYSTEM_BACKUPONUPDATE_LBL_TOGGLE_' . ($willBackup ? 'DEACTIVATE' : 'ACTIVATE'))) .
			'<p class="text-muted"><em>' .
			Text::_('PLG_SYSTEM_BACKUPONUPDATE_LBL_CONTENT_TIP') .
			'</em></p>';

		$this->app->enqueueMessage($message, $messageType);
	}
}
PK��#]#�,���(system/backuponupdate/backuponupdate.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<extension version="2.5.0" type="plugin" group="system" method="upgrade">
	<name>PLG_SYSTEM_BACKUPONUPDATE</name>
	<author>Nicholas K. Dionysopoulos</author>
	<authorEmail>nicholas@dionysopoulos.me</authorEmail>
	<authorUrl>https://www.akeeba.com</authorUrl>
	<copyright>Copyright (c)2006-2023 Nicholas K. Dionysopoulos</copyright>
	<license>GNU General Public License version 3, or later</license>
	<creationDate>2023-02-08</creationDate>
	<version>8.2.7</version>
	<description>PLG_SYSTEM_BACKUPONUPDATE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="backuponupdate">backuponupdate.php</filename>
		<filename>.htaccess</filename>
		<filename>web.config</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_system_backuponupdate.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_system_backuponupdate.sys.ini</language>
	</languages>
    <config addfieldpath="/administrator/components/com_akeeba/fields">
        <fields name="params">
            <fieldset name="basic">
                <field name="profileid" type="backupprofiles" default="1"
                       label="PLG_SYSTEM_BACKUPONUPDATE_PROFILE_LABEL"
                       description="PLG_SYSTEM_BACKUPONUPDATE_PROFILE_DESC"
                />

				<field name="description" type="text" default="" size="30"
					   label="COM_AKEEBA_CONFIG_DESCRIPTION_LABEL"
					   description="COM_AKEEBA_CONFIG_DESCRIPTION_DESC"/>

			</fieldset>
        </fields>
    </config>

	<scriptfile>script.php</scriptfile>
</extension>
PK��#]|��N system/backuponupdate/web.confignu�[���<?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>PK��#]sPw��system/sessiongc/sessiongc.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="system" method="upgrade">
	<name>plg_system_sessiongc</name>
	<author>Joomla! Project</author>
	<creationDate>February 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.8.6</version>
	<description>PLG_SYSTEM_SESSIONGC_XML_DESCRIPTION</description>
	<files>
		<filename plugin="sessiongc">sessiongc.php</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_system_sessiongc.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_system_sessiongc.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="enable_session_gc"
					type="radio"
					label="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_LABEL"
					description="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="uint"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="enable_session_metadata_gc"
					type="radio"
					label="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_LABEL"
					description="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="uint"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="gc_probability"
					type="number"
					label="PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_LABEL"
					description="PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_DESC"
					filter="uint"
					validate="number"
					min="1"
					default="1"
					showon="enable_session_gc:1[OR]enable_session_metadata_gc:1"
				/>

				<field
					name="gc_divisor"
					type="number"
					label="PLG_SYSTEM_SESSIONGC_GC_DIVISOR_LABEL"
					description="PLG_SYSTEM_SESSIONGC_GC_DIVISOR_DESC"
					filter="uint"
					validate="number"
					min="1"
					default="100"
					showon="enable_session_gc:1[OR]enable_session_metadata_gc:1"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]ҽ�F��system/sessiongc/sessiongc.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.sessiongc
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Session\MetadataManager;

/**
 * Garbage collection handler for session related data
 *
 * @since  3.8.6
 */
class PlgSystemSessionGc extends CMSPlugin
{
	/**
	 * Application object
	 *
	 * @var    CMSApplication
	 * @since  3.8.6
	 */
	protected $app;

	/**
	 * Database driver
	 *
	 * @var    JDatabaseDriver
	 * @since  3.8.6
	 */
	protected $db;

	/**
	 * Runs after the HTTP response has been sent to the client and performs garbage collection tasks
	 *
	 * @return  void
	 *
	 * @since   3.8.6
	 */
	public function onAfterRespond()
	{
		$session = Factory::getSession();

		if ($this->params->get('enable_session_gc', 1))
		{
			$probability = $this->params->get('gc_probability', 1);
			$divisor     = $this->params->get('gc_divisor', 100);

			$random = $divisor * lcg_value();

			if ($probability > 0 && $random < $probability)
			{
				$session->gc();
			}
		}

		if ($this->app->get('session_handler', 'none') !== 'database' && $this->params->get('enable_session_metadata_gc', 1))
		{
			$probability = $this->params->get('gc_probability', 1);
			$divisor     = $this->params->get('gc_divisor', 100);

			$random = $divisor * lcg_value();

			if ($probability > 0 && $random < $probability)
			{
				$metadataManager = new MetadataManager($this->app, $this->db);
				$metadataManager->deletePriorTo(time() - $session->getExpire());
			}
		}
	}
}
PK��#]�)��system/sessiongc/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��system/debug/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�i�>>system/debug/debug.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_debug</name>
	<author>Joomla! Project</author>
	<creationDate>December 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_DEBUG_XML_DESCRIPTION</description>
	<files>
		<filename plugin="debug">debug.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_debug.ini</language>
		<language tag="en-GB">en-GB.plg_system_debug.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="filter_groups"
					type="usergrouplist"
					label="PLG_DEBUG_FIELD_ALLOWED_GROUPS_LABEL"
					description="PLG_DEBUG_FIELD_ALLOWED_GROUPS_DESC"
					multiple="true"
					filter="int_array"
					size="10"
				/>

				<field
					name="session"
					type="radio"
					label="PLG_DEBUG_FIELD_SESSION_LABEL"
					description="PLG_DEBUG_FIELD_SESSION_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="profile"
					type="radio"
					label="PLG_DEBUG_FIELD_PROFILING_LABEL"
					description="PLG_DEBUG_FIELD_PROFILING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="queries"
					type="radio"
					label="PLG_DEBUG_FIELD_QUERIES_LABEL"
					description="PLG_DEBUG_FIELD_QUERIES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="query_types"
					type="radio"
					label="PLG_DEBUG_FIELD_QUERY_TYPES_LABEL"
					description="PLG_DEBUG_FIELD_QUERY_TYPES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="memory"
					type="radio"
					label="PLG_DEBUG_FIELD_MEMORY_LABEL"
					description="PLG_DEBUG_FIELD_MEMORY_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="logs"
					type="radio"
					label="PLG_DEBUG_FIELD_LOGS_LABEL"
					description="PLG_DEBUG_FIELD_LOGS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="log_priorities"
					type="list"
					label="PLG_DEBUG_FIELD_LOG_PRIORITIES_LABEL"
					description="PLG_DEBUG_FIELD_LOG_PRIORITIES_DESC"
					multiple="true"
					default="all"
					>
					<option value="all">PLG_DEBUG_FIELD_LOG_PRIORITIES_ALL</option>
					<option value="emergency">PLG_DEBUG_FIELD_LOG_PRIORITIES_EMERGENCY</option>
					<option value="alert">PLG_DEBUG_FIELD_LOG_PRIORITIES_ALERT</option>
					<option value="critical">PLG_DEBUG_FIELD_LOG_PRIORITIES_CRITICAL</option>
					<option value="error">PLG_DEBUG_FIELD_LOG_PRIORITIES_ERROR</option>
					<option value="warning">PLG_DEBUG_FIELD_LOG_PRIORITIES_WARNING</option>
					<option value="notice">PLG_DEBUG_FIELD_LOG_PRIORITIES_NOTICE</option>
					<option value="info">PLG_DEBUG_FIELD_LOG_PRIORITIES_INFO</option>
					<option value="debug">PLG_DEBUG_FIELD_LOG_PRIORITIES_DEBUG</option>
				</field>

				<field
					name="log_categories"
					type="text"
					label="PLG_DEBUG_FIELD_LOG_CATEGORIES_LABEL"
					description="PLG_DEBUG_FIELD_LOG_CATEGORIES_DESC"
					size="60"
				/>

				<field
					name="log_category_mode"
					type="radio"
					label="PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_LABEL"
					description="PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno btn-group-reversed"
					>
					<option value="0">PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_INCLUDE</option>
					<option value="1">PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_EXCLUDE</option>
				</field>

				<field
					name="refresh_assets"
					type="radio"
					label="PLG_DEBUG_FIELD_REFRESH_ASSETS_LABEL"
					description="PLG_DEBUG_FIELD_REFRESH_ASSETS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>

			<fieldset
				name="language"
				label="PLG_DEBUG_LANGUAGE_FIELDSET_LABEL"
				>

				<field
					name="language_errorfiles"
					type="radio"
					label="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_LABEL"
					description="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="language_files"
					type="radio"
					label="PLG_DEBUG_FIELD_LANGUAGE_FILES_LABEL"
					description="PLG_DEBUG_FIELD_LANGUAGE_FILES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="language_strings"
					type="radio"
					label="PLG_DEBUG_FIELD_LANGUAGE_STRING_LABEL"
					description="PLG_DEBUG_FIELD_LANGUAGE_STRING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="strip-first"
					type="radio"
					label="PLG_DEBUG_FIELD_STRIP_FIRST_LABEL"
					description="PLG_DEBUG_FIELD_STRIP_FIRST_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="strip-prefix"
					type="textarea"
					label="PLG_DEBUG_FIELD_STRIP_PREFIX_LABEL"
					description="PLG_DEBUG_FIELD_STRIP_PREFIX_DESC"
					cols="30"
					rows="4"
				/>

				<field
					name="strip-suffix"
					type="textarea"
					label="PLG_DEBUG_FIELD_STRIP_SUFFIX_LABEL"
					description="PLG_DEBUG_FIELD_STRIP_SUFFIX_DESC"
					cols="30"
					rows="4"
				/>
			</fieldset>

			<fieldset
				name="logging"
				label="PLG_DEBUG_LOGGING_FIELDSET_LABEL"
				>
				<field
					name="log-deprecated"
					type="radio"
					label="PLG_DEBUG_FIELD_LOG_DEPRECATED_LABEL"
					description="PLG_DEBUG_FIELD_LOG_DEPRECATED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="log-everything"
					type="radio"
					label="PLG_DEBUG_FIELD_LOG_EVERYTHING_LABEL"
					description="PLG_DEBUG_FIELD_LOG_EVERYTHING_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="log-executed-sql"
					type="radio"
					label="PLG_DEBUG_FIELD_EXECUTEDSQL_LABEL"
					description="PLG_DEBUG_FIELD_EXECUTEDSQL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�+Gb�b�system/debug/debug.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.Debug
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Utilities\ArrayHelper;

/**
 * Joomla! Debug plugin.
 *
 * @since  1.5
 */
class PlgSystemDebug extends JPlugin
{
	/**
	 * xdebug.file_link_format from the php.ini.
	 *
	 * @var    string
	 * @since  1.7
	 */
	protected $linkFormat = '';

	/**
	 * True if debug lang is on.
	 *
	 * @var    boolean
	 * @since  3.0
	 */
	private $debugLang = false;

	/**
	 * Holds log entries handled by the plugin.
	 *
	 * @var    array
	 * @since  3.1
	 */
	private $logEntries = array();

	/**
	 * Holds SHOW PROFILES of queries.
	 *
	 * @var    array
	 * @since  3.1.2
	 */
	private $sqlShowProfiles = array();

	/**
	 * Holds all SHOW PROFILE FOR QUERY n, indexed by n-1.
	 *
	 * @var    array
	 * @since  3.1.2
	 */
	private $sqlShowProfileEach = array();

	/**
	 * Holds all EXPLAIN EXTENDED for all queries.
	 *
	 * @var    array
	 * @since  3.1.2
	 */
	private $explains = array();

	/**
	 * Holds total amount of executed queries.
	 *
	 * @var    int
	 * @since  3.2
	 */
	private $totalQueries = 0;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.3
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.8.0
	 */
	protected $db;

	/**
	 * Container for callback functions to be triggered when rendering the console.
	 *
	 * @var    callable[]
	 * @since  3.7.0
	 */
	private static $displayCallbacks = array();

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   1.5
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// Log the deprecated API.
		if ($this->params->get('log-deprecated', 0))
		{
			JLog::addLogger(array('text_file' => 'deprecated.php'), JLog::ALL, array('deprecated'));
		}

		// Log everything (except deprecated APIs, these are logged separately with the option above).
		if ($this->params->get('log-everything', 0))
		{
			JLog::addLogger(array('text_file' => 'everything.php'), JLog::ALL, array('deprecated', 'databasequery'), true);
		}

		// Get the application if not done by JPlugin. This may happen during upgrades from Joomla 2.5.
		if (!$this->app)
		{
			$this->app = JFactory::getApplication();
		}

		// Get the db if not done by JPlugin. This may happen during upgrades from Joomla 2.5.
		if (!$this->db)
		{
			$this->db = JFactory::getDbo();
		}

		$this->debugLang = $this->app->get('debug_lang');

		// Skip the plugin if debug is off
		if ($this->debugLang == '0' && $this->app->get('debug') == '0')
		{
			return;
		}

		// Only if debugging or language debug is enabled.
		if (JDEBUG || $this->debugLang)
		{
			JFactory::getConfig()->set('gzip', 0);
			ob_start();
			ob_implicit_flush(false);
		}

		$this->linkFormat = ini_get('xdebug.file_link_format');

		if ($this->params->get('logs', 1))
		{
			$priority = 0;

			foreach ($this->params->get('log_priorities', array()) as $p)
			{
				$const = 'JLog::' . strtoupper($p);

				if (!defined($const))
				{
					continue;
				}

				$priority |= constant($const);
			}

			// Split into an array at any character other than alphabet, numbers, _, ., or -
			$categories = preg_split('/[^\w.-]+/', $this->params->get('log_categories', ''), -1, PREG_SPLIT_NO_EMPTY);
			$mode       = $this->params->get('log_category_mode', 0);

			JLog::addLogger(array('logger' => 'callback', 'callback' => array($this, 'logger')), $priority, $categories, $mode);
		}

		// Prepare disconnect handler for SQL profiling.
		$db = $this->db;
		$db->addDisconnectHandler(array($this, 'mysqlDisconnectHandler'));

		// Log deprecated class aliases
		foreach (JLoader::getDeprecatedAliases() as $deprecation)
		{
			JLog::add(
				sprintf(
					'%1$s has been aliased to %2$s and the former class name is deprecated. The alias will be removed in %3$s.',
					$deprecation['old'],
					$deprecation['new'],
					$deprecation['version']
				),
				JLog::WARNING,
				'deprecated'
			);
		}
	}

	/**
	 * Add the CSS for debug.
	 * We can't do this in the constructor because stuff breaks.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onAfterDispatch()
	{
		// Only if debugging or language debug is enabled.
		if ((JDEBUG || $this->debugLang) && $this->isAuthorisedDisplayDebug())
		{
			JHtml::_('stylesheet', 'cms/debug.css', array('version' => 'auto', 'relative' => true));
		}

		// Disable asset media version if needed.
		if (JDEBUG && (int) $this->params->get('refresh_assets', 1) === 0)
		{
			$this->app->getDocument()->setMediaVersion(null);
		}

		// Only if debugging is enabled for SQL query popovers.
		if (JDEBUG && $this->isAuthorisedDisplayDebug())
		{
			JHtml::_('bootstrap.tooltip');
			JHtml::_('bootstrap.popover', '.hasPopover', array('placement' => 'top'));
		}
	}

	/**
	 * Show the debug info.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onAfterRespond()
	{
		// Do not render if debugging or language debug is not enabled.
		if (!JDEBUG && !$this->debugLang)
		{
			return;
		}

		// User has to be authorised to see the debug information.
		if (!$this->isAuthorisedDisplayDebug())
		{
			return;
		}

		// Only render for HTML output.
		if (JFactory::getDocument()->getType() !== 'html')
		{
			return;
		}

		// Capture output.
		$contents = ob_get_contents();

		if ($contents)
		{
			ob_end_clean();
		}

		// No debug for Safari and Chrome redirection.
		if (strpos($contents, '<html><head><meta http-equiv="refresh" content="0;') === 0
			&& strpos(strtolower(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''), 'webkit') !== false)
		{
			echo $contents;

			return;
		}

		// Load language.
		$this->loadLanguage();

		$html = array();

		// Some "mousewheel protecting" JS.
		$html[] = "<script>function toggleContainer(name)
		{
			var e = document.getElementById(name);// MooTools might not be available ;)
			e.style.display = e.style.display === 'none' ? 'block' : 'none';
		}</script>";

		$html[] = '<div id="system-debug" class="profiler">';

		$html[] = '<h2>' . JText::_('PLG_DEBUG_TITLE') . '</h2>';

		if (JDEBUG)
		{
			if (JError::getErrors())
			{
				$html[] = $this->display('errors');
			}

			if ($this->params->get('session', 1))
			{
				$html[] = $this->display('session');
			}

			if ($this->params->get('profile', 1))
			{
				$html[] = $this->display('profile_information');
			}

			if ($this->params->get('memory', 1))
			{
				$html[] = $this->display('memory_usage');
			}

			if ($this->params->get('queries', 1))
			{
				$html[] = $this->display('queries');
			}

			if (!empty($this->logEntries) && $this->params->get('logs', 1))
			{
				$html[] = $this->display('logs');
			}
		}

		if ($this->debugLang)
		{
			if ($this->params->get('language_errorfiles', 1))
			{
				$languageErrors = JFactory::getLanguage()->getErrorFiles();
				$html[]         = $this->display('language_files_in_error', $languageErrors);
			}

			if ($this->params->get('language_files', 1))
			{
				$html[] = $this->display('language_files_loaded');
			}

			if ($this->params->get('language_strings', 1))
			{
				$html[] = $this->display('untranslated_strings');
			}
		}

		foreach (self::$displayCallbacks as $name => $callable)
		{
			$html[] = $this->displayCallback($name, $callable);
		}

		$html[] = '</div>';

		echo str_replace('</body>', implode('', $html) . '</body>', $contents);
	}

	/**
	 * Add a display callback to be rendered with the debug console.
	 *
	 * @param   string    $name      The name of the callable, this is used to generate the section title.
	 * @param   callable  $callable  The callback function to be added.
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 * @throws  InvalidArgumentException
	 */
	public static function addDisplayCallback($name, $callable)
	{
		// TODO - When PHP 5.4 is the minimum the parameter should be typehinted "callable" and this check removed
		if (!is_callable($callable))
		{
			throw new InvalidArgumentException('A valid callback function must be given.');
		}

		self::$displayCallbacks[$name] = $callable;

		return true;
	}

	/**
	 * Remove a registered display callback
	 *
	 * @param   string  $name  The name of the callable.
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public static function removeDisplayCallback($name)
	{
		unset(self::$displayCallbacks[$name]);

		return true;
	}

	/**
	 * Method to check if the current user is allowed to see the debug information or not.
	 *
	 * @return  boolean  True if access is allowed.
	 *
	 * @since   3.0
	 */
	private function isAuthorisedDisplayDebug()
	{
		static $result = null;

		if ($result !== null)
		{
			return $result;
		}

		// If the user is not allowed to view the output then end here.
		$filterGroups = (array) $this->params->get('filter_groups', array());

		if (!empty($filterGroups))
		{
			$userGroups = JFactory::getUser()->get('groups');

			if (!array_intersect($filterGroups, $userGroups))
			{
				$result = false;

				return false;
			}
		}

		$result = true;

		return true;
	}

	/**
	 * General display method.
	 *
	 * @param   string  $item    The item to display.
	 * @param   array   $errors  Errors occurred during execution.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function display($item, array $errors = array())
	{
		$title = JText::_('PLG_DEBUG_' . strtoupper($item));

		$status = '';

		if (count($errors))
		{
			$status = ' dbg-error';
		}

		$fncName = 'display' . ucfirst(str_replace('_', '', $item));

		if (!method_exists($this, $fncName))
		{
			return __METHOD__ . ' -- Unknown method: ' . $fncName . '<br />';
		}

		$html = array();

		$js = "toggleContainer('dbg_container_" . $item . "');";

		$class = 'dbg-header' . $status;

		$html[] = '<div class="' . $class . '" onclick="' . $js . '"><a href="javascript:void(0);"><h3>' . $title . '</h3></a></div>';

		// @todo set with js.. ?
		$style = ' style="display: none;"';

		$html[] = '<div ' . $style . ' class="dbg-container" id="dbg_container_' . $item . '">';
		$html[] = $this->$fncName();
		$html[] = '</div>';

		return implode('', $html);
	}

	/**
	 * Display method for callback functions.
	 *
	 * @param   string    $name      The name of the callable.
	 * @param   callable  $callable  The callable function.
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	protected function displayCallback($name, $callable)
	{
		$title = JText::_('PLG_DEBUG_' . strtoupper($name));

		$html = array();

		$js = "toggleContainer('dbg_container_" . $name . "');";

		$class = 'dbg-header';

		$html[] = '<div class="' . $class . '" onclick="' . $js . '"><a href="javascript:void(0);"><h3>' . $title . '</h3></a></div>';

		// @todo set with js.. ?
		$style = ' style="display: none;"';

		$html[] = '<div ' . $style . ' class="dbg-container" id="dbg_container_' . $name . '">';
		$html[] = call_user_func($callable);
		$html[] = '</div>';

		return implode('', $html);
	}

	/**
	 * Display session information.
	 *
	 * Called recursively.
	 *
	 * @param   string   $key      A session key.
	 * @param   mixed    $session  The session array, initially null.
	 * @param   integer  $id       Used to identify the DIV for the JavaScript toggling code.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displaySession($key = '', $session = null, $id = 0)
	{
		if (!$session)
		{
			$session = JFactory::getSession()->getData();
		}

		$html = array();
		static $id;

		if (!is_array($session))
		{
			$html[] = $key . '<pre>' . $this->prettyPrintJSON($session) . '</pre>' . PHP_EOL;
		}
		else
		{
			foreach ($session as $sKey => $entries)
			{
				$display = true;

				if (is_array($entries) && $entries)
				{
					$display = false;
				}

				if (is_object($entries))
				{
					$o = ArrayHelper::fromObject($entries);

					if ($o)
					{
						$entries = $o;
						$display = false;
					}
				}

				if (!$display)
				{
					$js = "toggleContainer('dbg_container_session" . $id . '_' . $sKey . "');";

					$html[] = '<div class="dbg-header" onclick="' . $js . '"><a href="javascript:void(0);"><h3>' . $sKey . '</h3></a></div>';

					// @todo set with js.. ?
					$style = ' style="display: none;"';

					$html[] = '<div ' . $style . ' class="dbg-container" id="dbg_container_session' . $id . '_' . $sKey . '">';
					$id++;

					// Recurse...
					$this->displaySession($sKey, $entries, $id);

					$html[] = '</div>';

					continue;
				}

				if (is_array($entries))
				{
					$entries = implode($entries);
				}

				if (is_string($entries))
				{
					$html[] = $sKey . '<pre>' . $this->prettyPrintJSON($entries) . '</pre>' . PHP_EOL;
				}
			}
		}

		return implode('', $html);
	}

	/**
	 * Display errors.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayErrors()
	{
		$html = array();

		$html[] = '<ol>';

		while ($error = JError::getError(true))
		{
			$col = (E_WARNING == $error->get('level')) ? 'red' : 'orange';

			$html[] = '<li>';
			$html[] = '<b style="color: ' . $col . '">' . $error->getMessage() . '</b><br />';

			$info = $error->get('info');

			if ($info)
			{
				$html[] = '<pre>' . print_r($info, true) . '</pre><br />';
			}

			$html[] = $this->renderBacktrace($error);
			$html[] = '</li>';
		}

		$html[] = '</ol>';

		return implode('', $html);
	}

	/**
	 * Display profile information.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayProfileInformation()
	{
		$html = array();

		$htmlMarks = array();

		$totalTime = 0;
		$totalMem  = 0;
		$marks     = array();
		$bars      = array();
		$barsMem   = array();

		foreach (JProfiler::getInstance('Application')->getMarks() as $mark)
		{
			$totalTime += $mark->time;
			$totalMem  += (float) $mark->memory;
			$htmlMark  = sprintf(
				JText::_('PLG_DEBUG_TIME') . ': <span class="label label-time">%.2f&nbsp;ms</span> / <span class="label label-default">%.2f&nbsp;ms</span>'
				. ' ' . JText::_('PLG_DEBUG_MEMORY') . ': <span class="label label-memory">%0.3f MB</span> / <span class="label label-default">%0.2f MB</span>'
				. ' %s: %s',
				$mark->time,
				$mark->totalTime,
				$mark->memory,
				$mark->totalMemory,
				$mark->prefix,
				$mark->label
			);

			$marks[] = (object) array(
				'time'   => $mark->time,
				'memory' => $mark->memory,
				'html'   => $htmlMark,
				'tip'    => $mark->label,
			);
		}

		$avgTime = $totalTime / max(count($marks), 1);
		$avgMem  = $totalMem / max(count($marks), 1);

		foreach ($marks as $mark)
		{
			if ($mark->time > $avgTime * 1.5)
			{
				$barClass   = 'bar-danger';
				$labelClass = 'label-important label-danger';
			}
			elseif ($mark->time < $avgTime / 1.5)
			{
				$barClass   = 'bar-success';
				$labelClass = 'label-success';
			}
			else
			{
				$barClass   = 'bar-warning';
				$labelClass = 'label-warning';
			}

			if ($mark->memory > $avgMem * 1.5)
			{
				$barClassMem   = 'bar-danger';
				$labelClassMem = 'label-important label-danger';
			}
			elseif ($mark->memory < $avgMem / 1.5)
			{
				$barClassMem   = 'bar-success';
				$labelClassMem = 'label-success';
			}
			else
			{
				$barClassMem   = 'bar-warning';
				$labelClassMem = 'label-warning';
			}

			$barClass    .= " progress-$barClass";
			$barClassMem .= " progress-$barClassMem";

			$bars[] = (object) array(
				'width' => round($mark->time / ($totalTime / 100), 4),
				'class' => $barClass,
				'tip'   => $mark->tip . ' ' . round($mark->time, 2) . ' ms',
			);

			$barsMem[] = (object) array(
				'width' => round((float) $mark->memory / ($totalMem / 100), 4),
				'class' => $barClassMem,
				'tip'   => $mark->tip . ' ' . round($mark->memory, 3) . '  MB',
			);

			$htmlMarks[] = '<div>' . str_replace('label-time', $labelClass, str_replace('label-memory', $labelClassMem, $mark->html)) . '</div>';
		}

		$html[] = '<h4>' . JText::_('PLG_DEBUG_TIME') . '</h4>';
		$html[] = $this->renderBars($bars, 'profile');
		$html[] = '<h4>' . JText::_('PLG_DEBUG_MEMORY') . '</h4>';
		$html[] = $this->renderBars($barsMem, 'profile');

		$html[] = '<div class="dbg-profile-list">' . implode('', $htmlMarks) . '</div>';

		$db = $this->db;

		//  fix  for support custom shutdown function via register_shutdown_function().
		$db->disconnect();

		$log = $db->getLog();

		if ($log)
		{
			$timings = $db->getTimings();

			if ($timings)
			{
				$totalQueryTime = 0.0;
				$lastStart      = null;

				foreach ($timings as $k => $v)
				{
					if (!($k % 2))
					{
						$lastStart = $v;
					}
					else
					{
						$totalQueryTime += $v - $lastStart;
					}
				}

				$totalQueryTime *= 1000;

				if ($totalQueryTime > ($totalTime * 0.25))
				{
					$labelClass = 'label-important';
				}
				elseif ($totalQueryTime < ($totalTime * 0.15))
				{
					$labelClass = 'label-success';
				}
				else
				{
					$labelClass = 'label-warning';
				}

				$html[] = '<br /><div>' . JText::sprintf(
						'PLG_DEBUG_QUERIES_TIME',
						sprintf('<span class="label ' . $labelClass . '">%.2f&nbsp;ms</span>', $totalQueryTime)
					) . '</div>';

				if ($this->params->get('log-executed-sql', 0))
				{
					$this->writeToFile();
				}
			}
		}

		return implode('', $html);
	}

	/**
	 * Display memory usage.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayMemoryUsage()
	{
		$bytes = memory_get_usage();

		return '<span class="label label-default">' . JHtml::_('number.bytes', $bytes) . '</span>'
			. ' (<span class="label label-default">'
			. number_format($bytes, 0, JText::_('DECIMALS_SEPARATOR'), JText::_('THOUSANDS_SEPARATOR'))
			. ' '
			. JText::_('PLG_DEBUG_BYTES')
			. '</span>)';
	}

	/**
	 * Display logged queries.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayQueries()
	{
		$db  = $this->db;
		$log = $db->getLog();

		if (!$log)
		{
			return null;
		}

		$timings    = $db->getTimings();
		$callStacks = $db->getCallStacks();

		$db->setDebug(false);

		$selectQueryTypeTicker = array();
		$otherQueryTypeTicker  = array();

		$timing  = array();
		$maxtime = 0;

		if (isset($timings[0]))
		{
			$startTime         = $timings[0];
			$endTime           = $timings[count($timings) - 1];
			$totalBargraphTime = $endTime - $startTime;

			if ($totalBargraphTime > 0)
			{
				foreach ($log as $id => $query)
				{
					if (isset($timings[$id * 2 + 1]))
					{
						// Compute the query time: $timing[$k] = array( queryTime, timeBetweenQueries ).
						$timing[$id] = array(
							($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000,
							$id > 0 ? ($timings[$id * 2] - $timings[$id * 2 - 1]) * 1000 : 0,
						);
						$maxtime     = max($maxtime, $timing[$id]['0']);
					}
				}
			}
		}
		else
		{
			$startTime         = null;
			$totalBargraphTime = 1;
		}

		$bars           = array();
		$info           = array();
		$totalQueryTime = 0;
		$duplicates     = array();

		foreach ($log as $id => $query)
		{
			$did = md5($query);

			if (!isset($duplicates[$did]))
			{
				$duplicates[$did] = array();
			}

			$duplicates[$did][] = $id;

			if ($timings && isset($timings[$id * 2 + 1]))
			{
				// Compute the query time.
				$queryTime      = ($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000;
				$totalQueryTime += $queryTime;

				// Run an EXPLAIN EXTENDED query on the SQL query if possible.
				$hasWarnings          = false;
				$hasWarningsInProfile = false;

				if (isset($this->explains[$id]))
				{
					$explain = $this->tableToHtml($this->explains[$id], $hasWarnings);
				}
				else
				{
					$explain = JText::sprintf('PLG_DEBUG_QUERY_EXPLAIN_NOT_POSSIBLE', htmlspecialchars($query));
				}

				// Run a SHOW PROFILE query.
				$profile = '';

				if (isset($this->sqlShowProfileEach[$id]) && $db->getServerType() === 'mysql')
				{
					$profileTable = $this->sqlShowProfileEach[$id];
					$profile      = $this->tableToHtml($profileTable, $hasWarningsInProfile);
				}

				// How heavy should the string length count: 0 - 1.
				$ratio     = 0.5;
				$timeScore = $queryTime / ((strlen($query) + 1) * $ratio) * 200;

				// Determine color of bargraph depending on query speed and presence of warnings in EXPLAIN.
				if ($timeScore > 10)
				{
					$barClass   = 'bar-danger';
					$labelClass = 'label-important';
				}
				elseif ($hasWarnings || $timeScore > 5)
				{
					$barClass   = 'bar-warning';
					$labelClass = 'label-warning';
				}
				else
				{
					$barClass   = 'bar-success';
					$labelClass = 'label-success';
				}

				// Computes bargraph as follows: Position begin and end of the bar relatively to whole execution time.
				// TODO: $prevBar is not used anywhere. Remove?
				$prevBar = $id && isset($bars[$id - 1]) ? $bars[$id - 1] : 0;

				$barPre   = round($timing[$id][1] / ($totalBargraphTime * 10), 4);
				$barWidth = round($timing[$id][0] / ($totalBargraphTime * 10), 4);
				$minWidth = 0.3;

				if ($barWidth < $minWidth)
				{
					$barPre -= ($minWidth - $barWidth);

					if ($barPre < 0)
					{
						$minWidth += $barPre;
						$barPre   = 0;
					}

					$barWidth = $minWidth;
				}

				$bars[$id] = (object) array(
					'class' => $barClass,
					'width' => $barWidth,
					'pre'   => $barPre,
					'tip'   => sprintf('%.2f ms', $queryTime),
				);
				$info[$id] = (object) array(
					'class'       => $labelClass,
					'explain'     => $explain,
					'profile'     => $profile,
					'hasWarnings' => $hasWarnings,
				);
			}
		}

		// Remove single queries from $duplicates.
		$total_duplicates = 0;

		foreach ($duplicates as $did => $dups)
		{
			if (count($dups) < 2)
			{
				unset($duplicates[$did]);
			}
			else
			{
				$total_duplicates += count($dups);
			}
		}

		// Fix first bar width.
		$minWidth = 0.3;

		if ($bars[0]->width < $minWidth && isset($bars[1]))
		{
			$bars[1]->pre -= ($minWidth - $bars[0]->width);

			if ($bars[1]->pre < 0)
			{
				$minWidth     += $bars[1]->pre;
				$bars[1]->pre = 0;
			}

			$bars[0]->width = $minWidth;
		}

		$memoryUsageNow = memory_get_usage();
		$list           = array();

		foreach ($log as $id => $query)
		{
			// Start query type ticker additions.
			$fromStart  = stripos($query, 'from');
			$whereStart = stripos($query, 'where', $fromStart);

			if ($whereStart === false)
			{
				$whereStart = stripos($query, 'order by', $fromStart);
			}

			if ($whereStart === false)
			{
				$whereStart = strlen($query) - 1;
			}

			$fromString = substr($query, 0, $whereStart);
			$fromString = str_replace(array("\t", "\n"), ' ', $fromString);
			$fromString = trim($fromString);

			// Initialise the select/other query type counts the first time.
			if (!isset($selectQueryTypeTicker[$fromString]))
			{
				$selectQueryTypeTicker[$fromString] = 0;
			}

			if (!isset($otherQueryTypeTicker[$fromString]))
			{
				$otherQueryTypeTicker[$fromString] = 0;
			}

			// Increment the count.
			if (stripos($query, 'select') === 0)
			{
				$selectQueryTypeTicker[$fromString]++;
				unset($otherQueryTypeTicker[$fromString]);
			}
			else
			{
				$otherQueryTypeTicker[$fromString]++;
				unset($selectQueryTypeTicker[$fromString]);
			}

			$text = $this->highlightQuery($query);

			if ($timings && isset($timings[$id * 2 + 1]))
			{
				// Compute the query time.
				$queryTime = ($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000;

				// Timing
				// Formats the output for the query time with EXPLAIN query results as tooltip:
				$htmlTiming = '<div style="margin: 0 0 5px;"><span class="dbg-query-time">';
				$htmlTiming .= JText::sprintf(
					'PLG_DEBUG_QUERY_TIME',
					sprintf(
						'<span class="label %s">%.2f&nbsp;ms</span>',
						$info[$id]->class,
						$timing[$id]['0']
					)
				);

				if ($timing[$id]['1'])
				{
					$htmlTiming .= ' ' . JText::sprintf(
							'PLG_DEBUG_QUERY_AFTER_LAST',
							sprintf('<span class="label label-default">%.2f&nbsp;ms</span>', $timing[$id]['1'])
						);
				}

				$htmlTiming .= '</span>';

				if (isset($callStacks[$id][0]['memory']))
				{
					$memoryUsed        = $callStacks[$id][0]['memory'][1] - $callStacks[$id][0]['memory'][0];
					$memoryBeforeQuery = $callStacks[$id][0]['memory'][0];

					// Determine colour of query memory usage.
					if ($memoryUsed > 0.1 * $memoryUsageNow)
					{
						$labelClass = 'label-important';
					}
					elseif ($memoryUsed > 0.05 * $memoryUsageNow)
					{
						$labelClass = 'label-warning';
					}
					else
					{
						$labelClass = 'label-success';
					}

					$htmlTiming .= ' ' . '<span class="dbg-query-memory">'
						. JText::sprintf(
							'PLG_DEBUG_MEMORY_USED_FOR_QUERY',
							sprintf('<span class="label ' . $labelClass . '">%.3f&nbsp;MB</span>', $memoryUsed / 1048576),
							sprintf('<span class="label label-default">%.3f&nbsp;MB</span>', $memoryBeforeQuery / 1048576)
						)
						. '</span>';

					if ($callStacks[$id][0]['memory'][2] !== null)
					{
						// Determine colour of number or results.
						$resultsReturned = $callStacks[$id][0]['memory'][2];

						if ($resultsReturned > 3000)
						{
							$labelClass = 'label-important';
						}
						elseif ($resultsReturned > 1000)
						{
							$labelClass = 'label-warning';
						}
						elseif ($resultsReturned == 0)
						{
							$labelClass = '';
						}
						else
						{
							$labelClass = 'label-success';
						}

						$htmlResultsReturned = '<span class="label ' . $labelClass . '">' . (int) $resultsReturned . '</span>';
						$htmlTiming          .= ' <span class="dbg-query-rowsnumber">'
							. JText::sprintf('PLG_DEBUG_ROWS_RETURNED_BY_QUERY', $htmlResultsReturned) . '</span>';
					}
				}

				$htmlTiming .= '</div>';

				// Bar.
				$htmlBar = $this->renderBars($bars, 'query', $id);

				// Profile query.
				$title = JText::_('PLG_DEBUG_PROFILE');

				if (!$info[$id]->profile)
				{
					$title = '<span class="dbg-noprofile">' . $title . '</span>';
				}

				$htmlProfile = $info[$id]->profile ?: JText::_('PLG_DEBUG_NO_PROFILE');

				$htmlAccordions = JHtml::_(
					'bootstrap.startAccordion', 'dbg_query_' . $id, array(
						'active' => $info[$id]->hasWarnings ? ('dbg_query_explain_' . $id) : '',
					)
				);

				$htmlAccordions .= JHtml::_('bootstrap.addSlide', 'dbg_query_' . $id, JText::_('PLG_DEBUG_EXPLAIN'), 'dbg_query_explain_' . $id)
					. $info[$id]->explain
					. JHtml::_('bootstrap.endSlide');

				$htmlAccordions .= JHtml::_('bootstrap.addSlide', 'dbg_query_' . $id, $title, 'dbg_query_profile_' . $id)
					. $htmlProfile
					. JHtml::_('bootstrap.endSlide');

				// Call stack and back trace.
				if (isset($callStacks[$id]))
				{
					$htmlAccordions .= JHtml::_('bootstrap.addSlide', 'dbg_query_' . $id, JText::_('PLG_DEBUG_CALL_STACK'), 'dbg_query_callstack_' . $id)
						. $this->renderCallStack($callStacks[$id])
						. JHtml::_('bootstrap.endSlide');
				}

				$htmlAccordions .= JHtml::_('bootstrap.endAccordion');

				$did = md5($query);

				if (isset($duplicates[$did]))
				{
					$dups = array();

					foreach ($duplicates[$did] as $dup)
					{
						if ($dup != $id)
						{
							$dups[] = '<a class="alert-link" href="#dbg-query-' . ($dup + 1) . '">#' . ($dup + 1) . '</a>';
						}
					}

					$htmlQuery = '<div class="alert alert-error">' . JText::_('PLG_DEBUG_QUERY_DUPLICATES') . ': ' . implode('&nbsp; ', $dups) . '</div>'
						. '<pre class="alert" title="' . htmlspecialchars(JText::_('PLG_DEBUG_QUERY_DUPLICATES_FOUND'), ENT_COMPAT, 'UTF-8') . '">' . $text . '</pre>';
				}
				else
				{
					$htmlQuery = '<pre>' . $text . '</pre>';
				}

				$list[] = '<a name="dbg-query-' . ($id + 1) . '"></a>'
					. $htmlTiming
					. $htmlBar
					. $htmlQuery
					. $htmlAccordions;
			}
			else
			{
				$list[] = '<pre>' . $text . '</pre>';
			}
		}

		$totalTime = 0;

		foreach (JProfiler::getInstance('Application')->getMarks() as $mark)
		{
			$totalTime += $mark->time;
		}

		if ($totalQueryTime > ($totalTime * 0.25))
		{
			$labelClass = 'label-important';
		}
		elseif ($totalQueryTime < ($totalTime * 0.15))
		{
			$labelClass = 'label-success';
		}
		else
		{
			$labelClass = 'label-warning';
		}

		if ($this->totalQueries === 0)
		{
			$this->totalQueries = $db->getCount();
		}

		$html = array();

		$html[] = '<h4>' . JText::sprintf('PLG_DEBUG_QUERIES_LOGGED', $this->totalQueries)
			. sprintf(' <span class="label ' . $labelClass . '">%.2f&nbsp;ms</span>', $totalQueryTime) . '</h4><br />';

		if ($total_duplicates)
		{
			$html[] = '<div class="alert alert-error">'
				. '<h4>' . JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_TOTAL_NUMBER', $total_duplicates) . '</h4>';

			foreach ($duplicates as $dups)
			{
				$links = array();

				foreach ($dups as $dup)
				{
					$links[] = '<a class="alert-link" href="#dbg-query-' . ($dup + 1) . '">#' . ($dup + 1) . '</a>';
				}

				$html[] = '<div>' . JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_NUMBER', count($links)) . ': ' . implode('&nbsp; ', $links) . '</div>';
			}

			$html[] = '</div>';
		}

		$html[] = '<ol><li>' . implode('<hr /></li><li>', $list) . '<hr /></li></ol>';

		if (!$this->params->get('query_types', 1))
		{
			return implode('', $html);
		}

		// Get the totals for the query types.
		$totalSelectQueryTypes = count($selectQueryTypeTicker);
		$totalOtherQueryTypes  = count($otherQueryTypeTicker);
		$totalQueryTypes       = $totalSelectQueryTypes + $totalOtherQueryTypes;

		$html[] = '<h4>' . JText::sprintf('PLG_DEBUG_QUERY_TYPES_LOGGED', $totalQueryTypes) . '</h4>';

		if ($totalSelectQueryTypes)
		{
			$html[] = '<h5>' . JText::_('PLG_DEBUG_SELECT_QUERIES') . '</h5>';

			arsort($selectQueryTypeTicker);

			$list = array();

			foreach ($selectQueryTypeTicker as $query => $occurrences)
			{
				$list[] = '<pre>'
					. JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES', $this->highlightQuery($query), $occurrences)
					. '</pre>';
			}

			$html[] = '<ol><li>' . implode('</li><li>', $list) . '</li></ol>';
		}

		if ($totalOtherQueryTypes)
		{
			$html[] = '<h5>' . JText::_('PLG_DEBUG_OTHER_QUERIES') . '</h5>';

			arsort($otherQueryTypeTicker);

			$list = array();

			foreach ($otherQueryTypeTicker as $query => $occurrences)
			{
				$list[] = '<pre>'
					. JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES', $this->highlightQuery($query), $occurrences)
					. '</pre>';
			}

			$html[] = '<ol><li>' . implode('</li><li>', $list) . '</li></ol>';
		}

		return implode('', $html);
	}

	/**
	 * Render the bars.
	 *
	 * @param   array    &$bars  Array of bar data
	 * @param   string   $class  Optional class for items
	 * @param   integer  $id     Id if the bar to highlight
	 *
	 * @return  string
	 *
	 * @since   3.1.2
	 */
	protected function renderBars(&$bars, $class = '', $id = null)
	{
		$html = array();

		foreach ($bars as $i => $bar)
		{
			if (isset($bar->pre) && $bar->pre)
			{
				$html[] = '<div class="dbg-bar-spacer" style="width:' . $bar->pre . '%;"></div>';
			}

			$barClass = trim('bar dbg-bar progress-bar ' . (isset($bar->class) ? $bar->class : ''));

			if ($id !== null && $i == $id)
			{
				$barClass .= ' dbg-bar-active';
			}

			$tip = empty($bar->tip) ? '' : ' title="' . htmlspecialchars($bar->tip, ENT_COMPAT, 'UTF-8') . '"';

			$html[] = '<a class="bar dbg-bar ' . $barClass . '"' . $tip . ' style="width: '
				. $bar->width . '%;" href="#dbg-' . $class . '-' . ($i + 1) . '"></a>';
		}

		return '<div class="progress dbg-bars dbg-bars-' . $class . '">' . implode('', $html) . '</div>';
	}

	/**
	 * Render an HTML table based on a multi-dimensional array.
	 *
	 * @param   array    $table         An array of tabular data.
	 * @param   boolean  &$hasWarnings  Changes value to true if warnings are displayed, otherwise untouched
	 *
	 * @return  string
	 *
	 * @since   3.1.2
	 */
	protected function tableToHtml($table, &$hasWarnings)
	{
		if (!$table)
		{
			return null;
		}

		$html = array();

		$html[] = '<table class="table table-striped dbg-query-table">';
		$html[] = '<thead>';
		$html[] = '<tr>';

		foreach (array_keys($table[0]) as $k)
		{
			$html[] = '<th>' . htmlspecialchars($k) . '</th>';
		}

		$html[]    = '</tr>';
		$html[]    = '</thead>';
		$html[]    = '<tbody>';
		$durations = array();

		foreach ($table as $tr)
		{
			if (isset($tr['Duration']))
			{
				$durations[] = $tr['Duration'];
			}
		}

		rsort($durations, SORT_NUMERIC);

		foreach ($table as $tr)
		{
			$html[] = '<tr>';

			foreach ($tr as $k => $td)
			{
				if ($td === null)
				{
					// Display null's as 'NULL'.
					$td = 'NULL';
				}

				// Treat special columns.
				if ($k === 'Duration')
				{
					if ($td >= 0.001 && ($td == $durations[0] || (isset($durations[1]) && $td == $durations[1])))
					{
						// Duration column with duration value of more than 1 ms and within 2 top duration in SQL engine: Highlight warning.
						$html[]      = '<td class="dbg-warning">';
						$hasWarnings = true;
					}
					else
					{
						$html[] = '<td>';
					}

					// Display duration in milliseconds with the unit instead of seconds.
					$html[] = sprintf('%.2f&nbsp;ms', $td * 1000);
				}
				elseif ($k === 'Error')
				{
					// An error in the EXPLAIN query occurred, display it instead of the result (means original query had syntax error most probably).
					$html[]      = '<td class="dbg-warning">' . htmlspecialchars($td);
					$hasWarnings = true;
				}
				elseif ($k === 'key')
				{
					if ($td === 'NULL')
					{
						// Displays query parts which don't use a key with warning:
						$html[]      = '<td><strong>' . '<span class="dbg-warning" title="'
							. htmlspecialchars(JText::_('PLG_DEBUG_WARNING_NO_INDEX_DESC'), ENT_COMPAT, 'UTF-8') . '">'
							. JText::_('PLG_DEBUG_WARNING_NO_INDEX') . '</span>' . '</strong>';
						$hasWarnings = true;
					}
					else
					{
						$html[] = '<td><strong>' . htmlspecialchars($td) . '</strong>';
					}
				}
				elseif ($k === 'Extra')
				{
					$htmlTd = htmlspecialchars($td);

					// Replace spaces with &nbsp; (non-breaking spaces) for less tall tables displayed.
					$htmlTd = preg_replace('/([^;]) /', '\1&nbsp;', $htmlTd);

					// Displays warnings for "Using filesort":
					$htmlTdWithWarnings = str_replace(
						'Using&nbsp;filesort',
						'<span class="dbg-warning" title="'
						. htmlspecialchars(JText::_('PLG_DEBUG_WARNING_USING_FILESORT_DESC'), ENT_COMPAT, 'UTF-8') . '">'
						. JText::_('PLG_DEBUG_WARNING_USING_FILESORT') . '</span>',
						$htmlTd
					);

					if ($htmlTdWithWarnings !== $htmlTd)
					{
						$hasWarnings = true;
					}

					$html[] = '<td>' . $htmlTdWithWarnings;
				}
				else
				{
					$html[] = '<td>' . htmlspecialchars($td);
				}

				$html[] = '</td>';
			}

			$html[] = '</tr>';
		}

		$html[] = '</tbody>';
		$html[] = '</table>';

		return implode('', $html);
	}

	/**
	 * Disconnect handler for database to collect profiling and explain information.
	 *
	 * @param   JDatabaseDriver  &$db  Database object.
	 *
	 * @return  void
	 *
	 * @since   3.1.2
	 */
	public function mysqlDisconnectHandler(&$db)
	{
		$db->setDebug(false);

		$this->totalQueries = $db->getCount();

		$dbVersion5037 = $db->getServerType() === 'mysql' && version_compare($db->getVersion(), '5.0.37', '>=');

		if ($dbVersion5037)
		{
			try
			{
				// Check if profiling is enabled.
				$db->setQuery("SHOW VARIABLES LIKE 'have_profiling'");
				$hasProfiling = $db->loadResult();

				if ($hasProfiling)
				{
					// Run a SHOW PROFILE query.
					$db->setQuery('SHOW PROFILES');
					$this->sqlShowProfiles = $db->loadAssocList();

					if ($this->sqlShowProfiles)
					{
						foreach ($this->sqlShowProfiles as $qn)
						{
							// Run SHOW PROFILE FOR QUERY for each query where a profile is available (max 100).
							$db->setQuery('SHOW PROFILE FOR QUERY ' . (int) $qn['Query_ID']);
							$this->sqlShowProfileEach[(int) ($qn['Query_ID'] - 1)] = $db->loadAssocList();
						}
					}
				}
				else
				{
					$this->sqlShowProfileEach[0] = array(array('Error' => 'MySql have_profiling = off'));
				}
			}
			catch (Exception $e)
			{
				$this->sqlShowProfileEach[0] = array(array('Error' => $e->getMessage()));
			}
		}

		if (in_array($db->getServerType(), array('mysql', 'postgresql'), true))
		{
			$log = $db->getLog();

			foreach ($log as $k => $query)
			{
				$dbVersion56 = $db->getServerType() === 'mysql' && version_compare($db->getVersion(), '5.6', '>=');
				$dbVersion80 = $db->getServerType() === 'mysql' && version_compare($db->getVersion(), '8.0', '>=');

				if ($dbVersion80)
				{
					$dbVersion56 = false;
				}

				if ((stripos($query, 'select') === 0) || ($dbVersion56 && ((stripos($query, 'delete') === 0) || (stripos($query, 'update') === 0))))
				{
					try
					{
						$db->setQuery('EXPLAIN ' . ($dbVersion56 ? 'EXTENDED ' : '') . $query);
						$this->explains[$k] = $db->loadAssocList();
					}
					catch (Exception $e)
					{
						$this->explains[$k] = array(array('Error' => $e->getMessage()));
					}
				}
			}
		}
	}

	/**
	 * Displays errors in language files.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayLanguageFilesInError()
	{
		$errorfiles = JFactory::getLanguage()->getErrorFiles();

		if (!count($errorfiles))
		{
			return '<p>' . JText::_('JNONE') . '</p>';
		}

		$html = array();

		$html[] = '<ul>';

		foreach ($errorfiles as $file => $error)
		{
			$html[] = '<li>' . $this->formatLink($file) . str_replace($file, '', $error) . '</li>';
		}

		$html[] = '</ul>';

		return implode('', $html);
	}

	/**
	 * Display loaded language files.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayLanguageFilesLoaded()
	{
		$html = array();

		$html[] = '<ul>';

		foreach (JFactory::getLanguage()->getPaths() as /* $extension => */ $files)
		{
			foreach ($files as $file => $status)
			{
				$html[] = '<li>';

				$html[] = $status
					? JText::_('PLG_DEBUG_LANG_LOADED')
					: JText::_('PLG_DEBUG_LANG_NOT_LOADED');

				$html[] = ' : ';
				$html[] = $this->formatLink($file);
				$html[] = '</li>';
			}
		}

		$html[] = '</ul>';

		return implode('', $html);
	}

	/**
	 * Display untranslated language strings.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayUntranslatedStrings()
	{
		$stripFirst = $this->params->get('strip-first', 1);
		$stripPref  = $this->params->get('strip-prefix');
		$stripSuff  = $this->params->get('strip-suffix');

		$orphans = JFactory::getLanguage()->getOrphans();

		if (!count($orphans))
		{
			return '<p>' . JText::_('JNONE') . '</p>';
		}

		ksort($orphans, SORT_STRING);

		$guesses = array();

		foreach ($orphans as $key => $occurance)
		{
			if (is_array($occurance) && isset($occurance[0]))
			{
				$info = $occurance[0];
				$file = $info['file'] ?: '';

				if (!isset($guesses[$file]))
				{
					$guesses[$file] = array();
				}

				// Prepare the key.
				if (($pos = strpos($info['string'], '=')) > 0)
				{
					$parts = explode('=', $info['string']);
					$key   = $parts[0];
					$guess = $parts[1];
				}
				else
				{
					$guess = str_replace('_', ' ', $info['string']);

					if ($stripFirst)
					{
						$parts = explode(' ', $guess);

						if (count($parts) > 1)
						{
							array_shift($parts);
							$guess = implode(' ', $parts);
						}
					}

					$guess = trim($guess);

					if ($stripPref)
					{
						$guess = trim(preg_replace(chr(1) . '^' . $stripPref . chr(1) . 'i', '', $guess));
					}

					if ($stripSuff)
					{
						$guess = trim(preg_replace(chr(1) . $stripSuff . '$' . chr(1) . 'i', '', $guess));
					}
				}

				$key = strtoupper(trim($key));
				$key = preg_replace('#\s+#', '_', $key);
				$key = preg_replace('#\W#', '', $key);

				// Prepare the text.
				$guesses[$file][] = $key . '="' . $guess . '"';
			}
		}

		$html = array();

		foreach ($guesses as $file => $keys)
		{
			$html[] = "\n\n# " . ($file ? $this->formatLink($file) : JText::_('PLG_DEBUG_UNKNOWN_FILE')) . "\n\n";
			$html[] = implode("\n", $keys);
		}

		return '<pre>' . implode('', $html) . '</pre>';
	}

	/**
	 * Simple highlight for SQL queries.
	 *
	 * @param   string  $query  The query to highlight.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function highlightQuery($query)
	{
		$newlineKeywords = '#\b(FROM|LEFT|INNER|OUTER|WHERE|SET|VALUES|ORDER|GROUP|HAVING|LIMIT|ON|AND|CASE)\b#i';

		$query = htmlspecialchars($query, ENT_QUOTES);

		$query = preg_replace($newlineKeywords, '<br />&#160;&#160;\\0', $query);

		$regex = array(

			// Tables are identified by the prefix.
			'/(=)/'                                        => '<b class="dbg-operator">$1</b>',

			// All uppercase words have a special meaning.
			'/(?<!\w|>)([A-Z_]{2,})(?!\w)/x'               => '<span class="dbg-command">$1</span>',

			// Tables are identified by the prefix.
			'/(' . $this->db->getPrefix() . '[a-z_0-9]+)/' => '<span class="dbg-table">$1</span>',

		);

		$query = preg_replace(array_keys($regex), array_values($regex), $query);

		$query = str_replace('*', '<b style="color: red;">*</b>', $query);

		return $query;
	}

	/**
	 * Render the backtrace.
	 *
	 * Stolen from JError to prevent it's removal.
	 *
	 * @param   Exception  $error  The Exception object to be rendered.
	 *
	 * @return  string     Rendered backtrace.
	 *
	 * @since   2.5
	 */
	protected function renderBacktrace($error)
	{
		return JLayoutHelper::render('joomla.error.backtrace', array('backtrace' => $error->getTrace()));
	}

	/**
	 * Replaces the Joomla! root with "JROOT" to improve readability.
	 * Formats a link with a special value xdebug.file_link_format
	 * from the php.ini file.
	 *
	 * @param   string  $file  The full path to the file.
	 * @param   string  $line  The line number.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function formatLink($file, $line = '')
	{
		return JHtml::_('debug.xdebuglink', $file, $line);
	}

	/**
	 * Store log messages so they can be displayed later.
	 * This function is passed log entries by JLogLoggerCallback.
	 *
	 * @param   JLogEntry  $entry  A log entry.
	 *
	 * @return  void
	 *
	 * @since   3.1
	 */
	public function logger(JLogEntry $entry)
	{
		$this->logEntries[] = $entry;
	}

	/**
	 * Display log messages.
	 *
	 * @return  string
	 *
	 * @since   3.1
	 */
	protected function displayLogs()
	{
		$priorities = array(
			JLog::EMERGENCY => '<span class="badge badge-important">EMERGENCY</span>',
			JLog::ALERT     => '<span class="badge badge-important">ALERT</span>',
			JLog::CRITICAL  => '<span class="badge badge-important">CRITICAL</span>',
			JLog::ERROR     => '<span class="badge badge-important">ERROR</span>',
			JLog::WARNING   => '<span class="badge badge-warning">WARNING</span>',
			JLog::NOTICE    => '<span class="badge badge-info">NOTICE</span>',
			JLog::INFO      => '<span class="badge badge-info">INFO</span>',
			JLog::DEBUG     => '<span class="badge">DEBUG</span>',
		);

		$out = '';

		$logEntriesTotal = count($this->logEntries);

		// SQL log entries
		$showExecutedSQL = $this->params->get('log-executed-sql', 0);

		if (!$showExecutedSQL)
		{
			$logEntriesDatabasequery = count(
				array_filter(
					$this->logEntries, function ($logEntry)
					{
						return $logEntry->category === 'databasequery';
					}
				)
			);
			$logEntriesTotal         -= $logEntriesDatabasequery;
		}

		// Deprecated log entries
		$logEntriesDeprecated = count(
			array_filter(
				$this->logEntries, function ($logEntry)
				{
					return $logEntry->category === 'deprecated';
				}
			)
		);
		$showDeprecated       = $this->params->get('log-deprecated', 0);

		if (!$showDeprecated)
		{
			$logEntriesTotal -= $logEntriesDeprecated;
		}

		$showEverything = $this->params->get('log-everything', 0);

		$out .= '<h4>' . JText::sprintf('PLG_DEBUG_LOGS_LOGGED', $logEntriesTotal) . '</h4><br />';

		if ($showDeprecated && $logEntriesDeprecated > 0)
		{
			$out .= '
			<div class="alert alert-warning">
				<h4>' . JText::sprintf('PLG_DEBUG_LOGS_DEPRECATED_FOUND_TITLE', $logEntriesDeprecated) . '</h4>
				<div>' . JText::_('PLG_DEBUG_LOGS_DEPRECATED_FOUND_TEXT') . '</div>
			</div>
			<br />';
		}

		$out   .= '<ol>';
		$count = 1;

		foreach ($this->logEntries as $entry)
		{
			// Don't show database queries if not selected.
			if (!$showExecutedSQL && $entry->category === 'databasequery')
			{
				continue;
			}

			// Don't show deprecated logs if not selected.
			if (!$showDeprecated && $entry->category === 'deprecated')
			{
				continue;
			}

			// Don't show everything logs if not selected.
			if (!$showEverything && !in_array($entry->category, array('deprecated', 'databasequery'), true))
			{
				continue;
			}

			$out .= '<li id="dbg_logs_' . $count . '">';
			$out .= '<h5>' . $priorities[$entry->priority] . ' ' . $entry->category . '</h5><br />
				<pre>' . $entry->message . '</pre>';

			if ($entry->callStack)
			{
				$out .= JHtml::_('bootstrap.startAccordion', 'dbg_logs_' . $count, array('active' => ''));
				$out .= JHtml::_('bootstrap.addSlide', 'dbg_logs_' . $count, JText::_('PLG_DEBUG_CALL_STACK'), 'dbg_logs_backtrace_' . $count);
				$out .= $this->renderCallStack($entry->callStack);
				$out .= JHtml::_('bootstrap.endSlide');
				$out .= JHtml::_('bootstrap.endAccordion');
			}

			$out .= '<hr /></li>';
			$count++;
		}

		$out .= '</ol>';

		return $out;
	}

	/**
	 * Renders call stack and back trace in HTML.
	 *
	 * @param   array  $callStack  The call stack and back trace array.
	 *
	 * @return  string  The call stack and back trace in HMTL format.
	 *
	 * @since   3.5
	 */
	protected function renderCallStack(array $callStack = array())
	{
		$htmlCallStack = '';

		if ($callStack !== null)
		{
			$htmlCallStack .= '<div>';
			$htmlCallStack .= '<table class="table table-striped dbg-query-table">';
			$htmlCallStack .= '<thead>';
			$htmlCallStack .= '<tr>';
			$htmlCallStack .= '<th>#</th>';
			$htmlCallStack .= '<th>' . JText::_('PLG_DEBUG_CALL_STACK_CALLER') . '</th>';
			$htmlCallStack .= '<th>' . JText::_('PLG_DEBUG_CALL_STACK_FILE_AND_LINE') . '</th>';
			$htmlCallStack .= '</tr>';
			$htmlCallStack .= '</thead>';
			$htmlCallStack .= '<tbody>';

			$count = count($callStack);

			foreach ($callStack as $call)
			{
				// Dont' back trace log classes.
				if (isset($call['class']) && strpos($call['class'], 'JLog') !== false)
				{
					$count--;
					continue;
				}

				$htmlCallStack .= '<tr>';

				$htmlCallStack .= '<td>' . $count . '</td>';

				$htmlCallStack .= '<td>';

				if (isset($call['class']))
				{
					// If entry has Class/Method print it.
					$htmlCallStack .= htmlspecialchars($call['class'] . $call['type'] . $call['function']) . '()';
				}
				else
				{
					if (isset($call['args']))
					{
						// If entry has args is a require/include.
						$htmlCallStack .= htmlspecialchars($call['function']) . ' ' . $this->formatLink($call['args'][0]);
					}
					else
					{
						// It's a function.
						$htmlCallStack .= htmlspecialchars($call['function']) . '()';
					}
				}

				$htmlCallStack .= '</td>';

				$htmlCallStack .= '<td>';

				// If entry doesn't have line and number the next is a call_user_func.
				if (!isset($call['file']) && !isset($call['line']))
				{
					$htmlCallStack .= JText::_('PLG_DEBUG_CALL_STACK_SAME_FILE');
				}
				// If entry has file and line print it.
				else
				{
					$htmlCallStack .= $this->formatLink(htmlspecialchars($call['file']), htmlspecialchars($call['line']));
				}

				$htmlCallStack .= '</td>';

				$htmlCallStack .= '</tr>';
				$count--;
			}

			$htmlCallStack .= '</tbody>';
			$htmlCallStack .= '</table>';
			$htmlCallStack .= '</div>';

			if (!$this->linkFormat)
			{
				$htmlCallStack .= '<div>[<a href="https://xdebug.org/docs/all_settings#file_link_format" target="_blank" rel="noopener noreferrer">';
				$htmlCallStack .= JText::_('PLG_DEBUG_LINK_FORMAT') . '</a>]</div>';
			}
		}

		return $htmlCallStack;
	}

	/**
	 * Pretty print JSON with colors.
	 *
	 * @param   string  $json  The json raw string.
	 *
	 * @return  string  The json string pretty printed.
	 *
	 * @since   3.5
	 */
	protected function prettyPrintJSON($json = '')
	{
		// In PHP 5.4.0 or later we have pretty print option.
		if (version_compare(PHP_VERSION, '5.4', '>='))
		{
			$json = json_encode($json, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
		}

		// Escape HTML in session vars
		$json = htmlentities($json);

		// Add some colors
		$json = preg_replace('#"([^"]+)":#', '<span class=\'black\'>"</span><span class=\'green\'>$1</span><span class=\'black\'>"</span>:', $json);
		$json = preg_replace('#"(|[^"]+)"(\n|\r\n|,)#', '<span class=\'grey\'>"$1"</span>$2', $json);
		$json = str_replace('null,', '<span class=\'blue\'>null</span>,', $json);

		return $json;
	}

	/**
	 * Write query to the log file
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	protected function writeToFile()
	{
		$app    = JFactory::getApplication();
		$domain = $app->isClient('site') ? 'site' : 'admin';
		$input  = $app->input;
		$file   = $app->get('log_path') . '/' . $domain . '_' . $input->get('option') . $input->get('view') . $input->get('layout') . '.sql.php';

		// Get the queries from log.
		$current = '';
		$db      = $this->db;
		$log     = $db->getLog();
		$timings = $db->getTimings();

		foreach ($log as $id => $query)
		{
			if (isset($timings[$id * 2 + 1]))
			{
				$temp    = str_replace('`', '', $log[$id]);
				$temp    = str_replace(array("\t", "\n", "\r\n"), ' ', $temp);
				$current .= $temp . ";\n";
			}
		}

		if (JFile::exists($file))
		{
			JFile::delete($file);
		}

		$head   = array('#');
		$head[] = '#<?php die(\'Forbidden.\'); ?>';
		$head[] = '#Date: ' . gmdate('Y-m-d H:i:s') . ' UTC';
		$head[] = '#Software: ' . \JPlatform::getLongVersion();
		$head[] = "\n";

		// Write new file.
		JFile::write($file, implode("\n", $head) . $current);
	}
}
PK��#]��W8�2�2system/fields/fields.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.Fields
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Form\Form;
use Joomla\Registry\Registry;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Multilanguage;

JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');

/**
 * Fields Plugin
 *
 * @since  3.7
 */
class PlgSystemFields extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Normalizes the request data.
	 *
	 * @param   string  $context  The context
	 * @param   object  $data     The object
	 * @param   Form    $form     The form
	 *
	 * @return  void
	 *
	 * @since   3.8.7
	 */
	public function onContentNormaliseRequestData($context, $data, Form $form)
	{
		if (!FieldsHelper::extract($context, $data))
		{
			return true;
		}

		// Loop over all fields
		foreach ($form->getGroup('com_fields') as $field)
		{
			if ($field->disabled === true)
			{
				/**
				 * Disabled fields should NEVER be added to the request as
				 * they should NEVER be added by the browser anyway so nothing to check against
				 * as "disabled" means no interaction at all.
				 */

				// Make sure the data object has an entry before delete it
				if (isset($data->com_fields[$field->fieldname]))
				{
					unset($data->com_fields[$field->fieldname]);
				}

				continue;
			}

			// Make sure the data object has an entry
			if (isset($data->com_fields[$field->fieldname]))
			{
				continue;
			}

			// Set a default value for the field
			$data->com_fields[$field->fieldname] = false;
		}
	}

	/**
	 * The save event.
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $item     The table
	 * @param   boolean  $isNew    Is new item
	 * @param   array    $data     The validated data
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterSave($context, $item, $isNew, $data = array())
	{
		// Check if data is an array and the item has an id
		if (!is_array($data) || empty($item->id) || empty($data['com_fields']))
		{
			return true;
		}

		// Create correct context for category
		if ($context == 'com_categories.category')
		{
			$context = $item->extension . '.categories';

			// Set the catid on the category to get only the fields which belong to this category
			$item->catid = $item->id;
		}

		// Check the context
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return true;
		}

		// Compile the right context for the fields
		$context = $parts[0] . '.' . $parts[1];

		// Loading the fields
		$fields = FieldsHelper::getFields($context, $item);

		if (!$fields)
		{
			return true;
		}

		// Loading the model
		$model = JModelLegacy::getInstance('Field', 'FieldsModel', array('ignore_request' => true));

		// Loop over the fields
		foreach ($fields as $field)
		{
			// Determine the value if it is (un)available from the data
			if (key_exists($field->name, $data['com_fields']))
			{
				$value = $data['com_fields'][$field->name] === false ? null : $data['com_fields'][$field->name];
			}
			// Field not available on form, use stored value
			else
			{
				$value = $field->rawvalue;
			}

			// If no value set (empty) remove value from database
			if (is_array($value) ? !count($value) : !strlen($value))
			{
				$value = null;
			}

			// JSON encode value for complex fields
			if (is_array($value) && (count($value, COUNT_NORMAL) !== count($value, COUNT_RECURSIVE) || !count(array_filter(array_keys($value), 'is_numeric'))))
			{
				$value = json_encode($value);
			}

			// Setting the value for the field and the item
			$model->setFieldValue($field->id, $item->id, $value);
		}

		return true;
	}

	/**
	 * The save event.
	 *
	 * @param   array    $userData  The date
	 * @param   boolean  $isNew     Is new
	 * @param   boolean  $success   Is success
	 * @param   string   $msg       The message
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onUserAfterSave($userData, $isNew, $success, $msg)
	{
		// It is not possible to manipulate the user during save events
		// Check if data is valid or we are in a recursion
		if (!$userData['id'] || !$success)
		{
			return true;
		}

		$user = JFactory::getUser($userData['id']);

		$task = JFactory::getApplication()->input->getCmd('task');

		// Skip fields save when we activate a user, because we will lose the saved data
		if (in_array($task, array('activate', 'block', 'unblock')))
		{
			return true;
		}

		// Trigger the events with a real user
		$this->onContentAfterSave('com_users.user', $user, false, $userData);

		return true;
	}

	/**
	 * The delete event.
	 *
	 * @param   string    $context  The context
	 * @param   stdClass  $item     The item
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterDelete($context, $item)
	{
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts || empty($item->id))
		{
			return true;
		}

		$context = $parts[0] . '.' . $parts[1];

		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_fields/models', 'FieldsModel');

		$model = JModelLegacy::getInstance('Field', 'FieldsModel', array('ignore_request' => true));
		$model->cleanupValues($context, $item->id);

		return true;
	}

	/**
	 * The user delete event.
	 *
	 * @param   stdClass  $user    The context
	 * @param   boolean   $succes  Is success
	 * @param   string    $msg     The message
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onUserAfterDelete($user, $succes, $msg)
	{
		$item     = new stdClass;
		$item->id = $user['id'];

		return $this->onContentAfterDelete('com_users.user', $item);
	}

	/**
	 * The form event.
	 *
	 * @param   JForm     $form  The form
	 * @param   stdClass  $data  The data
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentPrepareForm(JForm $form, $data)
	{
		$context = $form->getName();

		// When a category is edited, the context is com_categories.categorycom_content
		if (strpos($context, 'com_categories.category') === 0)
		{
			$context = str_replace('com_categories.category', '', $context) . '.categories';

			// Set the catid on the category to get only the fields which belong to this category
			if (is_array($data) && key_exists('id', $data))
			{
				$data['catid'] = $data['id'];
			}

			if (is_object($data) && isset($data->id))
			{
				$data->catid = $data->id;
			}
		}

		$parts = FieldsHelper::extract($context, $form);

		if (!$parts)
		{
			return true;
		}

		$input = JFactory::getApplication()->input;

		// If we are on the save command we need the actual data
		$jformData = $input->get('jform', array(), 'array');

		if ($jformData && !$data)
		{
			$data = $jformData;
		}

		if (is_array($data))
		{
			$data = (object) $data;
		}

		FieldsHelper::prepareForm($parts[0] . '.' . $parts[1], $form, $data);

		return true;
	}

	/**
	 * The display event.
	 *
	 * @param   string    $context     The context
	 * @param   stdClass  $item        The item
	 * @param   Registry  $params      The params
	 * @param   integer   $limitstart  The start
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterTitle($context, $item, $params, $limitstart = 0)
	{
		return $this->display($context, $item, $params, 1);
	}

	/**
	 * The display event.
	 *
	 * @param   string    $context     The context
	 * @param   stdClass  $item        The item
	 * @param   Registry  $params      The params
	 * @param   integer   $limitstart  The start
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	public function onContentBeforeDisplay($context, $item, $params, $limitstart = 0)
	{
		return $this->display($context, $item, $params, 2);
	}

	/**
	 * The display event.
	 *
	 * @param   string    $context     The context
	 * @param   stdClass  $item        The item
	 * @param   Registry  $params      The params
	 * @param   integer   $limitstart  The start
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterDisplay($context, $item, $params, $limitstart = 0)
	{
		return $this->display($context, $item, $params, 3);
	}

	/**
	 * Performs the display event.
	 *
	 * @param   string    $context      The context
	 * @param   stdClass  $item         The item
	 * @param   Registry  $params       The params
	 * @param   integer   $displayType  The type
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	private function display($context, $item, $params, $displayType)
	{
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return '';
		}

		// If we have a category, set the catid field to fetch only the fields which belong to it
		if ($parts[1] == 'categories' && !isset($item->catid))
		{
			$item->catid = $item->id;
		}

		$context = $parts[0] . '.' . $parts[1];

		// Convert tags
		if ($context == 'com_tags.tag' && !empty($item->type_alias))
		{
			// Set the context
			$context = $item->type_alias;

			$item = $this->prepareTagItem($item);
		}

		if (is_string($params) || !$params)
		{
			$params = new Registry($params);
		}

		$fields = FieldsHelper::getFields($context, $item, $displayType);

		if ($fields)
		{
			$app = Factory::getApplication();

			if ($app->isClient('site') && Multilanguage::isEnabled() && isset($item->language) && $item->language == '*')
			{
				$lang = $app->getLanguage()->getTag();

				foreach ($fields as $key => $field)
				{
					if ($field->language == '*' || $field->language == $lang)
					{
						continue;
					}

					unset($fields[$key]);
				}
			}
		}

		if ($fields)
		{
			foreach ($fields as $key => $field)
			{
				$fieldDisplayType = $field->params->get('display', '2');

				if ($fieldDisplayType == $displayType)
				{
					continue;
				}

				unset($fields[$key]);
			}
		}

		if ($fields)
		{
			return FieldsHelper::render(
				$context,
				'fields.render',
				array(
					'item'            => $item,
					'context'         => $context,
					'fields'          => $fields
				)
			);
		}

		return '';
	}

	/**
	 * Performs the display event.
	 *
	 * @param   string    $context  The context
	 * @param   stdClass  $item     The item
	 *
	 * @return  void
	 *
	 * @since   3.7.0
	 */
	public function onContentPrepare($context, $item)
	{
		// Check property exists (avoid costly & useless recreation), if need to recreate them, just unset the property!
		if (isset($item->jcfields))
		{
			return;
		}

		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return;
		}

		$context = $parts[0] . '.' . $parts[1];

		// Convert tags
		if ($context == 'com_tags.tag' && !empty($item->type_alias))
		{
			// Set the context
			$context = $item->type_alias;

			$item = $this->prepareTagItem($item);
		}

		// Get item's fields, also preparing their value property for manual display
		// (calling plugins events and loading layouts to get their HTML display)
		$fields = FieldsHelper::getFields($context, $item, true);

		// Adding the fields to the object
		$item->jcfields = array();

		foreach ($fields as $key => $field)
		{
			$item->jcfields[$field->id] = $field;
		}
	}

	/**
	 * The finder event.
	 *
	 * @param   stdClass  $item  The item
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onPrepareFinderContent($item)
	{
		$section = strtolower($item->layout);
		$tax     = $item->getTaxonomy('Type');

		if ($tax)
		{
			foreach ($tax as $context => $value)
			{
				// This is only a guess, needs to be improved
				$component = strtolower($context);

				if (strpos($context, 'com_') !== 0)
				{
					$component = 'com_' . $component;
				}

				// Transform com_article to com_content
				if ($component === 'com_article')
				{
					$component = 'com_content';
				}

				// Create a dummy object with the required fields
				$tmp     = new stdClass;
				$tmp->id = $item->__get('id');

				if ($item->__get('catid'))
				{
					$tmp->catid = $item->__get('catid');
				}

				// Getting the fields for the constructed context
				$fields = FieldsHelper::getFields($component . '.' . $section, $tmp, true);

				if (is_array($fields))
				{
					foreach ($fields as $field)
					{
						// Adding the instructions how to handle the text
						$item->addInstruction(FinderIndexer::TEXT_CONTEXT, $field->name);

						// Adding the field value as a field
						$item->{$field->name} = $field->value;
					}
				}
			}
		}

		return true;
	}

	/**
	 * Prepares a tag item to be ready for com_fields.
	 *
	 * @param   stdClass  $item  The item
	 *
	 * @return  object
	 *
	 * @since   3.8.4
	 */
	private function prepareTagItem($item)
	{
		// Map core fields
		$item->id       = $item->content_item_id;
		$item->language = $item->core_language;

		// Also handle the catid
		if (!empty($item->core_catid))
		{
			$item->catid = $item->core_catid;
		}

		return $item;
	}
}
PK��#]W���system/fields/fields.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="system" method="upgrade">
	<name>plg_system_fields</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_SYSTEM_FIELDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="fields">fields.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_fields.ini</language>
		<language tag="en-GB">en-GB.plg_system_fields.sys.ini</language>
	</languages>
</extension>
PK��#]�)��system/fields/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��system/akversioncheck/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��Kf�� system/akversioncheck/script.phpnu�[���<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

use FOF40\InstallScript\Plugin;

defined('_JEXEC') || die;

// Load FOF if not already loaded
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
	throw new RuntimeException('This extension requires FOF 4.');
}

class plgSystemAkversioncheckInstallerScript extends Plugin
{
}
PK��#]@�؍FF(system/akversioncheck/akversioncheck.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<extension version="3.8.0" type="plugin" group="system" method="upgrade">
	<name>PLG_SYSTEM_AKVERSIONCHECK</name>
	<author>Nicholas K. Dionysopoulos</author>
	<authorEmail>nicholas@dionysopoulos.me</authorEmail>
	<authorUrl>https://www.akeeba.com</authorUrl>
	<copyright>Copyright (c)2006-2023 Nicholas K. Dionysopoulos</copyright>
	<license>GNU General Public License version 3, or later</license>
	<creationDate>2023-05-26</creationDate>
	<version>8.3.1</version>
	<description>PLG_SYSTEM_AKVERSIONCHECK_XML_DESCRIPTION</description>
	<files>
		<filename plugin="akversioncheck">akversioncheck.php</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_system_akversioncheck.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_system_akversioncheck.sys.ini</language>
	</languages>

	<scriptfile>script.php</scriptfile>
</extension>
PK��#]�Q�^p^p(system/akversioncheck/akversioncheck.phpnu�[���<?php
/**
 * @package   akversioncheck
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\Application\AdministratorApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Response\JsonResponse;

/**
 * Version Check — Stops Joomla Update lying about whether our software supports Joomla 4.
 *
 * For the record, we were the FIRST third party extensions developer to support Joomla 4 since it was still in Alpha 2
 * back in November 2017 — three and a half years before 4.0 stable was released. We have the easiest upgrade path of
 * any other third party extensions developer: upgrade your site to Joomla 4, install the updates your site finds, done.
 *
 * I had notified the core maitnainers that Joomla Update's idiotic pre-update check was based on a false premise, can
 * not work beyond the simplest use case (“latest version supports the current Joomla 3 and the next Joomla 4 version,
 * whichever these are”), and would simply end up as an automated slander against third party developers (it has caused
 * our sales to drop because people believe Joomla's lies about our PERFECTLY WORKING AND COMPATIBLE software being
 * ‘incompatible’ with Joomla 4).
 *
 * I notified them four times in the year before Joomla 4 was released. They were too stubborn to even put the minimal
 * effort any living creature with more than one working braincell would need to understand the magnitude and importance
 * of the problem.
 *
 * So here we are. I am met with a problem the Joomla project refuses to fix. You know what? It's not my first rodeo.
 *
 * I know how Joomla works. I know **very well** how Joomla's plugin system works. Darn it, I actually wrote the one
 * in Joomla 4, plus the migration and b/c code for concrete events which will be more prominent in Joomla 5. I will use
 * my deep knowledge of Joomla, its plugin system, and my experience to create this plugin which does three things:
 *
 * 1. Adds a notice on the update page about the CORRECT upgrade procedure should it detect you have some incredibly
 *    old, absolutely obsolete extensions of ours.
 *
 * 2. Report the latest available Joomla 3 versions of our extensions as compatible with Joomla 4 (because we constantly
 *    test them with it to make sure nothing breaks on upgrade, thank you very much!).
 *
 * 3. Remove the ugly, misleading, SLANDEROUS notices that our extensions will break your site just because they have
 *    some plugins which are not marked as core Joomla.
 *
 * It does so with elegance and a certain aplomb, if I may say so myself.
 *
 * @since 1.0.0
 */
class plgSystemAkversioncheck extends CMSPlugin
{
	/**
	 * Obsolete extensions.
	 *
	 * If any of these extensions is still installed you will see the message that you need to run MagicEraser.
	 *
	 * @since 1.0.0
	 */
	private const OBSOLETE_EXTENSIONS = [
		// Obsolete extensions
		'com_cmsupdate',
		'plg_system_akgeoip',
		'pkg_yubikey',
		'pkg_yubikey_plugins',
		'plg_system_oneclickaction',
		'pkg_compliance',

		// Libraries and frameworks
		'lib_f0f#prefix',
		'lib_fof30',
		'file_fof30',
		'file_akeebastrapper',
		'file_strapper',
		'files_strapper',
		'file_strapper30',

		// Obsolete extensions formerly bundled with Akeeba Backup
		'amod_akadmin',
		'plg_jmonitoring_akeebabackup',
		'plg_system_akeebaupdatecheck',
		'plg_system_aklazy',
		'plg_system_srp',

		// Obsolete extensions formerly bundled with Admin Tools
		'amod_atjupgrade',
		'plg_quickicon_atoolsjupdatecheck',
		'plg_system_atoolsjupdatecheck',
		'plg_system_atoolsupdatecheck',
		'plg_system_admintoolsactionlog',

		// Obsolete extensions formerly bundled with Akeeba Ticket System
		'plg_ats_alphauserpoints',
		'plg_ats_akeebasubs',
		'plg_ats_akeebasubslegacy',

		// Obsolete extensions formerly bundled with DocImport
		'plg_sh404sefextplugins_com_docimport',
		'mod_docimport_search',

		// Obsolete extensions formerly bundled with Akeeba Release System
		'plg_ars_bleedingedgediff',
		'plg_ars_bleedingedgematurity',
		'plg_ars_tainting',
		'plg_sh404sefextplugins_com_ars',
		'file_ars',
		'files_ars',
		'mod_arsdlid',
		'plg_system_arsjed',

		// Obsolete extensions formerly bundled with Akeeba Subscriptions
		'amod_akeebasubs',
		'mod_aktaxcountry',
		'plg_akeebasubs_aceshop',
		'plg_akeebasubs_acymailing',
		'plg_akeebasubs_adminemails',
		'plg_akeebasubs_affemails',
		'plg_akeebasubs_ageverification',
		'plg_akeebasubs_agora',
		'plg_akeebasubs_agreetoeu',
		'plg_akeebasubs_agreetotos',
		'plg_akeebasubs_atscreditslegacy',
		'plg_akeebasubs_autocity',
		'plg_akeebasubs_canalyticscommerce',
		'plg_akeebasubs_cb',
		'plg_akeebasubs_cbsync',
		'plg_akeebasubs_ccinvoices',
		'plg_akeebasubs_communityacl',
		'plg_akeebasubs_constantcontact',
		'plg_akeebasubs_customfields',
		'plg_akeebasubs_docman',
		'plg_akeebasubs_easydiscuss',
		'plg_akeebasubs_freshbooks',
		'plg_akeebasubs_frontenduseraccess',
		'plg_akeebasubs_gacommerce',
		'plg_akeebasubs_invoices',
		'plg_akeebasubs_iplogger',
		'plg_akeebasubs_iproperty',
		'plg_akeebasubs_jce',
		'plg_akeebasubs_jomsocial',
		'plg_akeebasubs_joomlaprofilesync',
		'plg_akeebasubs_juga',
		'plg_akeebasubs_jxjomsocial',
		'plg_akeebasubs_k2',
		'plg_akeebasubs_kunena',
		'plg_akeebasubs_mailchimp',
		'plg_akeebasubs_mijoshop',
		'plg_akeebasubs_needslogout',
		'plg_akeebasubs_ninjaboard',
		'plg_akeebasubs_phocadownload',
		'plg_akeebasubs_projectfork',
		'plg_akeebasubs_projectfork4',
		'plg_akeebasubs_recaptcha',
		'plg_akeebasubs_redshop',
		'plg_akeebasubs_redshopusersync',
		'plg_akeebasubs_reseller',
		'plg_akeebasubs_samplefields',
		'plg_akeebasubs_slavesubs',
		'plg_akeebasubs_sql',
		'plg_akeebasubs_subscriptionemailsdebug',
		'plg_akeebasubs_tienda',
		'plg_akeebasubs_tracktime',
		'plg_akeebasubs_userdelete',
		'plg_akeebasubs_vm',
		'plg_akeebasubs_vm2',
		'plg_akeebasubs_zohoinvoice',
		'plg_akpayment_2checkout',
		'plg_akpayment_2conew',
		'plg_akpayment_allopass',
		'plg_akpayment_alphauserpoints',
		'plg_akpayment_authorizenet',
		'plg_akpayment_be2bill',
		'plg_akpayment_beanstream',
		'plg_akpayment_braintree',
		'plg_akpayment_cardstream',
		'plg_akpayment_cashu',
		'plg_akpayment_ccavenue',
		'plg_akpayment_clickandbuy',
		'plg_akpayment_cmcic',
		'plg_akpayment_deltapay',
		'plg_akpayment_dwolla',
		'plg_akpayment_epaydk',
		'plg_akpayment_eselectplus',
		'plg_akpayment_eway',
		'plg_akpayment_ewayrapid3',
		'plg_akpayment_exact',
		'plg_akpayment_gocardless',
		'plg_akpayment_googlecheckout',
		'plg_akpayment_ifthen',
		'plg_akpayment_mercadopago',
		'plg_akpayment_mobilpaycc',
		'plg_akpayment_mobilpaysms',
		'plg_akpayment_moip',
		'plg_akpayment_moipassinaturas',
		'plg_akpayment_moneris',
		'plg_akpayment_nochex',
		'plg_akpayment_none',
		'plg_akpayment_offline',
		'plg_akpayment_pagseguro',
		'plg_akpayment_payfast',
		'plg_akpayment_paymill',
		'plg_akpayment_paymilldss3',
		'plg_akpayment_paypal',
		'plg_akpayment_paypalpaymentspro',
		'plg_akpayment_paypalproexpress',
		'plg_akpayment_paypoint',
		'plg_akpayment_paysafe',
		'plg_akpayment_payu',
		'plg_akpayment_postfinancech',
		'plg_akpayment_przelewy24',
		'plg_akpayment_rbkmoney',
		'plg_akpayment_realex',
		'plg_akpayment_robokassa',
		'plg_akpayment_saferpay',
		'plg_akpayment_sagepay',
		'plg_akpayment_scnet',
		'plg_akpayment_scnetintegrated',
		'plg_akpayment_skrill',
		'plg_akpayment_stripe',
		'plg_akpayment_suomenverkkomaksut',
		'plg_akpayment_upay',
		'plg_akpayment_verotel',
		'plg_akpayment_viva',
		'plg_akpayment_wepay',
		'plg_akpayment_worldpay',
		'plg_akpayment_zarinpal',
		'plg_ccinvoicetags_akeebasubs',
		'plg_sh404sefextplugins_com_akeebasubs',
		'plg_system_as2cocollation',
		'plg_system_affiliatesessiongeneration',
		'plg_system_aslogoutuser',
		'plg_system_aspaypalcollation',
		'plg_system_idevaffiliate',
		'plg_system_postaffiliatepro',
		'plg_user_aslogoutuser',
		'plg_user_asresetform',

		// Obsolete extensions formerly bundled with Akeeba YubiKey Authentication Plugins
		'plg_user_yubikey',
		'plg_authentication_yubikey',
		'plg_twofactorauth_yubikeytotp',
		'plg_twofactorauth_yubikeyplus',
		'plg_twofactorauth_u2f',

		// Obsolete extensions formerly bundled with Akeeba CMS Update
		'plg_system_cmsupdateemail',
		'plg_quickicon_cmsupdate',
	];

	/**
	 * Allowed extensions.
	 *
	 * These extensions will be marked as compatible with Joomla 4 even though they technically have no release for
	 * Joomla 4, or cannot be installed on Joomla 4.1 and later. These are extensions **KNOWN** to be safe, which can
	 * be removed after the upgrade to Joomla 4.
	 *
	 * @since 1.0.0
	 */
	private const ALLOWED_EXTENSIONS = [
		// ### Libraries and frameworks. They remain inactive in Joomla 4.
		'lib_f0f#prefix',
		'lib_fof',
		'lib_fof30',
		'file_fof30',
		'file_fof40',
		'file_fef',
		'file_akeebastrapper',
		'file_strapper',
		'files_strapper',
		'file_strapper30',

		// Obsolete extensions formerly bundled with Akeeba Backup
		'plg_jmonitoring_akeebabackup',

		// Obsolete extensions formerly bundled with Admin Tools
		'plg_system_admintoolsactionlog',

		// Obsolete extensions formerly bundled with Akeeba Ticket System
		'plg_ats_alphauserpoints',
		'plg_ats_akeebasubs',
		'plg_ats_akeebasubslegacy',

		// Obsolete extensions formerly bundled with DocImport
		'plg_sh404sefextplugins_com_docimport',

		// Obsolete extensions formerly bundled with Akeeba Release System
		'plg_ars_bleedingedgediff',
		'plg_ars_bleedingedgematurity',
		'plg_ars_tainting',
		'plg_sh404sefextplugins_com_ars',
		'file_ars',
		'files_ars',
		'mod_arsdlid',
		'plg_system_arsjed',

		// Obsolete extensions formerly bundled with Akeeba Subscriptions
		'amod_akeebasubs',
		'mod_aktaxcountry',
		'plg_akeebasubs_aceshop',
		'plg_akeebasubs_acymailing',
		'plg_akeebasubs_adminemails',
		'plg_akeebasubs_affemails',
		'plg_akeebasubs_ageverification',
		'plg_akeebasubs_agora',
		'plg_akeebasubs_agreetoeu',
		'plg_akeebasubs_agreetotos',
		'plg_akeebasubs_atscreditslegacy',
		'plg_akeebasubs_autocity',
		'plg_akeebasubs_canalyticscommerce',
		'plg_akeebasubs_cb',
		'plg_akeebasubs_cbsync',
		'plg_akeebasubs_ccinvoices',
		'plg_akeebasubs_communityacl',
		'plg_akeebasubs_constantcontact',
		'plg_akeebasubs_customfields',
		'plg_akeebasubs_docman',
		'plg_akeebasubs_easydiscuss',
		'plg_akeebasubs_freshbooks',
		'plg_akeebasubs_frontenduseraccess',
		'plg_akeebasubs_gacommerce',
		'plg_akeebasubs_invoices',
		'plg_akeebasubs_iplogger',
		'plg_akeebasubs_iproperty',
		'plg_akeebasubs_jce',
		'plg_akeebasubs_jomsocial',
		'plg_akeebasubs_joomlaprofilesync',
		'plg_akeebasubs_juga',
		'plg_akeebasubs_jxjomsocial',
		'plg_akeebasubs_k2',
		'plg_akeebasubs_kunena',
		'plg_akeebasubs_mailchimp',
		'plg_akeebasubs_mijoshop',
		'plg_akeebasubs_needslogout',
		'plg_akeebasubs_ninjaboard',
		'plg_akeebasubs_phocadownload',
		'plg_akeebasubs_projectfork',
		'plg_akeebasubs_projectfork4',
		'plg_akeebasubs_recaptcha',
		'plg_akeebasubs_redshop',
		'plg_akeebasubs_redshopusersync',
		'plg_akeebasubs_reseller',
		'plg_akeebasubs_samplefields',
		'plg_akeebasubs_slavesubs',
		'plg_akeebasubs_sql',
		'plg_akeebasubs_subscriptionemailsdebug',
		'plg_akeebasubs_tienda',
		'plg_akeebasubs_tracktime',
		'plg_akeebasubs_userdelete',
		'plg_akeebasubs_vm',
		'plg_akeebasubs_vm2',
		'plg_akeebasubs_zohoinvoice',
		'plg_akpayment_2checkout',
		'plg_akpayment_2conew',
		'plg_akpayment_allopass',
		'plg_akpayment_alphauserpoints',
		'plg_akpayment_authorizenet',
		'plg_akpayment_be2bill',
		'plg_akpayment_beanstream',
		'plg_akpayment_braintree',
		'plg_akpayment_cardstream',
		'plg_akpayment_cashu',
		'plg_akpayment_ccavenue',
		'plg_akpayment_clickandbuy',
		'plg_akpayment_cmcic',
		'plg_akpayment_deltapay',
		'plg_akpayment_dwolla',
		'plg_akpayment_epaydk',
		'plg_akpayment_eselectplus',
		'plg_akpayment_eway',
		'plg_akpayment_ewayrapid3',
		'plg_akpayment_exact',
		'plg_akpayment_gocardless',
		'plg_akpayment_googlecheckout',
		'plg_akpayment_ifthen',
		'plg_akpayment_mercadopago',
		'plg_akpayment_mobilpaycc',
		'plg_akpayment_mobilpaysms',
		'plg_akpayment_moip',
		'plg_akpayment_moipassinaturas',
		'plg_akpayment_moneris',
		'plg_akpayment_nochex',
		'plg_akpayment_none',
		'plg_akpayment_offline',
		'plg_akpayment_pagseguro',
		'plg_akpayment_payfast',
		'plg_akpayment_paymill',
		'plg_akpayment_paymilldss3',
		'plg_akpayment_paypal',
		'plg_akpayment_paypalpaymentspro',
		'plg_akpayment_paypalproexpress',
		'plg_akpayment_paypoint',
		'plg_akpayment_paysafe',
		'plg_akpayment_payu',
		'plg_akpayment_postfinancech',
		'plg_akpayment_przelewy24',
		'plg_akpayment_rbkmoney',
		'plg_akpayment_realex',
		'plg_akpayment_robokassa',
		'plg_akpayment_saferpay',
		'plg_akpayment_sagepay',
		'plg_akpayment_scnet',
		'plg_akpayment_scnetintegrated',
		'plg_akpayment_skrill',
		'plg_akpayment_stripe',
		'plg_akpayment_suomenverkkomaksut',
		'plg_akpayment_upay',
		'plg_akpayment_verotel',
		'plg_akpayment_viva',
		'plg_akpayment_wepay',
		'plg_akpayment_worldpay',
		'plg_akpayment_zarinpal',
		'plg_ccinvoicetags_akeebasubs',
		'plg_sh404sefextplugins_com_akeebasubs',
		'plg_system_as2cocollation',
		'plg_system_affiliatesessiongeneration',
		'plg_system_aslogoutuser',
		'plg_system_aspaypalcollation',
		'plg_system_idevaffiliate',
		'plg_system_postaffiliatepro',
		'plg_user_aslogoutuser',
		'plg_user_asresetform',

		// Obsolete extensions formerly bundled with Akeeba CMS Update
		'plg_system_cmsupdateemail',
		'plg_quickicon_cmsupdate',

		// Packages: Akeeba Backup
		'pkg_akeeba',
		'com_akeeba',
		'file_akeeba',
		'plg_actionlog_akeebabackup',
		'plg_console_akeebabackup',
		'plg_installer_akeebabackup',
		'plg_quickicon_akeebabackup',
		'plg_system_akversioncheck',
		'plg_system_backuponupdate',

		// Packages: Admin Tools
		'pkg_admintools',
		'com_admintools',
		'file_admintools',
		'plg_actionlog_admintools',
		'plg_installer_admintools',
		'plg_system_admintools',

		// Packages: Akeeba Ticket System
		'pkg_ats',
		'com_ats',
		'file_ats',
		'amod_atsstats',
		'mod_atscredits',
		'mod_atstickets',
		'plg_actionlog_ats',
		'plg_ats_akeebasubs',
		'plg_ats_autoclose',
		'plg_ats_autoreply',
		'plg_ats_customfields',
		'plg_ats_deletenotes',
		'plg_ats_easyavatar',
		'plg_ats_geolocation',
		'plg_ats_gravatar',
		'plg_ats_mailfetch',
		'plg_ats_postemail',
		'plg_ats_removeattachments',
		'plg_ats_sociallike',
		'plg_ats_usergroups',
		'plg_atsinstantreply_docimport',
		'plg_atsinstantreply_tickets',
		'plg_content_atscredits',
		'plg_editors-xtd_atscannedreplies',
		'plg_finder_ats',
		'plg_installer_ats',
		'plg_search_ats',
		'plg_sh404sefextplugins_ats',
		'plg_user_ats',

		// Packages: Akeeba Subscriptions
		'pkg_akeebasubs',
		'com_akeebasubs',
		'file_akeebasubs',
		'mod_akmysubs',
		'mod_aksexpires',
		'mod_akslevels',
		'mod_aksubslist',
		'plg_content_astimedrelease',
		'plg_content_asprice',
		'plg_content_asrestricted',
		'plg_content_aslink',
		'plg_system_asexpirationcontrol',
		'plg_system_asuserregredir',
		'plg_system_asexpirationnotify',
		'plg_system_asfixrenewalsflag',
		'plg_akeebasubs_atscredits',
		'plg_akeebasubs_subscriptionemails',
		'plg_akeebasubs_contentpublish',
		'plg_akeebasubs_joomla',

		// Packages: Akeeba Release System
		'pkg_ars',
		'com_ars',
		'file_ars',
		'mod_arsdlid',
		'mod_arsdownloads',
		'plg_content_arsdlid',
		'plg_content_arslatest',
		'plg_system_arsjed',
		'plg_editors-xtd_arslink',

		// Packages: Version Compatibility
		'pkg_compatibility',
		'com_compatibility',

		// Packages: Akeeba DataCompliance
		'pkg_datacompliance',
		'pkg_compliance',
		'com_datacompliance',
		'file_datacompliance',
		'plg_user_datacompliance',
		'plg_datacompliance_s3',
		'plg_datacompliance_ars',
		'plg_datacompliance_loginguard',
		'plg_datacompliance_akeebasubs',
		'plg_datacompliance_ats',
		'plg_datacompliance_joomla',
		'plg_datacompliance_email',
		'plg_system_datacompliancecookie',
		'plg_system_datacompliance',

		// Packages: Akeeba ContactUs
		'pkg_contactus',
		'com_contactus',
		'file_contactus',

		// Packages: Akeeba DocImport
		'pkg_docimport',
		'com_docimport',
		'file_docimport',
		'mod_docimport_categories',
		'mod_docimport_search',
		'plg_search_docimport',
		'plg_finder_docimport',

		// Packages: Akeeba Engage
		'pkg_engage',
		'com_engage',
		'file_engage',
		'plg_privacy_engage',
		'plg_content_engage',
		'plg_user_engage',
		'plg_datacompliance_engage',
		'plg_engage_akismet',
		'plg_engage_gravatar',
		'plg_engage_email',
		'plg_system_engagecache',
		'plg_actionlog_engage',

		// Packages: Akeeba LoginGuard
		'pkg_loginguard',
		'com_loginguard',
		'file_loginguard',
		'plg_user_loginguard',
		'plg_system_loginguard',
		'plg_actionlog_loginguard',
		'plg_loginguard_smsapi',
		'plg_loginguard_yubikey',
		'plg_loginguard_fixed',
		'plg_loginguard_webauthn',
		'plg_loginguard_pushbullet',
		'plg_loginguard_totp',
		'plg_loginguard_email',
		'plg_loginguard_u2f',

		// Packages: Akeeba SocialLogin
		'plg_sociallogin_apple',
		'plg_sociallogin_discord',
		'plg_sociallogin_google',
		'plg_sociallogin_microsoft',
		'plg_sociallogin_github',
		'plg_sociallogin_facebook',
		'plg_sociallogin_linkedin',
		'plg_sociallogin_twitter',
		'plg_system_sociallogin',

		// Dark Magic
		'plg_system_darkmagic',

		// Internal
		'tpl_akeeba',
		'plg_user_foftoken',
		'plg_system_dateshift',
		'plg_system_mailmagic',
		'amod_emailsetup',
		'pkg_passwordless',
		'plg_system_passwordless',
		'plg_content_fieldsorter',
		'plg_system_usertype',
		'amod_userstats',
		'plg_system_socialmagick',
		'plg_system_expose',
		'plg_system_ampcontent',
		'plg_system_combinator',
		'plg_system_bootify',
	];

	/**
	 * @var   AdministratorApplication
	 * @since 1.0.0
	 */
	protected $app;

	/**
	 * @var   JDatabaseDriver
	 * @since 1.0.0
	 */
	protected $dbo;

	/**
	 * Map extension names to extension IDs
	 *
	 * @var   array
	 * @since 1.0.0
	 */
	private $extensionIds = [];

	/**
	 * The IDs of self::ALLOWED_EXTENSIONS installed on the site.
	 *
	 * @var   int[]
	 * @since 1.0.0
	 */
	private $allowedExtensionIds = [];

	public function onAfterInitialise()
	{
		// This only applies on Joomla 3.10
		if (
			version_compare(JVERSION, '3.10.0', 'lt')
			|| version_compare(JVERSION, '3.10.999999', 'gt')
		)
		{
			return;
		}

		// Make sure this is the back-end
		try
		{
			$app = Factory::getApplication();
		}
		catch (Exception $e)
		{
			return;
		}

		if (!$app->isClient('administrator'))
		{
			return;
		}

		// Make sure a user is logged in
		$user = JFactory::getUser();

		if (!is_object($user) || $user->guest)
		{
			return;
		}

		// Make sure the user is a Super User or otherwise allowed to upgrade the site
		if (!$user->authorise('core.admin', 'com_joomlaupdate'))
		{
			return;
		}

		$component = $this->app->input->getCmd('option');
		$task      = $this->app->input->getCmd('task');

		if ($component == 'com_plugins')
		{
			$this->onDirectUnpublish($task);

			$this->onApplyOrSave($task);

			return;
		}

		if ($component !== 'com_joomlaupdate')
		{
			return;
		}

		if ($task === null)
		{
			$this->conditionallyShowMessage();
		}
		elseif ($task === 'update.fetchextensioncompatibility')
		{
			$this->populateAllowedExtensionIDs();

			$this->manipulateJoomlaUpdate();
		}
	}

	public function onBeforeRender()
	{
		// This only applies on Joomla 3.10
		if (
			version_compare(JVERSION, '3.10.0', 'lt')
			|| version_compare(JVERSION, '3.10.999999', 'gt')
		)
		{
			return;
		}

		// Make sure this is the back-end
		try
		{
			$app = Factory::getApplication();
		}
		catch (Exception $e)
		{
			return;
		}

		if (!$app->isClient('administrator'))
		{
			return;
		}

		// Make sure a user is logged in
		$user = JFactory::getUser();

		if (!is_object($user) || $user->guest)
		{
			return;
		}

		// Make sure the user is a Super User or otherwise allowed to upgrade the site
		if (!$user->authorise('core.admin', 'com_joomlaupdate'))
		{
			return;
		}

		$component = $this->app->input->getCmd('option');

		if ($component !== 'com_joomlaupdate')
		{
			return;
		}

		$doc = $this->app->getDocument();

		if (empty($doc))
		{
			return;
		}

		$nonCoreCriticalPlugins = $doc->getScriptOptions('nonCoreCriticalPlugins');

		if (empty($nonCoreCriticalPlugins))
		{
			return;
		}

		$this->populateAllowedExtensionIDs();

		$nonCoreCriticalPlugins = array_filter(
			$nonCoreCriticalPlugins,
			function (object $entry)
			{
				return !in_array($entry->extension_id, $this->allowedExtensionIds);
			}
		);

		$doc->addScriptOptions('nonCoreCriticalPlugins', $nonCoreCriticalPlugins, false);
	}

	private function onDirectUnpublish($task)
	{
		$allowedTasks = ['unpublish', 'plugins.unpublish'];

		if (!in_array($task, $allowedTasks))
		{
			return;
		}

		// Get a list of all IDs in the request
		$ids   = $this->app->input->get('cid', [], 'array');
		$ids[] = $this->app->input->getInt('id', null);

		// Get the plugin ID for System - Admin Tools
		$ourId = $this->getExtensionId('plg_system_akversioncheck');

		if (empty($ourId))
		{
			return;
		}

		// Does the ID exist in the array? We need to be thorough, we can't do a simple in_array.
		foreach ($ids as $id)
		{
			$id = (int) trim($id);

			if ($id == $ourId)
			{
				throw new RuntimeException(Text::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
			}
		}
	}

	private function onApplyOrSave($task)
	{
		$allowedTasks = ['apply', 'save', 'plugins.apply', 'plugins.save', 'plugin.apply', 'plugin.save'];

		if (!in_array($task, $allowedTasks))
		{
			return;
		}

		// Get a list of all IDs in the request
		$ids   = $this->app->input->get('cid', [], 'array');
		$ids[] = $this->app->input->getInt('id', null);
		$ids[] = $this->app->input->getInt('extension_id', null);

		// Get the plugin ID for System - Admin Tools
		$ourId = $this->getExtensionId('plg_system_akversioncheck');

		if (empty($ourId))
		{
			return;
		}

		// Does the ID exist in the array? We need to be thorough, we can't do a simple in_array.
		$found = false;

		foreach ($ids as $id)
		{
			$id = (int) trim($id);

			if ($id == $ourId)
			{
				$found = true;

				break;
			}
		}

		if (!$found)
		{
			return;
		}

		// Get the form data and look for the enabled field
		$jform = $this->app->input->get('jform', [], 'array');

		if (!isset($jform['enabled']))
		{
			// Not saving the "enabled" value
			return;
		}

		if ($jform['enabled'] == 1)
		{
			// The plugin is being activated
			return;
		}

		// Apparently someone tries to deactivate the plugin. NOPE.
		throw new RuntimeException(Text::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
	}


	private function manipulateJoomlaUpdate()
	{
		$id      = (int) $_GET['extension-id'];
		$version = $this->app->input->get('extension-version');

		// Must be one of our allowed extensions
		if (empty($id) || !in_array($id, $this->allowedExtensionIds))
		{
			return;
		}

		// Check for updates to the extension itself
		if (!class_exists(JoomlaupdateModelDefault::class))
		{
			require_once JPATH_ADMINISTRATOR . '/components/com_joomlaupdate/models/default.php';
		}

		/** @var JoomlaupdateModelDefault $model */
		$model = Joomla\CMS\MVC\Model\BaseDatabaseModel::getInstance('Default', 'JoomlaupdateModel');

		$currentCompatibilityStatus = $model->fetchCompatibility($id, JVERSION);
		$currentUpdateVersion       = false;
		$resultGroup                = 3;

		if ($currentCompatibilityStatus->state == 1 && !empty($currentCompatibilityStatus->compatibleVersions))
		{
			$resultGroup          = 2;
			$currentUpdateVersion = end($currentCompatibilityStatus->compatibleVersions);
		}

		// Construct the response
		$response = [
			'upgradeCompatibilityStatus' => [
				'state'             => 1,
				'compatibleVersion' => $currentUpdateVersion ?: $version,
			],
			'currentCompatibilityStatus' => [
				'state'             => 1,
				'compatibleVersion' => $currentUpdateVersion ?: $version,
			],
			'resultGroup'                => $resultGroup,
			'upgradeWarning'             => 0,
		];

		// Send the response
		$this->app->mimeType = 'application/json';
		$this->app->charSet  = 'utf-8';
		$this->app->setHeader('Content-Type', $this->app->mimeType . '; charset=' . $this->app->charSet);
		$this->app->sendHeaders();

		try
		{
			echo new JsonResponse($response);
		}
		catch (Exception $e)
		{
			echo $e;
		}

		$this->app->close();
	}

	private function populateAllowedExtensionIDs()
	{
		$this->allowedExtensionIds = array_filter(
			array_map(
				function (string $extension): ?int {
					return $this->getExtensionId($extension);
				},
				self::ALLOWED_EXTENSIONS
			)
		);
	}

	private function conditionallyShowMessage()
	{
		if (!class_exists(JoomlaupdateModelDefault::class))
		{
			require_once JPATH_ADMINISTRATOR . '/components/com_joomlaupdate/models/default.php';
		}
		// We must have an update
		/** @var JoomlaupdateModelDefault $model */
		$model      = Joomla\CMS\MVC\Model\BaseDatabaseModel::getInstance('Default', 'JoomlaupdateModel');
		$updateInfo = $model->getUpdateInformation();

		if (!$updateInfo['hasUpdate'])
		{
			return;
		}

		// The new version must be in the 4.x range
		if (version_compare($updateInfo['latest'], '4.0.0', 'lt'))
		{
			return;
		}

		// We must have obsolete extensions
		$hasAkeebaSubscriptions = $this->hasAkeebaSubscriptions();
		$hasObsoleteExtensions  = $this->hasObsoleteExtensions();

		if ($hasObsoleteExtensions || $hasAkeebaSubscriptions)
		{
			$this->loadLanguage();

			$message =
				'<h3>' .
				Text::_('PLG_SYSTEM_AKVERSIONCHECK_LBL_TITLE') .
				'</h3>' .
				'<p>' .
				Text::_('PLG_SYSTEM_AKVERSIONCHECK_LBL_CONTENT')
				. '</p>';

			if ($hasObsoleteExtensions)
			{
				$message .= '<p>' . Text::sprintf(
						$hasAkeebaSubscriptions ? 'PLG_SYSTEM_AKVERSIONCHECK_LBL_MAGICERASER_WITH_SUBS' : 'PLG_SYSTEM_AKVERSIONCHECK_LBL_MAGICERASER',
						'https://github.com/akeeba/magiceraser/releases/latest'
					);
			}

			if ($hasAkeebaSubscriptions)
			{
				$message .= '<p>' .
					Text::_('PLG_SYSTEM_AKVERSIONCHECK_LBL_AKEEBASUBSCRIPTIONS') .
					'</p>';
			}

			$message .= '<hr/>';

			$this->app->enqueueMessage($message, 'error');
		}
	}

	private function hasObsoleteExtensions(): bool
	{
		return array_reduce(
			self::OBSOLETE_EXTENSIONS,
			function (bool $carry, string $extension): bool {
				return $carry || !empty($this->getExtensionId($extension));
			},
			false
		);
	}

	private function hasAkeebaSubscriptions()
	{
		return !empty($this->getExtensionId('pkg_akeebasubs'))
			|| !empty($this->getExtensionId('com_akeebasubs'));
	}

	private function getExtensionId(string $extension): ?int
	{
		if (isset($this->extensionIds[$extension]))
		{
			return $this->extensionIds[$extension];
		}

		$this->extensionIds[$extension] = null;

		$criteria = $this->extensionNameToCriteria($extension);

		if (empty($criteria))
		{
			return $this->extensionIds[$extension];
		}

		$db    = Factory::getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName('extension_id'))
			->from($db->quoteName('#__extensions'));

		foreach ($criteria as $key => $value)
		{
			$query->where($db->qn($key) . ' = ' . $db->quote($value));
		}

		try
		{
			$this->extensionIds[$extension] = (int) $db->setQuery($query)->loadResult();
		}
		catch (RuntimeException $e)
		{
			return null;
		}

		return $this->extensionIds[$extension];
	}

	private function extensionNameToCriteria(string $extensionName): array
	{
		$parts = explode('_', $extensionName, 3);

		switch ($parts[0])
		{
			case 'pkg':
				return [
					'type'    => 'package',
					'element' => $extensionName,
				];

			case 'com':
				return [
					'type'    => 'component',
					'element' => $extensionName,
				];

			case 'plg':
				return [
					'type'    => 'plugin',
					'folder'  => $parts[1],
					'element' => $parts[2],
				];

			case 'mod':
				return [
					'type'      => 'module',
					'element'   => $extensionName,
					'client_id' => 0,
				];

			// That's how we note admin modules
			case 'amod':
				return [
					'type'      => 'module',
					'element'   => substr($extensionName, 1),
					'client_id' => 1,
				];

			case 'file':
			case 'files':
				return [
					'type'    => 'file',
					'element' => $extensionName,
				];

			case 'lib':
				$element = substr($extensionName, 4);

				if (substr($element, -7) === '#prefix')
				{
					$element = 'lib_' . substr($element, 0, -7);
				}

				return [
					'type'    => 'library',
					'element' => $element,
				];

			case 'tpl':
				return [
					'type'    => 'template',
					'element' => substr($extensionName, 4),
				];
		}

		return [];
	}
}
PK��#]{�͠�%system/bfnetwork/bfnetwork/bfStep.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

final class STEP
{
    /**
     * Our steps of the audit, broken down into sections mainly for
     * Reporting.
     */
    const TESTCONNECTION         = 1;
    const REQUESTSCANNERCONFIG   = 2;
    const SCANNINGROOTDIRS       = 3;
    const INITIALSCANNINGFOLDERS = 4;
    const INITIALSCANNINGFILES   = 5;
    const LOOKINGUPMODIFIEDFILES = 6;
    const GETHASHFAILURECOUNT    = 7;
    const DBINFO                 = 8;
    const DEEPSCAN               = 9;
    const COMPILEEXTENSIONS      = 10;
    const VERIFYEXTENSIONS       = 11;
    const BESTPRACTICESECURITY   = 12;
    const COMPLETE               = 13;

    /**
     * @var int The current step we are running
     */
    private $_currentStep;

    /**
     * @var array Inverse of our CONST's so that we can convert both ways
     */
    private $steps = array(
        '1'  => 'TESTCONNECTION',
        '2'  => 'REQUESTSCANNERCONFIG',
        '3'  => 'SCANNINGROOTDIRS',
        '4'  => 'INITIALSCANNINGFOLDERS',
        '5'  => 'INITIALSCANNINGFILES',
        '6'  => 'LOOKINGUPMODIFIEDFILES',
        '7'  => 'GETHASHFAILURECOUNT',
        '8'  => 'DBINFO',
        '9'  => 'DEEPSCAN',
        '10' => 'COMPILEEXTENSIONS',
        '11' => 'VERIFYEXTENSIONS',
        '12' => 'BESTPRACTICESECURITY',
        '13' => 'COMPLETE',
    );

    /**
     * Initialise the audit, setting the current step to run.
     *
     * @param int $currentStep
     */
    public function __construct($currentStep = null)
    {
        if (!$currentStep) {
            $currentStep = STEP::TESTCONNECTION;
        }
        $this->_currentStep = $currentStep;
    }

    /**
     * Force the audit onto the next step in the audit process,
     * this is a STEP (Section) not a TICK!
     *
     * @return int The current step
     */
    public function nextStepPlease()
    {
        // If we are almost complete then mark it as so
        if ($this->_currentStep > count($this->steps)) {
            $this->_currentStep = STEP::COMPLETE;
        } else {
            // Increase the step by one
            ++$this->_currentStep;
        }

        return $this->_currentStep;
    }

    /**
     * Get the current step.
     *
     * @return string The name of the step
     */
    public function __toString()
    {
        return $this->steps[$this->_currentStep];
    }

    /**
     * Get the method name for a step.
     *
     * @param int $step
     *
     * @return string
     */
    public function getStepFunction($step)
    {
        return strtolower($this->steps[$step]).'Action';
    }
}
PK��#]%{ż"system/bfnetwork/bfnetwork/VERSIONnu�[���A6018PK��#]�i��4system/bfnetwork/bfnetwork/bfApplicationMyjoomla.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

defined('_JEXEC') or die();

/*
 * Our very own myJoomla implementation of some core Joomla features
 * We need this so that we can overwrite troublesome methods in the class
 *
 * Class JApplicationMyjoomla
 */
if (class_exists('JApplicationCms')) {
    /**
     * Joomla 3.0.0 +.
     *
     * Class JApplicationMyjoomla
     */
    class JApplicationMyjoomla extends JApplicationCms
    {
        /**
         * @var array The details of the redirect
         */
        private $_redirectDetails = array();

        /**
         * Override the redirect method
         * We need this so we can stop Joomla from running exit(0) and killing us!
         * This is useful when an extension update aborts and redirects to com_installer
         * It will probably be even more use as we blur the edges of what Joomla can achieve.
         *
         * @param string $url
         * @param bool   $moved
         */
        public function redirect($url, $moved = false)
        {
            $this->setRedirect($url, $moved);

            // Note we DO NOT exit(0) or die here - yes this *could* cause issues, but at the moment we have seen none.
        }

        private function setRedirect($url, $moved = false)
        {
            $this->_redirectDetails = array(
                'headers'      => $this->getHeaders(),
                'messagequeue' => $this->getMessageQueue(),
                'url'          => $url,
            );
        }

        /**
         * Return the details of any set redirect.
         *
         * @return array
         */
        public function getRedirectDetails()
        {
            return $this->_redirectDetails;
        }

        /**
         * Return the current state of the language filter.
         *
         * @return bool
         *
         * @since	3.2
         */
        public function getLanguageFilter()
        {
            return false;
        }
    }
} elseif (class_exists('JApplication')) {
    /**
     * Joomla 1.5.0 - 1.5.26
     * Joomla 2.5.0 - 2.5.28.
     *
     * Class JApplicationMyjoomla
     */
    class JApplicationMyjoomla extends JApplication
    {
        /**
         * @var array The details of the redirect
         */
        private $_redirectDetails = array();

        /**
         * Override the redirect method
         * We need this so we can stop Joomla from running exit(0) and killing us!
         * This is useful when an extension update aborts and redirects to com_installer
         * It will probably be even more use as we blur the edges of what Joomla can achieve.
         *
         * @param string $url
         * @param bool   $moved
         */
        public function redirect($url, $moved = false)
        {
            $this->setRedirect($url, $moved);

            // Note we DO NOT exit(0) or die here - yes this *could* cause issues, but at the moment we have seen none.
        }

        private function setRedirect($url, $moved = false)
        {
            $this->_redirectDetails = array(
                'headers'      => $this->getHeaders(),
                'messagequeue' => $this->getMessageQueue(),
                'url'          => $url,
            );
        }

        /**
         * Return the details of any set redirect.
         *
         * @return array
         */
        public function getRedirectDetails()
        {
            return $this->_redirectDetails;
        }
    }
}
PK��#]M���"system/bfnetwork/bfnetwork/HOST_IDnu�[���AM8eXAPK��#]ƛ�%''&system/bfnetwork/bfnetwork/openssl.cnfnu�[���# @package Blue Flame Network (bfNetwork)
# @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Blue Flame Digital Solutions Limited. All rights reserved.
# @license GNU General Public License version 3 or later
# @link http://www.phil-taylor.com/
# @author Phil Taylor / Blue Flame Digital Solutions Limited.
#
# bfNetwork is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# bfNetwork is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this package.  If not, see http://www.gnu.org/licenses/


# minimalist openssl.cnf file for use with phpseclib

HOME			= .
RANDFILE		= $ENV::HOME/.rnd

[ v3_ca ]
PK��#]����&system/bfnetwork/bfnetwork/bfTimer.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * Some of this taken from Akeeba Backup.
 *
 * @copyright Copyright (c)2009 Nicholas K. Dionysopoulos
 * @license GNU GPL version 3 or, at your option, any later version
 */
class bfTimer
{
    /**
     * @var int Maximum execution time allowance per step
     */
    private $max_exec_time = null;

    /**
     * @var int Timestamp of execution start
     */
    public $start_time = null;

    /**
     * Public constructor, creates the timer object and calculates the execution
     * time limits.
     */
    public function __construct()
    {
        // Initialize start time
        $this->start_time = $this->microtime_float();

        // Get PHP's maximum execution time (our upper limit)
        if (@function_exists('ini_get')) {
            $php_max_exec_time = @ini_get('max_execution_time');

            if ((!is_numeric($php_max_exec_time)) || (0 == $php_max_exec_time)) {
                // If we have no time limit, set a hard limit of about 10
                // seconds
                // (safe for Apache and IIS timeouts, verbose enough for users)
                $php_max_exec_time = _BF_CONFIG_PHP_MAX_EXEC_TIME;
            }
        } else {
            // If ini_get is not available, use a rough default
            $php_max_exec_time = _BF_CONFIG_PHP_MAX_EXEC_TIME;
        }

        // Apply an arbitrary correction to counter Decryption load time
        --$php_max_exec_time;
        --$php_max_exec_time;

        // Apply bias
        $this->max_exec_time = $php_max_exec_time;
        // Use the most appropriate time limit value

        // Overrule EVERYthing above :-) set hard limit
        if (_BF_CONFIG_PHP_MAX_EXEC_TIME_HARD_LIMIT !== null) {
            $this->max_exec_time = _BF_CONFIG_PHP_MAX_EXEC_TIME_HARD_LIMIT;
        }

        // crappy webhost
        if (ini_get('max_execution_time') < $this->max_exec_time) {
            $this->max_exec_time = ini_get('max_execution_time');
            --$this->max_exec_time;
        }
    }

    /**
     * @return bfTimer
     */
    public static function getInstance()
    {
        static $instance;
        if (!isset($instance)) {
            $instance = new bfTimer();
        }

        return $instance;
    }

    /**
     * Wake-up function to reset internal timer when we get unserialized.
     */
    public function __wakeup()
    {
        // Re-initialize start time on wake-up
        $this->start_time = $this->microtime_float();
    }

    /**
     * Gets the number of seconds left, before we hit the "must break" threshold.
     *
     * @return float
     */
    public function getTimeLeft()
    {
        return $this->max_exec_time - $this->getRunningTime();
    }

    /**
     * Gets the time elapsed since object creation/unserialization, effectively
     * how
     * long Akeeba Engine has been processing data.
     *
     * @return float
     */
    public function getRunningTime()
    {
        return $this->microtime_float() - $this->start_time;
    }

    /**
     * Returns the current timestamp in decimal seconds.
     */
    public function microtime_float()
    {
        list($usec, $sec) = explode(' ', microtime());

        return (float) $usec + (float) $sec;
    }

    /**
     * Reset the timer.
     * It should only be used in CLI mode!
     */
    public function resetTime()
    {
        $this->start_time = $this->microtime_float();
    }

    /**
     * @return int|string|null
     */
    public function getMaxTime()
    {
        return $this->max_exec_time;
    }

    /**
     * @return float|int|null
     */
    public function getStartTime()
    {
        return $this->start_time;
    }
}
PK��#]*Y&�Q�Q�)system/bfnetwork/bfnetwork/bfSnapshot.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require 'bfEncrypt.php';

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */

// require all we need to access Joomla API
require 'bfInitJoomla.php';
require_once 'bfActivitylog.php';

final class bfSnapshot
{
    public $_data;
    private $db;
    private $version;
    private $config;

    public function __construct()
    {
        $this->cleanOurCrap();

        // Ask Joomla to report config through its API
        $this->config = JFactory::getApplication('site');

        // Connect to the database
        $this->initDb();

        $session_save_path = @ini_get('session_save_path') ? ini_get('session_save_path') : '/tmp';

        $this->_data = array(
            'version'                    => $this->getJoomlaVersion(),
            'connectorversion'           => file_get_contents('./VERSION'),
            'php_version'                => PHP_VERSION,
            'php_disabled_functions'     => ini_get('disable_functions'),
            'display_errors'             => ini_get('display_errors'),
            'register_globals'           => (int) ini_get('register_globals'),
            'safe_mode'                  => (int) ini_get('safe_mode'),
            'file_uploads'               => (int) ini_get('file_uploads'),
            'magic_quotes_gpc'           => (int) ini_get('magic_quotes_gpc'),
            'magic_quotes_runtime'       => (int) ini_get('magic_quotes_runtime'),
            'session_autostart'          => (int) ini_get('session_autostart'),
            'gc_probability'             => (int) ini_get('session.gc_probability'),
            'mysql_version'              => $this->initDb(),
            'session_save_path'          => $session_save_path,
            'is_windows_host'            => (int) ('WIN' == substr(PHP_OS, 0, 3)) ? 1 : 0,
            'session_save_path_writable' => (int) is_writable($session_save_path),
            'db_prefix'                  => $this->config->getCfg('dbprefix', ''),
            'dbs_visible'                => $this->getVisibleDbsCount(),
            'db_user_is_root'            => (int) ('root' == $this->config->getCfg('user', '') ? 1 : 0),
            'db_bak_tables'              => (int) $this->hasBakTables(),
            'memory_limit'               => ini_get('memory_limit'),
            'has_installation_folders'   => (int) $this->hasInstallationFolders(),
            'site_debug_enabled'         => (int) $this->config->getCfg('debug') ? 1 : 0,
            'has_ftp_configured'         => (int) $this->checkFTPLayer(),
            'numberofsuperadmins'        => $this->getNumberOfSuperAdmins(),
            'adminusernames'             => $this->getAdminUserNameCount(),
            'neverloggedinusers'         => $this->getNeverLoggedInUsersCount(),
            'hasjce'                     => $this->hasExtensionWithNameInstalled('com_jce'),
            'hasakeebabackup'            => $this->hasExtensionWithNameInstalled('com_akeeba'),
            'site_offline'               => $this->config->getCfg('offline', ''),
            'cache_enabled'              => $this->config->getCfg('caching', ''),
            'sef_enabled'                => $this->config->getCfg('sef', ''),
            'tmplogfolderswritable'      => (int) $this->hastmplogfolderswritable(),
            'extensionupdatesavailable'  => null, // Now called in separate job was $this->hasUpdatesAvailable(),
            'defaulttemplateused'        => (int) $this->hasUsedDefaultTemplate(),
            'tpequalsone'                => $this->hastpequalsone(),
            'configsymlinked'            => (is_link(JPATH_BASE.'/configuration.php') ? 1 : 0),
            'kickstartseen'              => (file_exists(JPATH_BASE.'/kickstart.php') ? 1 : 0),
            'fpaseen'                    => (int) $this->fpaexists(),
            'userregistrationenabled'    => (int) JComponentHelper::getParams('com_users')->get('allowUserRegistration'),
            'has_root_htaccess'          => (int) (file_exists(JPATH_BASE.'/.htaccess') ? 1 : 0),
            'adminhtaccess'              => (int) (file_exists(JPATH_BASE.'/administrator/.htaccess') ? 1 : 0),
            'gzipenabled'                => (int) $this->config->getCfg('gzip', ''),
            'gcerrorreportingnone'       => (int) $this->getErrorReportingLevel(),
            'livesitevarset'             => strlen($this->config->getCfg('live_site')) > 1 ? 1 : 0,
            'cookiedomainpath'           => ($this->config->getCfg('cookie_path') || $this->config->getCfg('cookie_domain')) ? 1 : 0,
            'sessionlifetime'            => (int) $this->config->getCfg('lifetime'),
            'akeebabackupscount'         => (int) $this->getNumberOfAkeebaBackups(),
            'md5passwords'               => (int) $this->hasmd5passwords(),
            'tmplogfoldersdefaultpaths'  => (int) $this->hastmplogfoldersdefaultpaths(),
            'max_allowed_packet'         => (int) $this->getMaxAllowedPacket(),
            'jceversion'                 => $this->checkJCEVersion(),
            'fluff'                      => (int) $this->checkfluff(),
            'db_schema'                  => $this->checkdbschema(),
            'robots_blocks_media'        => (int) $this->checkRobotsBlocksMedia(),
            'server_hostname'            => function_exists('gethostname') ? gethostname() : php_uname('n'),
            'akeeba_dir_problems'        => $this->getAkeebaOutputDirectoryProblems(),
            'diskspace'                  => $this->getDiskSpace(),
            'eol_issues'                 => $this->testEOLIssues(),
            'hacked'                     => $this->checkIf100percentHackedOrNot(),
            'new_usertype'               => $this->getNewUserType(),
            'non2faadmins'               => $this->getNon2FaAdmins(),
            'users_hacked'               => $this->checkJoomlaUserHelperHack2016(),
            'sessiongcpublished'         => $this->getSessionGCStatus(),
            'twofactorenabled'           => $this->getTwoFactorPluginsEnabled(),
            'adminfilterfixed'           => $this->getAdminFilterFixed(),
            'plaintextpasswordsfixed'    => $this->getPlaintextpasswordsFixed(),
            'uploadsettingsfixed'        => $this->getUploadsettingsfixed(),
            'mailtofrienddisabled'       => $this->getMailtofrienddisabled(),
            'captchaenabled'             => $this->getCaptchaDetails(),
            'useractionlogenabled'       => (int) $this->getUseractionlogenabled(),
            'plgprivacyconsentenabled'   => (int) $this->getPrivacyConsentPluginEnabled(),
            'useractionlogiplogenabled'  => (int) $this->getActionLogsIPLoggingEnabled(),
            'systemlogrotationenabled'   => (int) $this->getSystemLogRotationEnabled(),
            'hasprivacypolicy'           => (int) $this->hasprivacypolicy(),
            'privacypendingremove'       => (int) $this->getPrivacypendingremove(),
            'privacycompletedexport'     => (int) $this->getPrivacycompletedexport(),
            'privacypendingexport'       => (int) $this->getPrivacypendingexport(),
            'privacycompletedremove'     => (int) $this->getPrivacycompletedremove(),
            'privacyoverdue'             => (int) $this->getPrivacyoverdue(),
            'privacyconfirmedremove'     => (int) $this->getPrivacyconfirmedremove(),
            'privacyconfirmedexport'     => (int) $this->getPrivacyconfirmedexport(),
            'enablepurge30days'          => (int) $this->getPurge30Days(),
        );
    }

    /**
     * Get the number of days to delete logs after from the System - User Actions Log.
     *
     * @return int
     */
    public function getPurge30Days()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }

        $this->db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'PLG_SYSTEM_ACTIONLOGS'");

        $params = $this->db->LoadResult();

        if ('{}' == $params) {
            return null;
        }

        $params = json_decode($params);

        return $params->logDeletePeriod;
    }

    public function getPrivacypendingremove()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 0 and request_type = 'remove'");

        return $this->db->LoadResult();
    }

    public function getPrivacyconfirmedremove()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 1 and request_type = 'remove'");

        return $this->db->LoadResult();
    }

    public function getPrivacyconfirmedexport()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 1 and request_type = 'export'");

        return $this->db->LoadResult();
    }

    public function getPrivacycompletedexport()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 2 and request_type = 'export'");

        return $this->db->LoadResult();
    }

    public function getPrivacypendingexport()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 0 and request_type = 'export'");

        return $this->db->LoadResult();
    }

    public function getPrivacycompletedremove()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }
        $this->db->setQuery("select count(*) from #__privacy_requests where status = 2 and request_type = 'remove'");

        return $this->db->LoadResult();
    }

    /**
     * Get the overdue requests.
     *
     * @return bool
     */
    public function getPrivacyoverdue()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }
        // Load the parameters.
        $params = \Joomla\CMS\Component\ComponentHelper::getComponent('com_privacy')->getParams();
        $notify = (int) $params->get('notify', 14);
        $now    = JFactory::getDate()->toSql();
        $period = '-'.$notify;

        $query = $this->db->getQuery(true)
            ->select('COUNT(*)');
        $query->from($this->db->quoteName('#__privacy_requests'));
        $query->where($this->db->quoteName('status').' = 1 ');
        $query->where($query->dateAdd($this->db->quote($now), $period, 'DAY').' > '.$this->db->quoteName('requested_at'));
        $this->db->setQuery($query);

        return $this->db->LoadResult();
    }

    /**
     * Joomla 3.9.0+ Check for system log rotation plugin.
     *
     * @return mixed
     */
    public function getSystemLogRotationEnabled()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }

        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `name` = 'plg_system_logrotation' and enabled = 1");

        return $this->db->LoadResult();
    }

    /**
     * Joomla 3.9.0+ Check for action log ip logging enabled.
     *
     * @return mixed
     */
    public function hasprivacypolicy()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }

        $this->db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'plg_system_privacyconsent'");

        $params = json_decode($this->db->LoadResult());

        return $params->privacy_article > 0 ? 1 : 0;
    }

    /**
     * Joomla 3.9.0+ Check for action log ip logging enabled.
     *
     * @return mixed
     */
    public function getActionLogsIPLoggingEnabled()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }

        $this->db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'com_actionlogs'");

        $params = json_decode($this->db->LoadResult());

        return $params->ip_logging;
    }

    /**
     * Joomla 3.9.0+ Check for action log ip logging enabled.
     *
     * @return mixed
     */
    public function getUseractionlogenabled()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }

        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE (`name` = 'PLG_ACTIONLOG_JOOMLA' or `name` = 'PLG_SYSTEM_ACTIONLOGS') and enabled = 1");

        return 2 == $this->db->LoadResult() ? 1 : 0;
    }

    /**
     * Joomla 3.9.0+ Check for plg_privacy_actionlogs enabled.
     *
     * @return mixed
     */
    public function getPrivacyConsentPluginEnabled()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }

        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `name` = 'plg_system_privacyconsent' and enabled = 1");

        return $this->db->LoadResult();
    }

    /**
     * Checks if the FTP Layer is in anyway configured.
     *
     * @return bool
     */
    private function checkFTPLayer()
    {
        $ftp_pass   = $this->config->getCfg('ftp_pass', '');
        $ftp_user   = $this->config->getCfg('ftp_user', '');
        $ftp_enable = $this->config->getCfg('ftp_enable', '');
        $ftp_host   = $this->config->getCfg('ftp_host', '');
        $ftp_root   = $this->config->getCfg('ftp_root', '');

        if ($ftp_pass || $ftp_user || '1' == $ftp_enable || $ftp_host || $ftp_root) {
            return true;
        }

        return false;
    }

    /**
     * Clean up old myJoomla.com files and features.
     */
    private function cleanOurCrap()
    {
        // cleanup old files
        $oldFiles = array(
            'upgrade.zip',
            './bfViewLog.php',
            './bfDev.php',
            './bfDb.php',
            './bfMysql.php',
            './j25_30_bfnetwork.xml', // dont get confused with the one in the folder above this.
            './install.bfnetwork.php',
            './bfnetwork.xml',
            './bfJson.php',
            './tmp/log.tmp',
            './tmp/tmp.ob',
        );

        foreach ($oldFiles as $file) {
            if (file_exists($file)) {
                @unlink($file);
            }
        }

        // cleanup
        if (file_exists('../j25_30_bfnetwork.xml')) {
            @copy('../j25_30_bfnetwork.xml', '../bfnetwork.xml');
            @unlink('../j25_30_bfnetwork.xml');
        }

        $fileContent = file_get_contents('../bfnetwork.php');
        if (!preg_match('/bfPlugin/', $fileContent)) {
            $fileContent = str_replace(array(
                "\n\n",
                '// For more details please contact Phil Taylor <phil@phil-taylor.com>',
                '// This is NOT a Joomla Extension or Plugin and is NOT designed for consumption within Joomla - yet :)', ), '', $fileContent);
            $fileContent = $fileContent."
/**
 * All our code is in the sub folder, as that is what is auto-upgraded
 * and fully maintained by the automated processes at myJoomla.com
 */
require 'bfnetwork/bfPlugin.php';";

            file_put_contents('../bfnetwork.php', $fileContent);
        }

        bfActivitylog::getInstance();

        // Soon we will enable this...
        //        $this->db = JFactory::getDBO();
        //        $this->db->setQuery('UPDATE #__extensions SET enabled = 0 where element = "bfnetwork"');
        //        $this->db->query();
    }

    /**
     * Init the Joomla db connection.
     */
    private function initDb()
    {
        $this->db = JFactory::getDBO();

        $dbVerString = '';

        if ('JDatabaseDriverMysqli' == get_class($this->db)) {
            $dbVerString = @mysqli_get_server_info($this->db->getConnection())->server_info;
        }

        if (!$dbVerString && 'JDatabaseDriverMysql' == get_class($this->db) && function_exists('mysql_get_server_info')) {
            $dbVerString = @mysql_get_server_info($this->db->getConnection());
        }

        if (!$dbVerString && method_exists($this->db, 'getConnection') && $this->db->getConnection()) {
            $dbVerString = $this->db->getConnection()->server_info;
        }

        if (!$dbVerString && function_exists('mysql_get_server_info')) {
            // crappy Joomla 1.5.x versions - I hat the @ supressor yeah yeah - but its CRAP!
            $dbVerString = @mysql_get_server_info($this->db->_resource);
        }

        return $dbVerString;
    }

    private function getJoomlaVersion()
    {
        $VERSION = new JVersion();

        // Store in our object for switching configs
        $this->version = $VERSION->getShortVersion();

        return $VERSION->getShortVersion();
    }

    /**
     * How many databases can I see?
     *
     * We need to reconnect again to the db so we are ot going through the Joomla
     * DB Layer because it just crashes too far up the stack for us to catch the
     * exception
     *
     * @return int
     */
    private function getVisibleDbsCount()
    {
        $count = 0;

        try {
            // Create correct commands based on how old and crap the server is!
            switch ($this->config->getCfg('dbtype')) {
                default:
                case 'mysqli':

                    $link = mysqli_connect($this->config->getCfg('host'), $this->config->getCfg('user'), $this->config->getCfg('password'));
                    if (!$link) {
                        return null;
                    }

                    $res = mysqli_query($link, 'SHOW DATABASES where `Database` NOT IN ("test","performance_schema", "information_schema", "mysql")');
                    if (!$res) {
                        return null;
                    }

                    $count = $res->num_rows;

                    // tidy up
                    mysqli_close($link);
                    break;

                // Yes we have to cope with the old guys too!!!
                case 'mysql':
                    /*
                     * If you are trying to open multiple, separate MySQL connections with the same MySQL user,
                     * password, and hostname, you must set $new_link = TRUE to prevent mysql_connect from using an existing connection.
                     *
                     * @see http://uk1.php.net/manual/en/function.mysql-connect.php#comments
                     * @see http://uk1.php.net/manual/en/function.mysql-close.php#47865
                     */

                    // PHP upgraded to PHP 7+ on a site with mysql abstraction type
                    if (!function_exists('mysql_connect')) {
                        throw new Exception('Your site is incorrectly configured for PHP 7. Your Joomla Global Config states to use the "mysql" database abstraction layer but your server doesnt have the mysql* functions available as you are running PHP 7+ - to fix this you should select mysqli from the database type in Joomla Global Config and save your Joomla global configuration again (note it looks strange and already selected as Joomla on PHP7 will remove the mysql option in the dropdown - but be assured once you save the configuration in Joomla this will fix the issues.');
                    }

                    $link = mysql_connect($this->config->getCfg('host'), $this->config->getCfg('user'), $this->config->getCfg('password'), true);
                    if (!$link) {
                        return null;
                    }

                    // get the list of databases - if we can, if we have no access then returns null
                    $res = mysql_query('SHOW DATABASES  where `Database` NOT IN ("test", "information_schema","performance_schema", "mysql")');

                    if (!$res) {
                        return null;
                    }

                    // get the list of dbs
                    while ($row = mysql_fetch_row($res)) {
                        ++$count;
                    }

                    // tidy up
                    mysql_close($link);
                    break;
            }

            // return number seen
            return $count;
        } catch (Exception $e) {
            die($e->getMessage());
        }
    }

    /**
     * Do we have any backup tables.
     *
     * @return string
     */
    private function hasBakTables()
    {
        $this->db->setQuery("SHOW TABLES WHERE `Tables_in_{$this->config->getCfg('db', '')}` like 'bak_%'");

        return $this->db->loadResult() ? true : false;
    }

    /**
     * See if we have any installation folders.
     *
     * @return string "TRUE|FALSE" if we do
     */
    private function hasInstallationFolders()
    {
        $folders = $this->getFolders(JPATH_BASE);
        foreach ($folders as $folder) {
            if (preg_match('/installation|installation.old|docs\/installation|install|installation.bak|installation.old|installation.backup|installation.delete/i', $folder)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Function taken from Akeeba filesystem.php.
     *
     * Akeeba Engine
     * The modular PHP5 site backup engine
     *
     * @copyright Copyright (c)2009 Nicholas K. Dionysopoulos
     * @license   GNU GPL version 3 or, at your option, any later version
     *
     * @version   Id: scanner.php 158 2010-06-10 08:46:49Z nikosdion
     */
    private function getFolders($folder)
    {
        // Initialize variables
        $arr   = array();
        $false = false;

        $folder = trim($folder);

        if (!is_dir($folder) && !is_dir($folder.DIRECTORY_SEPARATOR) || is_link($folder.DIRECTORY_SEPARATOR) || is_link($folder) || !$folder) {
            return $false;
        }

        if (@file_exists($folder.DIRECTORY_SEPARATOR.'.myjoomla.ignore.folder')) {
            return array();
        }

        $handle = @opendir($folder);
        if (false === $handle) {
            $handle = @opendir($folder.DIRECTORY_SEPARATOR);
        }
        // If directory is not accessible, just return FALSE
        if (false === $handle) {
            return $false;
        }

        while ((false !== ($file = @readdir($handle)))) {
            if (('.' != $file) && ('..' != $file) && (null != trim($file))) {
                $ds    = ('' == $folder) || (DIRECTORY_SEPARATOR == $folder) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) ? '' : DIRECTORY_SEPARATOR;
                $dir   = trim($folder.$ds.$file);
                $isDir = @is_dir($dir);
                if ($isDir) {
                    $arr[] = $this->cleanupFileFolderName(str_replace(JPATH_BASE, '', $folder.DIRECTORY_SEPARATOR.$file));
                }
            }
        }
        @closedir($handle);

        return $arr;
    }

    /**
     * Clean up a string, a path name.
     *
     * @param string $str
     *
     * @return string
     */
    private function cleanupFileFolderName($str)
    {
        $str = str_replace('////', '/', $str);
        $str = str_replace('///', '/', $str);
        $str = str_replace('//', '/', $str);
        $str = str_replace('\\/', '/', $str);
        $str = str_replace('\\t', '/t', $str);
        $str = str_replace("\/", '/', $str);

        return addslashes($str);
    }

    /**
     * The the number of super admins.
     *
     * @todo remove hard coded 8 and look for the correct group_id if people have messed with ACL
     *
     * @return int The number of super admins
     */
    private function getNumberOfSuperAdmins()
    {
        if (preg_match('/^1\.5/', $this->version)) {
            $this->db->setQuery('SELECT count(*) FROM #__users WHERE gid = 25');
        } else {
            $this->db->setQuery('SELECT count(*) FROM #__user_usergroup_map WHERE group_id = 8');
        }

        return (int) $this->db->LoadResult();
    }

    /**
     * Report if any users have a username of 'admin'.
     *
     * @return int
     */
    private function getAdminUserNameCount()
    {
        $this->db->setQuery('SELECT COUNT(*) FROM #__users WHERE username = "admin"');

        return (int) $this->db->LoadResult();
    }

    private function getNeverLoggedInUsersCount()
    {
        $this->db->setQuery('SELECT COUNT(*) FROM #__users WHERE lastvisitDate IS NULL');

        return (int) $this->db->LoadResult();
    }

    /**
     * See if we have extension installed.
     *
     * @return string "TRUE|FALSE" if we do
     */
    private function hasExtensionWithNameInstalled($name)
    {
        $count   = 0;
        $folders = $this->getFolders(JPATH_BASE.'/administrator/components/');
        foreach ($folders as $folder) {
            if (preg_match('/'.$name.'/i', $folder, $matches)) {
                ++$count;
            }
        }

        return $count;
    }

    private function hastmplogfolderswritable()
    {
        return is_writeable($this->config->getCfg('tmp_path')) && $this->config->getCfg('log_path');
    }

    /**
     * @return bool
     */
    private function hasUsedDefaultTemplate()
    {
        $core_templates = array(
            'atomic',
            'beez_20',
            'beez_5',
            'beez3',
            'ja_purity',
            'protostar',
            'rhuk_milkyway',
            'rhuk_milkyway_2',
        );

        if (preg_match('/^1\.5/', $this->version)) {
            $this->db->setQuery('SELECT template FROM #__templates_menu WHERE client_id = 0 limit 1');
        } else {
            $this->db->setQuery('SELECT template FROM #__template_styles WHERE client_id=0 AND home=1');
        }

        return (bool) in_array($this->db->loadResult(), $core_templates);
    }

    private function hastpequalsone()
    {
        if (strpos($this->version, '1.5.') || 1 == JComponentHelper::getParams('com_templates')
                ->get('template_positions_display')
        ) {
            // allowed - which is bad
            $tpequalsone = 1;
        } else {
            // not allowed - which is good
            $tpequalsone = 0;
        }

        return $tpequalsone;
    }

    private function fpaexists()
    {
        $files = scandir(JPATH_BASE);
        foreach ($files as $file) {
            if (preg_match('/fpa.*\.php/i', $file)) {
                return true;
            }
        }

        return false;
    }

    private function getErrorReportingLevel()
    {
        $er = $this->config->getCfg('error_reporting');
        if (!is_int($er)) {
            switch ($er) {
                case 'none':
                    $er = 0;
                    break;
                case 'simple':
                    $er = 7;
                    break;
                case 'maximum':
                    $er = 2047;
                    break;
                case 'development':
                    $er = -1;
                    break;
                default:
                    $er = $er; // yeah yeah I know!
                    break;
            }
        }

        return $er;
    }

    private function getNumberOfAkeebaBackups()
    {
        $count  = 0;
        $folder = JPATH_BASE.'/administrator/components/com_akeeba/backup';
        if (file_exists($folder)) {
            $folderContents = scandir($folder);

            foreach ($folderContents as $file) {
                if (preg_match('/\.jpa$/i', $file)) {
                    ++$count;
                }
            }
        }

        return $count;
    }

    private function hasmd5passwords()
    {
        $this->db->setQuery('SELECT count(*) FROM #__users WHERE CHAR_LENGTH(password) = 32');

        return (int) $this->db->LoadResult();
    }

    private function hastmplogfoldersdefaultpaths()
    {
        $logPath          = $this->config->getCfg('log_path');
        $tmpPath          = $this->config->getCfg('tmp_path');
        $expectedLogPath1 = JPATH_BASE.'/logs';
        $expectedLogPath2 = JPATH_BASE.'/administrator/logs'; // Introduced in Joomla 3.6.0
        $expectedTmpPath  = JPATH_BASE.'/tmp';

        return (int) (($expectedLogPath1 == $logPath || $expectedLogPath2 == $logPath) && $expectedTmpPath == $tmpPath);
    }

    private function getMaxAllowedPacket()
    {
        $this->db->setQuery('SHOW VARIABLES LIKE "max_allowed_packet"');
        $res = $this->db->loadObjectList();

        return $res[0]->Value;
    }

    /**
     * @return string
     */
    private function checkJCEVersion()
    {
        $versionFile = JPATH_BASE.'/administrator/components/com_jce/jce.xml';
        if (file_exists($versionFile)) {
            $xml = file_get_contents($versionFile);
            preg_match('/\<version\>(.*)\<\/version\>/', $xml, $matches);
            if (count($matches)) {
                return $matches[1];
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    private function checkfluff()
    {
        $fluffFiles = array(
            '/.drone.yml',
            '/robots.txt.dist',
            '/web.config.txt',
            '/joomla.xml',
            '/build.xml',
            '/LICENSE.txt',
            '/README.txt',
            '/htaccess.txt',
            '/LICENSES.php',
            '/configuration.php-dist',
            '/CHANGELOG.php',
            '/COPYRIGHT.php',
            '/CREDITS.php',
            '/INSTALL.php',
            '/LICENSE.php',
            '/CONTRIBUTING.md',
            '/phpunit.xml.dist',
            '/README.md',
            '/.travis.yml',
            '/travisci-phpunit.xml',
            '/images/banners/osmbanner1.png',
            '/images/banners/osmbanner2.png',
            '/images/banners/shop-ad-books.jpg',
            '/images/banners/shop-ad.jpg',
            '/images/banners/white.png',
            '/images/headers/blue-flower.jpg',
            '/images/headers/maple.jpg',
            '/images/headers/raindrops.jpg',
            '/images/headers/walden-pond.jpg',
            '/images/headers/windows.jpg',
            '/images/joomla_black.gif',
            '/images/joomla_black.png',
            '/images/joomla_green.gif',
            '/images/joomla_logo_black.jpg',
            '/images/powered_by.png',
            '/images/sampledata/fruitshop/apple.jpg',
            '/images/sampledata/fruitshop/bananas_2.jpg',
            '/images/sampledata/fruitshop/fruits.gif',
            '/images/sampledata/fruitshop/tamarind.jpg',
            '/images/sampledata/parks/animals/180px_koala_ag1.jpg',
            '/images/sampledata/parks/animals/180px_wobbegong.jpg',
            '/images/sampledata/parks/animals/200px_phyllopteryx_taeniolatus1.jpg',
            '/images/sampledata/parks/animals/220px_spottedquoll_2005_seanmcclean.jpg',
            '/images/sampledata/parks/animals/789px_spottedquoll_2005_seanmcclean.jpg',
            '/images/sampledata/parks/animals/800px_koala_ag1.jpg',
            '/images/sampledata/parks/animals/800px_phyllopteryx_taeniolatus1.jpg',
            '/images/sampledata/parks/animals/800px_wobbegong.jpg',
            '/images/sampledata/parks/banner_cradle.jpg',
            '/images/sampledata/parks/landscape/120px_pinnacles_western_australia.jpg',
            '/images/sampledata/parks/landscape/120px_rainforest_bluemountainsnsw.jpg',
            '/images/sampledata/parks/landscape/180px_ormiston_pound.jpg',
            '/images/sampledata/parks/landscape/250px_cradle_mountain_seen_from_barn_bluff.jpg',
            '/images/sampledata/parks/landscape/727px_rainforest_bluemountainsnsw.jpg',
            '/images/sampledata/parks/landscape/800px_cradle_mountain_seen_from_barn_bluff.jpg',
            '/images/sampledata/parks/landscape/800px_ormiston_pound.jpg',
            '/images/sampledata/parks/landscape/800px_pinnacles_western_australia.jpg',
            '/images/sampledata/parks/parks.gif',
        );

        $fluffCount = 0;
        foreach ($fluffFiles as $file) {
            $fileWithPath = JPATH_BASE.$file;
            if (file_exists($fileWithPath)) {
                ++$fluffCount;
            }
        }

        return (int) $fluffCount;
    }

    private function checkdbschema()
    {
        $schemaData = new stdClass();
        // Handle crap versions
        if (preg_match('/^1\.7/', $this->version) || preg_match('/^1\.6/', $this->version)) {
            $schemaData->latest  = '1.6';
            $schemaData->current = '1.6';

        // Handle Anything Recent
        } elseif (!preg_match('/^1\.5/', $this->version) && file_exists(JPATH_ADMINISTRATOR.'/components/com_installer/models/database.php')) {
            require JPATH_ADMINISTRATOR.'/components/com_installer/models/database.php';

            $InstallerModelDatabase = new InstallerModelDatabase();
            $changeSet              = $InstallerModelDatabase->getItems();

            $schemaData->latest  = $changeSet->getSchema();
            $schemaData->current = $InstallerModelDatabase->getSchemaVersion();
        } else { // Handle Joomla 1.5
            $schemaData->latest  = '1.5';
            $schemaData->current = '1.5';
        }

        return json_encode($schemaData);
    }

    private function checkRobotsBlocksMedia()
    {
        $robots_blocks_media = 0;

        if (file_exists(JPATH_BASE.'/robots.txt')) {
            $robotsTxTContent = file_get_contents(JPATH_BASE.'/robots.txt');

            if (preg_match('/Disallow:\s\/(templates|media)\//', $robotsTxTContent)) {
                $robots_blocks_media = 1;
            }
        }

        return $robots_blocks_media;
    }

    private function getAkeebaOutputDirectoryProblems()
    {
        $problems = 0;

        try {
            // If using PHP 5.2 then ABORT as Akeeba stuff needs newer PHP version
            if (version_compare(PHP_VERSION, '5.3.0', '<')) {
                throw new Exception('PHP version below 5.3.0');
            } else {
                require 'bfPHPFiveThreePlusOnly.php';
            }

            // Check Akeeba Installed - Prerequisite
            if (!file_exists(JPATH_SITE.'/libraries/f0f/include.php')
                || !file_exists(JPATH_SITE.'/administrator/components/com_akeeba/engine/Factory.php')
                || !file_exists(JPATH_SITE.'/administrator/components/com_akeeba/engine/serverkey.php')
            ) {
                throw new Exception('Cannot load Akeeba, maybe not installed');
            }

            if (!defined('AKEEBAENGINE')) {
                define('AKEEBAENGINE', 1);
            }

            require_once JPATH_SITE.'/libraries/f0f/include.php';
            require_once JPATH_SITE.'/administrator/components/com_akeeba/engine/Factory.php';

            $serverKeyFile = JPATH_BASE.'/administrator/components/com_akeeba/engine/serverkey.php';
            if (!defined('AKEEBA_SERVERKEY') && file_exists($serverKeyFile)) {
                include $serverKeyFile;
            }

            // Get the list of profiles
            $profileList = F0FModel::getTmpInstance('Profiles', 'AkeebaModel')->getProfilesList();

            // for each profile
            foreach ($profileList as $config) {
                // if encrypted
                if ('###AES128###' == substr($config->configuration, 0, 12)) {
                    $php53 = new bfPHPFiveThreePlusOnly();

                    $config->configuration = $php53->getAkeebaConfig($config->configuration);
                }

                // Convert ini to useable array
                $data = parse_ini_string($config->configuration, true);

                // find the folder
                $dir = $data['akeeba']['basic.output_directory'];

                if ('[DEFAULT_OUTPUT]' != $dir && (!is_writable($dir) || !file_exists($dir))) {
                    ++$problems;
                }
            }

            return $problems;
        } catch (Exception $e) {
            // No need to pass back issues when looking for Akeeba or PHP versions - we will just ignore it
            // After all if the site is running in PHP 5.2 they have bigger issues!!!

            return $problems;
        }
    }

    private function getDiskSpace()
    {
        $data = array(
            'free'  => disk_free_space(JPATH_BASE),
            'total' => disk_total_space(JPATH_BASE),
        );

        $data['used'] = $data['total'] - $data['free'];

        $data['percentUsed'] = sprintf('%.2f', ($data['used'] / $data['total']) * 100);

        $data['free']  = $this->formatSize($data['free']);
        $data['total'] = $this->formatSize($data['total']);
        $data['used']  = $this->formatSize($data['used']);

        return json_encode($data);
    }

    private function formatSize($bytes)
    {
        $types = array('B', 'KB', 'MB', 'GB', 'TB');
        for ($i = 0; $bytes >= 1024 && $i < (count($types) - 1); $bytes /= 1024, $i++);

        return round($bytes, 2).' '.$types[$i];
    }

    public function testEOLIssues()
    {
        $data = array();

        /**
         * Joomla 1,5 & 2.5 Series
         * [20151201] - Core - Remote Code Execution Vulnerability.
         *
         * @see    http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-8562
         * @secure md5 debug.php    Joomla 2.5.x    54a2f22406d8ee4b281d1a4543cb072b
         * @secure md5 session.php  Joomla 2.5.x    e9ac6f13100536eefa9241191c85c4b0
         * @secure md5 session.php  Joomla 1.5.x    63651a22d38b69f66959199955c5490c
         */
        $file  = JPATH_BASE.'/libraries/joomla/session/session.php';
        $file2 = JPATH_BASE.'/plugins/system/debug/debug.php';

        if (file_exists($file)) {
            $data['CVE20158562']['session'] = md5_file($file);
        } else {
            $data['CVE20158562']['session'] = 'NON_EXIST';
        }

        if (file_exists($file2)) {
            $data['CVE20158562']['debug'] = md5_file($file2);
        } else {
            $data['CVE20158562']['debug'] = 'NON_EXIST';
        }

        /**
         * Joomla 1,5.xxx.
         *
         * @see    http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=31626
         * @secure md5 media.php 3de2ea3338d49956b5dabf3a3fa1200d
         */
        $file = JPATH_BASE.'/administrator/components/com_media/helpers/media.php';

        if (file_exists($file)) {
            $data['fileupload_15']['media'] = md5_file($file);
        } else {
            $data['fileupload_15']['media'] = 'NON_EXIST';
        }

        /**
         * Joomla 1.5.xxx.
         *
         * @see    http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=31626
         * @secure md5 file.php 0eabdf91e2c7a26493eeb3dbe7a3fb39
         */
        $file = JPATH_BASE.'/libraries/joomla/filesystem/file.php';

        if (file_exists($file)) {
            $data['fileupload_15']['file'] = md5_file($file);
        } else {
            $data['fileupload_15']['file'] = 'NON_EXIST';
        }

        return json_encode($data);
    }

    /**
     * Run some very specific checks to see if this site is hacked or not.
     */
    private function checkIf100percentHackedOrNot()
    {
        // oh, not dont this yet :) doing it service site instead :)
    }

    private function getNewUserType()
    {
        $this->db->setQuery("SELECT params FROM #__extensions WHERE name ='com_users'");
        $paramsJsonString = $this->db->loadResult();
        preg_match('/new_usertype\":\"([0-9]*)\"/', $paramsJsonString, $matches);

        return count($matches) ? $matches[1] : null;
    }

    private function getNon2FaAdmins()
    {
        try {
            $this->db->setQuery("select count(*) from #__users as u
                              left join #__user_usergroup_map as ugm on ugm.user_id = u.id
                              where (otpKey = \"\"  or otpKey IS NULL)
                             and (ugm.group_id IN (select id from #__usergroups where title= 'Super Users'))");

            return $this->db->loadResult();
        } catch (\Exception $e) {
            return 0;
        }
    }

    /**
     * Check for joomla.user.helper.XXXXX usernames - hack seen in Q4 2016.
     *
     * @return mixed
     */
    private function checkJoomlaUserHelperHack2016()
    {
        $this->db->setQuery("select count(*) from #__users where username LIKE 'joomla.user.helper.%'");

        return $this->db->loadResult();
    }

    /**
     * Check the session gc plugin in Joomla 3.
     *
     * @return int
     */
    public function getSessionGCStatus()
    {
        $res = 2;

        // Session GC
        $this->db->setQuery("select count(*) from #__extensions where name = 'plg_system_sessiongc'");
        $hasSessionGcPlugin = $this->db->LoadResult();

        if ($hasSessionGcPlugin) {
            $this->db->setQuery("select enabled from #__extensions where name = 'plg_system_sessiongc'");
            $res = $this->db->LoadResult();
        }

        return $res;
    }

    /**
     * Check how many Two Factor Plugins are enabled.
     */
    public function getTwoFactorPluginsEnabled()
    {
        // Session GC
        $this->db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `folder` = 'twofactorauth' and enabled = 1");

        return $this->db->LoadResult();
    }

    /**
     * Load filters from com_config without using a helper.
     */
    public function getAdminFilterFixed()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_config'");
        $params = json_decode($this->db->LoadResult());

        if ('NONE' == $params->filters->{7}->filter_type) {
            return 0;
        } elseif ('BL' == $params->filters->{7}->filter_type) {
            return 1;
        } else {
            return 2;
        }
    }

    /**
     * Load sendpassword from params from com_users without using a helper.
     */
    public function getPlaintextpasswordsFixed()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_users'");
        $params = json_decode($this->db->LoadResult());

        return 1 - $params->sendpassword;
    }

    /**
     * Load Flash Upload Settings from params from com_media without using a helper.
     */
    public function getUploadsettingsfixed()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_media'");
        $params = json_decode($this->db->LoadResult());
        if (
            !preg_match('/swf/ism', $params->upload_extensions)
            &&
            !preg_match('/application\/x-shockwave-flash/ism', $params->upload_mime)
        ) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * Load params from com_content without using a helper.
     */
    public function getMailtofrienddisabled()
    {
        $this->db->setQuery("select params from #__extensions where element = 'com_content'");
        $params = json_decode($this->db->LoadResult());

        if (
            0 == $params->show_email_icon
        ) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * Get the configuration of the google recaptcha plugin and global config.
     */
    private function getCaptchaDetails()
    {
        $this->db->setQuery("SELECT count(*) FROM #__extensions WHERE (name ='plg_captcha_recaptcha' or name = 'plg_captcha_recaptcha_invisible') and enabled = 1");

        return 0 != $this->db->loadResult() ? 1 : 0;
    }

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

    private function hasUpdatesAvailable()
    {
        set_time_limit(60);
        ob_start();
        require 'bfUpdates.php';
        $upCheck                   = new bfUpdates();
        $extensionupdatesavailable = $upCheck->getUpdates(true);
        ob_clean();

        return $extensionupdatesavailable;
    }
}

$data = new bfSnapshot();
bfEncrypt::reply(bfReply::SUCCESS, $data->getData());
PK��#]|�wfK�K�"system/bfnetwork/bfnetwork/LICENSEnu�[���                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
PK��#]�+�37374system/bfnetwork/bfnetwork/lib/download/download.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */

/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class AcuDownload
{
    /**
     * Parameters passed from the GUI when importing from URL.
     *
     * @var array
     */
    private $params = array();

    /**
     * The download adapter which will be used by this class.
     *
     * @var AcuDownloadInterface
     */
    private $adapter = null;

    public function __construct()
    {
        // Find the best fitting adapter
        $allAdapters = AcuDownload::getFiles(dirname(__FILE__).'/adapter', array(), array('abstract.php'));
        $priority    = 0;

        foreach ($allAdapters as $adapterInfo) {
            $adapter = new $adapterInfo['classname']();

            if (!$adapter->isSupported()) {
                continue;
            }

            if ($adapter->priority > $priority) {
                $this->adapter = $adapter;
                $priority      = $adapter->priority;
            }
        }
    }

    /**
     * Forces the use of a specific adapter.
     *
     * @param  $className  The name of the class or the name of the adapter, e.g. 'AcuDownloadAdapterCurl' or 'curl'
     */
    public function setAdapter($className)
    {
        $adapter = null;

        if (class_exists($className, true)) {
            $adapter = new $className();
        } elseif (class_exists('AcuDownloadAdapter'.ucfirst($className))) {
            $className = 'AcuDownloadAdapter'.ucfirst($className);
            $adapter   = new $className();
        }

        if (is_object($adapter) && ($adapter instanceof AcuDownloadInterface)) {
            $this->adapter = $adapter;
        }
    }

    /**
     * Used to decode the $params array.
     *
     * @param string $key     The parameter key you want to retrieve the value for
     * @param mixed  $default The default value, if none is specified
     *
     * @return mixed The value for this parameter key
     */
    private function getParam($key, $default = null)
    {
        if (array_key_exists($key, $this->params)) {
            return $this->params[$key];
        } else {
            return $default;
        }
    }

    /**
     * Download data from a URL and return it.
     *
     * @param string $url The URL to download from
     *
     * @return bool|string The downloaded data or false on failure
     */
    public function getFromURL($url)
    {
        try {
            return $this->adapter->downloadAndReturn($url);
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Performs the staggered download of file.
     *
     * @param array $params A parameters array, as sent by the user interface
     *
     * @return array A return status array
     */
    public function importFromURL($params)
    {
        $this->params = $params;

        // Fetch data
        $filename    = $this->getParam('file');
        $frag        = $this->getParam('frag', -1);
        $totalSize   = $this->getParam('totalSize', -1);
        $doneSize    = $this->getParam('doneSize', -1);
        $maxExecTime = $this->getParam('maxExecTime', 5);
        $runTimeBias = $this->getParam('runTimeBias', 75);
        $minExecTime = $this->getParam('minExecTime', 1);

        $localFilename = 'myjoomla-upgradefile.zip';

        // This would have been //JFactory::getConfig()->get('tmp_path', JPATH_ROOT . '/tmp');
        $tmpDir = dirname(__FILE__).'/../../tmp';
        $tmpDir = rtrim($tmpDir, '/\\');

        /**
         * debugMsg('Importing from URL');
         * debugMsg('  file      : ' . $filename);
         * debugMsg('  frag      : ' . $frag);
         * debugMsg('  totalSize : ' . $totalSize);
         * debugMsg('  doneSize  : ' . $doneSize);.
         * /**/

        // Init retArray
        $retArray = array(
            'status'    => true,
            'error'     => '',
            'frag'      => $frag,
            'totalSize' => $totalSize,
            'doneSize'  => $doneSize,
            'percent'   => 0,
        );

        try {
            $timerParameters = array(
                'min_exec_time' => $minExecTime,
                'max_exec_time' => $maxExecTime,
                'run_time_bias' => $runTimeBias,
            );
            $timer = new AcuTimer($timerParameters);
            $start = $timer->getRunningTime(); // Mark the start of this download
            $break = false; // Don't break the step

            // Figure out where on Earth to put that file
            $local_file = $tmpDir.'/'.$localFilename;

            //debugMsg("- Importing from $filename");

            while (($timer->getTimeLeft() > 0) && !$break) {
                // Do we have to initialize the file?
                if (-1 == $frag) {
                    //debugMsg("-- First frag, killing local file");
                    // Currently downloaded size
                    $doneSize = 0;

                    if (@file_exists($local_file)) {
                        @unlink($local_file);
                    }

                    // Delete and touch the output file
                    $fp = @fopen($local_file, 'wb');

                    if (false !== $fp) {
                        @fclose($fp);
                    }

                    // Init
                    $frag = 0;

                    //debugMsg("-- First frag, getting the file size");
                    $retArray['totalSize'] = $this->adapter->getFileSize($filename);
                    $totalSize             = $retArray['totalSize'];
                }

                // Calculate from and length
                $length = 1048576;
                $from   = $frag * $length;
                $to     = $length + $from - 1;

                // Try to download the first frag
                $required_time = 1.0;
                //debugMsg("-- Importing frag $frag, byte position from/to: $from / $to");

                try {
                    $result = $this->adapter->downloadAndReturn($filename, $from, $to);

                    if (false === $result) {
                        throw new Exception(JText::sprintf('COM_CMSUPDATE_ERR_LIB_COULDNOTDOWNLOADFROMURL', $filename), 500);
                    }
                } catch (Exception $e) {
                    $result = false;
                    $error  = $e->getMessage();
                }

                if (false === $result) {
                    // Failed download
                    if (0 == $frag) {
                        // Failure to download first frag = failure to download. Period.
                        $retArray['status'] = false;
                        $retArray['error']  = $error;

                        //debugMsg("-- Download FAILED");

                        return $retArray;
                    } else {
                        // Since this is a staggered download, consider this normal and finish
                        $frag = -1;
                        //debugMsg("-- Import complete");
                        $totalSize = $doneSize;
                        $break     = true;
                    }
                }

                // Add the currently downloaded frag to the total size of downloaded files
                if ($result) {
                    $filesize = strlen($result);
                    //debugMsg("-- Successful download of $filesize bytes");
                    $doneSize += $filesize;

                    // Append the file
                    $fp = @fopen($local_file, 'ab');

                    if (false === $fp) {
                        //debugMsg("-- Can't open local file $local_file for writing");
                        // Can't open the file for writing
                        $retArray['status'] = false;
                        $retArray['error']  = JText::sprintf('COM_CMSUPDATE_ERR_LIB_COULDNOTWRITELOCALFILE', $local_file);

                        return $retArray;
                    }

                    fwrite($fp, $result);
                    fclose($fp);

                    //debugMsg("-- Appended data to local file $local_file");

                    ++$frag;

                    //debugMsg("-- Proceeding to next fragment, frag $frag");

                    if (($filesize < $length) || ($filesize > $length)) {
                        // A partial download or a download larger than the frag size means we are done
                        $frag = -1;
                        //debugMsg("-- Import complete (partial download of last frag)");
                        $totalSize = $doneSize;
                        $break     = true;
                    }
                }

                // Advance the frag pointer and mark the end
                $end = $timer->getRunningTime();

                // Do we predict that we have enough time?
                $required_time = max(1.1 * ($end - $start), $required_time);

                if ($required_time > (10 - $end + $start)) {
                    $break = true;
                }

                $start = $end;
            }

            if (-1 == $frag) {
                $percent = 100;
            } elseif ($doneSize <= 0) {
                $percent = 0;
            } else {
                if ($totalSize > 0) {
                    $percent = 100 * ($doneSize / $totalSize);
                } else {
                    $percent = 0;
                }
            }

            // Update $retArray
            $retArray = array(
                'status'    => true,
                'error'     => '',
                'frag'      => $frag,
                'totalSize' => $totalSize,
                'doneSize'  => $doneSize,
                'percent'   => $percent,
            );
        } catch (Exception $e) {
            //debugMsg("EXCEPTION RAISED:");
            //debugMsg($e->getMessage());
            $retArray['status'] = false;
            $retArray['error']  = $e->getMessage();
        }

        return $retArray;
    }

    /**
     * This method will crawl a starting directory and get all the valid files
     * that will be analyzed by __construct. Then it organizes them into an
     * associative array.
     *
     * @param string $path          Folder where we should start looking
     * @param array  $ignoreFolders Folder ignore list
     * @param array  $ignoreFiles   File ignore list
     *
     * @return array Associative array, where the `fullpath` key contains the path to the file,
     *               and the `classname` key contains the name of the class
     */
    protected static function getFiles($path, array $ignoreFolders = array(), array $ignoreFiles = array())
    {
        $return = array();

        $files = self::scanDirectory($path, $ignoreFolders, $ignoreFiles);

        // Ok, I got the files, now I have to organize them
        foreach ($files as $file) {
            $clean = str_replace($path, '', $file);
            $clean = trim(str_replace('\\', '/', $clean), '/');

            $parts = explode('/', $clean);

            $return[] = array(
                'fullpath'  => $file,
                'classname' => 'AcuDownloadAdapter'.ucfirst(basename($parts[0], '.php')),
            );
        }

        return $return;
    }

    /**
     * Recursive function that will scan every directory unless it's in the
     * ignore list. Files that aren't in the ignore list are returned.
     *
     * @param string $path          Folder where we should start looking
     * @param array  $ignoreFolders Folder ignore list
     * @param array  $ignoreFiles   File ignore list
     *
     * @return array List of all the files
     */
    protected static function scanDirectory($path, array $ignoreFolders = array(), array $ignoreFiles = array())
    {
        $return = array();

        $handle = @opendir($path);

        if (!$handle) {
            return $return;
        }

        while (false !== ($file = readdir($handle))) {
            if ('.' == $file || '..' == $file) {
                continue;
            }

            $fullpath = $path.'/'.$file;

            if ((is_dir($fullpath) && in_array($file, $ignoreFolders)) || (is_file($fullpath) && in_array($file, $ignoreFiles))) {
                continue;
            }

            if (is_dir($fullpath)) {
                $return = array_merge(self::scanDirectory($fullpath, $ignoreFolders, $ignoreFiles), $return);
            } else {
                $return[] = $path.'/'.$file;
            }
        }

        return $return;
    }
}
PK��#]�i�;;9system/bfnetwork/bfnetwork/lib/download/adapter/fopen.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * A download adapter using URL fopen() wrappers.
 */
class AcuDownloadAdapterFopen extends AcuDownloadAdapterAbstract implements AcuDownloadInterface
{
    public function __construct()
    {
        $this->priority              = 100;
        $this->supportsFileSize      = false;
        $this->supportsChunkDownload = true;
        $this->name                  = 'fopen';

        // If we are not allowed to use ini_get, we assume that URL fopen is
        // disabled.
        if (!function_exists('ini_get')) {
            $this->isSupported = false;
        } else {
            $this->isSupported = ini_get('allow_url_fopen');
        }
    }

    /**
     * Download a part (or the whole) of a remote URL and return the downloaded
     * data. You are supposed to check the size of the returned data. If it's
     * smaller than what you expected you've reached end of file. If it's empty
     * you have tried reading past EOF. If it's larger than what you expected
     * the server doesn't support chunk downloads.
     *
     * If this class' supportsChunkDownload returns false you should assume
     * that the $from and $to parameters will be ignored.
     *
     * @param string $url  The remote file's URL
     * @param int    $from Byte range to start downloading from. Use null for start of file.
     * @param int    $to   Byte range to stop downloading. Use null to download the entire file ($from is ignored)
     *
     * @return string the raw file data retrieved from the remote URL
     *
     * @throws Exception A generic exception is thrown on error
     */
    public function downloadAndReturn($url, $from = null, $to = null)
    {
        if (empty($from)) {
            $from = 0;
        }

        if (empty($to)) {
            $to = 0;
        }

        if ($to < $from) {
            $temp = $to;
            $to   = $from;
            $from = $temp;
            unset($temp);
        }

        if (!(empty($from) && empty($to))) {
            $options = array(
                'http' => array(
                    'method' => 'GET',
                    'header' => "Range: bytes=$from-$to\r\n",
                ), 'ssl' => array(
                    'verify_peer'      => false, // FFS!!! CRAP SERVERS
                    'verify_peer_name' => false, // FFS!!! CRAP SERVERS
                ),
            );
            $context = stream_context_create($options);
            $result  = @file_get_contents($url, false, $context, $from - $to + 1);
        } else {
            $options = array(
                'http' => array(
                    'method' => 'GET',
                ), 'ssl' => array(
                    'verify_peer'      => false, // FFS!!! CRAP SERVERS
                    'verify_peer_name' => false, // FFS!!! CRAP SERVERS
                ),
            );
            $context = stream_context_create($options);
            $result  = @file_get_contents($url, false, $context);
        }

        if (false === $result) {
            $error = JText::sprintf('COM_CMSUPDATE_ERR_LIB_FOPEN_ERROR');
            throw new Exception($error, 1);
        } else {
            return $result;
        }
    }
}
PK��#]�<�>>8system/bfnetwork/bfnetwork/lib/download/adapter/curl.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * A download adapter using the cURL PHP integration.
 */
class AcuDownloadAdapterCurl extends AcuDownloadAdapterAbstract implements AcuDownloadInterface
{
    public function __construct()
    {
        $this->priority              = 110;
        $this->supportsFileSize      = true;
        $this->supportsChunkDownload = true;
        $this->name                  = 'c'.'u'.'r'.'l';
        $this->isSupported           = function_exists('c'.'u'.'r'.'l'.'_init') && function_exists('c'.'u'.'r'.'l'.'_exec') && function_exists('c'.'u'.'r'.'l'.'_close');
    }

    /**
     * Download a part (or the whole) of a remote URL and return the downloaded
     * data. You are supposed to check the size of the returned data. If it's
     * smaller than what you expected you've reached end of file. If it's empty
     * you have tried reading past EOF. If it's larger than what you expected
     * the server doesn't support chunk downloads.
     *
     * If this class' supportsChunkDownload returns false you should assume
     * that the $from and $to parameters will be ignored.
     *
     * @param string $url  The remote file's URL
     * @param int    $from Byte range to start downloading from. Use null for start of file.
     * @param int    $to   Byte range to stop downloading. Use null to download the entire file ($from is ignored)
     *
     * @return string the raw file data retrieved from the remote URL
     *
     * @throws Exception A generic exception is thrown on error
     */
    public function downloadAndReturn($url, $from = null, $to = null, $nofollow = false)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

        if (empty($from)) {
            $from = 0;
        }

        if (empty($to)) {
            $to = 0;
        }

        if ($to < $from) {
            $temp = $to;
            $to   = $from;
            $from = $temp;
            unset($temp);
        }

        if (!(empty($from) && empty($to))) {
            curl_setopt($ch, CURLOPT_RANGE, "$from-$to");
        }

        if (!@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1) && !$nofollow) {
            // Safe Mode is enabled. We have to fetch the headers and
            // parse any redirections present in there.
            curl_setopt($ch, CURLOPT_AUTOREFERER, true);
            curl_setopt($ch, CURLOPT_FAILONERROR, true);
            curl_setopt($ch, CURLOPT_HEADER, true);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);

            // Get the headers.
            $data = curl_exec($ch);
            curl_close($ch);

            // Init
            $newURL = $url;

            // Parse the headers.
            $lines = explode("\n", $data);

            foreach ($lines as $line) {
                if ('Location:' == substr($line, 0, 9)) {
                    $newURL = trim(substr($line, 9));
                }
            }

            if ($url != $newURL) {
                return $this->downloadAndReturn($newURL);
            } else {
                return $this->downloadAndReturn($newURL, null, null, true);
            }
        } else {
            @curl_setopt($ch, CURLOPT_MAXREDIRS, 20);

            if (function_exists('set_time_limit')) {
                set_time_limit(0);
            }
        }

        $result = curl_exec($ch);

        $errno       = curl_errno($ch);
        $errmsg      = curl_error($ch);
        $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (false === $result) {
            $error = JText::sprintf('COM_CMSUPDATE_ERR_LIB_'.'C'.'U'.'R'.'L'.'_ERROR'.$errmsg, $errno, $errmsg);
        } elseif ($http_status > 299) {
            $result = false;
            $errno  = $http_status;
            $error  = JText::sprintf('COM_CMSUPDATE_ERR_LIB_HTTPERROR', $http_status);
        }

        curl_close($ch);

        if (false === $result) {
            throw new Exception($error, $errno);
        } else {
            return $result;
        }
    }

    /**
     * Get the size of a remote file in bytes.
     *
     * @param string $url The remote file's URL
     *
     * @return int The file size, or -1 if the remote server doesn't support this feature
     */
    public function getFileSize($url)
    {
        $result = -1;

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_NOBODY, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        $data = curl_exec($ch);
        curl_close($ch);

        if ($data) {
            $content_length = 'unknown';
            $status         = 'unknown';

            if (preg_match("/^HTTP\/1\.[01] (\d\d\d)/", $data, $matches)) {
                $status = (int) $matches[1];
            }

            if (preg_match("/Content-Length: (\d+)/", $data, $matches)) {
                $content_length = (int) $matches[1];
            }

            if (200 == $status || ($status > 300 && $status <= 308)) {
                $result = $content_length;
            }
        }

        return $result;
    }
}
PK��#]�0����<system/bfnetwork/bfnetwork/lib/download/adapter/abstract.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */

/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
abstract class AcuDownloadAdapterAbstract implements AcuDownloadInterface
{
    public $priority = 100;

    public $name = '';

    public $isSupported = false;

    public $supportsChunkDownload = false;

    public $supportsFileSize = false;

    /**
     * Does this download adapter support downloading files in chunks?
     *
     * @return bool True if chunk download is supported
     */
    public function supportsChunkDownload()
    {
        return $this->supportsChunkDownload;
    }

    /**
     * Does this download adapter support reading the size of a remote file?
     *
     * @return bool True if remote file size determination is supported
     */
    public function supportsFileSize()
    {
        return $this->supportsFileSize;
    }

    /**
     * Is this download class supported in the current server environment?
     *
     * @return bool True if this server environment supports this download class
     */
    public function isSupported()
    {
        return $this->isSupported;
    }

    /**
     * Get the priority of this adapter. If multiple download adapters are
     * supported on a site, the one with the highest priority will be
     * used.
     *
     * @return bool
     */
    public function getPriority()
    {
        return $this->priority;
    }

    /**
     * Returns the name of this download adapter in use.
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Download a part (or the whole) of a remote URL and return the downloaded
     * data. You are supposed to check the size of the returned data. If it's
     * smaller than what you expected you've reached end of file. If it's empty
     * you have tried reading past EOF. If it's larger than what you expected
     * the server doesn't support chunk downloads.
     *
     * If this class' supportsChunkDownload returns false you should assume
     * that the $from and $to parameters will be ignored.
     *
     * @param string $url  The remote file's URL
     * @param int    $from Byte range to start downloading from. Use null for start of file.
     * @param int    $to   Byte range to stop downloading. Use null to download the entire file ($from is ignored)
     *
     * @return string the raw file data retrieved from the remote URL
     *
     * @throws Exception A generic exception is thrown on error
     */
    public function downloadAndReturn($url, $from = null, $to = null)
    {
        return '';
    }

    /**
     * Get the size of a remote file in bytes.
     *
     * @param string $url The remote file's URL
     *
     * @return int The file size, or -1 if the remote server doesn't support this feature
     */
    public function getFileSize($url)
    {
        return -1;
    }
}
PK��#]�p
���5system/bfnetwork/bfnetwork/lib/download/interface.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */

/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
interface AcuDownloadInterface
{
    /**
     * Does this download adapter support downloading files in chunks?
     *
     * @return bool True if chunk download is supported
     */
    public function supportsChunkDownload();

    /**
     * Does this download adapter support reading the size of a remote file?
     *
     * @return bool True if remote file size determination is supported
     */
    public function supportsFileSize();

    /**
     * Is this download class supported in the current server environment?
     *
     * @return bool True if this server environment supports this download class
     */
    public function isSupported();

    /**
     * Get the priority of this adapter. If multiple download adapters are
     * supported on a site, the one with the highest priority will be
     * used.
     *
     * @return bool
     */
    public function getPriority();

    /**
     * Returns the name of this download adapter in use.
     *
     * @return string
     */
    public function getName();

    /**
     * Download a part (or the whole) of a remote URL and return the downloaded
     * data. You are supposed to check the size of the returned data. If it's
     * smaller than what you expected you've reached end of file. If it's empty
     * you have tried reading past EOF. If it's larger than what you expected
     * the server doesn't support chunk downloads.
     *
     * If this class' supportsChunkDownload returns false you should assume
     * that the $from and $to parameters will be ignored.
     *
     * @param string $url  The remote file's URL
     * @param int    $from Byte range to start downloading from. Use null for start of file.
     * @param int    $to   Byte range to stop downloading. Use null to download the entire file ($from is ignored)
     *
     * @return string the raw file data retrieved from the remote URL
     *
     * @throws Exception A generic exception is thrown on error
     */
    public function downloadAndReturn($url, $from = null, $to = null);

    /**
     * Get the size of a remote file in bytes.
     *
     * @param string $url The remote file's URL
     *
     * @return int The file size, or -1 if the remote server doesn't support this feature
     */
    public function getFileSize($url);
}
PK��#]��@߲�.system/bfnetwork/bfnetwork/lib/timer/timer.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * The Timer class is used to intelligently prevent timeout errors when
 * performing long operations.
 */
class AcuTimer
{
    /**
     * Maximum execution time allowance per step.
     *
     * @var int
     */
    private $max_exec_time = null;

    /**
     * Minimum execution time per step.
     *
     * @var int
     */
    private $min_exec_time = null;

    /**
     * Timestamp of execution start.
     *
     * @var int
     */
    private $start_time = null;

    /**
     * Public constructor, creates the timer object and calculates the
     * execution time limits.
     *
     * @param array $params The configuration parameters for the timer
     *
     * @return AcuTimer
     */
    public function __construct($params = array())
    {
        if (!is_array($params)) {
            $params = array();
        }

        $defaultParams = array(
            'max_exec_time' => 14,
            'min_exec_time' => 1,
            'run_time_bias' => 75,
        );

        $params = array_merge($defaultParams, $params);

        // Initialize start time
        $this->start_time = $this->microtime_float();

        // Store the minimum execution time
        $this->min_exec_time = $params['min_exec_time'];

        // Get configured max time per step and bias
        $config_max_exec_time = $params['max_exec_time'];
        $bias                 = $params['run_time_bias'] / 100;

        // Get PHP's maximum execution time (our upper limit)
        if (@function_exists('ini_get')) {
            $php_max_exec_time = @ini_get('maximum_execution_time');

            if ((!is_numeric($php_max_exec_time)) || (0 == $php_max_exec_time)) {
                // If we have no time limit, set a hard limit of about 10 seconds
                // (safe for Apache and IIS timeouts, verbose enough for users)
                $php_max_exec_time = 14;
            }
        } else {
            // If ini_get is not available, use a rough default
            $php_max_exec_time = 14;
        }

        // Apply an arbitrary correction to counter CMS load time
        $php_max_exec_time = $php_max_exec_time - max($php_max_exec_time * 0.1, 1);

        // Apply bias
        $php_max_exec_time    = $php_max_exec_time * $bias;
        $config_max_exec_time = $config_max_exec_time * $bias;

        // Use the most appropriate time limit value
        if ($config_max_exec_time > $php_max_exec_time) {
            $this->max_exec_time = $php_max_exec_time;
        } else {
            $this->max_exec_time = $config_max_exec_time;
        }
    }

    /**
     * Wake-up function to reset internal timer when we get unserialized.
     */
    public function __wakeup()
    {
        // Re-initialize start time on wake-up
        $this->start_time = $this->microtime_float();
    }

    /**
     * Gets the number of seconds left, before we hit the "must stop" threshold.
     *
     * @return float The time left in decimal seconds
     */
    public function getTimeLeft()
    {
        return $this->max_exec_time - $this->getRunningTime();
    }

    /**
     * Gets the time elapsed since object creation/unserialization, effectively how
     * long you have been processing data since you instantiated AcuTimer.
     *
     * @return float The number of elapsed time in decimal seconds
     */
    public function getRunningTime()
    {
        return $this->microtime_float() - $this->start_time;
    }

    /**
     * Returns the current timestamp in decimal seconds.
     *
     * @return float Current timestamp in decimal seconds
     */
    private function microtime_float()
    {
        list($usec, $sec) = explode(' ', microtime());

        return (float) $usec + (float) $sec;
    }

    /**
     * Enforce the minimum execution time. Call this at the end of your long
     * processing to make sure that it doesn't take less time than the
     * minimum execution time. This is used to avoid being blocked by
     * overzealous server protection solutions.
     */
    public function enforce_min_exec_time()
    {
        // Try to get a sane value for PHP's maximum_execution_time INI parameter
        if (@function_exists('ini_get')) {
            $php_max_exec = @ini_get('maximum_execution_time');
        } else {
            $php_max_exec = 10;
        }

        if (('' == $php_max_exec) || (0 == $php_max_exec)) {
            $php_max_exec = 10;
        }

        // Decrease $php_max_exec time by 500 msec we need (approx.) to tear down
        // the application, as well as another 500msec added for rounding
        // error purposes. Also make sure this is never going to be less than 0.
        $php_max_exec = max($php_max_exec * 1000 - 1000, 0);

        // Get the "minimum execution time per step" Akeeba Backup configuration variable
        $minexectime = $this->min_exec_time;

        if (!is_numeric($minexectime)) {
            $minexectime = 0;
        }

        // Make sure we are not over PHP's time limit!
        if ($minexectime > $php_max_exec) {
            $minexectime = $php_max_exec;
        }

        // Get current running time
        $elapsed_time = $this->getRunningTime() * 1000;

        // Only run a sleep delay if we haven't reached the minexectime execution time
        if (($minexectime > $elapsed_time) && ($elapsed_time > 0)) {
            $sleep_msec = $minexectime - $elapsed_time;

            if (function_exists('usleep')) {
                usleep(1000 * $sleep_msec);
            } elseif (function_exists('time_nanosleep')) {
                $sleep_sec  = floor($sleep_msec / 1000);
                $sleep_nsec = 1000000 * ($sleep_msec - ($sleep_sec * 1000));
                time_nanosleep($sleep_sec, $sleep_nsec);
            } elseif (function_exists('time_sleep_until')) {
                $until_timestamp = time() + $sleep_msec / 1000;
                time_sleep_until($until_timestamp);
            } elseif (function_exists('sleep')) {
                $sleep_sec = ceil($sleep_msec / 1000);
                sleep($sleep_sec);
            }
        } elseif ($elapsed_time > 0) {
            // No sleep required, even if user configured us to be able to do so.
        }
    }

    /**
     * Reset the timer. It should only be used in CLI mode!
     */
    public function resetTime()
    {
        $this->start_time = $this->microtime_float();
    }
}
PK��#]5��8DD(system/bfnetwork/bfnetwork/lib/.htaccessnu�[���<Files ~ "^.*$">
Order deny,allow
Deny from all
Satisfy all
</Files>PK��#]��TA�4�4Hsystem/bfnetwork/bfnetwork/lib/update/provider/collection/collection.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */

/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class AcuUpdateProviderCollection
{
    /**
     * Reads a "collection" XML update source and returns the complete tree of categories
     * and extensions applicable for platform version $jVersion.
     *
     * @param string $url      The collection XML update source URL to read from
     * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION
     *
     * @return array A list of update sources applicable to $jVersion
     */
    public function getAllUpdates($url, $jVersion = null)
    {
        // Get the target platform
        if (is_null($jVersion)) {
            $jVersion = JVERSION;
        }

        // Initialise return value
        $updates = array(
            'metadata' => array(
                'name'        => '',
                'description' => '',
            ),
            'categories' => array(),
            'extensions' => array(),
        );

        // Download and parse the XML file
        $donwloader = new AcuDownload();
        $xmlSource  = $donwloader->getFromURL($url);

        try {
            $xml = new SimpleXMLElement($xmlSource, LIBXML_NONET);
        } catch (Exception $e) {
            return $updates;
        }

        // Sanity check
        if (('extensionset' != $xml->getName())) {
            unset($xml);

            return $updates;
        }

        // Initialise return value with the stream metadata (name, description)
        $rootAttributes = $xml->attributes();
        foreach ($rootAttributes as $k => $v) {
            $updates['metadata'][$k] = (string) $v;
        }

        // Initialise the raw list of updates
        $rawUpdates = array(
            'categories' => array(),
            'extensions' => array(),
        );

        // Segregate the raw list to a hierarchy of extension and category entries
        foreach ($xml->children() as $extension) {
            switch ($extension->getName()) {
                case 'category':
                    // These are the parameters we expect in a category
                    $params = array(
                        'name'                  => '',
                        'description'           => '',
                        'category'              => '',
                        'ref'                   => '',
                        'targetplatformversion' => $jVersion,
                    );

                    // These are the attributes of the element
                    $attributes = $extension->attributes();

                    // Merge them all
                    foreach ($attributes as $k => $v) {
                        $params[$k] = (string) $v;
                    }

                    // We can't have a category with an empty category name
                    if (empty($params['category'])) {
                        continue;
                    }

                    // We can't have a category with an empty ref
                    if (empty($params['ref'])) {
                        continue;
                    }

                    if (empty($params['description'])) {
                        $params['description'] = $params['category'];
                    }

                    if (!array_key_exists($params['category'], $rawUpdates['categories'])) {
                        $rawUpdates['categories'][$params['category']] = array();
                    }

                    $rawUpdates['categories'][$params['category']][] = $params;

                    break;

                case 'extension':
                    // These are the parameters we expect in a category
                    $params = array(
                        'element'               => '',
                        'type'                  => '',
                        'version'               => '',
                        'name'                  => '',
                        'detailsurl'            => '',
                        'targetplatformversion' => $jVersion,
                    );

                    // These are the attributes of the element
                    $attributes = $extension->attributes();

                    // Merge them all
                    foreach ($attributes as $k => $v) {
                        $params[$k] = (string) $v;
                    }

                    // We can't have an extension with an empty element
                    if (empty($params['element'])) {
                        continue;
                    }

                    // We can't have an extension with an empty type
                    if (empty($params['type'])) {
                        continue;
                    }

                    // We can't have an extension with an empty version
                    if (empty($params['version'])) {
                        continue;
                    }

                    if (empty($params['name'])) {
                        $params['name'] = $params['element'].' '.$params['version'];
                    }

                    if (!array_key_exists($params['type'], $rawUpdates['extensions'])) {
                        $rawUpdates['extensions'][$params['type']] = array();
                    }

                    if (!array_key_exists($params['element'], $rawUpdates['extensions'][$params['type']])) {
                        $rawUpdates['extensions'][$params['type']][$params['element']] = array();
                    }

                    $rawUpdates['extensions'][$params['type']][$params['element']][] = $params;
                    break;

                default:
                    break;
            }
        }

        unset($xml);

        if (!empty($rawUpdates['categories'])) {
            foreach ($rawUpdates['categories'] as $category => $entries) {
                $update                           = $this->filterListByPlatform($entries, $jVersion);
                $updates['categories'][$category] = $update;
            }
        }

        if (!empty($rawUpdates['extensions'])) {
            foreach ($rawUpdates['extensions'] as $type => $extensions) {
                $updates['extensions'][$type] = array();

                if (!empty($extensions)) {
                    foreach ($extensions as $element => $entries) {
                        $update                                 = $this->filterListByPlatform($entries, $jVersion);
                        $updates['extensions'][$type][$element] = $update;
                    }
                }
            }
        }

        return $updates;
    }

    /**
     * Filters a list of updates, returning only those available for the
     * specified platform version $jVersion.
     *
     * @param array  $updates  An array containing update definitions (categories or extensions)
     * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION
     *
     * @return array|null The update definition that is compatible, or null if none is compatible
     */
    private function filterListByPlatform($updates, $jVersion = null)
    {
        // Get the target platform
        if (is_null($jVersion)) {
            $jVersion = JVERSION;
        }

        $versionParts          = explode('.', $jVersion, 4);
        $platformVersionMajor  = $versionParts[0];
        $platformVersionMinor  = (count($versionParts) > 1) ? $platformVersionMajor.'.'.$versionParts[1] : $platformVersionMajor;
        $platformVersionNormal = (count($versionParts) > 2) ? $platformVersionMinor.'.'.$versionParts[2] : $platformVersionMinor;
        $platformVersionFull   = (count($versionParts) > 3) ? $platformVersionNormal.'.'.$versionParts[3] : $platformVersionNormal;

        $pickedExtension   = null;
        $pickedSpecificity = -1;

        foreach ($updates as $update) {
            // Test the target platform
            $targetPlatform = (string) $update['targetplatformversion'];

            if ($targetPlatform === $platformVersionFull) {
                $pickedExtension   = $update;
                $pickedSpecificity = 4;
            } elseif (($targetPlatform === $platformVersionNormal) && ($pickedSpecificity <= 3)) {
                $pickedExtension   = $update;
                $pickedSpecificity = 3;
            } elseif (($targetPlatform === $platformVersionMinor) && ($pickedSpecificity <= 2)) {
                $pickedExtension   = $update;
                $pickedSpecificity = 2;
            } elseif (($targetPlatform === $platformVersionMajor) && ($pickedSpecificity <= 1)) {
                $pickedExtension   = $update;
                $pickedSpecificity = 1;
            }
        }

        return $pickedExtension;
    }

    /**
     * Returns only the category definitions of a collection.
     *
     * @param string $url      The URL of the collection update source
     * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION
     *
     * @return array An array of category update definitions
     */
    public function getCategories($url, $jVersion = null)
    {
        $allUpdates = $this->getAllUpdates($url, $jVersion);

        return $allUpdates['categories'];
    }

    /**
     * Returns the update source for a specific category.
     *
     * @param string $url      The URL of the collection update source
     * @param string $category The category name you want to get the update source URL of
     * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION
     *
     * @return string|null The update stream URL, or null if it's not found
     */
    public function getCategoryUpdateSource($url, $category, $jVersion = null)
    {
        $allUpdates = $this->getAllUpdates($url, $jVersion);

        if (array_key_exists($category, $allUpdates['categories'])) {
            return $allUpdates['categories'][$category]['ref'];
        } else {
            return null;
        }
    }

    /**
     * Get a list of updates for extensions only, optionally of a specific type.
     *
     * @param string $url      The URL of the collection update source
     * @param string $type     The extension type you want to get the update source URL of, empty to get all extension types
     * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION
     *
     * @return array|null An array of extension update definitions or null if none is found
     */
    public function getExtensions($url, $type = null, $jVersion = null)
    {
        $allUpdates = $this->getAllUpdates($url, $jVersion);

        if (empty($type)) {
            return $allUpdates['extensions'];
        } elseif (array_key_exists($type, $allUpdates['extensions'])) {
            return $allUpdates['extensions'][$type];
        } else {
            return null;
        }
    }

    /**
     * Get the update source URL for a specific extension, based on the type and element, e.g.
     * type=file and element=joomla is Joomla! itself.
     *
     * @param string $url      The URL of the collection update source
     * @param string $type     The extension type you want to get the update source URL of
     * @param string $element  The extension element you want to get the update source URL of
     * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION
     *
     * @return string|null The update source URL or null if the extension is not found
     */
    public function getExtensionUpdateSource($url, $type, $element, $jVersion = null)
    {
        $allUpdates = $this->getExtensions($url, $type, $jVersion);

        if (empty($allUpdates)) {
            return null;
        } elseif (array_key_exists($element, $allUpdates)) {
            return $allUpdates[$element]['detailsurl'];
        } else {
            return null;
        }
    }
}
PK��#]���r<M<M@system/bfnetwork/bfnetwork/lib/update/provider/joomla/joomla.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Provides update information for the Joomla! CMS.
 */
class AcuUpdateProviderJoomla
{
    /**
     * The source for LTS updates.
     *
     * @var string
     */
    protected static $lts_url = 'http://update.joomla.org/core/list.xml';

    /**
     * The source for STS updates.
     *
     * @var string
     */
    protected static $sts_url = 'http://update.joomla.org/core/sts/list_sts.xml';

    /**
     * The source for test release updates.
     *
     * @var string
     */
    protected static $test_url = 'http://update.joomla.org/core/test/list_test.xml';

    /**
     * Reads a "collection" XML update source and picks the correct source URL
     * for the extension update source.
     *
     * @param string $url      The collection XML update source URL to read from
     * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION
     *
     * @return string The URL of the extension update source, or empty if no updates are provided / fetching failed
     */
    public function getUpdateSourceFromCollection($url, $jVersion = null)
    {
        $provider = new AcuUpdateProviderCollection();

        return $provider->getExtensionUpdateSource($url, 'file', 'joomla', $jVersion);
    }

    /**
     * Reads an "extension" XML update source and returns all listed update
     * entries.
     *
     * @param string $url The extension XML update source URL to read from
     *
     * @return array An array of update entries
     */
    public function getUpdatesFromExtension($url)
    {
        // Initialise
        $ret = array();

        // Get and parse the XML source
        $donwloader = new AcuDownload();
        $xmlSource  = $donwloader->getFromURL($url);

        try {
            $xml = new SimpleXMLElement($xmlSource, LIBXML_NONET);
        } catch (Exception $e) {
            return $ret;
        }

        // Sanity check
        if (('updates' != $xml->getName())) {
            unset($xml);

            return $ret;
        }

        // Let's populate the list of updates
        foreach ($xml->children() as $update) {
            // Sanity check
            if ('update' != $update->getName()) {
                continue;
            }

            $entry = array(
                'infourl'        => array('title' => '', 'url' => ''),
                'downloads'      => array(),
                'tags'           => array(),
                'targetplatform' => array(),
            );

            $properties = get_object_vars($update);

            foreach ($properties as $nodeName => $nodeContent) {
                switch ($nodeName) {
                    default:
                        $entry[$nodeName] = $nodeContent;
                        break;

                    case 'infourl':
                    case 'downloads':
                    case 'tags':
                    case 'targetplatform':
                        break;
                }
            }

            $infourlNode               = $update->xpath('infourl');
            $entry['infourl']['title'] = (string) $infourlNode[0]['title'];
            $entry['infourl']['url']   = (string) $infourlNode[0];

            $downloadNodes = $update->xpath('downloads/downloadurl');
            foreach ($downloadNodes as $downloadNode) {
                $entry['downloads'][] = array(
                    'type'   => (string) $downloadNode['type'],
                    'format' => (string) $downloadNode['format'],
                    'url'    => (string) $downloadNode,
                );
            }

            $tagNodes = $update->xpath('tags/tag');
            foreach ($tagNodes as $tagNode) {
                $entry['tags'][] = (string) $tagNode;
            }

            $targetPlatformNode                 = $update->xpath('targetplatform');
            $entry['targetplatform']['name']    = (string) $targetPlatformNode[0]['name'];
            $entry['targetplatform']['version'] = (string) $targetPlatformNode[0]['version'];

            $ret[] = $entry;
        }

        unset($xml);

        return $ret;
    }

    /**
     * Determines the properties of a version: STS/LTS, normal or testing.
     *
     * @param string $jVersion       The version number to check
     * @param string $currentVersion The current Joomla! version number
     *
     * @return array The properties analysis
     */
    public function getVersionProperties($jVersion, $currentVersion = null)
    {
        // Initialise
        $ret = array(
            'lts' => true,
            // Is this an LTS release? False means STS.
            'current' => false,
            // Is this a release in the $currentVersion branch?
            'upgrade' => 'none',
            // Upgrade relation of $jVersion to $currentVersion: 'none' (can't upgrade), 'lts' (next or current LTS), 'sts' (next or current STS) or 'current' (same release, no upgrade available)
            'testing' => false,
            // Is this a testing (alpha, beta, RC) release?
        );

        // Get the current version if none is defined
        if (is_null($currentVersion)) {
            $currentVersion = JVERSION;
        }

        // Sanitise version numbers
        $jVersion       = $this->sanitiseVersion($jVersion);
        $currentVersion = $this->sanitiseVersion($currentVersion);

        // Get the base version
        $baseVersion = substr($jVersion, 0, 3);

        // Get the minimum and maximum current version numbers
        $current_minimum = substr($currentVersion, 0, 3);
        $current_maximum = $current_minimum.'.9999';

        // Initialise STS/LTS version numbers
        $sts_minimum = false;
        $sts_maximum = false;
        $lts_minimum = false;

        // Is it an LTS or STS release?
        switch ($baseVersion) {
            case '1.5':
                $ret['lts'] = true;
                break;

            case '1.6':
                $ret['lts']  = false;
                $sts_minimum = '1.7';
                $sts_maximum = '1.7.999';
                $lts_minimum = '2.5';
                break;

            case '1.7':
                $ret['lts']  = false;
                $sts_minimum = false;
                $lts_minimum = '2.5';
                break;

            default:
                $majorVersion = substr($jVersion, 0, 1);
                $minorVersion = substr($jVersion, 2, 1);

                if ('5' == $minorVersion) {
                    $ret['lts'] = true;
                    // This is an LTS release, it can be superseded by .0 through .4 STS releases on the next branch...
                    $sts_minimum = ($majorVersion + 1).'.0';
                    $sts_maximum = ($majorVersion + 1).'.4.9999';
                    // ...or a .5 LTS on the next branch
                    $lts_minimum = ($majorVersion + 1).'.5';
                } else {
                    $ret['lts'] = false;
                    // This is an STS release, it can be superseded by a .1/.2/.3/.4 STS release on the same branch...
                    $sts_minimum = $majorVersion.'.1';
                    $sts_maximum = $majorVersion.'.4.9999';
                    // ...or a .5 LTS on the same branch
                    $lts_minimum = $majorVersion.'.5';
                }
                break;
        }

        // Is it a current release?
        if (version_compare($jVersion, $current_minimum, 'ge') && version_compare($jVersion, $current_maximum, 'le')) {
            $ret['current'] = true;
        }

        // Is this a testing release?
        $versionParts    = explode('.', $jVersion);
        $lastVersionPart = array_pop($versionParts);

        if (in_array(substr($lastVersionPart, 0, 1), array('a', 'b'))) {
            $ret['testing'] = true;
        } elseif ('rc' == substr($lastVersionPart, 0, 2)) {
            $ret['testing'] = true;
        } elseif ('dev' == substr($lastVersionPart, 0, 3)) {
            $ret['testing'] = true;
        }

        // Find the upgrade relation of $jVersion to $currentVersion
        if (version_compare($jVersion, $currentVersion, 'eq')) {
            $ret['upgrade'] = 'current';
        } elseif ((false !== $sts_minimum) && version_compare($jVersion, $sts_minimum, 'ge') && version_compare($jVersion, $sts_maximum, 'le')) {
            $ret['upgrade'] = 'sts';
        } elseif ((false !== $lts_minimum) && version_compare($jVersion, $lts_minimum, 'ge')) {
            $ret['upgrade'] = 'lts';
        } elseif ($baseVersion == $current_minimum) {
            $ret['upgrade'] = $ret['lts'] ? 'lts' : 'sts';
        } else {
            $ret['upgrade'] = 'none';
        }

        return $ret;
    }

    /**
     * Filters a list of updates, making sure they apply to the specifed CMS
     * release.
     *
     * @param array  $updates  A list of update records returned by the getUpdatesFromExtension method
     * @param string $jVersion The current Joomla! version number
     *
     * @return array A filtered list of updates. Each update record also includes version relevance information.
     */
    public function filterApplicableUpdates($updates, $jVersion = null)
    {
        if (empty($jVersion)) {
            $jVersion = JVERSION;
        }

        $versionParts          = explode('.', $jVersion, 4);
        $platformVersionMajor  = $versionParts[0];
        $platformVersionMinor  = $platformVersionMajor.'.'.$versionParts[1];
        $platformVersionNormal = $platformVersionMinor.'.'.$versionParts[2];
        $platformVersionFull   = (count($versionParts) > 3) ? $platformVersionNormal.'.'.$versionParts[3] : $platformVersionNormal;

        $ret = array();

        foreach ($updates as $update) {
            // Check each update for platform match
            if ('joomla' != strtolower($update['targetplatform']['name'])) {
                continue;
            }

            $targetPlatformVersion = $update['targetplatform']['version'];

            if (($targetPlatformVersion !== $platformVersionMajor) && ($targetPlatformVersion !== $platformVersionMinor) && ($targetPlatformVersion !== $platformVersionNormal) && ($targetPlatformVersion !== $platformVersionFull)) {
                continue;
            }

            // Get some information from the version number
            $updateVersion     = $update['version'];
            $versionProperties = $this->getVersionProperties($updateVersion, $jVersion);

            if ('none' == $versionProperties['upgrade']) {
                continue;
            }

            // The XML files are ill-maintained. Maybe we already have this update?
            if (!array_key_exists($updateVersion, $ret)) {
                $ret[$updateVersion] = array_merge($update, $versionProperties);
            }
        }

        return $ret;
    }

    /**
     * Joomla! has a lousy track record in naming its alpha, beta and release
     * candidate releases. The convention used seems to be "what the hell the
     * current package maintainer thinks looks better". This method tries to
     * figure out what was in the mind of the maintainer and translate the
     * funky version number to an actual PHP-format version string.
     *
     * @param string $version The whatever-format version number
     *
     * @return string A standard formatted version number
     */
    public function sanitiseVersion($version)
    {
        $test                   = strtolower($version);
        $alphaQualifierPosition = strpos($test, 'alpha-');
        $betaQualifierPosition  = strpos($test, 'beta-');
        $rcQualifierPosition    = strpos($test, 'rc-');
        $rcQualifierPosition2   = strpos($test, 'rc');
        $devQualifiedPosition   = strpos($test, 'dev');

        if (false !== $alphaQualifierPosition) {
            $betaRevision = substr($test, $alphaQualifierPosition + 6);
            if (!$betaRevision) {
                $betaRevision = 1;
            }
            $test = substr($test, 0, $alphaQualifierPosition).'.a'.$betaRevision;
        } elseif (false !== $betaQualifierPosition) {
            $betaRevision = substr($test, $betaQualifierPosition + 5);
            if (!$betaRevision) {
                $betaRevision = 1;
            }
            $test = substr($test, 0, $betaQualifierPosition).'.b'.$betaRevision;
        } elseif (false !== $rcQualifierPosition) {
            $betaRevision = substr($test, $rcQualifierPosition + 5);
            if (!$betaRevision) {
                $betaRevision = 1;
            }
            $test = substr($test, 0, $rcQualifierPosition).'.rc'.$betaRevision;
        } elseif (false !== $rcQualifierPosition2) {
            $betaRevision = substr($test, $rcQualifierPosition2 + 5);
            if (!$betaRevision) {
                $betaRevision = 1;
            }
            $test = substr($test, 0, $rcQualifierPosition2).'.rc'.$betaRevision;
        } elseif (false !== $devQualifiedPosition) {
            $betaRevision = substr($test, $devQualifiedPosition + 6);
            if (!$betaRevision) {
                $betaRevision = '';
            }
            $test = substr($test, 0, $devQualifiedPosition).'.dev'.$betaRevision;
        }

        return $test;
    }

    /**
     * Reloads the list of all updates available for the specified Joomla! version
     * from the network.
     *
     * @param array  $sources  The enabled sources to look into
     * @param string $jVersion The Joomla! version we are checking updates for
     *
     * @return array A list of updates for the installed, current, lts and sts versions
     */
    public function getUpdates($sources = array(), $jVersion = null)
    {
        // Make sure we have a valid list of sources
        if (empty($sources) || !is_array($sources)) {
            $sources = array();
        }

        $defaultSources = array('lts' => true, 'sts' => true, 'test' => true, 'custom' => '');

        $sources = array_merge($defaultSources, $sources);

        // Use the current JVERSION if none is specified
        if (empty($jVersion)) {
            $jVersion = JVERSION;
        }

        // Get the current branch' min/max versions
        $versionParts      = explode('.', $jVersion, 4);
        $currentMinVersion = $versionParts[0].'.'.$versionParts[1];
        $currentMaxVersion = $versionParts[0].'.'.$versionParts[1].'.9999';

        // Retrieve all updates
        $allUpdates = array();
        foreach ($sources as $source => $value) {
            if ((false === $value) || empty($value)) {
                continue;
            }

            switch ($source) {
                case 'lts':
                    $url = self::$lts_url;
                    break;

                case 'sts':
                    $url = self::$sts_url;
                    break;

                case 'test':
                    $url = self::$test_url;
                    break;

                case 'custom':
                    $url = $value;
                    break;
            }

            $url = $this->getUpdateSourceFromCollection($url, $jVersion);

            if (!empty($url)) {
                $updates = $this->getUpdatesFromExtension($url);

                if (!empty($updates)) {
                    $applicableUpdates = $this->filterApplicableUpdates($updates, $jVersion);

                    if (!empty($applicableUpdates)) {
                        $allUpdates = array_merge($allUpdates, $applicableUpdates);
                    }
                }
            }
        }

        $ret = array(
            // Currently installed version (used to reinstall, if available)
            'installed' => array(
                'version' => '',
                'package' => '',
                'infourl' => '',
            ),
            // Current branch
            'current' => array(
                'version' => '',
                'package' => '',
                'infourl' => '',
            ),
            // Upgrade to STS release
            'sts' => array(
                'version' => '',
                'package' => '',
                'infourl' => '',
            ),
            // Upgrade to LTS release
            'lts' => array(
                'version' => '',
                'package' => '',
                'infourl' => '',
            ),
            // Upgrade to LTS release
            'test' => array(
                'version' => '',
                'package' => '',
                'infourl' => '',
            ),
        );

        foreach ($allUpdates as $update) {
            $sections = array();

            if ('current' == $update['upgrade']) {
                $sections[0] = 'installed';
            } elseif (version_compare($update['version'], $currentMinVersion, 'ge') && version_compare($update['version'], $currentMaxVersion, 'le')) {
                $sections[0] = 'current';
            } else {
                $sections[0] = '';
            }

            $sections[1] = $update['lts'] ? 'lts' : 'sts';

            if ($update['testing']) {
                $sections = array('test');
            }

            foreach ($sections as $section) {
                if (empty($section)) {
                    continue;
                }

                $existingVersionForSection = $ret[$section]['version'];

                if (empty($existingVersionForSection)) {
                    $existingVersionForSection = '0.0.0';
                }

                if (version_compare($update['version'], $existingVersionForSection, 'ge')) {
                    $ret[$section]['version'] = $update['version'];
                    $ret[$section]['package'] = $update['downloads'][0]['url'];
                    $ret[$section]['infourl'] = $update['infourl']['url'];
                }
            }
        }

        // Catch the case when the latest current branch version is the installed version (up to date site)
        if (empty($ret['current']['version']) && !empty($ret['installed']['version'])) {
            $ret['current'] = $ret['installed'];
        }

        return $ret;
    }
}
PK��#]�s�N� � Osystem/bfnetwork/bfnetwork/lib/AdminTools/Model/AdminPassword/AdminPassword.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */

namespace Akeeba\AdminTools\Admin\Model;

defined('_JEXEC') or die;

use JFile;
use JUserHelper;

/**
 * @copyright Copyright (c)2010-2018 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 * @license   Forked from Admin Tools 5.2.0
 * With huge thanks to Nicholas K. Dionysopoulos / Akeeba Ltd for their dedication to Joomla Security
 */
class AdminPassword
{
    /**
     * The username for the administrator password protection.
     *
     * @var string
     */
    public $username = '';

    /**
     * The password for the administrator password protection.
     *
     * @var string
     */
    public $password = '';

    /**
     * Applies the back-end protection, creating an appropriate .htaccess and
     * .htpasswd file in the administrator directory.
     *
     * @return bool
     */
    public function protect()
    {
        \JLoader::import('joomla.filesystem.file');

        $cryptpw      = $this->apacheEncryptPassword();
        $htpasswd     = $this->username.':'.$cryptpw."\n";
        $htpasswdPath = JPATH_ADMINISTRATOR.'/.htpasswd';
        $htaccessPath = JPATH_ADMINISTRATOR.'/.htaccess';

        if (!@file_put_contents($htpasswdPath, $htpasswd) && !JFile::write($htpasswdPath, $htpasswd)) {
            return false;
        }

        $path     = rtrim(JPATH_ADMINISTRATOR, '/\\').'/';
        $htaccess = <<<ENDHTACCESS
AuthUserFile "$path.htpasswd"
AuthName "Restricted Area"
AuthType Basic
require valid-user

RewriteEngine On
RewriteRule \.htpasswd$ - [F,L]
ENDHTACCESS;

        $status = @file_put_contents($htaccessPath, $htaccess);

        if (!$status) {
            $status = JFile::write($htaccessPath, $htaccess);
        }

        if (!$status || !is_file($path.'/.htpasswd')) {
            if (!@unlink($htpasswdPath)) {
                JFile::delete($htpasswdPath);
            }

            return false;
        }

        return true;
    }

    /**
     * Removes the administrator protection by removing both the .htaccess and
     * .htpasswd files from the administrator directory.
     *
     * @return bool
     */
    public function unprotect()
    {
        $htaccessPath = JPATH_ADMINISTRATOR.'/.htaccess';
        $htpasswdPath = JPATH_ADMINISTRATOR.'/.htpasswd';

        if (!@unlink($htaccessPath) && !JFile::delete($htaccessPath)) {
            return false;
        }

        if (!@unlink($htpasswdPath) && !JFile::delete($htpasswdPath)) {
            return false;
        }

        return true;
    }

    /**
     * Returns true if both a .htpasswd and .htaccess file exist in the back-end.
     *
     * @return bool
     */
    public function isLocked()
    {
        $htaccessPath = JPATH_ADMINISTRATOR.'/.htaccess';
        $htpasswdPath = JPATH_ADMINISTRATOR.'/.htpasswd';

        return @file_exists($htpasswdPath) && @file_exists($htaccessPath);
    }

    /**
     * @return string|null
     */
    protected function apacheEncryptPassword()
    {
        $os        = strtoupper(PHP_OS);
        $isWindows = 'WIN' == substr($os, 0, 3);

        $encryptedPassword = null;

        // First try to use bCrypt on Apache 2.4 TODO Reliably detect Apache 2.4
        /*
            if (defined('PASSWORD_BCRYPT') && version_compare(PHP_VERSION, '5.3.10', 'ge'))
            {
                $encryptedPassword = password_hash($password, PASSWORD_BCRYPT);
            }
        */

        // Iterated and salted MD5 (APR1)
        $salt              = JUserHelper::genRandomPassword(4);
        $encryptedPassword = $this->apr1_hash($this->password, $salt, 1000);

        // SHA-1 encrypted – should never run
        if (empty($encryptedPassword) && \function_exists('base64_encode') && \function_exists('sha1')) {
            $encryptedPassword = '{SHA}'.base64_encode(sha1($this->password, true));
        }

        // Traditional crypt(3) – should never run
        if (empty($encryptedPassword) && \function_exists('crypt') && !$isWindows) {
            $salt              = JUserHelper::genRandomPassword(2);
            $encryptedPassword = crypt($this->password, $salt);
        }

        // If all else fails use plain text passwords (only happens on Windows)
        if (empty($encryptedPassword)) {
            $encryptedPassword = $this->password;
        }

        return $encryptedPassword;
    }

    /**
     * Perform the hashing of the password.
     *
     * @param string $password   The plain text password to hash
     * @param string $salt       The 8 byte salt to use
     * @param int    $iterations The number of iterations to use
     *
     * @return string The hashed password
     */
    protected function apr1_hash($password, $salt, $iterations)
    {
        $len  = \strlen($password);
        $text = $password.'$apr1$'.$salt;
        $bin  = md5($password.$salt.$password, true);

        for ($i = $len; $i > 0; $i -= 16) {
            $text .= substr($bin, 0, min(16, $i));
        }

        for ($i = $len; $i > 0; $i >>= 1) {
            $text .= ($i & 1) ? \chr(0) : $password[0];
        }

        $bin = $this->apr1_iterate($text, $iterations, $salt, $password);

        return $this->apr1_convertToHash($bin, $salt);
    }

    /**
     * @param $text
     * @param $iterations
     * @param $salt
     * @param $password
     *
     * @return string
     */
    protected function apr1_iterate($text, $iterations, $salt, $password)
    {
        $bin = md5($text, true);

        for ($i = 0; $i < $iterations; ++$i) {
            $new = ($i & 1) ? $password : $bin;

            if ($i % 3) {
                $new .= $salt;
            }

            if ($i % 7) {
                $new .= $password;
            }

            $new .= ($i & 1) ? $bin : $password;
            $bin = md5($new, true);
        }

        return $bin;
    }

    /**
     * @param $bin
     * @param $salt
     *
     * @return string
     */
    protected function apr1_convertToHash($bin, $salt)
    {
        $tmp = '$apr1$'.$salt.'$';

        $tmp .= $this->apr1_to64(
            (\ord($bin[0]) << 16) | (\ord($bin[6]) << 8) | \ord($bin[12]),
            4
        );

        $tmp .= $this->apr1_to64(
            (\ord($bin[1]) << 16) | (\ord($bin[7]) << 8) | \ord($bin[13]),
            4
        );

        $tmp .= $this->apr1_to64(
            (\ord($bin[2]) << 16) | (\ord($bin[8]) << 8) | \ord($bin[14]),
            4
        );

        $tmp .= $this->apr1_to64(
            (\ord($bin[3]) << 16) | (\ord($bin[9]) << 8) | \ord($bin[15]),
            4
        );

        $tmp .= $this->apr1_to64(
            (\ord($bin[4]) << 16) | (\ord($bin[10]) << 8) | \ord($bin[5]),
            4
        );

        $tmp .= $this->apr1_to64(
            \ord($bin[11]),
            2
        );

        return $tmp;
    }

    /**
     * Convert the input number to a base64 number of the specified size.
     *
     * @param int $num  The number to convert
     * @param int $size The size of the result string
     *
     * @return string The converted representation
     */
    protected function apr1_to64($num, $size)
    {
        static $seed = '';

        if (empty($seed)) {
            $seed = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
                'abcdefghijklmnopqrstuvwxyz';
        }

        $result = '';

        while (--$size >= 0) {
            $result .= $seed[$num & 0x3f];
            $num >>= 6;
        }

        return $result;
    }
}
PK��#]L�4]%%-system/bfnetwork/bfnetwork/lib/autoloader.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see      https://myJoomla.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
/**
 * @copyright  Copyright (c)2010-2014 Nicholas K. Dionysopoulos
 * @license    GNU General Public License version 3, or later
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * The main class autoloader for the Akeeba CMS Update library.
 */
class AcuAutoloader
{
    /**
     * An instance of this autoloader.
     *
     * @var AcuAutoloader
     */
    public static $autoloader = null;

    /**
     * The path to the ACU library's root directory.
     *
     * @var string
     */
    public static $acuPath = null;

    /**
     * Initialise this autoloader.
     *
     * @return AcuAutoloader
     */
    public static function init()
    {
        if (null == self::$autoloader) {
            self::$autoloader = new self();
        }

        return self::$autoloader;
    }

    /**
     * Public constructor. Registers the autoloader with PHP.
     */
    public function __construct()
    {
        self::$acuPath = realpath(dirname(__FILE__));

        spl_autoload_register(array($this, 'autoload_acu_core'));
    }

    /**
     * The actual autoloader.
     *
     * @param string $class_name The name of the class to load
     */
    public function autoload_acu_core($class_name)
    {
        // Make sure the class has a FOF prefix
        if ('Acu' != substr($class_name, 0, 3)) {
            return;
        }

        // Remove the prefix
        $class = substr($class_name, 3);

        // Change from camel cased (e.g. DownloadCurl) into a lowercase array (e.g. 'download','curl')
        $class = preg_replace('/(\s)+/', '_', $class);
        $class = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $class));
        $class = explode('_', $class);

        // First try finding in structured directory format (preferred)
        $path = self::$acuPath.'/'.implode('/', $class).'.php';

        if (@file_exists($path)) {
            include_once $path;
        }

        // Then try the duplicate last name structured directory format (not recommended)

        if (!class_exists($class_name, false)) {
            reset($class);
            $lastPart = end($class);
            $path     = self::$acuPath.'/'.implode('/', $class).'/'.$lastPart.'.php';

            if (@file_exists($path)) {
                include_once $path;
            }
        }
    }
}
PK��#]�I���,system/bfnetwork/bfnetwork/bfWorkarounds.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * Provide some code so that pathetic sh404sef doesn't cause Internal Server Errors
 * We tried to "educate" them but they do not care enough to understand what they are doing is against Best Practice
 * and placing global functions in the global scope is highly frowned upon by professional developers, would have been better to
 * have created these as namespaces static methods.
 */
if (!function_exists('wbStartsWith')) {
    /**
     * Used by the installer plugin for sh404sef.
     *
     * @copyright Copyright (c) 2011 - 2017 - Weeblr,llc
     * @License GNU General Public License
     *
     * @param $haystack
     * @param $needles
     *
     * @return bool
     */
    function wbStartsWith($haystack, $needles)
    {
        if (is_string($needles)) {
            return !empty($needles) && 0 === strpos($haystack, $needles);
        } elseif (is_array($needles)) {
            foreach ($needles as $needle) {
                if (!empty($needle) && 0 === strpos($haystack, $needle)) {
                    return true;
                }
            }
        }

        return false;
    }
}
PK��#]92�#system/bfnetwork/bfnetwork/FIRSTRUNnu�[���/**
 * @package Blue Flame Network (bfNetwork)
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license GNU General Public License version 3 or later
 * @link https://myJoomla.com/
 * @author Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */

 // This file forces a first run experience and will be deleted after use.PK��#]�%�Ύ�"system/bfnetwork/bfnetwork/MD5SUMSnu�[���d32239bcb673463ab874e80d47fae504|LICENSE
96e9be6e65024087218c574b007d6b0a|README
d41d8cd98f00b204e9800998ecf8427e|bfnetwork
f966247c6436627f13ebc74bc5a8e503|bfnetwork.php
ac0c3a44622017e7e9529ed902949273|bfnetwork.xml
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/Crypt
ea149611ae21cb2de47973a352098144|bfnetwork/Crypt/.htaccess
3d8579424a20cccb0b1314610524daf8|bfnetwork/Crypt/Base.php
1437b0446d44d3535e9b9518ae4f9cb8|bfnetwork/Crypt/Hash.php
7f9d20144f8b695f4d66a761938aeffe|bfnetwork/Crypt/RC4.php
82fb04ff74a0339a8f03ce65add49ca5|bfnetwork/Crypt/RSA.php
923f0abe5f4463f4b7709e2dc4be66b7|bfnetwork/Crypt/Random.php
a824c25a321156988f57012e51b0f6bf|bfnetwork/FIRSTRUN
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/Keys
ea149611ae21cb2de47973a352098144|bfnetwork/Keys/.htaccess
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/Math
ea149611ae21cb2de47973a352098144|bfnetwork/Math/.htaccess
77d21a235b29565022ac91d294c226fa|bfnetwork/Math/BigInteger.php
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/VERSION
b34f5c588f36c26ded511e9fee871b86|bfnetwork/bfActivitylog.php
6e4851ac641af3565a58e4de82c9cf8d|bfnetwork/bfApplicationMyjoomla.php
d970225e641bf4ef088b890029f3f17f|bfnetwork/bfAudit.php
a132cb4a4d5f4793cefe5952890b3192|bfnetwork/bfAuditor.php
1ea8ef7017bc6f6a742fc8611d20556c|bfnetwork/bfAutologin.php
51d4b92686ca6db68913f34842e1271d|bfnetwork/bfBackup.php
e34c7ec12ff1b9892b43b04c148008a2|bfnetwork/bfConfig.php
64c80f2bbe518fc38a20c4c41f40926f|bfnetwork/bfDb.php
ffad5cb01468823c42560d51c27ba17d|bfnetwork/bfEncrypt.php
0a69b6be308e013facb523f7d38ca2f9|bfnetwork/bfError.php
4cf71ec221fecba19a9f9002fb2213f8|bfnetwork/bfExtensions.php
c935172dffee50ed81569e771c152d94|bfnetwork/bfFilesystem.php
c7fec4455bd81bae709345970ee73986|bfnetwork/bfInitJoomla.php
c39fe864d5e0135c50c871930cbdacae|bfnetwork/bfLog.php
f2b0cf7da83b71a0948a0c922bf62229|bfnetwork/bfPHPFiveThreePlusOnly.php
1cf3b815b701ecb9f804d798cfae466c|bfnetwork/bfPing.php
9c909fb038526a1db079706b06a42dae|bfnetwork/bfPlugin.php
63f6ff17245dd4611cc5a7610b1dc7e9|bfnetwork/bfPref.php
895649581faab4aab8c10b1aa1c4279a|bfnetwork/bfPreferences.php
ba00f339719575e142d67f0d6aa94c18|bfnetwork/bfRestore.php
94cd8774935a9c93048cc2acc1cd432e|bfnetwork/bfSnapshot.php
1103bb8bc8a0f0938a56eadc33d5d963|bfnetwork/bfStep.php
e1066adc9ea09f42b4c3f323ec7b3adb|bfnetwork/bfTimer.php
fc9a555444ee7e077013d7ea833d1d31|bfnetwork/bfTools.php
e18454d6e8f1f455765f86126e06412d|bfnetwork/bfUpdates.php
c24ca06d33136bde6c3ff309dd36c6df|bfnetwork/bfUpgrade.php
083114ee9d70a8de5008074211388307|bfnetwork/bfUpgradeConnector.php
d091c8093c2b87e24a8f04593d74f347|bfnetwork/bfVersion.php
aabebd822d17cfb108207f3116c8e9ed|bfnetwork/bfWorkarounds.php
e1c1b436422095b7148b77a3d507b8dd|bfnetwork/bfZip.php
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/db
ea149611ae21cb2de47973a352098144|bfnetwork/db/.htaccess
735d5ffae6ed406026ce381884593663|bfnetwork/db/blank.sql
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib
ea149611ae21cb2de47973a352098144|bfnetwork/lib/.htaccess
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/AdminTools
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/AdminTools/Model
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/AdminTools/Model/AdminPassword
69ae8d6a99dda81b62e4f2b68d96c120|bfnetwork/lib/AdminTools/Model/AdminPassword/AdminPassword.php
c8d0813559251e1dd36bf97a8dd6cbf3|bfnetwork/lib/autoloader.php
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/download
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/download/adapter
e66bb96449df4b83fcdf626d2c5e21ca|bfnetwork/lib/download/adapter/abstract.php
9246e1ee51bafe300ef74db965e0f34d|bfnetwork/lib/download/adapter/curl.php
a5fb26c92e73fe6832214044bcc9decd|bfnetwork/lib/download/adapter/fopen.php
28927884f9d73a5bde4be4c420714224|bfnetwork/lib/download/download.php
f206c5905997f3b817f06053ed74b268|bfnetwork/lib/download/interface.php
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/timer
4c1d8916810dd862f5b1b7509e479afd|bfnetwork/lib/timer/timer.php
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/update
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/update/provider
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/update/provider/collection
5aea7038d6f000432df3b5ca39cd4ba8|bfnetwork/lib/update/provider/collection/collection.php
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/lib/update/provider/joomla
d40d1be189b254cee102192c91864968|bfnetwork/lib/update/provider/joomla/joomla.php
af5a4d3b163be635f7d1c62c5d953f6f|bfnetwork/openssl.cnf
d41d8cd98f00b204e9800998ecf8427e|bfnetwork/tmp
ea149611ae21cb2de47973a352098144|bfnetwork/tmp/.htaccess
5206637339f365a4b0be439c92ebabb0|bfnetwork/tmp/index.php
ba5fccabe071ecb008efdba0f05b4fd6|install.bfnetwork.php
e1bcf0d52f465ce6c26985db0b0a207a|j25_30_bfnetwork.xml
A601883A50AAE51F2713E12DF7BA0B55324A02BC
A6018PK��#]�lQ((!system/bfnetwork/bfnetwork/READMEnu�[���@package Blue Flame Network (bfNetwork)
@copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Blue Flame Digital Solutions Limited. All rights reserved.
@license GNU General Public License version 3 or later
@link http://www.phil-taylor.com/
@author Phil Taylor / Blue Flame Digital Solutions Limited.

bfNetwork is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

bfNetwork is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this package.  If not, see http://www.gnu.org/licenses/

For more details please contact Phil Taylor <phil@phil-taylor.com>
This is the secure endpoint for the https://manage.myJoomla.com service
PK��#]kH�&**+system/bfnetwork/bfnetwork/bfInitJoomla.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

if (!defined('_BF_AUDIT')) {
    if (!defined('_JEXEC')) {
        define('_JEXEC', 1);
    }
    define('_BF_AUDIT', 1);

    // We need this
    if (!defined('DS')) {
        define('DS', DIRECTORY_SEPARATOR);
    }

    // find out where our Joomla Base paths are
    if (file_exists(dirname(__FILE__).'/../../../configuration.php')) {
        define('JPATH_BASE', realpath(dirname(__FILE__).'/../../../'));
        if (!defined('JPATH_ADMINISTRATOR')) {
            define('JPATH_ADMINISTRATOR', realpath(dirname(__FILE__).'/../../../administrator/'));
        }
        // Fake a path - Needed for pathetic extension update postFlights like JCH Optimise Plugin
        define('JPATH_COMPONENT', realpath(dirname(__FILE__).'/../../../administrator/components/com_plugins'));
    } else {
        define('JPATH_BASE', realpath(dirname(__FILE__).'/../../../../'));

        if (!defined('JPATH_ADMINISTRATOR')) {
            define('JPATH_ADMINISTRATOR', realpath(dirname(__FILE__).'/../../../../administrator/'));
        }

        // Fake a path -  Needed for pathetic extension update postFlights like JCH Optimise Plugin
        define('JPATH_COMPONENT', realpath(dirname(__FILE__).'/../../../../administrator/components/com_plugins'));
    }

    // Joomla requires this
    require_once JPATH_BASE.DS.'includes'.DS.'defines.php';
    require_once JPATH_BASE.DS.'includes'.DS.'framework.php';

    /**
     * Crazy - we need to override some methods of the app.
     */
    require 'bfApplicationMyjoomla.php';

    // Joomla 3.0.0+
    if (class_exists('JApplicationCms')) {
        // Ensure Joomla then uses our Application so we can override methods
        JFactory::getApplication('myjoomla');
    } else {
        // Joomla 1.5.0 - 1.5.26
        // Joomla 2.5.0 - 2.5.28
        JFactory::getApplication('site');
    }

    // Yeah we need this as well for some reason :-(
    jimport('joomla.html.parameter');
}
PK��#]3+}DD,system/bfnetwork/bfnetwork/bfPreferences.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */
final class bfPreferences
{
    /**
     * @var array
     */
    public $default_alerting_filewatchlist = array(
        '/includes/defines.php',
        '/includes/framework.php',
        '/configuration.php',
    );

    /**
     * @var string
     */
    private $dieStatement = "<?php\nheader('HTTP/1.0 404 Not Found');\ndie();\n?>\n";

    /**
     * Incoming decrypted vars from the request.
     *
     * @var stdClass
     */
    private $_dataObj;

    /**
     * @var string
     */
    private $_configFile;

    /**
     * @var mixed|stdClass
     */
    private $prefs;

    /**
     * PHP 5 Constructor,
     * I inject the request to the object.
     *
     * @param stdClass $dataObj
     */
    public function __construct($dataObj = null)
    {
        $this->_configFile = dirname(__FILE__).'/tmp/bfLocalConfig.php';

        // Set the request vars
        $this->_dataObj = $dataObj;

        $this->prefs = $this->getPreferences();
    }

    public function getPreferences()
    {
        $this->ensurePrefsFileCreated();

        $prefs = file_get_contents($this->_configFile);
        $prefs = trim(str_replace($this->dieStatement, '', $prefs));

        if (trim($prefs)) {
            $data = json_decode($prefs);
        } else {
            $data = new stdClass();
        }

        if (!is_object($data)) {
            $data = new stdClass();
        }

        if (!property_exists($data, '_BF_LOG')) {
            $data->_BF_LOG = false;
        }

        $this->prefs = $data;

        return $this->prefs;
    }

    public function ensurePrefsFileCreated()
    {
        if (!file_exists($this->_configFile)) {
            $this->prefs          = new stdClass();
            $this->prefs->_BF_LOG = false;
            $this->writeFile();
        }
    }

    public function writeFile()
    {
        file_put_contents($this->_configFile, $this->dieStatement);
        file_put_contents($this->_configFile, json_encode($this->prefs), FILE_APPEND);
    }

    /**
     * I'm the controller - I run methods based on the request integer.
     */
    public function run($action)
    {
        return $this->$action();
    }

    public function savePreferencesFromService()
    {
        $this->prefs = json_decode($this->_dataObj->preferences);
        $this->writeFile();
    }

    public function savePreference()
    {
        $preference = $this->_dataObj->preference;
        $value      = $this->_dataObj->value;

        $this->prefs->$preference = $value;

        $this->writeFile();
    }
}
PK��#]5��8DD'system/bfnetwork/bfnetwork/db/.htaccessnu�[���<Files ~ "^.*$">
Order deny,allow
Deny from all
Satisfy all
</Files>PK��#]����;�;�.system/bfnetwork/bfnetwork/db/suspectfiles.txtnu�[���'4d5db0b7d56d0fb9868ec2bbe13201cf',
'1d1fda5d67bcf2473a7bf1d16bd02d2b',
'c968aadd582681a799300b35046a36b9',
'9278b2ffccc475129731b22c021a8077',
'34ec439de67d517b805d2578ca38dcee',
'ce178378d1400b383173a19176ec41e1',
'2c33356a7347925e29ef553247e930c0',
'd9ed344ead8de37144d526d0cd405357',
'7e9416f512f0152e1620769c14fdefcc',
'd5ee7c1d09fdf0c41b81bba19b763cad',
'03b1ae6cfdfb13977ff27d56180145cd',
'e78ba8e87be703f89ad3c13c4d3696d7',
'ca8d7a6306b1681429b7fd26922da9fb',
'5649f024d4f099b697b6c6ed55acf1c9',
'7053fe2b6c8375a628ae490820a9f838',
'7cf15792a1381cb384df3f88bde3d8c6',
'effbc9085a8c574f289a57c4d171c2d7',
'dc494e1bbbdb7b22573a71783e7f70c0',
'9f30b21025660b725873a0b8d9bb0f1e',
'14ba39290a115f19d3efede10b677424',
'0634e582591a45e6103c97fa9cc8594b',
'3602f96263fd4e073e9afd7a2b3f0c9a',
'887bb4ae57ce8c57d69b90f7b349ec8e',
'2aa8b733aaaa101eed7ed68d53bb7ad6',
'd5e762bbeea68f8922f63b298424966d',
'2bde579f41c06a7350e789c59ca95c69',
'11e163419a78048edb691557a08e7f05',
'835870fbf2eb545ff82f2f5ae1ef55e7',
'02fff9a22e33ad0628152048020069a8',
'ac558ffd0d7b52ef49c334d71f720817',
'99265b1bef6d3e948c314b397879fbd4',
'22f71383be1c921d2963d540aec9e668',
'1b65b261d3f9008ea52aeab2c263c34e',
'a4e69ca3d6feef43a433dd8ea855f7b2',
'd96d07b59bfff6b91a3ba494b59d7498',
'19e0b5e832a1a1a35fffa09250d8e2c2',
'11d0d70054148e924e11eb1c3ae0ec85',
'6064c4649c42f282e84bb619948210d7',
'a99d4d022019b04e99ae18da44e401cd',
'11967a5086537323d4e35ee1ab53d30b',
'e817d944a175695aaf8fc5d24f4a7b48',
'c3299263239067ffe732b88150ba7c61',
'8124584c4dfad48559107fd2e0d7a071',
'2822a122812055da521c92f76846ea0e',
'e4f8c7fd6d9207209fca02e643bd3e5b',
'48abd091c4cc9abd92df923bc873322a',
'afcc99768f9edc0213d09302922bdc77',
'fbab0dbb9a3b8bb2a168c80f38ee6fe2',
'4a44d82da21438e32d4f514ab35c26b6',
'13dfb4262dc2ba43fc6e47490b92d901',
'ea276af218af3a1092e732f01a8ecd87',
'422928cb888289ab643fd0f56c6831ea',
'627682f9783007af90184ae1b18c7aa3',
'64f5dee3f8e1512f9f1138a394d4fe90',
'3c13602dca617278d97841378732cc13',
'1c84a3c6913438a4f61ea98723b92db2',
'f7db2264903de05c0c41d71a4c9ddba3',
'7b6196c35db1b85cf6e34bb19837308d',
'2e8595f8bc6afd1b352fac8a87b0279b',
'7dfbfdd24c285bcdf3203f3f9233ad37',
'aadc041d5ae2b4ff6098edd628206928',
'b508d5387b9de7c5aa973b4cea2bd5b4',
'a8c4e434e79d9eb240e1e4993c42f6be',
'ec5b7bef44eafad92fd970779de140a7',
'356c64133d03d2e048d2d361f72fa879',
'0eb78d7fd8f4d19591300b04e4ec70d3',
'c52d0f0dd29eecfc0f5da476e7f611f4',
'0e07974476dcd1ad73c1dcd971d1a575',
'4adb50c437ef902ab3d69f4b64388819',
'd708c88599a2c9e5567e6ad5a2481a13',
'5163436b1d9084f4b4840441816f8ac7',
'4047c2352f2e4ad66a2de45d9194c04f',
'bcb7f0d6998c7f9e9e32055194909277',
'99cd23063db0466f4f7de3bd9a3bcf04',
'92b5776f37d2a348b5e6c9339506b703',
'134f4cbe9d3f525bb22582709b301c5f',
'07c547a1e43cd95a0a2ee9465e04c12b',
'f481f9b86055d54d899d6714423f274d',
'2b6f4b9e794b0741608c22a2112b4583',
'7b0b3d01a88878df63dec648160181ef',
'1097df1d1c62d75e271367a2545995f5',
'02b081a32b616f0d62f68d550d490be8',
'48365b7f5bec62cc402992b80be83fd1',
'cbe778e347949b4bf81e49f15609bdaa',
'5b5a4465dd42bf9772de2a0a94040cf6',
'98c08ac3876ce6ec143e4017729928ff',
'dd024a0f6b49afe9a786ed2e8d2d64b3',
'331bbb2459a98edf8c0ba86f7d9e0d89',
'8f90fce3a2ae8edca02b5741c23d6457',
'b42eaf548b8123a66654a01fd359e3dc',
'5861da1c9a3c0d9c30c98802af538ad3',
'3817e2d2b71b9a2ae7214eafbc4b8f3d',
'17012f6735901498e5e51b4400c61373',
'54f7a358576c34454bbe5c01d52c0c27',
'a1aa7c6c5bcc42c6210d9037e677736c',
'4c9101bdf6a84fc66ef1ab3789152830',
'0fb22b6bf6d189886e7353f67eb948ce',
'92b3c897090867c65cc169ab037a0f55',
'af17d89167bd317c22d516fcfa01bd12',
'f51dcad408787b5fe90857937ffca9e6',
'9b22eb3f2fe4e3bbf2d3e8923e871151',
'9bc11267adfbb4c5ff71849670505531',
'598ad08539aba7093b349927efe853ee',
'a9522374c2dbd63884512f65878e505f',
'd152a50feed7748766ca8c4bc33b1929',
'3c356cbde81a425556ee4fdc6fd060ca',
'fc2bc0b0e94da3428b5811379b7a0c60',
'c8d3cecd7a3e40ced879ea5d8d09b53f',
'6557de8faa4aec646049d0566f032a33',
'0ddaa20e848f2dacb91c9ad6d281cef2',
'01c0cb27b4cec53a2693074c66e88afa',
'e08558050ebdca3e293a18b29aff3cd9',
'eb510572b83042116d7ea136f1e7f9de',
'874da23325fde16d0664b5dbbe3e81ca',
'2fc84f709e328db384764211be4ac3eb',
'fb9b6d52037c500f0ee0f3c7887800e2',
'0f142196087f614d9c9c056e59a6e45b',
'5f9108d50b5d198b9338f7d96538f62b',
'29c8fa1cf30236e01a2933f0a81a06a9',
'91a72aa97634c55d6d5ff8dcd1ed4766',
'f123f5d7108c30878bc08f92fe825335',
'569570c1d619911bafc1fe9091716a9c',
'9110625da1853df99c3616b6af08dc88',
'ae5d5aac9abfeacc9f357ffaf667b560',
'2a018d45199ebf0b0af837e1defd7f88',
'e036647dc32606fe6b4d57d57118667c',
'12ed793d7a460b3b89d3091cc763d67e',
'1ddcce0ead4e448b15c5ba00e7a393de',
'222c801443e051efe7c4eb9d9a62797f',
'43563b720945334bc7b780aec3b161e5',
'dd32d0d3aae5f921a71ce5b1946ae72f',
'afc2ca822dcff307a551dcd44f319311',
'53812da557e4ccde20565977f1809a31',
'dea9b8001cd112ab6d6191cf14191a9a',
'b2630dbb2b34b2389199b49f2154222a',
'31b197bd183741aca0cbc8d5ab7e5233',
'38494e445db55799ac83c3fcaf44b69d',
'438f8ccff6ff30a151e269e7e09aadd8',
'029fe7bdbeb93e8a82ebd1567c28d4a6',
'e1ac4fa19fb877b7abd8f4e09c70d7ac',
'b401a61c48ca1632cfd789aed388c764',
'eba8c0e1a5fcaec3befeb7cf0c3c6c79',
'2b54f9d6548627a1c8ab45088840613e',
'65ffa4f97915e44196918aff64cb3929',
'fa7b4d5aff86c3e043afe43e8effddb3',
'a6cb8373fabeb2d3bfe252c778f9f573',
'bcf15f9d50c86bf3bbf2554fa7fdb3fe',
'd2b7a8f95cf8311cb00fdae8d77cef44',
'0a9eb262b8f43a30b415bf0d5daab2a7',
'c5ef42f0231dc3517fcab3d17303e0ec',
'281e514c92f93b51a5091e1c5ddfc72f',
'fb7657394acca6a44cc7c610693288eb',
'367cda5c3f989de3676c8b5e3b969a97',
'86f9f5a877da9422114beb4382bd2a18',
'f4e371ffcce494f9fd50674d76783f7e',
'015b2c98259f7bd34423518260f19677',
'e4b4f01b976b7c14141be509473d9067',
'fe73b2d4ae762f1da24ceeeb3f708dfd',
'7465f70b0d50f47ebbcd2ced751a5263',
'bb821e3df2f9370f228748f3aed6bc6d',
'26c3e581aea46075867ed2d05a111e22',
'94b97faa79839e2106756898f377adf1',
'c86ac8cd104cea8815273b61a6ba210f',
'7d9ce31406a39be7188c370d0501305b',
'92eef8ff7c0402d15b47b268192a4b6a',
'de9abc2e38420cad729648e93dfc6687',
'4761279110762fc1a8156a74ec7fbfa8',
'143e93d348830f1770599f8080d75cb1',
'9781f1cadd0944fdedc2caca3f30540f',
'023f295a6d8ac39e8c9bade3a7de91e0',
'24235f5239cb15be5f3c8e75f3b8c308',
'5f6ddd7f8d783dd518ff37a061a86bba',
'70bf12a3d7d8cbdc66b198208ce8e433',
'5b19d2323e783fa57147b838b943b03c',
'b67f103bae3f8752c2b701bc59405fed',
'17cb34b1b80a8ddd351d3d06560df9ae',
'11f3d28bfec755396089ec15bacccf5a',
'aeee3bae226ad57baf4be8745c3f6094',
'e4f7b51acddb426445d96ec57634ecae',
'8a9971693f478adf4e08daee29575500',
'4dd9fbfcf13624e99625f1e99690b070',
'63f3b3aa824e244d06b1157db106e6f0',
'7233debb5d39b914aeba37fa64a22fbc',
'e08501d24a9900b8cf9729994403c87e',
'17cd2620e9323e86d2785f3025b5416b',
'456af71dea4b1b927aac5c667d474ce6',
'519f1a6fd98c7ba5974d3d69f343645f',
'b759b6f74a02604e12a7101807e42190',
'8e1230fc38976bc8af2943f59711c174',
'424a10cb2db4d66aa830bb55e581a962',
'e15e091f143e746767298ce67422ec68',
'513979e1a59697106db8e278a7c9edf7',
'c2f3327d60884561970c63ffa09439a4',
'261fe3131c3bf6d98c8c4b57eabaa9e2',
'27ac7578e817ba7172e7737c228cba93',
'f0de460c4b6907c4ea9300599953ec1c',
'3a325382c0f6a2df2099771588cd5892',
'99d1fe1dffc232c8f0445907b992dcd6',
'd8bee16ec2c35b05f2f45aa5631c87b1',
'4c2ba7b4ad5e1f81299f0ebfcb4b8039',
'cc20b1ff17d4465aef3ddf17a87fb7ea',
'e495edd01db19151ded1212eefe7a04f',
'4aa4a74526f8719fd1500b662777521a',
'5d7c3d2e99646ffb1a351ff719b8fe8f',
'73675399674293587332a4a23f1017bd',
'f8ca726633df4db6587ee91971b1d327',
'2ccab122319ff0998225913b286e1cd9',
'2f6d2543519e5d06090eb46c915e2773',
'3d9d6d7439cf40807fe7b19394ba6ec1',
'f618a5b2560c53c066dec5043dfba30a',
'b3e6c707dd529e67f9d0e4213e28d0b2',
'0303fdbaf3867c21736fa653d4761741',
'1cff935a5cc24e09e128b53b1f360fcd',
'f6c52f033976335d2622fafd0f4025d5',
'0a37bd7f1dccc8663e9afdd3bee6c9dd',
'19075f0de3d5eadf60a1195fb3876f23',
'f5b668ad24e0a859ed9a8106f9e7e3fe',
'263ad8d1e770f83414c7b8a5e985ab35',
'ed82338b0bff3fb1ca82320944a239a2',
'671cad517edd254352fe7e0c7c981c39',
'cc852d8b8664cc3401e5430b0a0260d7',
'00af247aad52a609f425834867ca0e9e',
'4c0894831c92a5ff441db97798e85df6',
'95fac0ff73a698462138f08a0f92cdaa',
'17949d40b9f06f660f05945ffd13a49f',
'c45c8f18e6f613a51e6805ad1947b793',
'896758c7515a5ee1ccb1727656f8a835',
'abf0e735f8312f44e586efea9b53f48d',
'6c7529d76e73c696d48e7e9092584751',
'0d784f7de517638fa08f514e3dbeef86',
'e23734a48ceea334b0bc3decda85fce2',
'e456c0f39d72ec056283809bd90fb11e',
'5453468f502a250fe52f9779032677d2',
'0fdb401a49fc2e481e3dfd697078334b',
'620e6dc8e252318465de768315e7f8be',
'1d44bf5bf37f6ddf834fe93499bbd7b4',
'76117b2ee4a7ac06832d50b2d04070b8',
'3cbaa7a14556fe2f128c000b4c503dc0',
'4a0c78bf2c5a95afa22f76991b64a6e3',
'4c3119846c2bd9428a3b51c07f680e6c',
'7bd41ec73a8993782528d6f6f862a0f7',
'7e741caaca692a726b33fc65e701f2b7',
'2132c41fc85868e533c3db80fd6b5dbc',
'eee7b594131f33f200110d52d474173f',
'5a73bb196ec671ad57084ead1f2cfed8',
'8f2cb74cabb33aad3e20885a6624fdfd',
'674784b2383f4fc885963d82e7d6d06f',
'cd2c645687f56c6987edd0ee0e5f4236',
'7a8f981234254394f3d13e5a5274e542',
'dcae2381d17528cf54c028ebd292f33e',
'9b9126470403aaf292874ca6e36b65e6',
'b4a8e73839c7898fa71cf1b46ace04f0',
'e530ae9cfe939600ad6dab3a8ad72bcb',
'51aae2ec7e032ecaf23f197083709abc',
'1fbe6997067ff8c92c44fead06dd9d48',
'09c8eaad7812e4a2b1ab34e13868515e',
'aa8ff3b5c5b8f48c03f793ca2b6c5cf3',
'4b67bd3d09ccd397a6d2a031f92a418d',
'fcca031d6823abfa0b64a5871b131fce',
'81c3a3c3099d441079382d3729161b80',
'e2499b9535963b2e89a8bb7c0a0cefd6',
'4e7daef57ae0a767c8d2e15d845a8d19',
'983d34e9f4642457ffef7f6cfdd2d138',
'62f3786e1ad43361242f11e0cf7e4a13',
'ecdc6c20f62f99fa265ec9257b7bf2ce',
'ab53d59df563d19db09ca74b9b538f68',
'1b0176b30d511e1e2389bac85007a95c',
'33ed70bed5ae6b03750d3921e10e9be7',
'6360d0316c594b8e2874603a893658f7',
'433361c7700757d23190646dd0a12ffc',
'cd6a3f7a7f3d61a753d475e0a4f8267b',
'a910c98eb8bfca366bb6972f68784d49',
'30d8c2c3bcbbbcb54eed761b061fd8bb',
'4758185b5a411d6715ec32ad56bb356d',
'12d2f6eccb2b43db59e9c8725a14e145',
'0a15f473e2232b89dae1075e1afdac97',
'302734228b4f2504b8658545a0acdbbc',
'4e14cee76754a7d5f565109dc7b45e1a',
'ce4418d99798a5860a147b788ec79e25',
'c12a3fb9033b8af390075d9af40b7abf',
'95db9e71c0d9fcfc44fc394c730d4d72',
'56ec5e0be577c34d5bf796096e4b2640',
'5cd135ae1aae2abb27b9163680cdd208',
'89b44581dd1760b0d7181692b28c2997',
'103bd1efff7aa80ae8a08512042323c8',
'd1e5ff0148adc4e479492c6e839ca08f',
'bf28095fbd4e6c9ce53ec4bd57ae6257',
'd9d01804d9db269d04e3d4e438d6b691',
'66538db73de257aef5ccc19ce7601d0e',
'997f3f20373bf62e999dcc33c26b34b1',
'b7d60812186d45467bc07972715c7d7d',
'73741e3a4fc30463893a6125bcceb4aa',
'7eeaaedf4bc0a501277b5b24942622a7',
'9e78cba9912b4a9ffdf248d08b0733e9',
'f0b65a12d95eca14fc9274d2e14e145e',
'ba80465b221d6b223605c36914069a56',
'fe304b6b0950e14acd7e41a64ca13aa7',
'80c047c2cb2a110967e5ccb525da0979',
'c6381412df74dbf3bcd5a2b31522b544',
'821d9d6020011a6812b3eb381e564ec8',
'a004228bff8d6b630b77f2e4725b11d7',
'5dc419f7f1be4d2cfc96732dc222534f',
'0dac7af66f67b898d1322a53e908e981',
'694cdfd9c864a922a2537be48d65075d',
'9e480fc5913077e53a1eef7fb565be9c',
'e5785783b55153f5cd6ebcc1a16f85db',
'cf7baa5e0dcffbd4294658e33ce381bc',
'8209e0d33edeafe1b764fff3ebc2073d',
'f95c9c83636dcc3eac85619651aa4e34',
'9c34adbc8fd8d908cbb341734830f971',
'433706fdc539238803fd47c4394b5109',
'9048eb92a615911f42453122b1fbfd60',
'c79514f54e99fb676e2c6065413a1e8f',
'f65b0744e5e323084b34e2ff879c058a',
'82a0f239662b084b48d2a2bfbfef68a2',
'5617bb54f38caedc04445eabd5a75448',
'a237a8cf68242c529602d832eb5fe7d6',
'cf7f7df18b2826d73872c8361f42d93b',
'71ad57c5141ac667264c2660ce3e128e',
'5bd9e01ea8bb786457b1998ac788b2df',
'c3c33abd2f89dde4ecf7f1136c3375fb',
'27f3ca5e2f42901fad204a70de304ab2',
'0dcb8d0cdf823292c1ae8e716317f3a9',
'c2bf9efc7dbeeb1e8e9dbd68d4725f61',
'7b9e0661b1a3118857900d6ea660717f',
'92682436b1407a128069c3e032d20293',
'840cf5d8ead81e7b06ff31519c75c13f',
'ad75185234db60de879a62b642eb37a8',
'7aef45a83f27f7dd234b6d30d11ecbad',
'2f3d56968bcf2706d8819be568e7f561',
'063274b4442cd836f29889731dce32e1',
'101bf59a74790aefb1622cc7c24cdc63',
'256989ef6c5960a27e289250afb270cd',
'0cfd6f6e640b50e59d8d4cf01e0099b8',
'6e6e5098ee09b58664412ab19d2b8e9d',
'bf79eb03ae10f2184be3ecb25de32c0f',
'262f481561c759f355fd34ab6934e162',
'fb03c8f5268b20893e045325cad1f0a6',
'94d1ab9737f4a7b1178557f8d8b844d5',
'715a70be2dd56ff07d6544d074e761be',
'8c63f645164a7591535c79f0d0b7fb6f',
'7b2ffa2bd6e53edace8f7d1a8f7eda30',
'c643609b68aef6b2ef90a07acef28f35',
'52d487f2f14e3b043eacdc18000a2182',
'abbe4c70b86d3ad3f4cd825bf72c6ff6',
'f504eaaec1b64dc779876eefe0b99c47',
'bba1d7bf558d28e31e2637e0d461002e',
'e9df0d19cd4dae98e652b2b527ba476d',
'45036a4bd5b9191af86b749d56036571',
'127f756662c86616b3b910b5c4b931dd',
'6141414e50f379579cd3097c2053ad32',
'705de793bcdc7e379a2b1fd13f9a4a28',
'4245991edf8d7f37c306832c99356179',
'5c2db49e43b74928bf6089b30b96ba2f',
'3359c4100d76251f805a8db9e1c2ded4',
'6a7a5b097ca75b54a5ddb492b23809af',
'0743c0fef030a4080bdc7ef8b6edfda5',
'78e0286ae8b5bc55e26ff5ccf70312fd',
'a78da83b026d7b04667fa651aeb380a2',
'f10fe46c812fb158d2fb978edbac4327',
'c7d7ac9c4bdaf60887841d452c329521',
'97e4952443a100c9d4dd3c0cb75552cb',
'e922175a966c95bc804a3fdce0b1df97',
'55f5d58fc57a60bb15ae7633826bf904',
'c21f7323c08616372c3d7b50e17b018f',
'6357fdeda0a4b6bbd8dd91f724a07033',
'34004a84a9c4446acec6702803b902d1',
'87a55d3264ad0b3e0e814b78f30d5c8c',
'45b9f42b3fa2c7c41b0add04c6d99d97',
'f6a826c1936a25c34163a75f4b57304a',
'5fd8ae04796228cfc33a7a15097d481b',
'5390145c0bbe91a6e47657f654e91661',
'c16454112e172284867e3aee00431d80',
'2c1ff6a96b6edbae45cbb3cf31035f4a',
'67387151bd437db1a91ca5c1fa9616a8',
'5cd65b3d41e0d372632a38efe5518b3c',
'ce0b8b2205b844cc3650a2857dd27200',
'6187ae7ee887d3a7aa5fc24584dd7dc2',
'b2632d92c4159c7f95510ca92c47dc86',
'1401a8687818430bb6161b39abad6669',
'41e65e58bde75c48bc930cb21f002573',
'5e84219ad384d860968a8536f359042f',
'0f68194315e83b4a78adbbfd90bf02e9',
'e5e6dbdfe8f7872b4395424c0c72646c',
'9cd35c25cc0a049864b9e04c7840f0c7',
'2f77ae56b2193218dbdf058125db1ddd',
'b8c2501553b210dcdac742e874dda381',
'fbd50d08c3bcd482d651c16a8f7a5a8b',
'f13a90107a117363edfdd86027883213',
'133c0acf8c506de59a1dbc80eadf8d10',
'f45904d1e2b6e7702c4b8a085d0b6212',
'60e07aee35721caff2c270e3abb8dfa9',
'1b743c72e020340ac62adf10eda00081',
'190f402aee718d8fd7cbc4911478ca66',
'37cb1db26b1b0161a4bf678a6b4565bd',
'493b0ad9457b5223eb1b9d35c1026e4a',
'9cc89e4c023ea0f63b9b1953a4da10fa',
'ea99285b565a27a7125cda7f2113ed31',
'd36cfe3fd47b1507002368f694674eec',
'2601b6fc1579f263d2f3960ce775df70',
'09abb2564b4ef0b0cc103c599a69c92a',
'd5051b2cfe9a44b22a5a71675118ddc8',
'530708fc06523d9b88e6e3659ca8bd26',
'54cf9f08fc11673bf7f2cd762a4855c0',
'6053238178de2d2709f438f0b7165ce1',
'c127cb33039e0af9809ab482ca7202ce',
'49c97aafd1b02c38cfaf7060c03b93a5',
'd5c7190afe8af5a3799cb2372b093ba1',
'4bc7b2775b2532a57a5d4c01cf7641d4',
'c76b83e72d4c6c5f848e149ef48904a6',
'a2fa083f51a7aa5e64748071f10a1a4d',
'b1e7c0ff4cf30a48d005547cff665d4a',
'17e7c477dd2635afddf0b51a0d939814',
'2f7f6468e2f68cb569d97cbc04bdc227',
'4fefaefd5762263696409b3c1409332f',
'fb11ac822458fa69c518dd3b77b78971',
'ab1a06ab1a1fe94e3f3b7f80eedbc12f',
'76864e8f6586cee1bbbbc3d3f7323c95',
'f6e94946506a78f2a6d6f4da1b95eca5',
'514c1829024d6ed1054de8aa80e3e457',
'09d3eaff9c4fddaa8f7b0bdd6d393945',
'800950b047a861ae34442065ec7289fb',
'4c26496cc8d2c12eb11dac56a91ead69',
'c48bcde7a0aae87f38aa7b8bce75a488',
'ac645217fbc892f693d36fa570e9926c',
'b028f0a6ce88e7e91563d3db1e3e0971',
'802c8899a377120091cf7521417ec6fb',
'aebdb79537e9ea5f416dba21f31d2e99',
'7898cb42245575ccb9390396d35242d4',
'51f849b488a3a62733d1b062ee761696',
'22d5d25f3dc6b29b041bb837b1377987',
'4ddbee879d889cf3ec31790d17ffbc7c',
'8ce758b60dd4f8e406d072a8d93d10f0',
'1dcc711d35772234413f54c0540efb9a',
'cb6e3f3a2c400684648edf38dee5b261',
'd47ba845c70b01c9b3f6705b401d2323',
'5bd7baec76c581166a0f60c1a5d87c64',
'a53135ddadac002428f3148f81543d9e',
'29fd18cc802dd5dba23328b0bfffce63',
'8107d548d896ad9c6fca9fd417491971',
'2756b16ffe059c9477bdf29fecd42fbe',
'62ede4381e1630c7d1c0be4ae42f22c8',
'974cd303c5936514aeadf3855516e9a3',
'9a3e47ea74d4881e89c4e654e629ef15',
'bdc34812acc230f42e0656215acd3e7f',
'd8e0b78a956b552b53ef060afc036a36',
'd99976060561269babd84e7d28d09454',
'c0a77d42bb53610b4ec2daf01cda55b1',
'e4699b17d580be67ef335afde2f4bbe2',
'e70fce1922c5ab59ed0995ec9f69231b',
'49859a9d06f364a0d99683521fbeccfa',
'd48ea0b869c00d5cc495616027730522',
'1fb666f72d28889cd27c42d9e69a3788',
'd9db3993bbe1a4c8fd49823547188876',
'0b95e48de94f253c44487f20fa70e90c',
'c49c43f44fd6f37912cf1b685ff3a854',
'941d939cc3440a09d7d9858b24815f41',
'a2516ac6ee41a7cf931cbaef1134a9e4',
'0e96d0e113f45a4cc1d0e4d48aa5cd4f',
'46455722874e0cd05e29a3af1af0e3c5',
'ef282b47ee5ee713bdbfce35f6b15086',
'1da5ebc26e1e0d6f0aac6fdd0c0d20d1',
'cfccfce0eea618015301dca4b0141186',
'ae1211d96aae6bfa0989419464de28f4',
'afd3c9925bbe5f8946c0368d2aea2ae7',
'c30ac261af1f41f25520151ca78a2156',
'a63bb400a0f0be079ec96193167358ff',
'aa29256307aafd1c6a75ca481e0211ef',
'f6c3ed146bd129140db566740e54af82',
'f7453fd1bcba5a07a9b3bb732e6f0845',
'5c4554bb0b501ed03337c0082e824629',
'677ad7e6d7f554da63158f0015610326',
'e67a0ea15f904ab7358390bbf647ac06',
'2c49b8b1f3804ea0fc1122216998df6d',
'7f62e0e3ecaee9fc1b4753a1d171be4e',
'91af8a5e8263f578cfdc3a8f7327f450',
'3a9a1351b313f0be6422eea2441652fe',
'c61e477d308081afac0da8f25a662a25',
'435d0eab8f087a1bbde016b862fe7a49',
'030c7a2d601cec034710d7ee38e3de87',
'8fd7560a7c8ccd50983a16c7df29d35f',
'016650123088967d6796ae291283a17f',
'65fb1a091a14d565719ea0c284d04b0b',
'e931e983fad14b1dc6927442430b0421',
'eaeac18c5345c9efacd07cd757e2ec66',
'3fb8aa5dd1daaf0499ede370c6761dec',
'8e3ba415c8745970b1e383290bf95e80',
'48b15f923cbaadb6e7d5c42f5268e65c',
'6dd86b8e4fa7a7f0509494ca9ee92385',
'49f3bb093942b686999665c4f664bf41',
'fe3fa14ce450f45387ae1d1753466861',
'1587f6428653aebdf182bd248bf78d44',
'81cfa30b7e8b30b46b7320f5939f57b8',
'47d42a852827d1802495ac63079aa0e4',
'31046ff8677637761ba9b4a1f0307f2d',
'c0433345fb537e764ef2ab4d74944fa7',
'aa41e8106ca552c8be396c66d8bb68c2',
'4d4bcfbbdb98cbe06958de7a0c3af278',
'c5b1f593bc1e47a01bf3ec962f9329b8',
'41acb4604476f675a1d7d427cd76954f',
'5bb39ef2f720148d51e08e994f84d2dc',
'056b707c63e42c76e814c0b475253031',
'2c8e8addc6b6612c9c8fbcd083d18c85',
'905985e7e6bb94117663a9ed93ee935a',
'587b75b35403031dd0948db203713b18',
'97b0ef6bbed3e6d5b2994d42530ed587',
'5b47a5fcce72dbccb08427aaf1ed2399',
'0191aa041e561ff8d501ba53b9a8db52',
'bbcb8ac361f0321f8aae38525d1c0023',
'431da4edbca6178fcd7a088d6271727e',
'419cfaac02d7366afdb3ccb8274df62d',
'5fbe4d8edeb2769eda5f4add9bab901e',
'4ec91a8d8d17cd0b4a5bb0ba29bc5cd8',
'bd86b55085dbb5014e4669f1e694b4aa',
'ddc45ea03b7c3c5e7a66b23afc2109ba',
'28937540114605e1607adc9182bc17e8',
'609022a523ee1001f730dbee66ac8de4',
'0f69b1056335f0bbd41225b39277c45a',
'a04ac1de8d497ffc0bc7369e74c545f4',
'90225d2ff1617a1767bbd9a0421b52c8',
'1c6fb0f70fd21fa8aa5eb4aaec4fcc22',
'd96b40ea6c0581cdff234abd63d9d5e0',
'd57179665b3a08bf1c131bbb1ca81613',
'b99d843c249bddebb87e7eb00cfb9523',
'5db32fe550107ce4352ec6d1fdef0738',
'28b79d6167765909e8b9fb1f8beaa1ae',
'57e6098b9bf84b8d43f5b5e8da63421e',
'2b4143735ebadb3c8c1d50a707ce16b2',
'a35fa0ac54354899724393f891204e94',
'fec2918cd42139ff8a2cde3de256c949',
'04f3efeaecc2d4f50188bb2224cf6d43',
'c2ac9f1fc6fd9065867e311c7def71cd',
'fbbbb17ea58e01136510a12afc896b54',
'52bc30360e13b306e4573eff0bc8c24d',
'2640b3613223dbb3606d59aa8fc0465f',
'3639b6cab850b817e0224adde0da40fb',
'331a685915dede3d796db9edeab8834e',
'f25fd5710350c86a16a89b38890840ff',
'd85d6eceac96491d48b34c5e7fa9ca9f',
'977e0253ae55042bea31b43dbe120daa',
'b85174a7f92882b170b3f6fef0d8ff91',
'7078ebfb074716c73cc8566a9e902d05',
'803875e26eba1cfa688ab753d894831e',
'6fe64fee184a8af6a42a1fe09aaa64f6',
'a2694d2b8766b47132bc281beb3d9ff8',
'b60a69b008da13ed81ed7aa5344f76b5',
'd2b8b07006036aee6d931bb8a665b7d4',
'4805cc7a165b2ac071c09ee548304e61',
'9379a2abcbc52a4ad3782f697d5a336d',
'cbb9b7ac9862ee8e347ab8f1d16bd467',
'e32a6cfe38dd7f818977837e3176c85d',
'4f9783e888d4cdc598067d978d6b9a42',
'95df6cdcc0054478c5af92a42204b11a',
'084e2a080e4ff2d6ec2a7f30e32a9ff6',
'6284f11596b8fa56690f82c195b8d19f',
'5920102ea13927221d706e0e369b0edd',
'd6ba41c61c3a40e2c4dac9628256581d',
'22ae1c989175a25f89034dbb6f8c4e44',
'e2d2f7fd59dc9e68a812bac8456f7714',
'6c5ad181cf59c12a81667c51649baa02',
'ee888d239d0a437b5e6e994f72d6bea8',
'115342e56512f289d282ba0802714822',
'ae23136814f9c4a557adc46975cbcb6c',
'09b41e5d031c7f1c26cc93e87bfb4574',
'c5e2da8a3879a4f7ecd4f0ebcbe6b368',
'e68dd41aac992ede9be7aa75d20853d0',
'e48e404c8f7d3819cdf88ff6b5067679',
'fcee555d2d967416b050c91debf3b116',
'e02f3fb754a1613cf40d15bdb6ca270e',
'8f3183476e598c9164f2ce5529ca37f0',
'45abe1843a22c69f15a59449a15ff9ed',
'8dd43372844dda4e8824ef5ff9f02106',
'14f12655b6dfa82b1ae2b1fd9bec88b9',
'd6bf7a852140c147186f606193207eab',
'cc7306e6863a365b4bbc610e4c2e7cb2',
'5414a69e5964bb208539f7d637bfa2be',
'470cd9a4d8583ede661fc2370e178f81',
'8023cb69e6a13124a6a6785eb2ab80ca',
'5fd0cdfb13941bbb42a0939a2393c532',
'fe063301db7542cf65146ba5d56e5874',
'a6e664f71967c7b2f3f311e67ffcd5ed',
'0d868a680af8756bc7ff33143a6fbf98',
'07fd1189ed0ee3e9adcce4326bac2ecb',
'6a587fb53b4e380a376e3e51260fe0e2',
'b98b8cb9494bbc3c628a894ce122b2e0',
'e736f10e6d27d4dd79e4c6312ff99082',
'e8051e0679aad090cecdef8affa61152',
'32aedb9c6b3cd397a70af00cb0903766',
'e76a939dc7ee687b6fba52a15b737741',
'0d305aad96d7c3416386cf5d4af7a8c6',
'7f5844f64288ab479e96d0d229e22502',
'77ad0698b7ea5ee1be10e351d30bd9fe',
'b8c62d52d4ac430b4ee6b994e53f918e',
'3f95a7a40b76e96690056afb524acdb7',
'04f1ecf7fce0ef662668cf723ae3b41e',
'dd6771e4f6d0f263c54bc98469f93076',
'b02cc65a8367d295f87264fdfe083aeb',
'2913ec3e47627cd3f2a4bfd0845635c1',
'28a1f242d1c75ee7a262a098c9b8b10d',
'527fe8a00bb3c8075a63fbecc89c2480',
'9ea3e5a36a0aeae6f58ba7eaee94820b',
'eb0987e8e0dc6be66a8430b6a4f08a1f',
'b5f723e9baf197cb1061d3b6cb3dcaa0',
'a4085c8366f6c0cc22258d993a803648',
'dd4f4e62ce28381499f3c5aac6d931de',
'3f84ba7c350d417ee2707948b3bc5280',
'4e9633e14152047f6551d4338e63a60f',
'ddef5f1a9493a405e13ead18d740ff54',
'9744216450e4f4e9826b83dbe1c88e7b',
'010f543b1a98396571c551f80f95b277',
'9535d2fc4f2f48ab1fba7a878deafc6e',
'6c18a5cb8771819248485b7fd4bb869d',
'03371e9561be4388e4cd5c8b2871d820',
'ad354405da14c4cdc5957cc84bc2ee49',
'a12fc0a3d31e2f89727b9678148cd487',
'c9f6cf566c0fa88626291b36e06e6b27',
'3d46e8aa00c8735ca99d3530c6378657',
'2026af41e292023897e9507876bd6fb1',
'6023fb45edb39060d7be8cdb213b5448',
'd4b643cdf3615b6d0d7dbb52efb7fabe',
'8da7175d2bc8f253ebdf7a73dec2468c',
'43e808182d2f2ef11fd5fe09b65b8e81',
'c3c0b62abab96ce3223a9535b7089e2b',
'fc6ca6f1aab9a753ed7fee76e8a5708b',
'4e2b77a4ff719d85cb34e8ff981d2d6a',
'988d837ae9f4d578526321622f226a50',
'960ce8ffac4508a2ce2e564fbd735f0a',
'cfc70703070e19c5b3fe70d98ba2be94',
'ba333a424a4d6e90d66232166de37e99',
'254be330a6a1c53360bad9d058909ed8',
'af5ac0aecc55a21be600155dc88305eb',
'29ac8d4885ad0ecf41f69ef74a6fc968',
'f79e91bcd99eb9e5950a6e1129ea4561',
'974678fa1237a1379fe86f02ba931159',
'49ac8e46b8e09723f4d5ed7f494b93ff',
'bff39d02edca4556cdd57278ff2a903b',
'4aff43e0200f4ca5fd975e327001a90d',
'a903ab874db01275e02f252e93dd65d1',
'748a602172b8c15c7a2f1d214f5ee3e8',
'498faf29f55e80d0152b4acd3c28eea6',
'db0ba00d94962bea1bab188ed1a1c198',
'52779a27fa377ae404761a7ce76a5da7',
'e4a469ca03717f18fd3a03dea5425e79',
'cc8c76ed613eb05f83e4c2eef231f86c',
'd5cd613a8e8f24c8312f65a726eab252',
'945e1b27d84fa1bf6afdb86cc9124f8f',
'3eb3004f266c8dc0b06a82566db25a64',
'7477a3904dfd75354a28910188609c42',
'0714f80f35c1fddef1f8938b8d42a4c8',
'9a928d741d12ea08a624ee9ed5a8c39d',
'aa8e796b7a75143fefb6b928e4783a22',
'bd150f5b4b9a6bd382600ab594a6c024',
'd7a4b0df45d34888d5a09f745e85733f',
'5105ef6fcc841e6cd9a6a8ae4d37a8d7',
'1c555e799955ab952080e225ccda2db0',
'e250739b6264a815aaceb65dbdf0dc89',
'7ea39bb5703f9e2915075172c091688a',
'e4c1c6f8139158634abd8337f04663cb',
'629d1d030405a33b71c94083ce53f410',
'70d67c16955980d1fcf9f28736c1633a',
'5d796fc7745dbd4eda9106adb8a30fe5',
'4f90a524e348d5e3de6b0e557b1622f2',
'c20643f4628f2b8a5265f3fce71a3194',
'1432d04cd9588acfa47f7d9b55c0c471',
'31d5398067e7250e5fccd4c1ac177126',
'0f54aa09f2e7425832f28c42210be2ba',
'1445f3010b5f8e274dc7ba21e7e5df63',
'6a59820887e35fb417bee13f2b7c3262',
'd170e951995affe723c9a912a524c4bf',
'f1d25710d85f821e1c4b73ada0666707',
'b6a0311f8e7f4da60527acdce6714ff9',
'7a08738c49ea3fda7186baeb403e08a2',
'bd6d3b2763c705a01cc2b3f105a25fa4',
'e1b54c87b3ce52d4dcc5c4bf6fb14ea8',
'05177f85587bcbd55cab3487c3a8e5ec',
'2225a6245b3b057a504e51f9f3446913',
'e3240f7625d139b4eb792f46bca17942',
'ad592b1bb7a702731723cf665cf5180e',
'2e780298a0cb88d9a8a6f6a527c5fdeb',
'4974e78169be76a0f8cc34e26133ee65',
'be1b1376517c009d41621faa5f7bb5d4',
'8bc2885476426e1ff4b7c8b3e4b63796',
'47ec667679eb826374a24963b227cda6',
'b5fac76cbde229ce148e13524818c9ee',
'b67b8c2e07ec38fc5552b532cf6b067a',
'fe7d2ce8ea774265d195f8b8aced4af1',
'f7df292483d93a30a94979ce30a5ca24',
'e2e4dad3d34d7be5a79f9d52d555a726',
'54d2f140d44f5e144746679551e17b03',
'a3b3c3a34deea620f59cf7a244c86f27',
'fc30f06f126119f7c8ec000614d76b02',
'44b1eca72e8044efc61c0e269b2bd971',
'a34658781bb75403b169a3761bcb8d6f',
'4c1fba0b142b68744403b38420d88209',
'3d9bfca1d4ba4ae6edac82a3c0cea01d',
'783e88fdb779f6fdeb4fc010b7a69641',
'f2479982e0c8233bb76dc1f3c2bfa74b',
'381de34490a843dc548da6d91f60bf0c',
'8b5b60fe83c509435d8a6d2fd40e81e1',
'2aa7d396a98c378f1ef36f47f9c3602b',
'a9d7dc04f538098a0ac2861eb1d27d6f',
'6e9cdf50a23d9f0f4a11457a7c8bad48',
'3773c319c18154ed2362962ed7291aa7',
'611702ed7145b8919ae344872ee42638',
'b944ea6f1592b32310cceb311d195002',
'97593c85ef4fcb6eb96d1197a7addd7d',
'b0ad76404908295782346399b79d9341',
'fa18e5a2b3262bf70ae4961bb751cf09',
'ba05c5edda2e8fb2f1198d2ed9f0fdf8',
'e1eb385aa1fa3bc5d396899d2f30a786',
'0540d337db2ee453f8b14b4b989ca93a',
'18adee9cfb9224738107bb43b3f3c17b',
'21d6a4f65f26e8f1dae1e03d513fd208',
'b6661795dcade3a85a444cbb89787cd3',
'be0f67f3e995517d18859ed57b4b4389',
'0b5e7a4b11ff67a7e3d589284fd87093',
'bf2935232e37f1f2be7f5e08a0664f68',
'30a44b1eb6e41d76059163b079718349',
'3a2ca46ec07240b78097acc2965b352e',
'3eb1ee91f0df8730acd4ca73ef1af8fd',
'ea55af78557177cd1304089ab0b47e5b',
'7e6901503e2ddbb8e619bff6c78b8d7e',
'db9345fe04c675e8547910706f7c5d23',
'eb874e7221f0afb26203e611ec523f13',
'9c5bb5e3a46ec28039e8986324e42792',
'aff158199157c2a5c6addf7bb7d692a5',
'0f477d309284d24717422e310c30a542',
'9d56fab43db2bf26c022a31597a841d0',
'dbb738aa0cff75228cb720e60bcd0de8',
'23c7663b967b6713b1638cfcd1aca162',
'e262f14677cbb0efe6bf834a28ddd813',
'c3f670be6abda78006803d34bb44ebe2',
'6eae2ba7165f71a0a6fc356498fa9696',
'fbd00a364d4d0cd9392f1f320cd89f37',
'839c3afafb9a570e24eccd1b9b89f60a',
'690af50547f964f79ffcea7aee1b698a',
'c065578c1a178387342a5495cb6ddda8',
'3645f66a9ef284af236d563b49a6ea5a',
'd1feab8f9c2deb1526de101793d28f50',
'd0d836fd39292c05f7cb8f34c4e9c651',
'4a84ea06e1c068a84d90a32e89a98bb4',
'87f092ef325e601e189ef82b51c9e0e3',
'474fce41f3c2f5895ea2902294e58307',
'6fa153cc1fb92f9c1742111d3314525c',
'f03e1f5a20b05500e74a68f6e5062e91',
'264417e7bba3234e5cdf1f408f7c584a',
'0c5d8fd1329994ba0be1337ad54c5dca',
'2b7499bbe5021d10321ca3b723cdf3e5',
'34038eff5178686fd7910e5bc615f423',
'bd0588caeb05c3e4ee536308797e492e',
'896441a4e8839e486ed9a354a4ffa054',
'829e1f6c9479e41e5234a5dd97dfa4f8',
'39262b0045b32dcf54db537a28179079',
'f7a336f389a9c8ed46e4f3cfebba9064',
'9cfe372d49fe8bf2fac8e1c534153d9b',
'11935bdff315872c466d85a190c94b0b',
'8a8c8bb153bd1ee097559041f2e5cf0a',
'e093e6c48d944b80bd266c45c9030612',
'0c7394be5a3fafb05b0956cf928df59c',
'f6eb71156a9bf6f1e50ea0076dce7b0c',
'a54bebf7eda7baa453ddcc8e96ef669f',
'6ecb61b03dc401e32a6717ed8fe38125',
'8e60638739844fb00841da82dccd18d4',
'1ce41453d8ffab02d33c4352c0352537',
'decf76fc4e1e82406a67a8e1dd4a9573',
'3af09598e323d747d7d30e424e07e48e',
'599d5beafbb4f40360e75caac72a7bfd',
'6e1f26600d97f407111bd8ae3abc2c68',
'17ab5086aef89d4951fe9b7c7a561dda',
'486aaf32f8f5a3b73a53d794d206c45b',
'eedfad69374e4b477af6277ecf9aaa70',
'e449244a2799f47ede47f062d69f57fa',
'e1ee40a3f18a49483e78e1ae6c402074',
'18f005a711d8fbe11716dfca2e921e81',
'cd81e9693bf1fd79f021f700b7076678',
'9e5098db2f782cbfbf9662663590376a',
'fbd21acd2c830e2fef81adc79bdfd741',
'946ffcea7fa88c5d8f78941f9754b60a',
'3249b669bb11f49a76850660411720e2',
'f9242bf20afa481727fd48988bb4f457',
'be40d173c3c53d1188115573852c7571',
'1f9e7ebd8ef5532d10037f69da32ebd0',
'9023907cb5e21ee8b17dcdfe0beec0da',
'903cf1cde755e649392ca72c7f7db7ca',
'e1af37f426755d00f7051ef033eed0ba',
'5ffada14f03e059d633b26540da57e81',
'35465049a59d36a0d6065b31645f808f',
'1520681fc1eb75126b9bf9ed8266f0d7',
'b0fca2f1f6025a3404417fc1680b9b95',
'e3a0b5485683f9f02317396c75c056b5',
'c97faab5118967ee40f6f74b493f954b',
'1fbe7ba8e2050ec1eda0fedc94d0839f',
'42d7fd90ab4f48710f8b4c1c39ed8f62',
'c34e8933166530e3afd99a5ffe0e7217',
'21ab447f6d245d15fa6a64fe33fadc4f',
'd00900c3e7802a2cfeadf75d7c1aacea',
'9496973e8021a42bc6802fe18390cbd4',
'c67a37c189fb250380f5819aea9eac9d',
'901e1cbb48e947da8630341576fc77ac',
'ad24142b0a95838e87beaf890b894756',
'748f42c5429fa5872d8ce79255a43d12',
'b2d9412fc053a7022d875a3646bf7ece',
'aeecb867de3298ab3b65a85fcb278849',
'bebe802e7fe0aa244877507be0729c20',
'd354ca555db41c54408e1e831371c2cc',
'2d44e2b736acd8031cd6db063d2c228a',
'b22e0da8dbd02941b53fc76b92a820ae',
'eb5fcfbb95222cc7a0c75d839e63fe8f',
'35de0fa3c272b58b4edd27c4c187109f',
'c17a615f9f0f2349f035851f5118d9b6',
'896e7e72e47b080f984657b3e0a0e63d',
'51809c130a0b82e2594d50cdc2664ade',
'47d30d09b66e9bbdcae550a79140fa62',
'c2908a6f68f125396f99a2be548fef2d',
'dcd3b7e5cef258195d24fc92e87fcca5',
'1e6bf19e277f469f736dc28cf37314f8',
'b314b6d82e34c79647ba31639b83150d',
'2b15048e2971ef7c223429e268f8b46c',
'e2140a76b58cb66d90438cca5f59a1cc',
'e9b9f8cb0ced03754af8dd8a70a86395',
'0261f4a61cc83f9d4037cf7d51128dd0',
'75f072e4f073d76ac04a97cec66df9d7',
'57b78005fe6eb34af83068b05e402c1b',
'd0fb6a278a2a2b397162bf909aae1b5a',
'9a37495603c5d3be457689006166c93a',
'bd3a7df9c724691039b3f7ac37c3eb55',
'9d67b1182e40713640b672f84203db9d',
'e93ff23ed03d705853a3197e91e0e150',
'c4d721ad696ce0dbf59b5ccde6ad06f9',
'3d93b72700cb1a6e9e5bf64afa245c65',
'fa4bd1c64fc9fa0ff77e195c62b40c52',
'dbac4290ee30520a77e54fa78cac6322',
'26ca36f7fa39aafea177c1f37898d71e',
'9ca6ee22e4ea7e7dd968b6e1cff24548',
'd0cf4973adec4364037cfad74d0411b2',
'554c3576dfcbcd5811b4f8cca6fa90ca',
'1d4241eb56d427d7a28405b9b43002ae',
'26e68b9695ccc85f813ff954d5cd8e18',
'abc9a78c9855cade0a43047767c3ec61',
'7b0529789bf44a13f270b50baca1c2ce',
'd5561a9073ea8741f8ff6eeb92dac52e',
'5218e3a0f47e5d116452c222ed5a4fa1',
'30a422c2e0176d2a2795553bc189eb0b',
'b3d2f841caf05b4c92e8ea2b09ab7a1d',
'ee2e8f9d18a411cd8ca9e40dd3d2e83c',
'7a46c3fcbb0227d5b1a45d56e7499a6d',
'f6904c4ce82ca6845c038dcf45bb3843',
'2e0df8279e9dc668fd1749d146125f3e',
'ace77e04551634f5f93cfd8916f266df',
'8de24afa3959c32ae5027a3823aa080c',
'4a4d612a21725bafebeffd84d26e9549',
'a7acbd929d735ea588d28bf21ad8a52d',
'35fb37f3c806718545d97c6559abd262',
'9d4686ee40ceb223e0d75bb98847b095',
'b2b4e5f7554c9876df20af0fb7444d08',
'e89c120fac4c64241bca2e2f304f39ad',
'7478d00b557352c202c0922106336756',
'189d4c60101756d3ce4e6281e4a0d988',
'669617c94ca55ace85ac96338a012116',
'3e9f9f98b6ac1ca37ce619f046fea226',
'e1adda1f866367f52de001257b4d6c98',
'e47549af71aa22cc10c5ce04948a2eb8',
'8bf5244a1dd5691ad657ceb91bf9294a',
'dab61df27fef383e3e8963fa875ba002',
'1cb3a80e41438b36df08ce5fabca280c',
'7a88d75279de13505fca6620cb7bfbae',
'58b23624f51333092cf6d1d2bee1336a',
'828a171dd92a46943e07bc5718f17403',
'71cae0039866a3d2c5a570f335198d72',
'b9598aed1daa77f502bf473553846faa',
'12f36142d87686642b04bc70d7ff6511',
'06b3d60220f8d326d861c93fa2f28032',
'ea625be0dceb7156b9f4b21edaafae69',
'ea78ecaa4624cb0f2c12629f3f4bdef3',
'3f0aed87360c01eaeef7184a825a094a',
'9d3faeb0d2c456af2c86ff175e2b9509',
'b519248f76db5300f87249237c2bf867',
'93ddcfca9cdc5f72126a4ceb677023f6',
'6725b549b4e704506811a882ec8393d9',
'b86b9ff7adbcc3e9650df3c7dccc95ed',
'0e8b6d7a223c1e53b900255a4df3721b',
'49760a44ca8984e8bde62452b8c51719',
'9063654c9627b8bde8b3c1aebc43fd56',
'5696733c6d5fa6c56d90e96faaa17237',
'b15583f4eaad10a25ef53ab451a4a26d',
'c7ca58adf512f950ca8fbe43226708bd',
'78dd1426fb5599feb00612c5f6ed7f1f',
'68e837e5a79ecf555308197e8cdfa6aa',
'491de89743910cfafd8eab837c647f94',
'7d68b64fa7f9cfcac9df4bfc07017096',
'140d30691711175747b45a6aef7097ac',
'1f1a138f67d4f8560363a37bb2bf148f',
'f612e97dbe09b55c1fb040093f7c1200',
'8af70f8a7185d2735105b42f0a224d01',
'e20c72b508a3e8ad4377c1a08582a4c9',
'6a7833a5e84fcbdd068b1bafabd0947c',
'01c0010e5e720dd19276fd30c605db39',
'883393791a7c64ecfc95a417e212bc9f',
'b5132dd455e2fe65eb1efa52970552f4',
'6592e6e9fa462bedb4853d277eb364a6',
'0e82c0b647ecc5096ebe71077a5330bc',
'741eb3433f5a0095775ef3c8d0803dc6',
'616db8a7b58fc1c19482b459490ef56e',
'81fbd404fb3b82cdf8cf8050b0910d6d',
'fc5d591bec0939960877c5d2ea8b2115',
'e64ff18af964aecc8692daac22b017e5',
'60d545a25fe6012cb8f60fe65a17c0b6',
'0f4a134b91ad06ca0da383ff1d2ad18b',
'fe8dcc2e6bc3d96ba57be95d2b60b532',
'e749aa61c6ae4e817784a0c795542ebc',
'30b9161c44d8c07e5874c42146d726fa',
'01eacef79925d81d8d4a30751adcab3c',
'685f5d4f7f6751eaefc2695071569aab',
'7ba0c51bde673140dd3f78ec4b369def',
'9dbc095c4dd16435204e8329c6206fdd',
'2eaa99bba15e35308796b17c21f329f5',
'8c3abe9b8471777014ed9fb39ec5ecd8',
'9a3fae49e5df16fa0d2be1bd30c9c37f',
'ab0d6c232180caabd33d2ec9c219973a',
'ed5cead90f8e5cb91c3e0007e6b628b7',
'b6137ef61115b7901fd7588644cb8574',
'64582d916177f310988cc30804f1a56e',
'af443c289b9c9c0136ddf0a345ff57f9',
'0ce19b4ea0ff61a6671efe9154985158',
'5e83b6ed422399de04408b80f3e5470e',
'16fccb32ce7d182f9019d85427394deb',
'1963681942c6050860a7572124314b90',
'79294d8e544259acf748acefc8a2d8e6',
'f5d6f783d39336ee30e17e1bc7f8c2ef',
'a02a365d7a8f13d810dffa2088f584ac',
'46383df978ddb2d1e0b6161172ce76ce',
'687b69ba8c7355188b684713628a7dfd',
'20ffba6effeecec055ad61d4276d6d57',
'df12916df0287755412b579a69c462fc',
'7687d1d03ef837aeb401a5bf7b4c9a17',
'732787e7ccf9af27a7d870ae67241971',
'f102d38a21210857878e726724aa3e30',
'f1ca7c9d382b92e420db8f3149012fd6',
'e2830d3286001d1455479849aacbbb38',
'2f1759a80ad506a817b0c61f129c78a0',
'5082547db47ce0e278f834817a1a8a51',
'35cbfbfdda4e8860595f312d021e92e5',
'1c2feabfe5e8fdebcfb65acf86613cf9',
'6f48ce18dc80e01c1fb93705646f3a6d',
'14f716b6674f14db428d50be1d3f2d5d',
'366ad973a3f327dfbfb915b0faaea5a6',
'b946d1fcf71992707eef76999135767b',
'aa20a366f401fd02f76dcd1f7a4dafc8',
'390bbdf74af4f4725246f9c57e8304ec',
'020e2d14ebbbc12bab5093c69640a409',
'87726e1fdf737fa933ad7217acc2410f',
'911195a9b7c010f61b66439d9048f400',
'be8109989e21656bd44f20781fe6a41b',
'5578e913cf58cfeb69c850c9ca419858',
'907c6ede20c6f84cc122e091d01a907d',
'b51a6d35ec86a579ae2f67b916090732',
'dadc17eee3485c9511ebdcbba2d702a6',
'4ca6ed3c7bbe8ed43998a030c5eaf49a',
'b63128249680e0e5d34848b7c5dac271',
'304812664b2d9bd2e227c644be49b6d1',
'1e0cbe138b6be8fdf949a2e50e963b58',
'c6632e05a6bdec14adc01539b49ec809',
'197659d545376fd88bb6cfaf570270c1',
'4b2f74626d3db6c1d8b3f0fad6658017',
'1fa186a653cf748f828dee5561575b4c',
'6314f49c5cfb22a5d0f1c33bf576f2b6',
'56f87710f1e657daada8c6154ee6381f',
'd5de492c06a2a60fd7e88b59f89a419e',
'6ca15ecf9ba543543397d1913ec2455e',
'2c16fbd54566f57f697f058b9dc7e090',
'8b0e6779f25a17f0ffb3df14122ba594',
'396b2e0681cae6b64f3a33275efba181',
'fd092394a7fc2efd4f604ffbde742ddb',
'f4f37bb75b762466b80f6ef8fc7d9cad',
'76c13c6cbfae7bc1c591a5e4e60d90ad',
'eed14de3907c9aa2550d95550d1a2d5f',
'597514b3e6a19c8bde583b4df7f2e0a8',
'f7fbf65cd83e9a36a93753cf5cee59c6',
'f9724e1dfda07df6322437389da597d9',
'f8088d10e09c21d3ef213eecd61527e7',
'dacd1a15830fc233c87d3f94e69502ef',
'2dbe414d5a9cac1c6f472da080200cfa',
'383634b5a9532e57bd9abdb3b39d1d1b',
'eed68245c800bd669fcc2703e3d4d952',
'508fb6e5e2502d6b3ab5d22405092feb',
'c0841311752f9d6452cd2a48ea7b51c9',
'b3c7e9cfbfa3c099173d768df2734d86',
'0357ff01759c2e752fd2543985989f0b',
'b477397e691b9e3001c2dc39af4b52b0',
'7f973e4b901fa26ac41e966e031f4434',
'47f6be3754c560df94fd72eaa04a160c',
'27c8ce2198e27d5ce0afa6ef785234a5',
'e780943d0219340df310e58c8dd2c224',
'5c7820d2c1f92684f79a66e292b36fdd',
'817671e1bdc85e04cc3440bbd9288800',
'ecbaf13ebd5e48c0d93afeb185fc2244',
'd75533eaca32b408edced8b385d5df1c',
'ffde8a4c8be4a8fe8f63b35a7f8d777b',
'73728fa0a3f1772ee9c312249125d316',
'5e65cec80e47e419be404e3b2b3a4454',
'5f9ba02eb081bba2b2434c603af454d0',
'3b545877f0bddb7955744296ae0a87d2',
'eccf5c6063bb57d5362ce783bb766557',
'70ee854e034093b61191cbe1dc6b729d',
'048a54b0f740991a763c040f7dd67d2b',
'78735788bbe909a1b4218cc5eec9634d',
'be853befc5488d1dfb68dac6758cdc23',
'1c31f8a9b708aa40649b51fac2819096',
'a4f2499805e745a2a57cbde05e9e6238',
'7e77df141eae1573ad5f5bad8fe79054',
'efc5b4f8d71e924e69cb72a005fd2ce2',
'ea99608383acb5d2c112078b3b441fd5',
'e5b88f3412e132b669852b90b2fa5159',
'e43e2250bc4a9450d97f14fab1d9a638',
'76238e3eef4d1f17aaf4b29b680ca2de',
'e27122ba785627fca79b4a19c8eea38b',
'15450da19d963070b26121a8bb207c39',
'c32a5da15d7f5cc49ba07731d0b56a85',
'b49a2720622660494732b64af772826c',
'7ec3d4eb285e7948172b0fd3e7f34797',
'0a0990bb1afffddb2ae1f46ff5c6776f',
'aa99848ab346f3188d9712aaa7638a67',
'77e331abd03b6915c6c6c7fe999fcb50',
'43b836e1851e1ffa535caa6eedb9c7c7',
'f96e98ee2e53a1bc0958fdfef95c7525',
'4f60e33825bd45c39950302eba5911a1',
'f515e7901a8f63c3592d2ae3c7eafeda',
'0fd4b9473e1bc375dbf8ffeefca3b0cf',
'f1232a33b7711c48c6dac94895a63935',
'6ec2de4f1a87aa6abb24cfad1b6c3510',
'a6e3ea0dfc1cc85d96ee08cebf6c4dc3',
'6a211045b001610ad1d601b9ed97b248',
'a264cf9bdb46722b96de88384dde5b2c',
'c36b9f6e804ac5e04c0a56a1be661061',
'46d8badf5eb5ea9f156f7cb07cd0298f',
'1894c952d82a284750da86d3b10b7130',
'99f74b0bf26975dbe5ebd4501ef8677e',
'8d5618e61190cd13e84223681d0c247d',
'94ddfd0507bb72390d85af704e49cfe9',
'b880caf802e451eff55cdc624998efcc',
'fee3280750ae1b6fdef15b5363fa8a03',
'10d8d62876c999db4615ffdc10e3c683',
'264b733b25657a27320f4a77318e352e',
'6f03a5d446847d3db83dc82ab047b446',
'5be3b1bc76677a70553a66575f289a0a',
'6b07682dbdd3787d50b960ed0fc06bc4',
'd036ceed27f03509ef77ac3b505aca9a',
'a00be156e545670329b7a5329bf79273',
'eca599d7d063b4d277b7b14e5efe4a6e',
'56fd3e4f4f47fc073d1e98de4e9ff4ce',
'249bcc25128ba2ee7d85e299508d277e',
'db92528b77d37b4467cdc2f78f0c0c5d',
'9cee5196b7b434fe41058d2e0b64f5d2',
'69ae335e5fa68235ff5f9a2168d4bde7',
'baa8ea16e7f4b479dcaad0be7f9d9c8f',
'd6dde0de667966b5bad1839046e3f33d',
'8089e6f0467637343e4bec62521b7dd8',
'785f2d4b10b642bb08c8ec714a15b58b',
'92c080ce89f5acbc5099d864c03cfffb',
'03b266926c0f461943cab4786af9a4ee',
'dc83e8926001034ea2336c928e340bbc',
'75ce580f1c9762ef7836139ce8efece5',
'72ed704076378362996af5f45ef6f2c4',
'e2aba77c41e9615819e9c9b9cc8a1370',
'de0b7923a98c1e6a750222c2b5d5738d',
'fa8281ce0214c5d35b645f4d90d54482',
'40cb785a2cb29ad3a4e9dfd32a566a68',
'ec437ccfc1a321db7ea511dd8d24b957',
'3a773a5729044fc37f51f24bf6bbbc01',
'cc306a92178f303131541a3243e0e1d7',
'a5750bdf173f173a814488ed35159802',
'dd6cb45d1f995402a50b9cf976090dd8',
'df9835b9857ab20457555f2d3b7ffff3',
'5394b549874996985a51e38105cb5f6f',
'3924abc276f612b454a32d205184cf1b',
'758babef1e1787a7990f1e708a084d17',
'f5ff3e9bb3284ac4dae6fd57755ec318',
'cf059ffc62b73a78e7ad37d3459f25de',
'110a349e88b5225d8825cf4d5d5bcecd',
'12350730163f70ef5c3b769636ad2bf4',
'64e97ca9fdcf4136aa923622cb4c2853',
'40d801f6a7f6f7381ba6dbdfa58cd909',
'fdbc0f0b03f9713bc1e1a73800b2236f',
'6564b9930f50af3a167194249d940b86',
'f2615b636bbe8ecefd2b68b3a88b831e',
'349dc6a8fc29c7bb339a83a09116e3dc',
'34f0117973f6155c7e2323c8619fbb40',
'7c769f5198191384917bc83d0b48901d',
'37b85f5545f2d2071068532ed2d8a47c',
'df1ae406471c0e8bbae80c5d465aa319',
'3f3b4392b1a3a4df3b1f6c43abee524e',
'c5f5f05191d147957079ea7f0608127c',
'dc27d14372608707b681953bc064d59a',
'c13688feedd95795941f3a8483a0758e',
'1d3dd529591d3d50f17d9d086b8d4202',
'2775174823c912c135e0e1bedec467ce',
'e516002fef0e50d93b8bb9622ac2e98c',
'f8e7fe18f39008225c71b648e2428ddb',
'0a40a61827bdd6a4d3ab65cfaa22bee0',
'1fda37a2e48f3215b87ebc73b98180ce',
'1cebc7357e42c3e87737a47769b536bf',
'13ecc4323e05f1741bf955131af94b8d',
'63280a4edb333e03844601b7fc5c666d',
'77729ba9c3643e513216e81ebbec4c20',
'08e2cb07f21ddbd279c1c302f5338149',
'728531e2b54f26393fa4df5da11a6a45',
'04cc209832f7194e4442d4416ca0a36e',
'1bd0ff8a372ed2b5f38b41c5619859c9',
'c677e1fdaa9eca4098339b347a403496',
'dfde7e0a79ba484dc9028b5d1d2e9d6a',
'ab629e837829a9f00dfd98986aba1073',
'1433cf69b50949443b22b6dd9d3aceff',
'68f59ab9d0b32e9d8c6d5bbd0caa70f2',
'77423d66b5493a2d51b4584a094eb34c',
'a2f0b7815566c2cfc92ea306838791a9',
'f30dca4a681703178b4d1294425ae5f6',
'32fe7ef6d1fd0c2b12ce135da107c514',
'9b5154eceb9d3e30b574cf9fee289615',
'd6be5e03d87cf461d73ec4b6f8f0de4c',
'14705399df26109bd2ba9f9d4f5c125d',
'd30e4257c2e98baaed8be435b9cd9647',
'237f469a120d4d945fba6624db457ca4',
'c3b6035266a951fcd84f9df7ce960e9a',
'e5300b3a0bdc9bb7d66f52a682a0e4dc',
'd4a6c94c7a96b54a250d1038b9601f59',
'bc96f52ba36cda6eba4aba07115f6fce',
'0e9f8a8cf68c46e6881bc829e6dd70e0',
'eaf1c4931b08f81344e2ccbbb8b573e8',
'f88c87d7aa1ff44d470903f63e3b721f',
'e4e7efc12dc5a445566cb0ab9d0b3a50',
'12369fdd3be9356af9fcb7937e8322a8',
'b870fd8571445a3716a0ed2935a11ee3',
'13f5c7a035ecce5f9f380967cf9d4e92',
'b6709f10791488474318bad2fa8d170b',
'47167c479fc9e243997a3f3c6966abf8',
'9d8214762bf861e5ccb090b02b4b26c8',
'1d8e2fa18641bcfc9b81e63f2c828469',
'41dfbbcf54fe188e0ddc8cb607df81d9',
'9a80672c477612ae60577c02ce482de4',
'7ec7f30348471496350c3d5c4e9c0458',
'2e5ef14f4c40b6fb991fa0384db84ce4',
'194104576c8009f041a2249fec6d3a4b',
'4ca5a86ce24e8d8752872b3e925e54c8',
'50bc642d9e59fdc3eb392317263a0cd2',
'4729ff26238489e88c842ff6afa87327',
'0d1407e45444ebb6ba2f1510aeed77af',
'8431c623e1eeb7b9917e861615eb86b3',
'40cae0cef8440430a6eb1a832be90a9e',
'5ada62ec1aa35e09c9edb38ce53592c4',
'f1b701b53e72c8fb41829a578796da13',
'538dcf84894795e9152e5d7c27dc5f11',
'ecd5c0b64524b17c894aa49560a8ee1f',
'f829ca20eff23db7cb7b7643477c8190',
'e2a10f72050fdbf1df1ca01f915904b6',
'14049dbf8ff36ffccd6beb5474710447',
'5fd9d307eb6fc4cf7dc2a49e96e1fb5c',
'c1a3a721b0cc12a0b0d99992a075e5f9',
'a8acd77931b199a890e0e77d3978b50d',
'326c5f9abc57a1a7a1295325b54edc66',
'a94195d8ea48ac48a10209ccc536a8d4',
'9b601e087bec313ad05b0577f94afed1',
'd3e43de6ae80e447bcafe96646f21a16',
'a2c89029071bfcea3c30bd573e61da59',
'41139d73bed4016124b1c7e989eb756a',
'0f681fb475cc9e8383b196faea618741',
'4a6d4ca075fb0c801b4ff4bd5909b506',
'cd1befbdad38451e705a4fb0ea2d601a',
'182b16bdb7fd8936d8c8269cb9ac96dd',
'b2ceca3464d5d21ade97c282ca607e59',
'dfccc885ae1f14d9fc6334bebf19e388',
'2bc87e18064c4d3bdf5fe7379de9a7f7',
'91b5cd8d26dab73f08214cf05f57bd06',
'1aa5307790d72941589079989b4f900e',
'e238ba8067ae5e05cdad709d6eb5ca93',
'4745d510fed4378e4b1730f56f25e569',
'554e50c1265bb0934fcc8247ec3b9052',
'7c23be94f43b7e4f31d381d3cf089500',
'ac589ad9ea4dea74f58a169b2e621f3f',
'97f89c34fa70181bc5d28288daddbd5e',
'd5ac783eeea63c90f01ba79ee32c7475',
'15860e89a1f1d58fa3f1f3263483689d',
'd0e2904f4071536f75f16aa41afe4e7a',
'089ff24d978aeff2b4b2869f0c7d38a3',
'948ca21a3a430db6ec31027aa99e8b91',
'42f35b6bce346c8ebd3f6cfbd837bf48',
'eb76f4a79d6c2fc9a78d08bb18073127',
'06280b0352fcaa6e107da30cac623f1c',
'a19a311bb1e6d70e6a434ba60082f411',
'75f7ec1bd4144f06ea70fd9110ebcae3',
'f2c35e3b268796e5a1861baeeccb1bc8',
'2fc12603a3ca43aeb4c684fefee690fd',
'492185849a5dad2c634277431ed338db',
'3594844d381e7c690fa36f6bcf0939c8',
'bf1044af9e50265a3c56881e22b07103',
'94ef706cd7bdf5375f2f6f79cdf3723a',
'e2846dbcd7cf36b474afda377efc3fd0',
'8bf2a1cafb021fc0ea00c2c9fe999f7b',
'01c8013048943d515e2f697b8a54afa4',
'876afb519c897b0e047f8d956b23aa73',
'669c6e937b59e421226df148b2f117fd',
'a9a486c069199f52755a84708689f877',
'8f4eef496eb936173a380408d7ce462b',
'122618433954b50434db06fcddf90c0c',
'65a7ff1890e3f5b3e020aa981d925f24',
'0f66b655d8b4d0558e97078b99aa397c',
'43263dff8a4565e9696232142afbaf6e',
'840d9b7681388d798120308f76501a6c',
'fb708b9de0e4f2424dc67b782fd5286c',
'987f66b29bfb209a0b4f097f84f57c3b',
'0eb59a47975cf2fa1c9e1fc1ab53dc71',
'495ce585789d6e9bc81f9140e93f60ae',
'a587947823af13919bafa1c668a2c1b1',
'7011275099dc88fef0c9cbb0ba72738b',
'9f139c814d805c7f12a715f4bb9d7543',
'05f27b431c94e2b41c79223b8d20d4a6',
'bdd57663a29d06412b5cf5002b9a7351',
'63b1bd8f9045c78b51b05b0639f9158f',
'6e67a22130768ed1c975beefb3ea5f6f',
'8023394542cddf8aee5dec6072ed02b5',
'a9ff6d60cc0a61db01d1b506c2cf0cad',
'bf84251995f12c95e81c34c0663ffd65',
'89d01271213230ef874417386d5f1f31',
'8467bc9190e684fd8529dcd58f50c6aa',
'5f386198b07815108446a4d40b859ab3',
'4ee6b019e00e8e428cb2a57181146da2',
'124464bd1fbda6fc85e169b64444a6a7',
'e41b5750fbe79ab95faaab3e3c7dcbcd',
'115531d78994e82bebc14d95cc4f3a95',
'43f21aa6aafc2bb476ffdc930d81b14d',
'94eeed86390cfdc832f2c9beea0260d8',
'8da180700dc665cf8198d820c55ee086',
'0c5169a0bd0b951a6990e9fcc1b9bee5',
'b0b2bafd76caa3f961f48cac5bf17ab4',
'fbfef3f0719882d9ac666ac376c68036',
'91f57b920fa9bc23fce39df10af7c20a',
'3f6b38ba2814b59dbb3450bb7de8fc1b',
'e309a500efd3fc27364e2b77b73c6455',
'636bf3ea58dddec9e30cb94548099689',
'175f66c85ea2067316dcc345080519d7',
'ac899087acfbf7f20ae09a34a225a057',
'ee5aa953b9298aab49f7bbe11dbd142f',
'c0dc7a021f20383c430e8472c50350ce',
'dd1d7742b7c16d46e3dcc7097223286a',
'0404cf664bc5446e274cdbe9361d147c',
'd7e704b0f8ae118375e2a1cdb8eeecca',
'922a200bf13b9d50d95363b2cfb05c92',
'd8d6ef0980999bd637a7c77679dc48b9',
'aaa75976ab14b948228d3263a4cfaa7f',
'd0ae50da2051e8102b09c2bd479d1571',
'af3658c088ba0da49c2f7eef21a235e1',
'b29ee72e4229109ac089b84e0445a26e',
'5eae3091fbc7a491346bc6ebdab28be2',
'6545d8f958e649cf569f9dc25ffabf06',
'1ea24b3ae95b983c7a471a684bc980fb',
'966cb4b6891ae48aace43eb19a9a0282',
'258c53d0908ae41cf8d1428d60e3b164',
'4ac99d7ab6f98cb2f3ebc9ad53fd194c',
'97dee8cdc7820864e944fe99b739da43',
'be90e583a0520306511ed9e0df78b3cb',
'09a90c6d4ca33a15540f7b7393bae8f9',
'584d19c2f71654e8976e59b464bc0f7c',
'2d26aafce6f10efd15a367a49d21fe50',
'10df7df7d8d26c76fd5c13948572d130',
'393b7e6fb21431a30f1d3ed9ee490ca9',
'd42aec2891214cace99b3eb9f3e21a63',
'218f8e24e5206df284d66d12db706021',
'c525c41fcb4f39d340c15b58feb53007',
'4470a316fafb674022c249bbf4f3cb89',
'bdbb52adbd81973ff20d92adb5874fc7',
'de150d2408211153d050a64bedfd6b49',
'603be59da46d422caef058330072ca3d',
'4722e0ea7a73f4e9692661e0349030de',
'6d9c09799c2571de7038fc1646396fe5',
'f88d1ab7d364db3fa6e6da272cc8e431',
'7375659ee1ccbc238864ffcd9f3700b4',
'66aab075db9f2abaaf8fc246416ca554',
'c23b3a23c1365657cebfa3b1eb58e919',
'ce4bfe9aabca098e650155b564e7175f',
'868ff118529a9b45a86c5705439d7a55',
'e135eed75ce025d6d4cc72890d0134ae',
'7d8bf95ec3ead6e1cde9919920d1891f',
'76aec6cccb974e5258e194d8bb6c1d46',
'9168a0e72ba1fcba7ac139e391c99798',
'74d66d9351ca11c4597c089730ca020e',
'4c57a0dca859886d086f21a039b53a1d',
'94395c5025802bf468b97cb7122715ae',
'f429dab2883124f6ab82957165e8ca3c',
'ed6aa49c9308792c58a46e5044c485ac',
'14bbdacb8d99a3ae0a3efafcff8faf1b',
'5cda310da700dba838b0a8431543310b',
'2617b5c3ade84e79a409594cc35cf53f',
'acdc0166cd112d1af18886c773219112',
'8442a63c19a4b0708156a57b13b7f829',
'0b4d62c10451407a44626f218570354c',
'e0d3b34fbe71a77133951e0f0ff1de4b',
'57fb464824ac2ac4e15f7cb772d5f59d',
'7b5f448ce43c689e280e62df6128ba5e',
'0fbd6c97b5f1c0bfb11075c280962a38',
'ea67fe94d0a2a5004fea252a3703ccf7',
'286d6fc13587a3dd5095fffa881fb7eb',
'd1b7b311a7ffffebf51437d7cd97dc65',
'36387a82a919b5a7ddb7ca31e1631c1c',
'961e01a1a5798b0b966c4a8bc0197fa2',
'91745743b325854387685ea63bcf6578',
'861298f7566b4583ada2bb5e506ef1b8',
'838243b8fad9b9f72d29c48a71705749',
'cf96ae3bd86f71c4c7e4b69003d22afa',
'4eee77fc94e6ae08994e9d2acdc300a6',
'ef8255d787c94d9618de074f0bf6e035',
'dee6da3781e696aa602e34d6206a7afc',
'1b1cd71e95330d1516c2731f2690063b',
'e468c24c718c55d8c13a64c5db7a7b9e',
'2f9875828d71e18c9a9ca3bf368e0f89',
'7f5b6e6f9e67010dea7087f6dbaa443a',
'55e85dbb1bf05f25a1def936fb56e226',
'7ea7c525e7d8f1fdfcc0bfb5707f0fe5',
'6e1a7a6d3dfc3ac8f2c8048ceb3cb669',
'97fc1a1b34d1b95a64c04fdc8ef20c97',
'7beb23f4a9fa4d77a0c0c052f1188bbb',
'd5a107d7ebf784e1be8e1cb3e1625506',
'da8f203a54165c7f52464e4c2fd06cb9',
'3ad500c240a7ce6ca92d79c22a26570c',
'8b547d44b23b0e1fb7a80e53ea6d1697',
'62d343247d4b02b9245bf5953b7d0e2e',
'b7d280288f46fdc0ed342569c42dbf0f',
'843fca00a6d1eff2b1d695b9b955010f',
'244ca492623a3b55abb7b886b3eb546d',
'29420106d9a81553ef0d1ca72b9934d9',
'079062dcbcb42d0de00ea7b865292fed',
'c6e6ebda604ae9da42ebf391a73e589f',
'f9831d46158f2a3f4c38573dc6645cf8',
'e8c717b582ffd9e1d07b2c7ccb58ffc4',
'a4fdde1b27610a84200a9890ec88e845',
'db72d9ac8af7c2bd8226662e9c56f322',
'e7174d16dfc2887a3b42b5b2cb26d77a',
'e4be0b8b299a22e7d33ce72e86dbb6f0',
'46984f3c74963b917784754f41673605',
'2dd7505d182848678cd8a817ffd47a14',
'b268e6fa3bf3fe496cffb4ea574ec4c7',
'9373bbdad43899f8b2b2b2947b1d7876',
'c205ba8618ad28524dde197346124bb6',
'cbe9b2881a8f2a5cb9c6483e3b95994d',
'0b69ec4df6d69c6d0427f4ac0e46ce1e',
'56fe486a2eb5c63c6575ff3dceaa457d',
'77745db1bdc902c31afba4ca65ac9da1',
'94d9167232a650a4822a3fb802f64836',
'1ed6cc30f83ac867114f911892a01a2d',
'943e0c6974406b45ceaa2c8e60951ae2',
'4405acf857ae2c317357d53be656e780',
'bf82b17798656df7bf5d21b9872ff5f0',
'0a9e9daca35b9ab7330834036f5d94c3',
'e79db400ba7829611f835e6882cd672f',
'0b0cc560e8e25cd4905a618befebc511',
'30c9f5bdd20d44124c40e8c5487370a1',
'242c0fca1d83994e0f6beb0c39a0cbc8',
'd64929d55f2f5508deb278202cf9dd15',
'ea283140efc39464b180f7c5dce45f19',
'9a365533389281d698e57117eeb83968',
'3809bc86f5dcbb01c3f51a5592594da0',
'8be2ce7cf6ab30ff3e62c88d7d22b907',
'e63bcb987a78b58682de6d17b22c7644',
'0a3edcd2b391af3c5aaa9ac269111c06',
'30688ee3a268f632be981781cf10e7c0',
'75a6d7a89ab9f084f37c1c567af071e8',
'454e990be86aac8f7c8cde590382f6e2',
'd93c70dde19c3cc41dff3fd558a40295',
'8f7de2e7d2b29b18e80d33f6a8649d88',
'7d8a402f3dc0a840947db563330e1489',
'38fd7e45f9c11a37463c3ded1c76af4c',
'eb39df3c4b11155570eeb977a8ff622d',
'b0e27186008d2990c02820286a344c3b',
'24c22058ba934916e0b30a044c09069a',
'10479b0c840c3ce22464fbb198f998fb',
'd3f7a2079cfbd68965ed1aa0266799ef',
'db7dd9d944d982bc26ed0e56da53b0d5',
'dcbad54abaa66fd9a8df511017db958d',
'6286e9357aa781eab66db122e73a58f4',
'e4b1af6bc8fc57a39cde57b3393c33d6',
'8dea825ad42cb29157ea057ba5f1fa79',
'645fd02c2005cef194a77b0520a2ea60',
'ed8a12e0fdcbdc0a25d648ecf3b6eae6',
'7624f507a109dca1dc4ac0bc530e2447',
'b7c0abca68b48d6fbb6262ba8e4bbe39',
'0baf15cc2eb5f3334fa9a9f83c8715f3',
'9d69f3d6e07ca298e6443096bf401885',
'9c1512aee257012737ba2a7513a34749',
'941279d1e6a468777ccd8c20794ff69d',
'a8e8f6acb3843176a79cef48239e5885',
'516eb5f44603469b28424ab7d300417c',
'2ea7ef8eafe73cdb99e032b5a2742d67',
'8aace754835f8137d29a19ec00a4f8cf',
'4862fb078c8f41683ad2b60e0a08ebbc',
'07985cbe611ef5d37fec3bef4f5ebe78',
'8c872588b7744f0c1671de8ea34bd691',
'9c1e7379a3a03c96c886a084b97877e9',
'962d9b7789a9b20d10988bee003f1940',
'095278cfec182df8ed349650571686d0',
'f0d6e4c418144e0f4f0bdbf10d431522',
'2d0268239fb6d436eb477e88076f168a',
'd37542908d659d3fda7966f11d06f751',
'97ae7222d7f13e908c6d7f563cb1e72b',
'1645ef28e31fe6298f0bf4aac7850fae',
'15d273113db728efb61c0d188a55a0e4',
'5ebf16812b362d08b10e670f9f4410f1',
'863a4cfc0bec22049572349161bb7a8e',
'd50798e307cf5ea39b23d595b2ad6c95',
'bca95e9cf8c7ae37e34be5045bc23d7e',
'a0fb2b161df2c4b1f82f59c446f5a97f',
'13f8848c796bfe96d7ca55af47aa3d7f',
'99f0c5cfbf0737ae9ab8011259799847',
'91e595a6d5a0df41dfc5ba2931ec9a15',
'5a3af3326a70456d70672a82090e2a21',
'1a9bb1c2a3759b3ef2b6328c0ad868f8',
'fa39aa6ed5f59b4976696a5a591ffa10',
'e18c2a4a777680a644b51436c7f25d38',
'5141d04316f691929c3ade15abae0f39',
'a5662bf748346e3ef893dec99976b61f',
'7123aa393faa4fb37d3bb4b9dd6ec5ef',
'46ef04c5da6fad32c0a00dd5ab20e15e',
'd26fb00fc630011313b24eb253b9d489',
'1458fbbd586a86a990823cfff5b904be',
'5c5923862f1b4e2dbe7dbbb1b9717595',
'49013a2f0ec43f7355e4d3cd93e247f4',
'c1ebf07af912e3331564cd761e618819',
'f4d75d49254cd797c3b1e4506d7aa701',
'7518d9466c8901a3513bdd84940c1d01',
'527cf81f9272919bf872007e21c4bdda',
'3ea962b111b0c0909fe9484ec88d6183',
'a6ad61dd2d3b89bfd57bcfb5cf78f298',
'abb3c8787d136b794d0ed4dbdd7c0db0',
'39334a43e48f0eeaa8877380358517c0',
'63b3b0e7b3d972a96a25874978f864e2',
'907c0a3949ada5d69f7e6f137e275129',
'dace2bb66cf6c71811dce3a757228b19',
'31714e490ec3667683e7d912e2446925',
'eb7b3423fabfbc477afcdad8d346cbc2',
'8f799978b9d19a74b8f46e780e8f4865',
'492b3799465c3cbc2179b5c2196a89e5',
'a654f10d0233ecd5df95347585b411a8',
'a0ea84a88476306af6096dc3b57a9388',
'047aa9305576a34bf05eeaf4cf6dc9f8',
'5e2ede2d1c4fa1fcc3cbfe0c005d7b13',
'b8ace7f3d799804e5e27a9b92976d75c',
'538ecb3e8490882b00d4f746de282440',
'2ab09d66a66922a7fd676938b2719d0a',
'd9edf507f95310b830f5e6848d754d77',
'f175684fc976d109ef0142f28a8870b9',
'5b21befb35b3e68f8b3d11fc4ab3a1e3',
'2fe5e1021b51989cc9e65dd75b6e9c6f',
'285c316278393360963b59dc77a95d9d',
'e36869eed2b97b09c9e6f84072712de2',
'90df0f3b54044e1c9d2df98f9c2d250c',
'a1eb8839568930d7fc739152100e7dd1',
'960e166e0232fffc3caa445710a04273',
'51c51f1716c6971a37effbebdcddee59',
'e99e65b35c7617bd93a8df0fd59921f4',
'41f3571405b9467d067cf313429e56ab',
'051620dd0a322c11c6508ad536d235c5',
'e834c06f9f1a9af640a01fbdac07f47b',
'7e992cdef75e45223f151c8716f78ce1',
'7a21b9e362825c30c921bd00e4c1a528',
'd51d81be3246f31687eca53e0af8c47a',
'eae83a3b3d50c6689561bffa32f45413',
'774efd62a8b8d3a114aac60ec8ddffd3',
'd4a295839c46ce50e6a1f99d4b84e0b6',
'bb1772993cb0eb6390cd689bc1c1c748',
'7614b476882612d791080a832b9b6276',
'efede573c72110a0b03e5b4e3e7f023c',
'cd2c562d3b5f2d5369fd2bfd4b7b01e6',
'3b12000223b88e503dd9ccfcb245d9e4',
'e5884c457113f53a0509560f1d290c29',
'a7ad02079fd84b6a42de4e59945ee480',
'0b2d7a3da24bedf37eba2f932636d138',
'f798d88e5595f1c66a48b2b1d4184635',
'887430a4b6dc60eebef908ac4214b95d',
'dc03961d4b3b3a3de7ec342fc6421706',
'9e9ae0332ada9c3797d6cee92c2ede62',
'aa0995b961193edfb58065f7e8dfa5c7',
'4c75457a88e4734a7860ddb4d3269541',
'4882646a1a041bf273010baa6a6fe3a4',
'0e456a2a10223f8c45f8e32741b6491f',
'b94d8d6a24fccdd5b41c7736f9086a02',
'f44494ec0c2e62c7d9eb3b51aab0aaff',
'0c53bdc9f7579300df60f2733cd73220',
'7d3cf83efb63e2d007f5d6df0b11dc62',
'a7ef9ca698ab8acde65c5a498b6fed02',
'79ed6e940ac4816b847abaef533cb1d0',
'3a9f80e2a01d6f5248e860cd25efa02c',
'031cf048fd8fccbaaa501d6a95c0cd02',
'182ce4d957bbce85038d22ff0bc828cc',
'eb2817cfaed42f5541c05624522bf6bc',
'a2d5980c1569db7e6cc4cdf2bd00b8ce',
'92848d62409be75fcd9cd9cb40405a35',
'ea09889e1217c3088f357ee456547e20',
'b19bf0ae739316aa4fe555112a33b8a4',
'97abf42b3368bb6f6b45c0a3d6cc7279',
'ff8f37bfbbf5447ec4763917372f6cb0',
'bd52075e98f9ad995b0ddbd58aae14f7',
'b1b06368ba3344f7f20b2ecfb4751941',
'c30c886e2f81dc98823bdb93c721f6e2',
'fc0373432b381c352e6a5cb2edfe036f',
'a4fde6d5b6263ee905da8628a8ce0235',
'950189df1c828fb765bd96de23f80dab',
'2e360a300a0c52e95b30e4f26b243826',
'9e6676595fafc8dcb830f4e40d782896',
'90da3ec388a617e74e6998d4e7221aa3',
'045446e78639e86c60460a551d99f482',
'8dda06c69d24c59447b33889ca6836c2',
'1a777ec7b893a77b81b1ce9e6af35355',
'1b5102bdc41a7bc439eea8f0010310a5',
'd2ebe4ae1fface9c4890536763ef2035',
'7067be950bea69bdb477ae0f0a085374',
'f7ce2c029dd502afd1b8b299f21163cd',
'3ddc083baa235551e6e2c56f62073970',
'00afcf27cb5916b85c5999e6ab43462e',
'27d0328f4d2ba602cddce97e0a2d1d96',
'866f96d885c8679158b3caaefedb5cfe',
'1164504b5d7f8f7799e3d689c17ad1bd',
'8bf80b5a43148302f8c0ee67a2dc45af',
'cfd54e465a6524e53c40596baa19d547',
'5eb9fb80df00beb91c14d922f7370c72',
'10aba260930e1ffa95f6b3c8dbcac0be',
'0e35b42dd53b9e89d28454326dec46a4',
'e26fba2ffdc0b9598a0222614cd22cbe',
'b8e8097f528189d8faf95f0695da905a',
'4a4c33829f99c0883b852866a33a38dc',
'f6f246f3bcdef2a830ec7dd05ef3bf8e',
'ee722ea488420b8985de30075d99d9da',
'3a81d276b5d2ccf3656b4fa6047f6713',
'3da00dfd701b2160e93af22f723231ad',
'08a484944cef9725ae204fe82367b77a',
'd5a0e0cfb2e882fc879b6ec0ea7f27d5',
'6cdf4d3a81cc6f7a90bedd181825e92d',
'fd4b8c518553afe90387bd1c0359c6be',
'5135640b196e2c187dfce50311a5d27c',
'93cd62b0f73d3cced151266184a99ad4',
'e3b4d37362e6b19c5b298e6d5ea9d794',
'ccfb7b64cfe0d4240fecb0a1dc3af7e0',
'7f8535ac3c291203d1fc89417e48b854',
'aa0ba90671bbedbbb48ee3e18b56e029',
'ac78afe303d625ea509d0c409b42e1a5',
'7e474155d4ece3a35520cf08b0238520',
'4727f9f1016902f5d4f03c0cd44eb854',
'75b97d78a51fdf7a51d4eb6fbd64fd9e',
'905825ef8451dc37eca609c2437b8400',
'6da09af51e5007657937c184e7704d0d',
'15f7cc5512cb641e15ab6ffea6d7e390',
'f790ca593334d09ae3bb3400551b4052',
'73807a1527307f5920693cd1d6cb4eaa',
'3b64a3643d757562ff2ab0f6165e15fb',
'a36194942e794e149d80b631c9665028',
'904d2516c0cafb22cfbae3e9f5098c24',
'62086fe53de7da07bc231afbf58a01f8',
'242197d5a84af6c1301595283a0d6b85',
'35186bc85cc926955ad34b0d26a88a95',
'718cc45050a5716bb4491c1c016bdd9c',
'e0603fb55889f6263c2bb36a87f42c5b',
'29896ca17fa7323d795b2350045f8eb7',
'fb99d2ab95409be5d1b3b39a978a1af1',
'a001571b650ac96391d01a3e3c0a2ed1',
'5dbf70ce3a3ed87b8740688b7d5d573e',
'2ec88542f841205435a62e7ad6076fa7',
'cbbe7df1cc6fe39f67ad43d78671638d',
'808370faeb2ee8bfa02cc71bd839d0fa',
'4c641297fe142aea3fd1117cf80c2c8b',
'4487c44f7e7c7d48127c5557a052e826',
'26115608f8e0f5235b3fb916cf61f931',
'32754323dcdfc75a49d1b36b7bca8adc',
'101316c2408f68175dc701bb22ff6586',
'f02989f0035011b33b6476b2c4ab12bb',
'298f536527a3cb8fabeb6f00a8f6efa6',
'1699a36e2298ff9cf158f3e3e963af37',
'4142ee022a701bf12706e13bd2fbc5a1',
'4e913f159e33867be729631a7ca46850',
'5a874516a11f7888e0fcc419651413ad',
'41707e3b3257ddc8f2513cb227fb1d7b',
'b7dad57e80312d5842dcfbc531e5bfc7',
'29234fcfd6949f91fca3e64e1c165e3b',
'cd075ff4cb60a9f7a029320e78e38dfd',
'5f918e927ff3fb4a3ed09e3b174f92cb',
'915d97fd1f8aaeece999fa4a474db8a9',
'a559406221dbe956639833f46402b785',
'b33a0392a8a8c5e53221354d757cb910',
'ef1191ce16c4d4d1a38c9bf6efd6daf5',
'811b5aca935cc58d35ccdd94088f1bb1',
'bf079128f1ab88f6c6842fbf255ea8c2',
'2aaff3311101b7eb9c02a11dfacc8def',
'936d839e377474925b3089d5aa5cea4a',
'70eec59f0e9ea6d6c2a99e7978cdcd15',
'3b93da6a41350eeb00e2eb5d42576712',
'431991a0dcd8274a4676c79627d7c339',
'2b2af43044f54f53bbdada5181acfa99',
'8fa2c0cc889d84ed7dc6cc3ff0146ee5',
'c4dc58b53e5033664d1d3665eea5e3ac',
'a8140911916924dbfa5090ec4160dbd3',
'3988a3ce72363e23634ad7d7a8d83857',
'db7803021b3913c13a21042d2549e6c2',
'3ec2e9aa809f706dca2b654e45969079',
'd62ef6e3b4957f9f49d6c77dc40fd4cb',
'7bda24350ab5df4aebf306bc86a2fd41',
'97a4452f348f6d76ecb21a9c334bfb30',
'6ff03fe642e32eab20c1d4570c0846bc',
'98c47076f515ddae67782e1f13b48ed5',
'd665828c01fcb74ab38f94e2a1648601',
'cc379b8191af622ddbea63e75a49d2cf',
'f74d932896a0e0d60d65df09f33e5698',
'8bfa2eeb8a3ff6afc619258e39fded56',
'e67bb8ec04ee4686c2d03b57bcd8f904',
'7b9ea41862e9ba54d7fcf9c1aa1f8f15',
'139d5924b8bbe7dd6d6f250346d1e122',
'd8df798d97ed48bb605a89ba4f2da5ce',
'e071e3b8ef35e25a02c3eace02914de3',
'a24f1971be985522d77b652f8b377e2f',
'6a69b5c47f35bf48f95010f30eef9bde',
'6f99f6c0f7b323c1c92704a548932b2b',
'71eeedfca25d341e362aa09e8c82e705',
'7f45ddab0307034bb3aefa66d5a90666',
'9d9d1b4bab3d50725ba28295e6061daf',
'30a08bb3f9387979b5936b0a5aae605f',
'36c08fadfdc3e4ec7b0d07b87c146bd3',
'd32afa5ed49afb95bd94e70925cb63a8',
'f45876e14b7698a5f6a37d6280a6caf9',
'5066aee527a17af9a8a090dae7100c02',
'4bf1d477fb656ab96879fc4f1e0303bd',
'c478958ee813994853eb7bcaedaf87a8',
'0b2c6ac6b96c89769f2831d58a37fc51',
'5bcd6814c2ed482f0a7ccd4596720937',
'd22dd00c888e799a39652ae2a7f9214a',
'6150ac4cc142622d543d04292ffd46f6',
'9e69a8f499c660ee0b4796af14dc08f0',
'cdea86bd10a5f5cdc127b94befa3ec34',
'843266ecfb6c3977c3b9dd575e462584',
'5d26b9b1d0fda5c490429a3b0fd6bccd',
'2d6a077439f27a7d1db32ea552df85ad',
'8a258cfecf5aef562e77fa5aaa74dee3',
'924f3ce10f82805a2b308fe770d0c1fc',
'18c1ae0f9ffb4833919ca3b18ded257e',
'5c4c037da96b41d3a4ea4331febdaf7a',
'c3a019707b067780620f35aa9a0c8160',
'05bfe322dd531a004801c03ed0b60bd4',
'e63ebaf82565fdae4b989d34543e8bb5',
'b6355d02cfc45556c1993b8ac53d9c11',
'8d75a65fe527a82cd85cd5507da7c9cd',
'ca679aea1c7be7e7a7aba75dbb703beb',
'cc4992c48d7a0646acc196e4f0fa8f7c',
'a02822dd16c059c889081580f75c342c',
'94aa6f3aa30c416606051910a6515370',
'c661e8793d05f3051cfc4f4b2929cfcd',
'e38360fb2ab764b2c7c9d7ec9e04fced',
'd6ab6c56603b8e6f897c4ed7b62469cf',
'9ba9c1e0466edc5661cd9dd5db82aa3f',
'2d96370a1ae99391e29d26b12c9d4015',
'ca8aac0d2e9168c85b8fb7eb4b0750ee',
'6332566075f5278569accc189698791f',
'5dbe5015406191b3a068e2d7f623b47d',
'e6dd2dace5219971176d630739d6ab32',
'e1e5583fb18924a5d9b6746f1caf3477',
'6c8baf8c11ee4e48ff2a84222911bfe2',
'9203c388bbf8445ca2d050c0b6d68ebd',
'2aa70b00c8ce70298c9c2e6a5d89a2cc',
'5d97169067f7b07c00b2f59e8b81408f',
'afa79bd8e280198233832133cc1c9f56',
'ce0371839cec8d902ac6e1d7284e3a08',
'02c389c56601d579693979e9c5cae241',
'2fc55883bf5f69fb3845cd58f30ba642',
'ef8828e0bc0641a655de3932199c0527',
'215cedcaef5fd733416c8a794ce4d725',
'fcc338210b00d432ebd3006317abf88c',
'4f5c8b914cf124330fdbda6b945099e7',
'8465f6c0d1e9081f4bae030aa5cd4f92',
'339a4d9f731e1f10ceb768dc8535ebe0',
'3181cc1dfbd4bf99fb50eb0b1393d757',
'c86fdc89f16bf61d8da73cd20b412769',
'b1bad9d8f4202e4962788756473eeba2',
'e26a5f07cf293150018c203ac365569e',
'a50429f9bb44ff9d2a37876a5c5d20a1',
'c9dad31dceaeca273fe97c215e97b654',
'62ad2b8c5aa736c55eaa1f02a2b08cda',
'8f5b8db21ea6a7725c9b8ab5ff3f5467',
'df8722ddcd3088d7b79d382ce78aa864',
'94efcffc2a361535225c81a5c4a2ea0e',
'b0c6fd3005c1e94318d269160fa8c276',
'96168ccfa90eef5e8cc4c04aaece96da',
'fcf612923e354c76d57aa6d373a7051d',
'230a6f96ee08f6f1f68c898f6d20eba4',
'aaffad970c281dd3c273a1f5d62cce65',
'bb4e6411173ad76be06c4e7d09193174',
'76a7ca89343e218a852d48aaded48366',
'2a32cfa68ccebeaa66d5e81892b0c9eb',
'a39278bcfc1748dc320fb535c88f30b9',
'd19c3aad480baf383f3246c0458bce1a',
'07c9c9992814e47beb55b2573d2d255d',
'9a5bff6d8f1ab25237501d17523491fb',
'b44ea20a28d7e2ed9260a8d96caaae9e',
'01e6e51f50789152f109544f08bb0aa0',
'd8f9fbbc7a0bc702c15a5318cc618b99',
'4c135a918be182d8cd35088f74624da3',
'1a95f0163b6dea771da1694de13a3d8d',
'9fcc3cd9cbdc808426b52c2690baa864',
'617c761a5889d9214a4d83e48fd36c3e',
'f6ab1c4f687de3b323a2cef4443b1280',
'a0bab6ea47a4baf0c47d9f3569707ca8',
'a4c2ce983c04649e5f821bdde97c3a89',
'a173bca5f28e854d71b0c8182825f259',
'44e37394fa5c8a4072da43f06a8180c9',
'b7b530638159400fe355f838ba0f6dac',
'f5328cbb6a3ce4dfc79974359aa77df1',
'7a3a862ed66555fd88ab6b2a0187e934',
'51648e9a28f614cc9fe4fdb3c6fde326',
'84ff809b3e321a15108503426ae0fa14',
'663c64a5c67ee8d2a8fdaa61d719b0bc',
'55d9d9d373c4e5986c7af6ebb54c1a41',
'b07d495104dff24365ffa75c484994e9',
'f9fa405858844b126e87621579b40ffd',
'1321ce8fab5a37e8f713cba7231b0dce',
'cb81c7ac0c9ac9f007aa32b802500c43',
'fc37619a6ca57121e886cb2cc2c32d6a',
'ef66a2bb069822a926c03174c6941dec',
'eec34c014a497d5a39d4079ae3db91ec',
'8ac14da100eafca97af3ec093bde0091',
'f0481308626a9384679b3aa5bd68665b',
'6c3d29bcd828f7fd155a83c430567db0',
'ffe94ed29a51ec069da19d87db32872f',
'39d4fed707779d89f56730c4c5b52cf2',
'3b1febd7a480e3d5485b86051eac873d',
'98208691659099e708c77f9560a5f56a',
'd8a2137eb00fd96daa2fe4491a713d35',
'd556e4a719863a60ff43233d16a4ea7f',
'5655178857833dce159230cc6c99ddc0',
'6707dd06e67cab2c5f404e298bff60de',
'f604acd195532b384953fed0c9555958',
'829c0347e311b8a52eae58b22f84fa23',
'5ff8d2e48cb6233d1f0686768401bac7',
'fcb8c9141474f08ff8bbd65934222f31',
'8f18068ab3dc6b647233df190559df29',
'a4a54622799394d75da14748f29f428f',
'038cc2c0243ce2c334231c18e61a82f6',
'97fa996dc858ec607ffa4c319ce6a1c8',
'76c3cef6155bb29e86391cef3320be44',
'17051d1070643bce842d736f746df29a',
'12cdbd2acc2861f8b81673ff35e73dd9',
'f996fe382bb16c07e064eaba4ea3b64e',
'8baa99666bf3734cbdfdd10088e0cd9f',
'101718286dbd29353d09e894db5caabe',
'12d408858e870996254cf1b8fbaf4572',
'b01befdc3ef516bd0dbbe81932d5f907',
'e5988c498944c2218fae806e8d6757e3',
'554698b7101c958f92015bd8288d2f94',
'd8075cbb89f99d992f082c35f56d9fc8',
'08dc99bd5a59e77b2f4a2a9e8b23fb9f',
'5be2e88a1793b98046bf260cf91cd9d8',
'5084e26c633939ca56bc6fae44750b4b',
'd64d718a9ad37dbbf870152b9af257a2',
'b8f8881633bcad26b8baa6caffd45b93',
'63b7444abf3b2ad18a51101cb532a9bd',
'6bc9d4df980f70ce060c0c6a2770ae1b',
'40d0abceba125868be7f3f990f031521',
'70887da36e61e265c7652cf29fd9d232',
'a327479db576aa5f3b8f0fa16b650b26',
'379f63c3df8570a479017757c0826d2e',
'86db321f1f718c93bb64b0e352627448',
'481af5ef6cf7698a7d286c9152d40d84',
'0ffe5410da5d6ae0958e87eaaef3e6af',
'308e6bca0f35b8e8ab77b50f09cedc7c',
'a05d1367da6a2decd0c8e69e10a15456',
'e6da0d032221019241913248ff628900',
'41201bdb08c6d57548873492dc36cfa9',
'f902e59f5c363dc2906f77939056b99e',
'55093f6cad49aceb5412fe502f3652ed',
'ae0f75d466d47467398cf8a2b81828e7',
'62602792027d9a9915840f88e321c165',
'c44e1355e28a8b799128f54506e95fd4',
'aa4c6f25917f0d97e5c5e151f49157c0',
'd63da4cdbf74e2c3092722ec6025e4db',
'e710fc1492a0ec152c35a4065c5771d9',
'4d3cd17e55c60a2afce49101ed9a8598',
'd8e29e8d6cf0c27155044789cb082d9a',
'19352803d47570fea3087f017f35d9d4',
'5af7af28df5cccc196591802d331a6ea',
'54a1c8c2b78c05744f377fb2e7863995',
'28f8bcaa92957406d27cdfe55ad41636',
'e287acf3e389d3794d06e5a888b93f9f',
'f5fbb1083e870e59594676ff8febe042',
'fc286d463038324f8201c04945316377',
'53b59dd873eadf29821bb2013fb4f774',
'b7f954feed4ac773506c9a66d5741844',
'726deace97588f4ef0d4a00d2a75976b',
'854b909d718d79e020012ffa845f1932',
'e9448198030b8dd474a36e9eef566c21',
'80eab7984516e923569d959814bb4cfe',
'a64eb7601c4e7f66ae24d04b3766e345',
'838b9e6122e2c89f7078c4d07c7e12cb',
'20368e15f78fb7629d8745ada2c362a2',
'e13e0eaaef0895244371196d64662445',
'6fcf449c144a7c0b4565a6b02027cd55',
'9cb7a499144fd9a99af74fe00a76a1b5',
'1a885c9e18cb307d5a59b24eab594b54',
'769d28ae7a6e33752daeb08e209463bc',
'b8ae2083fd3541d80e7dfb5917fd42f0',
'12c4635575abeaae8a52fcb3be45f711',
'476094c21004fb39f3aecc62291d0d7a',
'290722d83c06b1aa7f40dbb0f828a593',
'196e8184c438d809424e526abc2fc303',
'ff065b19e54d62d7d06f7c48073b88a0',
'2cebf78f5d50a0813b02335a4b8d20b8',
'c297d3ab7380d6522f90f3af483e5e73',
'8ffe83cb8434d398a4f52ea89ffdd035',
'986894b466147a17cbd17c881731e089',
'c0e486b39282f194e995d3e38c0b1c9c',
'95cbc1303ce1616d7d3948097d44cef6',
'4d6c8f0dd9c996f3b45407705ce6ec28',
'5d6f4b055f937ae2638af0c3a4591f48',
'46c3d0c2cf6bec843db231d62a4edf60',
'cdf8a20ba0c1e24655ba3597282075d6',
'fd6102af66c0d0a2107a561e56cc045e',
'9971fb913887516ee7b1570b6d701760',
'98ba5a5cca6b30efacaee8f800e54696',
'bed7cbf3cd44413c7fd5e7cc6878b587',
'1e8c2224afc817b5084f1113a1b47dca',
'debcdc9c37c4dfd45ffb3644e639829c',
'022526559c9a27bac4dbbbd22e6fe252',
'03be24412af756121af41c266e01932d',
'b56faa43299d169e95cbaee18ee020f0',
'2326d2d4c4b83bc51bba594ac22ba0c7',
'67dd236da62cda2f353e642226cfb1fe',
'1ab31c8e311a04b14f47dabf45de7ebb',
'5e635940af5776f900b6bc9f1edba9d3',
'c5bfe4f083ca55c6282c16cd1f23cc20',
'0d728ef72ca8a0c0e988996a32a337c9',
'9b17a01959661ab9115b4ac2c98d064f',
'35f280c6dc7c89caf20520b741719437',
'62199f5ac721a0cb9b28f465a513874c',
'4609153e9d95008a785b48ec7150c722',
'7313afaf5e224daeca44c1a4fed40b24',
'3636a12948b65a168d64432a4a7e40c4',
'192d907901e01259adf8a04e414f6d34',
'5e220306d3b2a09808f2c95b4ec5f540',
'8a9c21a3dc6923ce3ef464b92623bf49',
'f0bd7d2fedcc39a3f0d694951a1864b9',
'1da210460199a1f363d946a53f9b6f71',
'6185cf48d38c8af4f2373896adc1d17d',
'ea48addfa58006e94998cd9fd916de5e',
'ff666c60aeae9a98343eab985d08f719',
'0ed2e9dab2f35d7bca10f5b53b96e9ca',
'c4ae271f3d708e40c8213a015e7f9909',
'0b53b67bb3b004a8681e1458dd1895d0',
'0bfa5690b9d14335d0888359166a001c',
'c9be3fa126e5e995d8ffa98b8a182f7d',
'07ecd6d135bf1ff2207c5abe756bb61b',
'6b4c799fe819ab4ca251059ec36d4fe0',
'f3d298ae5922711df1614a43ded48e33',
'6f9ba5efbc938c638ebb19b6efc072e8',
'421f8aadc6dbf40b9c5b424b6cc9dcb9',
'c5387316ee1b9dfe6867c8571d59e699',
'c7314110e174199d23025066be49c0c2',
'7aa88afa8b3a7b8cd35bba37ebd2b978',
'ee6c66d90959071b9068bb8b43754500',
'89b25a085f8a42cc0298d9e98479d25f',
'53d5ab4c72c7978b687ce023c6e41beb',
'fbfbb1f39fafb7254c40a099218d2b26',
'd2e891cdf5c4d6f1f66a2217b5161cdd',
'd75f322f26ff8655e42954fcbd43c6da',
'070baae537757c3153336d327f126f8c',
'5a958039279ae1af5f78028737f92e97',
'59f4188eee2af17041172141ebc62fb2',
'006a4946979ba2842c1a894c98f26bbb',
'1e1be12756964da1fff6c87cf30ee108',
'5871cf051972068e58a71bdf4442e0be',
'6b75ce0385f95e789ec983be0b2cccb0',
'24f849e0e093177dd13bff7145d9df93',
'fa892283f0957987b79c0cafa7e9d824',
'e5456090e50f509926919e7f68a43c5e',
'0f0c2419593225e0c3c6e7cac3efeedc',
'5e851f99a6ac4dd2568f7da79effb6f6',
'6d91cc6d4808a5869266ff1890e5d89f',
'a0fc4b3fae344c1f095cf23974cf0611',
'9613bf0ccfbf48d4c91f5c9c71669c51',
'3f4670fcc84916f762fd393637a8ede6',
'97f0f057d350c3053ee60364fed53182',
'0fbc1d4dc2dcecc490968aa38f550f70',
'ba5db12f2d7b5c4a9e6f886adf5bd866',
'9ad1011368cddc788fedbb5a383e1da6',
'f7cea43882a3d0863bc99400dc23d6c6',
'fb23c27a34384a10a2a7516ed27b8028',
'9f05ba1fbf4c241ce8e435fcb95e9e38',
'e65720a3073b5d0880fec5d5a9d2cd9a',
'0e80c1bc4431fbde485c32afc6a7fc84',
'ae4fd9816eadffeb84545a9c1c960cf4',
'47a42774b70bf619c615018b07948622',
'ceabe3be8ac9c1b1c85c8f2ca8e4f612',
'2e40565753baa36b1602ed046a0958ba',
'c2ead420bd263867b825556abdee2438',
'ebb58618b2ea0a5abd60a0fcda618a30',
'f29e06ac92c9d78032438e82fe26e7f4',
'70a0ee2624e5bbe5525ccadc467519f6',
'e7d716a299dbf44ed1ebd971cab5797f',
'5a46bd89fef473bfcebb774abd451dcf',
'bbe95f0d69eb02d35044028f0eaa051e',
'a410398e0a0d5908e292efd774a15318',
'084f4ed85f700d8ecc1868cf97b002e7',
'1fba0f33ae963aa29223be398ba2f599',
'7a2994c471d929c339c85fab80541f1f',
'0e4cde9efb4bec13e04b8909161f1c9d',
'd9a7f4e1725f417526f1083eaf54e97b',
'70d3dd98fd443aae2487291f4f535c3a',
'7d089ea3de7c39ce72a034cf438b7d3f',
'c70c178e195c18ba4a3c54fcbb00e400',
'8513c1dd724637d5680ad09bf39acd84',
'f084f83bc0a9aa07f9b3cd2337cb647c',
'864137aa602241be102d018412472091',
'25a5bfdec8038af63032c8426b91f1cb',
'4f74b9e5319e5d434667bd0e22b2bb23',
'cfe1c380fdb9d4a2742b950e1f7a6226',
'54df9814abd5b6b32f0cbc5aa5f06abc',
'2d53afc43c1ff96011e1f1737e50fc54',
'cf4630b005138abff1dd67c7afe62a34',
'f0ede67f567a4b4fb6ec48f7de5b9459',
'204fcdd58e7ebdf4b6e62293bf6a38ab',
'54cea3ae2cfdf58b300ff826c8bc0caf',
'694243426f81ede041c7675068f694c2',
'973fc89694097a41e684b43a21b1b099',
'87f66ca0fbedf8ccd1ff6cce56f44e1b',
'cc005137b55681ea5633d5a7e3e5dade',
'9a0f05183f4a9392f48f598f068a8384',
'95624fba84776700936a3b39a9cb5799',
'32f73bb9160ce797516cd7458b9c47bc',
'ec2b69b4caaa65ec3a9f921c352685b3',
'b34d5e2efa56c2c68e3b84641c14b0ca',
'c6340e8210d5ee547930a5cc2d8aa184',
'afbde1fea0af83416743ca548e434233',
'df755eaf9cdd90c361fba53166ccadd5',
'b600ff5dc24076934f819c273aff5948',
'e19aecb7b0b71484dbe1559e9c8dc9bd',
'85702ecfd7339f1f7d5f1ac9644e587e',
'ac56afe8cb45d7537f6c8dfc8d6b6022',
'78c18654b473f18559c7972cc019fbf0',
'ed184d3ba61c40c7d1c081cc0bb20a33',
'236291873043d1992793d1615e5c8193',
'4b5e41a52f04ee1bc5742bbb24640d38',
'3553ac687abb0bb2277bf0af3246501e',
'cdb44f406c929d5581b39b5160b85535',
'2e593966e6f72b62a83aef9ad86e88a1',
'0d692aa956ab761b5b311beb7498735a',
'aaf9e914f30e0621c57bae8f4816ca38',
'ec8d5caa960b3468bd425e9d09eff40d',
'e125f16e04290cf36eb222f969ff05ca',
'beb539c21b10bac00efb04091e20a07a',
'03603b0e75a1e7593426af83383791ce',
'8306b064fdbf415ee61f61ccd09679ca',
'b68b90ff6012a103e57d141ed38a7ee9',
'1fc9033b5d8ef34463e03b3dd0ca56be',
'f832a7d924dbfbf222057d4e94a5636e',
'513ebfcdfdb54393cb1bf076ba048c31',
'646533d90f231841af085f51ef7a63e1',
'fd8d897329b3716a8cf110729ada17eb',
'15ef20617176f15e5f39d5ec674fc159',
'96accd08becbe979af9e6c3046715f58',
'4ed67d1b5527d59b4f9747a95d284c41',
'ce109707dee88e4b3cb3b9b1d08c2358',
'e46b9fb0ae9b570ac9328dc52d3af943',
'1f7115bb398e136b7e9c822d32b964c0',
'2e4f151a1d77f5c987760d1a496509c2',
'f41476b430a70a5e2556dcf007de3c21',
'942242e7c00961652f58f98a4aee2a0a',
'00c08e61233d5fd577973bc6ee496b3a',
'2f68d5eb3287df9edb993c44528754c7',
'064871ffa419809157db14a8a1f060d7',
'f27dd571c1c8395dbbf34f39514fdebc',
'534693c5b008ca1fdfc53412a3c12138',
'f845eb8d2c7260361a09ddd1229fa374',
'4f610534b0013cada00ad7e4b0cae501',
'0e55c4b01afb1c7a521e3b70de10fd69',
'49b0dd13ba575c004b49325da5f36ce0',
'5e890c535a514146f110d01f249d79ea',
'51b4b7222d6899273c727dac359baef7',
'bec5c08964fa2fc4f9164b1b00e83164',
'607511a53874cc595aa863a4db3488a8',
'20671fafa76b2d2f4ba0d2690e3e07dc',
'4e082c4b17775badaf3021f2464a14b5',
'98c8fb5f3935d78ff240d54ef8d708ae',
'7685bc420d7838673f89d93f0466e30d',
'309a9148e58ac2ea2c83d8f3d49ade1c',
'e4ab415f6ac6fbfc5f250ff7ca55a1fd',
'138fddc0e731190f075e9582ee60503d',
'923629652803f8fb1d8761f7d5f71aa0',
'5726141bba4bd431e1e5f77518ba94db',
'7942ceda8b7cea5069a9f07193778edc',
'1c08e79f7f7dbd57cdc06bb5c650edd5',
'9287e0ed38cbbfadc910ccf1b88f0f05',
'b9335788dc5daa6326e10679e6a23774',
'd5c307a1fa8cd058970b0308790c0587',
'70832b947281178591990d720b43190c',
'f77b372b2091744906868eb41d6ce210',
'4a71b58e62c35451c412a076133c1be3',
'2d53816df858fd02f8bf8f4d5bf1ca77',
'c4d35c1e64f6fdc676a05d8b44625704',
'fed90c21337391c985a6c4f29e8e13c3',
'ccfaed0c5aa358c19b00c2c51a355c19',
'6afdf1443891ec7b43d7de8b60c1a755',
'90551d25304c2c226a9a93ddc719f4d2',
'9ad8e816424a42de0c52a7ca03da08b3',
'92c7dfe16d670eb237e2fd84b577c41a',
'5b489a50f5dded6cb3afe3e7a59996b7',
'4f4f6c90d59e0347237160949dc78838',
'1a12c8d89f95db4dcb7b995ba48f2a96',
'b0341cf251d3415e90d2419e8ac169ce',
'bc92a2fafa43098f222cf300ffa72be0',
'29b9e9af1060f33e71e7518ea99ad9f2',
'12911b73bc6a5d313b494102abcf5c57',
'9d4536c0209ad25570b7d0b62d84a2e2',
'2c73011c4fbdcf978a32c9e244a9c314',
'c09a4974287a3dce5002339b3541fe07',
'2efa59f7bbd11a52324a7450062068f9',
'b1dacf659600b61c060c57c21f4e723c',
'c54125ed8995aa75dc2e9f3635df9864',
'62a7b34690142e8a9aed5625644b92e4',
'2c8c5a1af767033f9fa47966841bd4cb',
'a2f8fa4cce578fc9c06f8e674b9e63fd',
'e336395b26916621784ca9dd30261e33',
'baca943f2dbe407551f14df3ad51ebc4',
'512d78abd975e80080cb8c7237a67246',
'4ce315d5b132b9dd3899881aeeff8871',
'ebc441ee90af4550420be922f9373b9f',
'b855e6a272571652bb5395192db70389',
'e0598814b1f7c354aa9d4b87f4e53575',
'1ac8e81c63ec4fa1e05dbdee91a8b509',
'5fa71c55b3f55b2529f87bfed31ec17d',
'3da55c18d2bbd7ee783a9e946a8a58bf',
'86e265b062eff579c804de3a4ec3220c',
'ff931683828a159f1dc59365eb5f411a',
'950606f766221b6c02e371b261e21d0b',
'dad55a53676401acb08f55365c15afcf',
'58242026b70dd896d3e8798cea88f941',
'6595ae67e768f02a3c70e5987f2a58a6',
'f4f03f1b7c68fa677afc424f911d07b8',
'b75c82e68870115b45f6892bd23e72cf',
'9dc9afab1169b14231bf3d8efaff7076',
'b9280e2b658b455b9c488725d8c3f984',
'18de17e3be726ea99b75d8da6fcc8e78',
'c38fcf0fb2e85a1cb887eb901c503ca4',
'9d9cf423b85cfb9fc5b3c28650b89bcc',
'd9a64d8d5d136876cd37f5cb45f129da',
'8a7a7239448c9925c5dfeceece0f09c5',
'bb1a6c34fe98fd0e763f74e64ea7b5f3',
'a541169f994ad909aa405e03bd0c7d22',
'820195f4d96c5303726424e561df3d47',
'c178498000636a5469e1ac70c90ad016',
'116420327344d601319f44efcc2f2009',
'24c17fa378521ebf9a1ce3d35127b386',
'34987be37e26e730a664cad6ad57d49a',
'f3ad80948da8778e3e480504eae9a5e5',
'10c2e0b5fa3a1542dfe81507556426e0',
'1317956ed86a75be11892b8f19a9aeee',
'faba2b301c6256f2a1d88cadf0fc5e45',
'50635cfab8b52190a732af2f18d8f7cc',
'653c9039cae26b68afb3ae21e02c2929',
'1868793b279b8287f5ee9eae6285ae4f',
'c846d7ac4cbe3a332d5ee5f5720a1ec8',
'd2f9bf363dd0fd478a20552b6a1a272a',
'b2b8319be9fc0409caf94f0c907009e7',
'77970bda2a9061e9f48385ea6cca0699',
'db7c7a5b2f137ddcbb9fda588b0b5257',
'd6864154458585feaf552491584cad3b',
'a5afeee805a361f5d9d38e602efdac71',
'226f3392539f9146b695d9dc974618b4',
'04d0ee5f8b5f738d9240b0b6e6371996',
'4df13c896802699ce857221a290c373c',
'7137747cb0ce60b0ea0f4d06d1f49717',
'a4f61bdb711f720f019c4a5f504cb850',
'fcb464c45b6d0c407645b5db892fc4d1',
'bbe700dd1ef6f6c032c2475165098281',
'62d9d68529c0940eb299ebca1cb856e1',
'0acf1d862704dc4a44cdda1fb925fe4a',
'e558023f615e7136420320a369b30548',
'bda2686ad7e4887eac70c6cae27a3a4c',
'1f79a96709b1d9fc536e736c73102fa0',
'9c9f99969615405a599cbf5ec89e501f',
'b70ea1634874e121b842b510dc5810f3',
'1d348e6a8f43f143da3d28be0c226202',
'b75849564e82d22c8b62e4507a08c563',
'53cb864a86bf41065cd48a6a1f7f23a7',
'4d6b68a1bde0c8ac6c90f1b3b3a05a44',
'79928b83838c5d658a3feff4faf56efa',
'fa81db15e9df56545a9afa691b9c83ae',
'b815611cc39f17f05a73444d699341d4',
'36c7495dbbafed0b7a0d77846a5e06bf',
'184083c8ceb800fb707b8920b9ee1a94',
'57c22d9207db93d481a7f24086c6509b',
'f9b776d41caa10d0fec61b1fe6a49e99',
'497e66bb9996cc21cc30ac94bdd37dc2',
'22f136408855dbf5a2c5a70e37f94133',
'8d5fb4423666609d5bc23b5511a919e7',
'4873d9d4435fd3b5ad455be0f82d7a05',
'99d2bf79240bfba45fdd2f63f693d3f0',
'e06b8eae9e2f6a1ecf783af619c15573',
'f01b4a3bbf65b645e791052a7b028ea5',
'34970468ff9d0f22d91625647a6d1941',
'1e1823392b32baa6dc47314b5636a214',
'09e2145823c6701d07d2d1362cede672',
'5b1d09f70dcfe7a3d687aaef136c18a1',
'fa35be5268bd558f7ed6090b8e286b22',
'5d37be44489e517e3c09147439f6cb2c',
'5ecd9e285cef8cb8770aa24f4dff3835',
'82adbc18c6a741055e08eea49030c6e5',
'7eeb031c71fe18176928a647a71e3d0b',
'0612ff7824881786fa64dc374581d9b0',
'3309935698dfbef3d33529b5779b07b4',
'191784fef7fd577fe0ef7fe139de00a5',
'eb1cfefbf22ec76dfaa82b5d20249945',
'515a48de1b44400465b575dae2ec8f9c',
'91223fcc260873a157b9843720b5efa2',
'44cc0deb765f65911c42d265db7c0423',
'a501072e156fbfbcd8b0356fe0024574',
'f1f6157c502f6a83c2df6ab7d8f29578',
'448e57ec71b00488c3767967b9e11050',
'e622d17b06ea549ea8e19151d32af643',
'8c948a8a1dcc4cb6a6cd665cdf143218',
'daffd52293a1fb3ec6666f27dab1635b',
'63a13257b46f53269a8f9214089c17ad',
'6dd4ee37f5fd0a2fd23c032f6d9f72ea',
'7117d015d7c43d7588a42a609ee4f3bd',
'ae1fa4459fbfb8a8c0693b32026357d6',
'eb3aed6735e7441df809a8fbab17694e',
'e5c20764ee440b9f06d5a9e456c1f32e',
'b09a19ccc1cf7c44a25c7fc091a166fb',
'dd9cd6a092d86b797bd45647b3e88e32',
'49a091a1358faa1bfc45469eee3d3e3c',
'2ac10e1cc1a396cae52b4115f0eb03d7',
'3b64a1fd6353f29a4054d598411b6fb8',
'a70d3447e6cf289b33c4ef86db956695',
'ea90f629ac58eb3e812d30bc41735462',
'2e802cdf289e2fda6aced385b5f3b063',
'6f4d7a3bcb17e9a6e87542572af2eae3',
'8b36f312be98e7e38bb6df7c89bf6f89',
'9b4cf0e166c219ca342705d54d032663',
'3c81a1c305abf6f54f5d278b360b4751',
'90af771185623260bda04a20bac98e89',
'f0e3841c1a3b576709feb4fec3e61a30',
'6b2ffa2320faaa82d1b5848b8f376459',
'4390ff6c8b614a05ae53c673c2c4bd66',
'967f1e72810298de16acb145c996bc6b',
'68f435084f38c7e4fa7674e20afd4889',
'5345c8fc097d23ce6f0250d1cd12a28b',
'de1ae2979f58753bd597a1e15655d3fd',
'b14867daa64d99fa3f63c233322e2953',
'379b834537f2a072130a6a562c7c261d',
'04e33136e0ee4395906810d1e1054dc3',
'125e0483a7e384c47418216a4dc792fb',
'da7521787e5711ea6c981983e4baa729',
'b493f0488c640c6493cf9e21a14e282e',
'9f315109e9c70bb3aa9180550a4b60e5',
'6e203e2acbd5656af70cca628ec0d8d3',
'fc08a681d6b06788cb6f0e6ddc89a830',
'44ea4c3c4e66c58749fc851351cd8f9e',
'2b5cb105c4ea9b5ebc64705b4bd86bf7',
'8cfb2ccd8538f1856c42410fdae53013',
'd990935d62c2c7467cfe664898038590',
'f06bfe964541db65eb6715eb0e806578',
'1baaec324ef5562dbf7c4d140bceffcd',
'064437f2f953ce3252209403ab63c1e4',
'37deaddb114cd6b71a962b4bc2642534',
'4342352f8a6e54c7b288db4df3005b30',
'354abdeea3b34dc442f3db2f5e29735e',
'42eb2b3e991dfbb29712c904f95efb57',
'922b128ddd90e1dc2f73088956c548ed',
'a18f7efa35e8c3e02c966b7aecddaf9a',
'1770d4eafe06ca85bd9a3a3b71739af2',
'06ebfddb65e905e53023d33524e0d1c9',
'38de1642aa72f75644173309cebee20d',
'242e54a54f2ad7409b6b4a0717250323',
'20572a1bf41a876b1066c291ab6dc79b',
'd7c58ecfc2b9804f4ec8e99d290375d4',
'b8c01132c950c6cdb39dec5db00126f1',
'0f84989ea3a96955fde2283dfd4e47ad',
'0bc35e59599f2221d463e41ef7e60b1d',
'224f5e1d7c496b0cb78f0c155adca809',
'77a807caab2b3f0ea8ba141155c1f285',
'249292fa288a33cf057c23a4e65864a9',
'7e943fecfb43cd738e31d6437d71d053',
'4a1ba87781ac8825af2b21af47c1a188',
'70057871b783232510f58b332dc50d84',
'0d953be6586da893aa65f57c1c564edc',
'53e99f3dfbf1afeda4f279de5b6f392d',
'76914bfaf5868bfc390af83d4ad5f271',
'2ef6477eb6f494313da008c38cf5195e',
'd12aa0af0ea6ff172ffbc723b7ddb99f',
'9bf017a516b59ffeb074159ec1f9f135',
'6e761848b6ce6ce4d8b726506fc79f9c',
'7de543baced01b84af5ce508aafa4372',
'98172b445e62bcf490fd58bd7313c6be',
'48f231fb72baa8cbb7d3ab4de8da0c81',
'4b6d82e71751f749ab5d692ba3d67f0c',
'd719563b8fd0a07d314a2f8d2d73ea08',
'b54562c9ac50bf8a4295e10dcfc9d704',
'4582378eaed0a5df5dec48739db62528',
'9a2aeec1c1afb61f087886d6566f0c01',
'48fb1f945209feb011149f21e9f512fb',
'677f25c313d3a59e3ee355d1d09d849e',
'4c2017ca65b8a4dad6c99464932ea1a1',
'ae35b5e4a6d73c59e2a8543cd5dcc514',
'fb11618c5e5b8a728aeb4b55c53116ee',
'c3720e7995b530f11412688318a73e78',
'7ca23ce5b9fa65df076271178d797de1',
'd69120fa58bc716261f70ad2f1cefc7d',
'4f75dcff96852820ae75cdc50fc6c3d0',
'108c24151930e01cecb38ab6e0660e8f',
'4ecdaf693fe68377cf973c3ec9c1d73f',
'b56d20e4ef3e6a49d51e247274346748',
'c5e9082b50297e251fdae9238b74e3a0',
'a32043b2a9600990fe53d291f101c2c8',
'1a704f6b3807288058c86162603fc1ac',
'00277fb8474b5d8fb659c1c07a1349d2',
'a18df07dd0b38111d09e06a97fa4e62f',
'db36e08bb39c4b9b1890d4be68c064ae',
'ab42a8b0b70bd8071fb4e8cd96e6f234',
'ce926fb74379fcdb69894e0bac5849c7',
'565f1eeed5054c1b5a0e268cc508b4cb',
'79e207a9efe9d11320f77290d61f2512',
'fe82bae25c74ed083aecb3305bf97660',
'702f264b6a0fe355918f6d1c07a07129',
'7b5ec99a894b260b8b04951302d424df',
'3b63ffaed67689e0adc8a680e48f7101',
'fdbf54d5bf3264eb1c4bff1fac548879',
'784078f476004782c044c230e8b9e18b',
'3fcb447e53625f4be065e0073f19bf1e',
'e5ca187b2e7d71da7267e2c603400fce',
'0226cf62f7c55e1e18f0f141acaf7634',
'8601d3b338b085bacfc32fca4e8454db',
'b4b2c193f8af66b093ce1f1d284406a5',
'd11e6a54fba32fee9c69aabe9515e69d',
'0aa3c915865113d8a9cf18e5b1d68f29',
'99cf97c605250f6df4dc50b39e1e627f',
'f92cb360be6f8af2c04d5ca913ebb96e',
'995c8d1010aef27fbde1dbe4a24190d5',
'982514ea4690260f19e0355c88a370db',
'4438ed68ba1108ae84ac896d8d9f2e51',
'8c082018736c94e56c691b0557474020',
'04104454455e0f74e622e2bdebf7b4f2',
'73c195d0da927fee655abc78e25de445',
'8671642568f9fea43a809bef5b125af7',
'caaa84806dc527ae98f8bf84120217ec',
'0c85b59b301c676591fd6370665bb4c8',
'ad120dedf13ae9ad9fec8e0984705ec3',
'4123555910d0753fab4f7ddbc0e833d6',
'febfb224f737c97bbe832c0c302c3a89',
'bc0b916086114065f5cdbcc1bb9ab6ab',
'b28e8dc4c2748671d44de4eddc9cb269',
'9d571d8f8d64a4bc4de4a4bb1e933aa4',
'cf304932c158fe8b4328347c6d7807e8',
'c9e407cc22d14322f4569720bca57aa6',
'33e0db8d9c2bdb3391a3e0715c6f233b',
'6d67f09ab7af31d2db26fa0c6af9248b',
'a3438d6b28e75a1767a910bedc6f5db4',
'20e1d05a7f8a324db3de13369e570529',
'803f384896ebfcacc11e71ea613016d7',
'16411f8788f85786865c0f0eef11d11d',
'c5de55ef70c356aedb03d34b8c010df6',
'345125b326df17fe55371f3d21144c99',
'932d7f25db8d41a4bbbbbaf4830c7388',
'905b06811f170e3cdf97f20c5990463d',
'48c8b6c2777b9f36eec89c569a744e07',
'a03170bfc770a20b3b2834ab04855cf9',
'fe68b0430b03bec19543e45ce56741d3',
'0592bbbecd4d5aabeb96297db8a1a69f',
'0c3739e27f980d695711e52f73e8be36',
'0c8c3e2500d486b5a5e7a34fb08cb492',
'2a3858fa9562aff8bd61bbfc27376cec',
'0254141ec6add43d8844cf5e6ed60a9f',
'7cf4d5454e5d9088f73cf69f2694175d',
'45f4a9367026934f3f52fdb36c425fc1',
'd020c88f8d4a48e63b7f6db9224ef56b',
'd50cc8bf8a0fdf076b4b363dae478eac',
'a6a2e6753f82395e3881e1f8ea042f00',
'd7980e66cfa6f180c12d944d1b1d711e',
'c1ea27d4220a29db10eac92d59b06cad',
'9a796c79c26f59ffcff3176dce06f8c0',
'f468c770a9a45130378b802ae93d815d',
'199f21aa5b00b68d777d4f13da958ed7',
'b9b16f7274f9329cf525e8b04182b216',
'cfaf8175afc7287fc73a29ff11dd9368',
'fdcb02b7d27180fb14366f793f1b39e3',
'a250c624905b79b0e076e851b6d83199',
'f47cf4e36fc070e1d7bc58294e148298',
'186de745dbd4feb397cc5f942a28ba4d',
'3d0455d2a0df11f4a1cceb1932b3861c',
'38ed6df09b75b5401e0003098417c3b8',
'f636e2bce1411dfa0d60c901ef8773fe',
'6eda1c6ac5c0a99a3d78ff1c5c0e5bd0',
'be646038e2ecb4416b9d4e8ab28d668c',
'f86882aa75dff8bda430219ce12b0101',
'18c2d06e2be8722f5caf52697e15a33e',
'605bc448cac9cbf956c573253f9d2895',
'fc6d5bb8ebffd1be52151b0e181c8632',
'c96693b6869a39c90be81053f5ce0abf',
'f983c2d499e755fb2b0862519317f59a',
'5ede1243809a2e2622540036b65d7b68',
'880f659caf7ba0aef3bf0a40750e966f',
'fdb04f4105b617447a203b4c5727996d',
'abd2d6342bdfc3cac6f7321d16bf833e',
'a38a4d32016d39d5e70f4031b28a8342',
'563a946b91e86ec9bfe1ee8a3c0fdd2a',
'681d01b45e0b4fc8acbd561031547ab5',
'805a2750f3ca0ea909b895bf386649c0',
'6ab3cf43a707549d64993f13dcb185cb',
'6b39afb00537520dd71095ee5d0db7b2',
'61fd5eac1ae8249c18c46bf8d451ef51',
'c2bc3a2443bc8407714e504b98985e2e',
'a222ef7b978a3137806461acb55a271a',
'28ee1ddb6998b68e9b15a1c173778a9d',
'dcc4c7fb6b57fa455cc1ba331d92eef5',
'83ca2eac2612f8ba2e572e8e169734b9',
'775aacbeddac9a19e308c9429ce95d3c',
'e447331f332a9b4a4a8fa3c2c90d4feb',
'6c6e546c0d5adfda2650c96aa99f9e5d',
'da72b7902fddd75b33d31091a34dae79',
'13c4241a0fbfe24c9317c65331737bc7',
'584ecfbd059fb66986f1fbab0b0ac8c5',
'e56df64476f048d37a9b77d2623ce417',
'427cbda112b3260ac7113fd6801c3aa9',
'ade65d2b0cb8bf25d4cb4af5730178c9',
'e975002948f7c0d57b0c3175fc1bddd4',
'10bc6a8752ba1aa46fa22cddad3621e7',
'ff6d03d51a1871385eb7c2e8480e626d',
'1015fad4369029f206fe6b6212c6c238',
'71a7c769e644d8cf3cf32419239212c7',
'f7d40998d786d44d4d67b136c37d3cdf',
'758e66e025d4056c5e34ccdb20cd9bcd',
'f1c4fbb951720d7cd6d92488bae7dc8f',
'c2473a2afae0b9f42f44a5cc15b58ba2',
'51a4ea75ff037128124c854f7c115d17',
'5924bcc045bb7039f55c6ce29234e29a',
'9ff4ba59162b642c496da37775678a17',
'e7493df97bc7f39a70cf6f0b3ed670e9',
'd5e59295821b17cd1a054dca1181e6bf',
'1570c048384175d8b62da1f220d52e82',
'ab7866589e62657cf49b51ec1c89131d',
'481316c3b21a2b3b08ec9336e814fbca',
'e36f10f089538b90803bb3dd4aea8ffa',
'ae9d22c648f16d5f89644885acb24412',
'f2e913f0d9090a21bead6578f4fd9d55',
'e653329e34afa0ec7e2b89d445dde591',
'3df7cc576f1e11c015b3689201ca2892',
'39e70e98dc3a6ec35cd52167366d1e1f',
'5ddbd37503d02437fc22224b7802e74f',
'59fa0f6eab7ccf499459671e9304b136',
'a97756044922375a7fee1ee7d61469b6',
'94fc7cfc6fb2e9ff5ac67193716da9aa',
'586f26171470de3775ecf5fc9443cbe9',
'61fd94cfbc34669b9b30b34bb8ba4556',
'8deaec6e22b45343d6be98bf6d25b21c',
'd42ceeb655e0bbb2762a7730027c795a',
'f7df6188fdd49a8fb29025610f782860',
'b933f26e66e3b6cba6d4dfa440b155bc',
'6046193026eab8758256a1332039084f',
'a51f798d6f217f3b726bbd3979f7879c',
'dfdda9c2a7a8e12e90cab19a1d80b51b',
'a729905b8c23c2af4f660091129f31f2',
'3a3b3a9819ede855cd2f67700df5d69a',
'575457c4f2f3685daef962e9a398b495',
'cf32abfa11b324e4a874de6d971c13d3',
'b4e8f59a5558049c9c06c68946a2aee0',
'9c1379dd04aca35f7d897914cf18ee37',
'e4abdd676fca22e30d171fc22a2870d0',
'36d4f34d0a22080f47bb1cb94107c60f',
'74845a22943352cf206a4a8f3df841b3',
'518af9104d57e8012243e2c5061c4e81',
'da6048d0dbe0c97dbf6984a87056b7e9',
'c35c144cac77bf614b1c87d330d204fe',
'b317e8abe7ca1084277b9a29f08a16d5',
'8adf14a2d45203941b90a70db95ab862',
'4aef803e84a056f9ab54ddd4c568b235',
'0d209a681a3161f430e48f055c290f2e',
'd737fb4ad6ec750f764e2c6670f7c7e1',
'a899c711bba28c0fb168183ee8e10a16',
'8cab13b4335eb5ffd3bd01125d075dd1',
'4d91da173438622913906917cc82dc0e',
'4b7760861cbb9a32e83fec6ab84efa1f',
'26113bbe2aa9b3bc778371637cff39f6',
'e4aa3f99734c4700f37887cfe79e0ca0',
'87b43144be6bd3ecd31f840afa2ec50e',
'89dd504bf6387ed7d8a17010eb3b8d34',
'2df84327641438782b5cde94cf9f8b62',
'5e2cb618d1487fdb8592de417c0fba3e',
'5f63188474e4708bdc16a54f34391440',
'f4c2941e91262c829524d51475e49d26',
'39bb43b64477d227238927c370d25479',
'd98e3e965bc924d0c04740ce23944524',
'082141ae2688e24a5a5d17783da99774',
'a2d5f1b5c1563c0282fce52a0df3f9f7',
'4cea35d6812ab4c44115973aabf239b0',
'2c2068d4de8382acdba25799bced7c5a',
'90dcd7764b31ff5259ac101fccac2296',
'4d75bcbd611f325a93255064853e22dc',
'1b9fc10b4bf6417606c61e5ef30669f1',
'76814b50cdb282821024f9aad9fd969c',
'6bad256731a70e237485cf6290b26311',
'8a635dcd7c11512334754191e8c2cf3e',
'6607df34cd0451462e245cd332eae2a2',
'a563f6f52f842b156c645f966756546b',
'a24eb256ada478b9346266ef0b2d66e9',
'5b334d494564393f419af745dc1eeec7',
'896978cd8de2334a93025f6e8f173090',
'f1348cdac9cf9ca357f6892a0c757a2c',
'ce0281d26a8129f2eb51800fce9c682f',
'4f1927345fee5c3f967430b7e90f0221',
'1db8022995dfa35cffe68e24d7378777',
'35e0c3cb720d0aabf3389d25b69ad67c',
'ab205a16450d85a0abb087a3fcba94b0',
'2e7d4c123b9f2c3f6952bee1d6568203',
'4267a842ef3647205784c42e0a7150a3',
'9ef02582d46495bad6cd1b3152f5ae00',
'fc7fa9228f47ee5a827acadb81c435cb',
'48610e78405feb5a359a11f2da775785',
'4e944ab79e5c8e262f57aae51d38d988',
'e60b33cf31f9d88d29c4652e86b5a601',
'bdbfd9dcb04c9679e882d550f3ffb4e1',
'794052b83bdb52dd2f0cfdb8d1c6d7e3',
'4436be74b8a4efb5899f85c56a7659df',
'c5e82add0cdcc41653f6888d8d390a66',
'14a598095e1b1201221bff08a2058742',
'65aa665dc0fa25cfc55131498f1c4b3b',
'8be5ca23906db9fb082ddfdc83d2e759',
'a4c4c4f3aa359e47e067a0768b0e5e3c',
'c6efadc0b5065aab7bd1aa07768fefff',
'699677d7e10a7a3a88b4f14b182fd61b',
'20937a66a51a18cb09d5b250318dac84',
'b9bfc2fe82e992d0827ea617f945a07d',
'dc4c16bc27b8ee7e5bde41e3a3760019',
'87e606152ed1a9743d40a9a388c68f5f',
'06d910c945a51a54257afdab063be1e9',
'9fcd5276a72c47142f0ce63c6ebf577c',
'894b3dbd1c7d8a69534d537f70f84893',
'26b2d3943395682e36da06ed493a3715',
'd2fdeb05899c3adfcee6b25e6f76204a',
'6afd8423144da62384304807db1d0941',
'6c456619bac5b534f196cc9a678b4279',
'aae62d2fb787edde018145303a8559ef',
'06ed0b2398f8096f1bebf092d0526137',
'8d0783bdec23dc8bb5fa47bae790da06',
'55725dcc75738364cb58f285cf4be81e',
'2139fd111ec48de04240c4c5de71490e',
'ac35996f2366741e5352ac151e44e55a',
'e6b52b13027db0378a334cb1225764d6',
'69fe126f2446871ef21d4728a214a3df',
'e147350a686e5cbe6a2cfc230d324aab',
'1ecf911886f5f255e461fc1403f22d5f',
'e4977626dd04566c9490e711f6292f34',
'7f3b47ba3a3856900830840249d7e5a4',
'06629a11e613cac3ca6747457e64c8fd',
'48a373d8344615fec44aeb19ceaedd5e',
'bd8def98f42e3a0823d1b5422043b6f3',
'0324ddfe5bfa9e8bea82962b6b2ae260',
'3e4207c19d6032fbf6b6c20642fad115',
'c181386c9cc8a6a408440c38264bbfcb',
'7ed1f576f6718518e37e7afed2454362',
'0260d55f84c42f6e7940e995e8601de0',
'2a0d1dc06b72692a1d26aa4128dcb86e',
'4f3539f1d5fb321adf90afd92a4fc6be',
'f6d38cd6b0d2ec6f55bf8fa5c1a469f1',
'ff403e28f41960f6107928402ebd2639',
'8e731b201c6916a5a7741da4036651ed',
'4bc8a01ce69ac1ed6b0762be79af1e27',
'8b160b576e2e7eb2ab78b34d95ce2fea',
'14e472ed2abf93637747d30558100cbd',
'62390b242b46ade52b3af13de2535e8c',
'5162dd4879fe6f100cbe5b300b85b95c',
'dd3025fdccfda0be21ec798b014bf12e',
'138b79a502dbfe6a066a9027d5c13e2d',
'b8f59071987edc26e51a898076cafbff',
'330429a3d2c860b07f1cc0d126c6f845',
'633203b8210ad75bfad017e5fec16e0c',
'cd19eac006032e4671073d903360be2f',
'052a43495b0dd9abc3fd991a9b95a39d',
'20a009eb0b2313dfa6e1ccab4bb47049',
'cf8d08410e96da6a96fc9b19db0e374a',
'7b04b7a707a2a4f96883ae16aaf14ad3',
'fb56dfeaffb72c5c94403293986d4f57',
'2faf7f381e16cdca58bc1b33705e484a',
'657498300017b6a105f189b156e982b3',
'968984621a9b623692ad620e83584107',
'dbfb155bbcd82614ed927333c0f8d502',
'43b0fd61f0bd3e54f55a3aeb71d701b9',
'93d1a2e13a3368a2472043bd6331afe9',
'f2e7711f6f9b0dd42e74a33702b995f7',
'15832a6eabab06a9feacb30c13ad9850',
'c07cefc504f9dbda2ef3d44fadc61c50',
'18e86bf64d7c78c341e57400089573e3',
'8faecd8fe9698f7640c741aa5621f363',
'365624bf73664286faefe750ee05ad79',
'53759521bd80ab07635c9571e105863f',
'b826d1c0dce0138805f4c52d59375809',
'34ea7379ba19eda97cfabedebe8ba59c',
'0bd943de1f74ab4c6fea1ae138adad5e',
'b254965133cec54f030241c9083d0ccd',
'7d53815e2dc8adfd60d7976da2e18442',
'cd25b2e67d37db7c72486968a2676795',
'dc9c21fd0da2868203d5ccee1515e961',
'260ddff3ce66bd02975181216c073659',
'e4f9746e27699cfaa8a95f8089f56877',
'82b45af1c9b57d7e8ec2742bc5e7a1fd',
'a41cb26afb838cb264bd77b2a3e74a08',
'5dd681b3d45ecd4d7a8d5e5273e85b19',
'5c62f76b10b7dc88cbe52627fe70c43a',
'69e7541f906ebcfeb4d3782d0d90d195',
'b812d1950cb54eca943562c61cd48ea2',
'caf18df632095c743aae0d00f2a5ee69',
'63df8ecdf54ff1c685ec43024f0d99a6',
'5da85aab18156564998ceacab72de28f',
'e876952889b110937c55b7fc46957e72',
'883cfc751084cdc28a3ff63f1f8421ae',
'0820491449c5850dbef4c869c0950965',
'6f5d90fbd3a20239748585337775168d',
'6f85128d4b65eebe30f5562aecfc39c0',
'c8f54a2f98f05b136789e0888cdc279a',
'35a8310bc386f93379f2ee5e39ea7c1f',
'1c5c6d16a3b3636abf5efc2ed32231a5',
'bd0b7b0d2b6d0af4fa0e6520f6e7d7b2',
'd0a104f3ac7308d7d4740377f0dba8a0',
'524b3161543f68b988b3715f25cfd5fc',
'c0ebdbfbb075fec437cd0e8495e202bb',
'7b2c605768f93e8df88aea0ecdc6650a',
'ead1d973fb61b0e21157634d9e8d689e',
'9148a476576cc56e9c7db0974d8e1154',
'9f63bf22037f3427ead8272958f0dbda',
'23292a9c650b6fb9ae3313056be011ce',
'b782882e903c13c4a329fed5772bdb4e',
'8b7d2824f6b42aeed59625bcb5e2f88b',
'fbf38d19cd97849ed94e3d983182eb0f',
'b523c33fba840fa94a6fc34cc643ecbd',
'71aa7c880db182cb2bc8781ad90cc5e0',
'e8d7a7ebc77e13451f268172acbcea0d',
'c01187bad451f7d17d9ac3a3c0a49b78',
'e21feb0892c9d6164cd8fedb0308928d',
'eccf5145d062f67b0c028beef2f39a9b',
'4b47391b5f2d0b6b7210ca259f01bff8',
'6c7f5a027c78ac9e6241a3685e4dc8b5',
'f80ecd82ef2219834cb36e03f65a9653',
'a242773d1dd7629ddade478c1df5b802',
'61a92ce63369e2fa4919ef0ff7c51167',
'aa5925a1f576584efb4e18b5de243fc9',
'9d0b886dfa0f90496aa1c687d1d41571',
'9d345a148798e3b10a930a95ff327597',
'b9d10c8213026d6ba8f989dbca194539',
'3d7ab44bed9feab618484c3bd6d76a39',
'b6cd47fd799e0c98759409571869db11',
'5a4d9891c7875315c48161b9195e82bc',
'2928df6e51ff436424e0f52ee7725869',
'a53e24f55f586bc6accc5874495ff544',
'5fe127146b33c83c1e5db5e0879b159b',
'9c9607e7d3ae05e6a4ad523f5ecd2ced',
'c1b4e45cb91039f5fe9f74d65c85cb24',
'9b1ee4d8cbb4b4e88138bc3f5fff6b87',
'2d982b36e8bd4216a752331c26e52dfe',
'b66190f366f99bee7748857c5d630d8d',
'2db37394b294205580e36a2e89c717ed',
'd3d3cf403ae6107107c673a25c7398c8',
'9a23be74e60a68a4391938493129e27a',
'06ed30671f86d051a67ee5bb25559134',
'cdbf560319fa004a6fa1167f52fd3e9a',
'aad80ed30f690b7ec5fa10daab0dd4bd',
'4fd65fe723dd5e3d16f056ecf803be63',
'c468d220fa46590c8415fbdff703d5d2',
'a5d70aa8d4a9c0b1a252c9a39ea2fa77',
'6979da9f8b3df1a562b2e2edf0b0a693',
'12bbdf6ef403720442a47a3cc730d034',
'a97ba8a5461b0db2fded63f22bc0fda5',
'5410303e916695e07e71854c51a63df2',
'fd76aec3cd8f7ab937012b3dc571c185',
'0b1082157b177f95831c41e04c8a3726',
'9a9f79ae6579b8b4c7f97e6698da84ef',
'245ef0feb89920e2d2e7a51068dec0ee',
'f9feaaca5338800f3caae6ad5d573a7b',
'417eec611c8e6b644fae2f086a663aad',
'21bea384bc02cb4a7ebd59d940da0e69',
'98282917c6614e9b9e034bc76ada94c4',
'db0a2019158bdab4655e570c8cbf4890',
'0f2567edfb0350d982f21f44412fe2d2',
'29a8a8eb965ff353f6c5b70a78742b57',
'b4764159901cbb6da443e789b775b928',
'f38b59407fd6ffa3b391b94b05c52d35',
'0a47de656ed2d163734330495b947b4c',
'd810bbd0f107923bb6b5c6ecd76a70af',
'4f399f023111c3a96bb4c94bb7f64977',
'18590c0251226bd3385c137086b850b5',
'7089af9c2a3c42d24de888c65574df61',
'c91f985c2155f8a4794fb65d3440902c',
'63ec816728c7b69d50a6b6ef581da132',
'0c52166d7305089ef9efad4daa17d3cf',
'68b6eaecb57358ae7339f7e6100dd9f0',
'f15e65d0333ec2bc2327319e9a7cb1a3',
'11b8e4ce9b8e974b03f7d75ab9862adb',
'5b091b5071122d5c9be0956991712e4d',
'3c8e36c71496b8b47f2ed4b004035fca',
'13bd68391af4038b49ea6768ceddc312',
'1c5b89ff4b3cec3a1a9a8f484a57dc73',
'cf19894c887cc82189f2e845318750c9',
'3372458e82a6736b56e1d81cad633df9',
'453b7e2661730878c6f2233e84685bc3',
'a3adb06fddc76a4625533f3fb6a49f04',
'777ed23a372bf5a13e631a9f0c974214',
'a9161d20e313361212313f8831f45cc2',
'339c220e657c409e3d4089197bb30cb3',
'c20a17a6c99020c7ce72cb53071e71e0',
'06e9bff6ca045bbb767e0a56ac2b3910',
'40c5f2612b1e456354635f0320ed4d57',
'b54e7dd77d783da8d193148680125ee0',
'b67e53f1438a6572fb67bb93175264a4',
'4f44d837079a1255849e5ebc4bd56775',
'e4a5ea443024400a28cad85e1ea07a18',
'bb435d13a017dba7b057111bbaa4b0d2',
'4a383d1ddd959a81a2ec8d4c2d179175',
'bfcd7d8b6ddcdba9bd7877ee6ecb5912',
'8c5cf1266061d4a3827e1b07d325130c',
'84a89b85fc5f595953f3302368f0fe08',
'11008b025022e44bed19144f0a1e72ad',
'2a1b17c015774887ddd688279d7d977a',
'1f790ca021f21d9b7eac0639e1d79a58',
'90693c008158a12d523cdfa8f7c36eb9',
'3d1739374fc0a31f04b63e4641023605',
'd074f873f3f67829f5af35cad932328a',
'9e159b15df61c3d48ee2412b1457d192',
'9138677114ce80e3a4f64cac88c08478',
'8195a44883e1b6f943fe794b5355d304',
'7e488222de572840f2a745bc0e4c29e3',
'fc37fb4f3691ef773dde4b54dbbd64e3',
'9333a6205db61dcc3299421402a739f0',
'55663f38d123043234c00fb8da1683dd',
'de7d2fd092b6262a81acbb96685186a8',
'0d089eba390a9bc8f456669ad2658884',
'8b9f3a1d5facef9cbc9f08b8f2f4d573',
'78ffbb4592d1fa496b946752fa5f3c50',
'de3c72c546c98287b0b10a6303ad6471',
'6895e951250a323e51044af90610dd0f',
'd0bf0f4d3f724e2b1a0a979a4b51b641',
'fea95d3478dc8ffa9319676b5eedd3a9',
'5213dfbb949ef82586cc94813e5a7251',
'eca3e66da95ae2fdcc106c521d138130',
'4676bc899cd62ff496e9a4a351caab3a',
'09e9d9402fecbd52a877eedc2af331e5',
'29c2ab4aa3af55cb165cb1115b97e81c',
'aa7dd33874a7b96c882e08a1aed7d946',
'f66eaab593d551c1fcb46799b197f7b2',
'af7b7b359330c9cc7c8728117de56e95',
'601b47ec7d6af5e363a0611e1aaf69ed',
'15ce30fe9b920b7020cd11f1ddd6a8ff',
'bae181eb57964bf3f36f241aca7d3c1c',
'95ba13f04f32ce5a2890ee2b666887f5',
'9700437ebdd7d99c582e785a4ccf4a27',
'a78af4789325cb0371bac92b3ff86e0f',
'43b8f0783de317702eac0806f467ca15',
'ef5ba943b9808f1f885c73842e8ea8e6',
'1e0236dd0d837980752f630a2887b4d0',
'acdbba993a5a4186fd864c5e4ea0ba4f',
'3f0632564638737cf0f221e595fe2a43',
'fd508e068dc9e479062cb12fa0060f82',
'aba744bee07b490c01e3b4414d97ee0a',
'5a90774c9b0289cea1ca6658cb21f5d5',
'c88bbb8528a38d20e95a0eb7afe6b718',
'0aedf3c23caf07de5dbc3db24c9bcf32',
'de809fa9dc89e8a095855401c7ab4a29',
'c90eed1fad0fb955fd94a9243c95b878',
'f9ae74c893550e84eeb02a91cbafbb4a',
'067148708c02f1cda4ca61ead0fe2693',
'52d8906b2fe2dbc7e7c2d5a35b3229cf',
'dc71378fb54de649d41ae4539a817e80',
'525e5a6672dfda48e7ba046f8ff56112',
'9749eed2a151352cc38bfa1711a1062c',
'1ff8e0eeda9d81935936e5bb32ca15af',
'7639ba088378da116c52af5798d4cea0',
'd9b6f1f7714f293b52cbf60104fed159',
'192b72f2cdb7d6a7f11021ae0942d601',
'e2fc1c4ff3cce6f5d0149c174358841f',
'e0afa36bdb09853507e1537899fc7574',
'5b7fb202ce0b0dd4ccb386337a1d4aa4',
'5f24d3de7d8c4fc522d3924f462d6ef6',
'cb95f35f201ced60f216df3c8846b0c0',
'1799a2b976308bdc0acf35078b2f0756',
'2bae5e081a517123420a790df3734fac',
'9e73a60d350a213f70231d0a37e1df2f',
'fc54a9276c4859ffbe81bc59719987c8',
'c887486cde01edb36e6c834c493412b0',
'e040eae61dbb1a14d5e12a10927ec36f',
'dbca6145e2a63c6e237abda0b69bf039',
'e0f0ea0e9c21c63e98843dc22e97c28b',
'30e79eec609d16ff154ac37c254b9c71',
'efe3259b081a1d0db1a0b820d5433440',
'b2b8c9f9380ae02ae280721b8d09cf49',
'408ce5baa3cedbffc75ac50a9a77647a',
'f31e10c86e41ac3265fde4c0889153dc',
'ea315fdfcbcb05668c8e2155b5b0f6e7',
'21fa54240d11e2892a1ce620d56862e1',
'b8bbe4b4fdd38f44d262eaa78e250537',
'519f82b24ef4bcb8fcad675afbb76761',
'dfbfb642db0e4a7c0716c300fc062264',
'd51dbadb0497d23998f47b381bb5c108',
'191f10fd23e17981c2c4cd727eee463d',
'fbdbd0116dcaed30baf427f6b57a53b5',
'2ac4d8c97340e119e0a25018487ba61f',
'104ee59400f6a9259dc18856e193bd06',
'dffa4dc1c4ece65839029455927352fe',
'4dad78c09aaebcb4c6d70f51ad29f040',
'd0abba2f4a035e11d2c3af265d09077c',
'329a2d4fb75296188d571349e43851a9',
'6163b30600f1e80d2bb5afaa753490b6',
'159d58cfc690aa9380a8821b7f5f49a4',
'3673c07cf0ba65899edf0b69e22f3f92',
'1f7c6c4ba1465634e44576edf2677ac8',
'124b2d86d3b7dee389266a113aaf678a',
'd5ac0615c2468f776f621564ef44c49a',
'8aa6c577574a3c6db4a93d211a92defa',
'18d984ed2b5616a3ecfadef3c2a7cf73',
'1867faa2d638912f9efa55a3047d4e2d',
'501914fd6bfe9568d4d5bebbfce0e6bf',
'ebb392d2abe3e078814ec2f4ac9488bb',
'33ed8d1e782787a43813d280fb825273',
'07966be09b55ab98b7602a0de9f93281',
'64efc6dd2bc9a807bb51f548c1112fbd',
'e96176741fa0d8c74b86129418229c77',
'c285998bac6c3db4e5d23fd38d470a55',
'19f7f3a624b5f6ae818d90a71890d6b6',
'd20e7f66f5f3adab73bbacda550fa6b2',
'22ddf9e3d7a856ea9a0929c3c0bd2b47',
'00871ea7672e9a34d1d3f827fcfbbe8f',
'3c1e8df40c14fb66b67fcd9f7dafef75',
'99bc07a57de34bd25cd922a24047906d',
'c8c070759390acd8eb3dfd1752369a3e',
'f56c07d49e4c8e91b0cc6eb1fb41f45c',
'305ff1b2d92e3e1fdfb3bb6948d50b2e',
'd8ffd81e65ec735ed357b27721b659ff',
'e8a96869c3fb034e0220140bbd9d5c08',
'c32cdbaac8d4b036afe0de44a66167be',
'61904d6f33e0bab8a9b2c3359a6ae6d6',
'a2d586b450ddedabf51006342b8ad0db',
'03e5a227e27a3f184eacf204deeda474',
'86f2d412bdac1d5a4182b9c0fcb7c2d3',
'c45da02258dbc38d15db61aa522032fa',
'8df56ae5735d5cf795eab2982dabbec8',
'dea0f36f5dd226656ebbfc3a3cd49048',
'c1cdffc98e252111ba4fd7fdc2fe88c1',
'95d1db948227724bef07127cdaae54a2',
'650e0d9beaca58bd86a292f9684e9ae0',
'792e77b2e00f44f14e92343e2b982573',
'7fdea8ae17eb12bea9832a33d7fd0058',
'bcad54bf7c53d9eabb67595c16184156',
'4d5bad82b31dad57309b22f4467d1693',
'b05f597a21b9e3f2cd5f97ef815aa523',
'4f31b641f72a0f533b4cb1e8b5d198d4',
'375661f64cba488250c7aae43863c86b',
'eddf7a8fde1e50a7f2a817ef7cece24f',
'd3b38daf14cef29eb447d2848968ae7a',
'59efe73a9be84ffec244fbea47bfeac8',
'96ff8f5335ba823071ec463600b15a40',
'787039ccc1f4a42248089f5188e7b6d2',
'6ddac21901baab2ba27ae3b9216a9c26',
'648fa6f0028bc1d5e12745184333fd42',
'a38923c08c7b41b65b326833800dbdd1',
'5f8a02716ffe8cab484cc265574db9c9',
'dec392cf6e7e22343f95f1a410267144',
'625965cccc8a428cb7776197178a4ae4',
'4b9771d118dd9b7787b33fd5472f3cde',
'1f7204dacb61453e3d158ac83164b267',
'd3c9f64b8d1675f02aa833d83a5c6342',
'51d11ec8775e95416be6b87abf3b5096',
'f7d5de6e2a3d15bd5169713d597b57fd',
'29576640791ac19308d3cd36fb3ba17b',
'1abcefaf4a12646ef6611df06acbf642',
'c705cbe575e086ce02e0ab9004d7cc36',
'2977b5b19c1fdb11fd5d3b19698e52d2',
'd356040cc468037d374055d5499ac420',
'ce07d7829eec53d79d3c3d41045067ed',
'9059cd70cb41b81bd9fe68f4e37d0824',
'582ef1a0e0a6d65ed24a6cb5ff213e7e',
'dcefb307572ad17ab4c29a15ead9b417',
'd089e7168373a0634e1ac18c0ee00085',
'84f8921f7214fd2e79dff4e1a92257de',
'5a7975f0a44697aa25f7335b5af99f54',
'd7d7052004d7342a92c51557c8028246',
'f36fb7c8a637b083c9285464b8a39bab',
'bf24f2c62da672643f02047ba18d3cd5',
'f3a28c6b50203943dcfe7bcf0be53053',
'b5510fa0bcdda732a9294097ff612cbc',
'ee6d0b61f5144a02c874c4089f2e8a3e',
'4d82bd181070e67a77ae519aabef0e37',
'b4ce9ca5d9021b4e7ffea8f41ab86706',
'6f8d6e47b7fda8b709772943c9427f71',
'7e074003e261307b2346e52caf4ff964',
'049d192527e2af23f51c9e2a5357d944',
'3a67504efb4047bae306b6e1fdae1840',
'1490282ae2316f4a5700cd190666c78f',
'8f01c6a4ca68547b2aaee7bca6279852',
'41b0fa9d95e079ca25bc3aef1bbf7c82',
'a666cd6e08d1fa7c0e25a32efb4633d4',
'3c4d87b51ff590b88cdad9192c953582',
'd4c247204240d67ddd6e8e7502b711a7',
'e1e6941b8f135e0b1f85770f529f2d93',
'3c6a6dbf5cf7125d0d9d07333fce7a2b',
'c6d379f8c2707ca617feb5c25322bc2a',
'7c3304271366996b836e30163b0d109f',
'31e7fbbc17125e267db5d123b7b07d65',
'bc90ded6793680bc7a2d7dd6317b9872',
'62cd77b733cc4207bad6fc0171bf6985',
'3b6f05d8fef661e05d59f3be1dab127e',
'80ffbe7eb643f22b049df129254da979',
'f1a254c0a2fcf8138d1ac803e2c0a2e6',
'80d301ecf9b8cad7258ab1ce0041ff23',
'7ac152dc989124ba74113a5d2e806e03',
'7b21c655669c0ca295e66e1e55a2a6ad',
'5fea79e32156909aaf6fe3811740bb9c',
'bb5cae2b7e9b3ee81377116952956fd2',
'96d80c6a67b7eb0adefbb2eb1f182853',
'8a9da119954732377deab012b6a55803',
'563bf3cbe55ebf1bf11cc988849891c6',
'9ec3c1270d8346f21d83eb0f29d47350',
'8705c4495a9fd1811f31e2507f93e63e',
'c519674397fd1189812fa5a45fe43dca',
'e32dfedb5b2ab835df93d9d752874865',
'e95587ca8156810a01ce72296178f9a0',
'4e518993337efff862a0d3ff90933a21',
'7697d2a9b04b2d97027da328d86932d3',
'b1706c4bbbf5e148a88b594c283551f0',
'b3481ac55994eacb53a0047436089736',
'8008b5297272d5dc7df671dd86076652',
'4c1811cc70c404002040b63803bd6c44',
'f4bf232ee4f2c364b9023b1734293253',
'c27bd5866871d3182f9a688adb0ae5da',
'86a5d636aebbb3e63f2c1dcf20c73c9d',
'f9b48908c03ddae2f7cebb786ae8ed81',
'81c72f4cda023958e9516b4dab413931',
'6bdf1efdbe6ac677e72cf89dfc283f2e',
'0965478c4823c0960db01a389bb2a519',
'b74ebd0baa418549f60f904e4f5671c9',
'679ef02283abf5e40fd1e67446ad6ffa',
'2d455d4b1726aec4e297d2e59a528424',
'f88a8fbe0a74b5b164bfaa1e801492fc',
'1ffce56f00e56570b35942fe50e60c7d',
'e676e3e6f8b196f53838bd7654f833d7',
'13d851447b8a39251f737d0007aa1262',
'3ae5c0df376db5ca805594b228905b94',
'a2199a326db05a783ee17e6f239f7f45',
'81287e5b759d35140abf1a7272e1b93c',
'19959ab029fe86c632fe232399404772',
'2d0c7bd467933290c13f4f4198f0b233',
'ff8c951b823a48387f739a170c116d4c',
'a6c51d65ffac2d953a248a9a8dc566c1',
'35869b38f6f370dd2fed5f7e0636339a',
'11b5d3e9db16de964351d6fbe1baca8f',
'4ed84c2393d80c3f31c62251b60a1b43',
'54f62ae9f2639b6d0f612ebebc0b1272',
'02bb0f8e8e8a7db8ccaecfca72b4b02d',
'a784a81f2dcf0d778e1132abd4696a9b',
'74d8c07c61d820c1c784761f23e9dcfc',
'1b2a62ef781bda6093d862243285ff0a',
'3ac0608a496c83d0095548a566d38c5f',
'62c069ec214fd0a5fc611dc7737a61b4',
'0ad1a641124044c84bea666cdc0ceb53',
'16840e8aecdae4ec84dd9f72cb0ffc95',
'f1ea2b15e44024bcf2c3a1fee86c38de',
'f8ebbe597c69a2156fda9d67e516aadc',
'd3a189ea8a7895cffe46dbc25f6b9aca',
'5f46ab30eab5133b92c9f19b67336289',
'f091d1b9274c881f8e41b2f96e6b9936',
'325fc9442ae66d6ad8e5e71bb1129894',
'a070b98ff6caf212310972f9baa64232',
'd66d07ac59d4e639f710f565740b1328',
'01b8cb88ea93c9b6353bc6c785c196d6',
'692f1b412030cbc1fa6768807227dd71',
'beac96a0f18033f2a6dabc822a125deb',
'81d332ac3fb9b7b2d9df4400900676af',
'0449fe92b443031d42fd8e3b5e3481ed',
'ecff41419f4e153ae6dba1764320e853',
'8b70adb096f58c792a26a4e22dd0bf17',
'd650774391a2a66918a5dc5aaa67d55f',
'16cf220a01156d404e8d1f2a0e831d76',
'fbf05ecce7551876a0b5e1b8ca2daf7b',
'99d93d5052ac859f205ba55f199089f8',
'12c70791cf912a8bed1b1ffe6ddc7a7e',
'2b594c6a08c9762db70607b0152ac966',
'b7fab507847347c3348da5862d356d2b',
'0f242a55d928acaa441c08625ca760c6',
'ffe2f618b6ede988bc558f99442aa669',
'171b7f4b6c0f4aa66d1d860ebb40125d',
'c878ebee41037c936b88f4dec4213dcb',
'9cd5c6d6e8f2559f3d22876e7c6d98db',
'914c8095b1573bc421dc7a95bf13f69a',
'0d561d018b50f9800881d7da51200d1f',
'53707d83865a2ec365e747786874aacb',
'91e4b6079e7944a168be9bb472e315c0',
'0dcd751735aa3b035d0d3664ab4c298f',
'd9f4adc4e3ccc3c21d4ec5d1ceb0673c',
'106004806a68547d722fe4d9279bc162',
'c2e8346a5515c81797af36e7e4a3828e',
'c2ca52f66bb4712a4dfc60587487bc99',
'57ac3b46b842cdad512bbbf5451f786e',
'15f61bc618dbcb8f06e52913b86c4e07',
'937c173da0f61867b255b50356b5f14f',
'14095dc9d34970baf70311acb50c3c08',
'7f3873343b33c91777766d2b5f6b7bd0',
'd75f9d53e7a5b75ef30dcbd89efaa222',
'd71790027e75184e71c5ec2d7b825242',
'ff6be9aad3b9fa955fe1115d58fe9615',
'a153ab8b273499f8bb605dac25cbae44',
'899623f430183596c391ca119f0f760c',
'579036c0644fc086a1010dcdd58b07de',
'38a3f9f2aa47c2e940695f3dba6a7bb2',
'43209b96e5f529291918dd495aff3307',
'5fae766b46c4af1bdb73a7392a33d8b4',
'c9f086f96f4c7a050616b0feaffd463a',
'9c617bf5c92b0df50de43be2dfff4f09',
'8cdba88cd35b09d2e62a2613fb64e8cf',
'9a27db69830d1f702a6158a923c0fcb1',
'd9cc4c7026632eb2c567d19bb6b2b179',
'5c21ce300a0d09c617efbac8fdaa4beb',
'118303f82656e5cc209a7a5a460fbcee',
'560d6b846b47d7cd7f5dfd7eed25bda2',
'80cfb11b9baba3d08404d0a18f2e1274',
'2b872201f9f17abc4a170bd152c0e41e',
'c829d17f3aac0c25e1b6b9d403264d0b',
'06b2ffdffeca04713f4702561c85d1dc',
'f8356c40e0a3ff6fcd5b9286fb47f6f5',
'cc4c1a4d48634db8b0953c2152099f19',
'bb32c1373710e29b0250e27cc608c5d1',
'04feb1a2bda2886c62962a551f759c60',
'bb11305a466dd8f6095a4414f9235ad6',
'bbd4c61df330f6e38adcd254ca91618d',
'ffd91f505d56189819352093268216ad',
'b2299db76282c62044e5dfc9c675333c',
'09056c2a3bc45144e24c0c935368eb46',
'a9a9b9c82233aaf1e9e62021a99d57ee',
'616c3541c8e1ca9f5d6404658ac57e96',
'594432ad02541bf5042fb1077d3018a9',
'ba45940c23f87a74860b8936d1f218f6',
'27cb9e6f582a93fd4fdd94955f0add54',
'b13906063e1e3a4ee8fdabf1b11ec932',
'78f610810a846a7d5cea41da9de2ba78',
'0f3ec21131289ea7fa496766a1bc0ba5',
'9da3a30e63d00466105ff973b1f13518',
'd0f84294dda890a8f915a54c812991fd',
'78b0744deb40df1f0bc14ddb5885c9a2',
'44b03a9d366f8f2edf4277309fe3ad0c',
'f494df20241d0719e16d049754e69454',
'a292872c5042ca3a4bde064b4b273ee2',
'b125868e0032d2a70cbd1a9ee3977a8a',
'4d03c87d7ce5c18aa4b5d00bbb73f721',
'd5785621a114ca6c6cd044a303d8850e',
'c27e223c9de866a84c96815666cfb7c5',
'8d178d0a0db6b0ad0ba40d8787a50234',
'129d598b06ffc7b320075095eea3bda5',
'92b43c24d457e109b03e233c12b302a2',
'64071df8817cda52e83cb9bff436967e',
'fa4abd0e922ce965f5f270afa9f59ac0',
'a435aa5ef401c7387bbe9873b72005ad',
'df7765a4f79f1cf84588ccb168d53834',
'680629b9b3f2d4996078df13356b1af7',
'27beae376cff62b0ac87c8cc93e484fd',
'2ea1fe0848251712240d54ac93396479',
'6d622da55739d0f2707a8a9e008a6a9b',
'cc57fd69758469cfe6484a1b770c4819',
'11ec8cef76d38c4f5d38ed73a1d3d25d',
'5295ee8dc2f5fd416be442548d68f7a6',
'54b0262a27918459e967da230ad7c708',
'974db1c132666410237253eaec3b3fc4',
'3a50c5a010bc7befda98880f721bdd15',
'4f70b28b1b7e156ef025cb40324e6beb',
'a360e061d59f8db4a19d5a0130a89c22',
'9d39b41982c54f5fb043d76442194d2f',
'fcfd9390b4a4f5fd92e19b9e56f71951',
'3885e148c7662d9681e3c4788f6ff4ce',
'ca7769dbe68d74609784de052c78d2e8',
'a04e27d3df46280b79adc234d044365a',
'534931d7038bd2558af8f6a70c25adc6',
'ef992d8fc9597a4f48c2c054d12d024e',
'03a870aafa9ea28a844561da432814f2',
'3286e17cd667f4dc10cf211347646157',
'9d63fe7cb234b582f17ef82425a43440',
'6ecd008b3d491755eaee8b0faac19f98',
'721ed10c299cdf114942205893d9f858',
'83f2f9fc6f205e940b9445f4a9e5599f',
'fb71ea2fe1bbb7e47334dba6138b93fc',
'91e4afc7444ed258640e85bcaf0fecfc',
'd03a2fe645225a79dcf7a62442257472',
'87076be6585e41eff5d686aaeb78e555',
'c19d346e6f0e7b7f4da491ec536e81e4',
'fd78f1f2a5cc8a6a3d8a9cee1695fd76',
'ab31b85e2f600d2f71138720e4edc788',
'e389573489169d27e2e66a967e07d5d7',
'65f24093b53299e2583f6af28a54805b',
'b9d6c0e04878c121fd2c7d7dca02bf0d',
'9fd9ace3241d25d1665f5cf45e22e3d6',
'8d7321bb16ec8544e90e8382dd3d9b19',
'0499fc68ebc44494943a9504e57d2574',
'2cb86952fac2036da654bec6214014de',
'24f6b13d5aa4406b28649ec1335be94f',
'dab1ed5b1fb91fe0c0248471506693af',
'23f2cfd42ebb235151712fa546dd0743',
'47c718ae522f6c975f98b326dbbf77a3',
'27f69bc20cb4443fb242f7cdeb986b68',
'f08c775f1d8cf2495c7b1458c2d6d5fc',
'8c2042a689d351dfe086295240f461f0',
'b399b74b1e31dc7d65c98b9d6aff8383',
'4690f88811544b5c14e2f69fe6e97496',
'6f77a35b555fa4d8d2908b57af4f0151',
'4d09aafd9d69e0f19813d5ecd5dd39ba',
'c2f546bb3cc97933647a5a12967733d7',
'27b7e0b74ce88431b418557ed1b36c8f',
'6cac7604200b14cf0275c5de801d4259',
'8338c8d9eab10bd38a7116eb534b5fa2',
'950b8e7c41085f9e9f6dea8b83222c29',
'1f779715347df16a289a033d2071a5a8',
'23272a763beed2c626dc73839993e970',
'4cc740ac5f3e5c237e6086b12ec3b61f',
'c3db7ff9b09705ba95360e05fa5340d7',
'f3ca29b7999643507081caab926e2e74',
'98a82bc8464f65e467efe5406ed8cd05',
'caf093f4efb8f064e113600fc13ec4f4',
'0dbbef5d3bc64e8a1d3dec06187b0715',
'5813512d3dce9699e0aed8d24b857c27',
'ae04d3f72f5a59a86a870bf19fd30c9b',
'2fdea03bd60293e31264ba25fa3a7e56',
'f9f675453bbd4656b4fc6720d6aab158',
'd8ebfee6d81b54d1ded4fc0bafed8908',
'df16cc3882e01f625f312cce9afd3b0f',
'1c74db35734ac19fc93a66bd9f3c3827',
'7d63ce505660137a6b61b091a19f5f89',
'495e4f1c64a84dea048694521d4def8d',
'151ad3ea877cdf8fb9fa477bad26671f',
'cda800f3a463f0240a1b2eb7c295e120',
'588ce4a7b33f2c78c9dec2df5f002acf',
'1386a9b6c70d276119a7cff026ce808a',
'b1cf6236b37b888876bec88e7bd4b615',
'01c618017cffcfe5e50e4c87b97e58af',
'95ad3cdc5bc01a942c0647594dd2e4a9',
'71db4b4df9c3c6cc2ee46650374c2931',
'ca321bf8109e48ae42d76b07838f321f',
'd31fd911ec6ee43935071a163fad9e84',
'adae49fc572c0bb960505e81d5aec155',
'fdeb91aedcdc29df32cf1986f2de8218',
'988f74ab3755c9fed949182080e55cd2',
'c7f6b8cfb2921eddfdc7e1230b2db8f8',
'4a70db72c2577873612e8ac07dfd6bd4',
'e8103bdd9dd52cea8fdaa8573efe9948',
'99731375fd28e176ade32cd612bd5c6b',
'b6dc3627e2cd7f4854128c4d1654d1f4',
'da692883c5d305678152304be83d8c94',
'5f9e301ed8dfa27b930f67415d3139b0',
'fd35b8421d2bd6ead3244571843a3722',
'a222df3aa5b018e1cd97539044345d55',
'6713186f8dcf12f815b2932ba1e9e711',
'6b3af9ee452c7464f8e8144394a9a415',
'95ca90372869486739c677df57a8d8bb',
'9b9f009330cb66bedb12b6a55e160ee8',
'412b8e4aa513b977d6ebcd6c65988342',
'8efa321b17306c999b457733e55042d3',
'fd57382e5e7ac08404023ab14937f794',
'5329f9ab312b61b2657264579377700b',
'09c6f9202285937bf13a2a5b0ae8387b',
'889bfc9fbb8ee7832044fc575324d01a',
'4027e1fb5af0f637618bca84c2a0c2ad',
'be18a8339638fbdcf326aa3d735e7bec',
'67c204d6d1989fe33d0768236f7a86c1',
'0080174ed3a0eaba721d983209de361f',
'1fa6a31acf14b9805b61cbf43d66786b',
'15d8244f299c2dea28b015e3c4b637a0',
'05ce81aa7ae536350365195499d2c90e',
'002568a565bb3a7dd09999f51c05c80c',
'4a69ea40367fe9c19fe675c6963c1e37',
'8da3f8cca0151501da3454eb605c0c2e',
'26aa670a7be5e2f9fee488caa7f9e508',
'b84b706524c2b101ecc73f790c52f114',
'8397449a5a911015fd56affd72db4bc7',
'669ea143139260fb550602071c450333',
'6c2112038e7a695af3b3d5687aa02c7d',
'407081be34600e1981d54a899893aec4',
'da3c61a00d0f81753aaed9632de7294b',
'5cce97ba5d04f12d112ac7b5ac812b47',
'199d86a17ff4abd474f308c3b0865c09',
'efa74ee1b72033902276f672d525eebe',
'a10c4807a43f9ff6bc9aa67e926c27c9',
'97c5201e2664b1b1988bd501039c13b4',
'cc45facc6ec3e5896e06f4e9f42c1b0f',
'a077fdae6629f54f8e7fdd79388ddb10',
'4ff4552326a4a40959c640fae4c353d3',
'99fdb42443221a7685abedb5ac89aad6',
'fdc455f9e9add9f1cfb05ff70b4f4103',
'6a5916694d2c3fa5f273375484c8993e',
'6da42b1af6f8d9bbcb9b925f0a132c00',
'cccd576042bf88fb5e1f6ff23cc62935',
'c261dfb73bcad3e4fa04f877f1f19af6',
'f35da863b9b060fa0609ebe318da3229',
'8fbc93c2052d47ba7e320c5b529458d9',
'c6eeacbe779518ea78b8f7ed5f63fc11',
'82ba963b565043fe90c21498af8c1da6',
'52920f744664d7dfa30112fa1b183a32',
'fff46cc12d005a847cbd3102dfdeb84b',
'de9731412e4a9f1b0b066ba7b7490483',
'1a503170d5eaa9eac4258cb7a6861dd2'
PK��#]��d
d
'system/bfnetwork/bfnetwork/db/blank.sqlnu�[���DROP TABLE IF EXISTS `bf_core_hashes`;
DROP TABLE IF EXISTS `bf_folders_to_scan`;
DROP TABLE IF EXISTS `bf_files`;
DROP TABLE IF EXISTS `bf_folders`;
DROP TABLE IF EXISTS `bf_scan_state`;

CREATE TABLE `bf_core_hashes` (
  `id`           INT(11)    NOT NULL AUTO_INCREMENT,
  `filewithpath` MEDIUMTEXT NOT NULL,
  `hash`         VARCHAR(32)         DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `filewithpath` (`filewithpath`(255)),
  KEY `hash` (`hash`)
)
  ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

CREATE TABLE `bf_folders_to_scan` (
  `id`             INT(11) NOT NULL AUTO_INCREMENT,
  `folderwithpath` TEXT,
  PRIMARY KEY (`id`)
)
  ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

CREATE TABLE `bf_files` (
  `id`             INT(11) NOT NULL AUTO_INCREMENT,
  `filewithpath`   TEXT,
  `fileperms`      VARCHAR(255)     DEFAULT NULL,
  `filemtime`      VARCHAR(255)     DEFAULT NULL,
  `toggler`        INT(11)          DEFAULT NULL,
  `currenthash`    VARCHAR(32)      DEFAULT NULL,
  `lasthash`       VARCHAR(255)     DEFAULT NULL,
  `iscorefile`     INT(11)          DEFAULT NULL,
  `hashfailed`     INT(1)           DEFAULT NULL,
  `hashchanged`    INT(1)           DEFAULT NULL,
  `hacked`         INT(1)           DEFAULT NULL,
  `suspectcontent` INT(1)           DEFAULT NULL,
  `falsepositive`  INT(1)           DEFAULT NULL,
  `mailer`         INT(1)           DEFAULT NULL,
  `uploader`       INT(1)           DEFAULT NULL,
  `encrypted`      INT(1)           DEFAULT NULL,
  `queued`         INT(11)          DEFAULT NULL,
  `size`           INT(11)          DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `currenthash` (`currenthash`),
  KEY `iscorefile` (`iscorefile`),
  KEY `filewithpath` (`filewithpath`(200)),
  KEY `size` (`size`),
  KEY `hashfailed` (`hashfailed`),
  KEY `size_2` (`size`, `hashfailed`, `filewithpath`(255), `iscorefile`, `currenthash`),
  KEY `encrypted` (`encrypted`),
  KEY `queued` (`queued`),
  KEY `mailer` (`mailer`),
  KEY `uploader` (`uploader`),
  KEY `hacked` (`hacked`),
  KEY `suspectcontent` (`suspectcontent`)
)
  ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

CREATE TABLE `bf_folders` (
  `id`             INT(11) NOT NULL AUTO_INCREMENT,
  `folderwithpath` TEXT,
  `folderinfo`     VARCHAR(255)     DEFAULT NULL,
  `foldermtime`    VARCHAR(255)     DEFAULT NULL,
  `filesinfolder`  INT(11)          DEFAULT NULL,
  `queued`         INT(11)          DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `folderwithpath` (`folderwithpath`(255)),
  KEY `folderinfo` (`folderinfo`),
  KEY `foldermtime` (`foldermtime`),
  KEY `queued` (`queued`),
  KEY `filesinfolder` (`filesinfolder`)
)
  ENGINE = InnoDB
  DEFAULT CHARSET = utf8;PK��#],~��(system/bfnetwork/bfnetwork/bfVersion.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require 'bfEncrypt.php';

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */

// load mini-Joomla
require 'bfInitJoomla.php';

// Get some Joomla version
$VERSION = new JVersion();

// Get the connector version
$connectorVersion = file_get_contents('VERSION');

// Reply with all the versions
bfEncrypt::reply('success', array(
    'version'          => $VERSION->getShortVersion(),
    'platform'         => $VERSION->PRODUCT,
    'connectorversion' => $connectorVersion,
));
PK��#];
r ��+system/bfnetwork/bfnetwork/Keys/private.keynu�[���-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDUQyDdQtndYEZrR65Aagx1MWfrQX14t6k7bwlRNbIvfMs+ni4Jrw9Ldn8ZfNJE
oK8MbW6H9G0MZLA/hPNUjY3ffrA63ycY+ep+zQ160vfFrZmPAv29XqFgpNfMkERBiTII4fisIt9C
55CZA44/c/TMaBMx9BoYA4/lm3WTpinonQIDAQABAoGAXJqsy9tOkXZfQo6TRyb9KGPVop1/0BrQ
ik13EycKBg273iXEkBT/5zxbVxNN6QLxW8qiXk4VBUMoYY3vWwQm0H6+QzWmQid2PwNFAsIWB5oA
EI9OaM9Ijbg6B5L4Qd/gXHuJOpzrZR5Xt6/eddGS5ZNsbRjLFSTy+QymAxmVggECQQD8IkK86Vhc
c3ENIbCcRY2irRvb+Ue7zg3y618GdUfiWKZBjrlCDulvJD1nestgSy1LAPh4ExRDo1F/iybxGZfl
AkEA14RahCTmKzbRERyWJds/NIrwy1eefCJIzaVf0AGAYjWIMldp3px45lRhRaMW0PhZSnc3SfUg
Qe2+FjGgI94SWQJBAPWspH7SmAita7Cx7Ra4JwQlzQmQYjc61hinA5aVXI/OdWFXomgdg5OKKlLU
MasIVX/J2FGXtZ0aW+T9P9qZZ4kCQBriIKRhMfDsCpI23aflPHIibrz+tf9IC4rTeSsqNMiLYuzc
qJEjNZWNqwCTwnHYuNKoIlZwZFC1BkQgdphiyCkCQQD4YdbXdH4Hmt7X9zWqooLoLJatwbBPSntk
AZQQLb8+AM5Irj3pE+8EOweobRXRD6dMYvkQdI2sB8x+tbDFOaQM
-----END RSA PRIVATE KEY-----PK��#]��;*system/bfnetwork/bfnetwork/Keys/public.keynu�[���-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgozyE0GYZnppaMbbY6QufB80nryitpAHPulOy
QVX+sRr9gYSYZRepWBLrjvJzLfvevIriBM9jwDolZi8vkNR8TMDhc+P4kwxZEB45fFL3daA9i+fI
71BKxa41Ru1ZiogXjjxVs1OuecFdtQnXI6HYQPKbmFqqELbD4fBkJXiGyQIDAQAB
-----END PUBLIC KEY-----PK��#]5��8DD)system/bfnetwork/bfnetwork/Keys/.htaccessnu�[���<Files ~ "^.*$">
Order deny,allow
Deny from all
Satisfy all
</Files>PK��#]/��DXZXZ'system/bfnetwork/bfnetwork/bfPlugin.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

// no direct access
defined('_JEXEC') or die('Restricted access');

require_once 'bfLog.php';
require_once 'bfActivitylog.php';
require_once 'bfPreferences.php';

if (class_exists('JPlugin') && !class_exists('PlgSystemBfnetwork')) {
    class PlgSystemBfnetwork extends JPlugin
    {
        private $user;
        private $db;

        public function __construct($subject, $config = array())
        {
            $this->user = JFactory::getUser();
            $this->db   = JFactory::getDbo();
            $prefs      = new bfPreferences();
            $prefs->getPreferences(); // force creation of prefs file if needed

            parent::__construct($subject, $config);
        }

        public function ____EXAMPLE____($one, $options = array())
        {
            bfLog::log('____EXAMPLE____');

            bfActivitylog::getInstance()->log(
                $this->user->name,            //$who = 'not me!',
                $this->user->id,              //$who_id = 0,  User Id is not in
                '____EXAMPLE____',            //$what = 'dunno',
                '____EXAMPLE____',            //$where = 'er?',
                '0',                          //$where_id = 0,
                null,                         //$ip = NULL,
                null,                         //$useragent = NULL
                null,                         //$meta = NULL
                $options['action'],           //$options = NULL
                'alertname_something'         //$alertname = NULL
            );
        }

        public function onAfterInitialise()
        {
            bfLog::log(__METHOD__);
        }

        public function onAfterRender()
        {
            $prefs       = new bfPreferences();
            $preferences = $prefs->getPreferences();

            if (property_exists($preferences, 'alerting_filewatchlist')) {
                $fileList = json_decode($preferences->alerting_filewatchlist);
            } else {
                $fileList = json_decode(json_encode($prefs->default_alerting_filewatchlist));
            }

            foreach ($fileList as $file) {
                if (!file_exists(JPATH_SITE.$file)) {
                    continue;
                }

                $createLock = false;

                $pathinfo = pathinfo($file);

                $md5LockFile = str_replace('//', '/', JPATH_SITE.$pathinfo['dirname'].'/.myjoomla.'.basename($file).'.md5');

                bfLog::log('LOCK FILE = '.$md5LockFile);

                $currentMd5 = md5_file(JPATH_SITE.$file);
                bfLog::log('CURRENT MD5 = '.$currentMd5);

                if (file_exists($md5LockFile)) {
                    bfLog::log('LOCK FILE EXISTS = '.$md5LockFile);
                    $lastMd5 = file_get_contents($md5LockFile);
                } else {
                    bfLog::log('LOCK FILE NOT EXISTS = '.$md5LockFile);
                    $lastMd5 = md5_file(JPATH_SITE.$file);

                    bfLog::log("CREATING LOCK FILE with $currentMd5");
                    // @ as not to upset crap servers :-(
                    $res = @file_put_contents($md5LockFile, $currentMd5);
                    bfLog::log('file_put_contents was = '.$res);

                    // if we could not write the lock file then bail!
                    if (!file_exists($md5LockFile)) {
                        return;
                    }
                }

                bfLog::log("COMPARING =   $lastMd5 !!! $currentMd5");
                if ($lastMd5 !== $currentMd5) {
                    $createLock = true;
                    bfLog::log("ALERTING COMPARING !==  >   $lastMd5 !!! $currentMd5");
                    bfActivitylog::getInstance()->log(
                        'Someone',
                        '-911',
                        'modified file',
                        $file,
                        null,
                        'system',
                        null,
                        null,
                        null,
                        'alerting_filewatchlist_alert'
                    );
                }

                if (true === $createLock) {
                    bfLog::log("CREATING LOCK FILE with $currentMd5");
                    // @ as not to upset crap servers :-(
                    $res = @file_put_contents($md5LockFile, $currentMd5);
                    bfLog::log('file_put_contents was = '.$res);
                }
            }
            bfLog::log(__METHOD__);
        }

        public function onAfterRoute()
        {
            bfLog::log(__METHOD__);
        }

        public function onBeforeCompileHead()
        {
            bfLog::log(__METHOD__);
        }

        public function onBeforeRender()
        {
            bfLog::log(__METHOD__);
        }

        public function onCheckAnswer()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentAfterDelete()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentAfterDisplay()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentAfterSave()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentAfterTitle()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentBeforeDelete()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentBeforeDisplay()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentBeforeSave()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentChangeState()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentPrepare()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentPrepareData($form, $data)
        {
            bfLog::log(__METHOD__);
        }

        /**
         * Alert when a users details are viewed
         * Alert when someone views the Joomla Global Configuration
         * Alert when someone saves the Joomla Global Configuration
         * Alert when someone views options in any other extension.
         *
         * @param $form
         * @param $data
         */
        public function onContentPrepareForm($form, $data)
        {
            bfLog::log(__METHOD__.' : '.$_SERVER['REQUEST_METHOD'].' : '.$form->getName());

            $jinput = JFactory::getApplication()->input;
            $option = $jinput->get('option', '', 'cmd');

            switch ($form->getName()) {
                case 'com_users.user':
                    switch ($_SERVER['REQUEST_METHOD']) {
                        case 'GET':

                            // a blank form, before creating a new user
                            if (0 == $data->id) {
                                return;
                            }

                            bfActivitylog::getInstance()->log(
                                $this->user->name,
                                $this->user->id,
                                'viewed user details',
                                $option,
                                $this->getExtensionId($option),
                                null,
                                null,
                                json_encode(array(
                                    'id'       => $data->id,
                                    'username' => $data->username,
                                )),
                                $form->getName(),
                                'alerting_viewuser'
                            );
                            break;
                        case 'POST':
                            break;
                    }
                    break;
                case 'com_config.application':

                    switch ($_SERVER['REQUEST_METHOD']) {
                        case 'GET':
                            bfActivitylog::getInstance()->log(
                                $this->user->name,
                                $this->user->id,
                                'viewed Joomla Global Configuration page',
                                'com_config',
                                $this->getExtensionId($option),
                                null,
                                null,
                                null,
                                $form->getName(),
                                'alerting_com_config_application_viewed'
                            );
                            break;

                        case 'POST':

                            bfActivitylog::getInstance()->log(
                                $this->user->name,
                                $this->user->id,
                                'saved Joomla Global Configuration page',
                                'com_config',
                                $this->getExtensionId($option),
                                null,
                                null,
                                null,
                                $form->getName(),
                                'alerting_com_config_application_saved'
                            );
                            break;
                    }
                    break;
                case 'com_config.component':
                    $com_name = $jinput->get('component', '', 'cmd');
                    switch ($_SERVER['REQUEST_METHOD']) {
                        case 'GET':
                            bfActivitylog::getInstance()->log(
                                $this->user->name,
                                $this->user->id,
                                'viewed '.$this->getExtensionName($com_name).' component Configuration page',
                                'com_config',
                                $this->getExtensionId($option),
                                null,
                                null,
                                $com_name,
                                $form->getName(),
                                'alerting_com_config_component_viewed'
                            );
                            break;

                        case 'POST':
                            bfActivitylog::getInstance()->log(
                                $this->user->name,
                                $this->user->id,
                                'saved '.$this->getExtensionName($com_name).' component Configuration page',
                                'com_config',
                                $this->getExtensionId($option),
                                null,
                                null,
                                $com_name,
                                $form->getName(),
                                'alerting_com_config_component_saved'
                            );
                            break;
                    }
                    break;
            }
        }

        public function onContentSearch()
        {
            bfLog::log(__METHOD__);
        }

        public function onContentSearchAreas()
        {
            bfLog::log(__METHOD__);
        }

        public function onDisplay()
        {
            bfLog::log(__METHOD__);
        }

        public function onExtensionAfterInstall()
        {
            bfLog::log(__METHOD__);
        }

        /**
         * Alert when someone saves options in any other extension.
         *
         * @param $context
         * @param $data
         * @param $isNew
         */
        public function onExtensionAfterSave($context, $data, $isNew)
        {
            bfLog::log(__METHOD__);

            if (defined('_alerting_com_config_component_saved')) {
                return;
            } // Joomla 3.5 fires this and onContentPrepareForm/POST

            /*
             * Roksprocket Kills us :(
             */
            if (!$data) {
                return;
            }
            if (!property_exists($data, 'element')) {
                return;
            }
            if (!$context) {
                return;
            }

            bfActivitylog::getInstance()->log(
                $this->user->name,
                $this->user->id,
                'saved '.$this->getExtensionName($data->element).' configuration',
                'com_config',
                $this->getExtensionId('com_config'),
                null,
                null,
                json_encode($data),
                $context,
                'alerting_com_config_component_saved'
            );
        }

        public function onExtensionAfterUninstall()
        {
            bfLog::log(__METHOD__);
        }

        public function onExtensionAfterUpdate()
        {
            bfLog::log(__METHOD__);
        }

        public function onExtensionBeforeInstall()
        {
            bfLog::log(__METHOD__);
        }

        public function onExtensionBeforeSave($context, $table, $isNew)
        {
            bfLog::log(__METHOD__);
        }

        public function onExtensionBeforeUninstall()
        {
            bfLog::log(__METHOD__);
        }

        public function onFinderAfterDelete()
        {
            bfLog::log(__METHOD__);
        }

        public function onFinderAfterSave()
        {
            bfLog::log(__METHOD__);
        }

        public function onFinderBeforeDelete()
        {
            bfLog::log(__METHOD__);
        }

        public function onFinderBeforeSave()
        {
            bfLog::log(__METHOD__);
        }

        public function onFinderCategoryChangeState()
        {
            bfLog::log(__METHOD__);
        }

        public function onFinderChangeState()
        {
            bfLog::log(__METHOD__);
        }

        public function onGetContent()
        {
            bfLog::log(__METHOD__);
        }

        public function onGetIcons()
        {
            bfLog::log(__METHOD__);
        }

        public function onGetInsertMethod()
        {
            bfLog::log(__METHOD__);
        }

        public function onGetWebServices()
        {
            bfLog::log(__METHOD__);
        }

        public function onInit()
        {
            bfLog::log(__METHOD__);
        }

        public function onInstallerAfterInstaller()
        {
            bfLog::log(__METHOD__);
        }

        public function onInstallerBeforeInstallation()
        {
            bfLog::log(__METHOD__);
        }

        public function onInstallerBeforeInstaller()
        {
            bfLog::log(__METHOD__);
        }

        public function onSave()
        {
            bfLog::log(__METHOD__);
        }

        public function onSearch()
        {
            bfLog::log(__METHOD__);
        }

        public function onSearchAreas()
        {
            bfLog::log(__METHOD__);
        }

        public function onSetContent()
        {
            bfLog::log(__METHOD__);
        }

        /**
         * Alert when a Super Admin logs in to admin console
         * Alert when a non-super admin attempts to login to admin.
         *
         * @param $user - Note user's id is NOT in this array :-(
         * @param $options
         */
        public function onUserLogin($user, $options = array())
        {
            bfLog::log(__METHOD__);

            if ('administrator' == JFactory::getApplication()->getName()) {
                // Reload the user from the database
                $userFromDb = JFactory::getUser(JUserHelper::getUserId($user['username']));

                // Check the user is authorised to login here
                $result = (bool) $userFromDb->authorise($options['action']);

                $what  = (false === $result ? 'login attempt not authorised' : 'logged in');
                $alert = (false === $result ? 'alerting_superadminfailedlogin' : 'alerting_superadminlogin');

                bfActivitylog::getInstance()->log(
                    $userFromDb->name,
                    $userFromDb->id,
                    $what,
                    'onUserLogin',
                    '0',
                    null,
                    null,
                    json_encode($options),
                    $options['action'],
                    $alert
                );
            }
        }

        /**
         * Alert when a Super Admin logs out of the admin console.
         *
         * @param $user
         * @param $options
         */
        public function onUserLogout($user, $options = array())
        {
            bfLog::log(__METHOD__);

            if ('administrator' == JFactory::getApplication()->getName()) {
                $userFromDb = JFactory::getUser(JUserHelper::getUserId($user['id']));

                bfActivitylog::getInstance()->log(
                    $userFromDb->name,
                    $user['id'],
                    'logged out',
                    'onUserLogout',
                    '0',
                    null,
                    null,
                    json_encode($options),
                    (1 == $options['clientid'] ? 'core.logout.admin' : 'core.logout.site'),
                    (1 == $options['clientid'] ? 'alerting_superadminlogout' : 'alerting_normaluserlogout')
                );
            }
        }

        /**
         * After user group save event handler.
         *
         * @param $context
         * @param $data
         * @param $isNew
         */
        public function onUserAfterSaveGroup($context, $data, $isNew)
        {
            bfLog::log(__METHOD__);
        }

        /**
         * Before user group delete event handler.
         *
         * @param $group_properties
         */
        public function onUserBeforeDeleteGroup($group_properties)
        {
            bfLog::log(__METHOD__);
        }

        /**
         * After user group delete event handler.
         *
         * @param $group_properties
         * @param $mysterious_arg
         * @param $error
         */
        public function onUserAfterDeleteGroup($group_properties, $mysterious_arg, $error)
        {
            bfLog::log(__METHOD__);
        }

        /**
         * Alert when a new user is created
         * Alert when a users details are saved.
         *
         * @param $user
         * @param $isNew
         * @param $success
         * @param $msg
         */
        public function onUserAfterSave($user, $isNew, $success, $msg)
        {
            bfLog::log(__METHOD__);
            $jinput   = JFactory::getApplication()->input;
            $com_name = $jinput->get('option', '', 'cmd');

            $loggedInUser = JFactory::getUser();

            if (true === $isNew) {
                bfActivitylog::getInstance()->log(
                    $loggedInUser->name,
                    $loggedInUser->id,
                    'created a new user',
                    'onUserAfterSave',
                    $this->getExtensionId($com_name),
                    null,
                    null,
                    json_encode(array(
                        'id'       => $user['id'],
                        'username' => $user['username'],
                    )),
                    'com_users',
                    'alerting_newuser'
                );
            } else {
                bfActivitylog::getInstance()->log(
                    $loggedInUser->name,
                    $loggedInUser->id,
                    'updated user',
                    'onUserAfterSave',
                    $this->getExtensionId($com_name),
                    null,
                    null,
                    json_encode(array(
                        'id'       => $user['id'],
                        'username' => $user['username'],
                    )),
                    'com_users',
                    'alerting_saveuser'
                );
            }
        }

        /**
         * After user delete event handler.
         *
         * @param $user
         * @param $success
         * @param $msg
         */
        public function onUserAfterDelete($user, $success, $msg)
        {
            bfLog::log(__METHOD__);
        }

        /**
         * Get the extension id from the db.
         *
         * @param $element string
         *
         * @return int
         */
        private function getExtensionId($element)
        {
            $sql = 'SELECT extension_id FROM #__extensions WHERE element = %s';
            $this->db->setQuery(sprintf($sql, $this->db->quote($element)));

            return (int) $this->db->loadResult();
        }

        /**
         * convert com_something into a english string.
         *
         * @param $com_name string
         *
         * @return string
         */
        private function getExtensionName($com_name)
        {
            $lang = JFactory::getLanguage();
            $lang->load($com_name);
            $lang->load($com_name, JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load($com_name, JPATH_ADMINISTRATOR, null, true);
            $lang->load($com_name, JPATH_ADMINISTRATOR.'/components/'.$com_name.'/', null, true);
            $lang->load($com_name, JPATH_SITE, 'en-GB', true);
            $lang->load($com_name, JPATH_SITE, null, true);
            $lang->load($com_name, JPATH_SITE.'/components/'.$com_name.'/', null, true);

            // convert some known crappiness :-(
            if ('com_jce' == $com_name) {
                $com_name = 'WF_ADMIN_TITLE';
            }

            return JText::_($com_name);
        }

        /**
         * @use  $this->debug($user, $options);
         */
        private function debug()
        {
            echo '<pre>';
            foreach (func_get_args() as $row) {
                var_dump($row);
            }
            echo '</pre>';
            die;
        }
    }
}
PK��#]�#X%system/bfnetwork/bfnetwork/bfPing.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require 'bfEncrypt.php';

/*
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */

if ('???PING???' == $dataObj->ping) {
    // Woohoo
    bfEncrypt::reply(bfReply::SUCCESS, 1);
} else {
    // Uh-oh!
    bfEncrypt::reply(bfReply::FAILURE, 0);
}
PK��#]Aa��ff&system/bfnetwork/bfnetwork/bfTools.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require 'bfEncrypt.php';

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 *
 * I'M NOT PROUD OF THIS FILE - it has grown a lot over the years and there are a lot of workarounds so that we can be
 * fully compatible from Joomla 1.5.0 to the latest Joomla version, and on all the crazy configurations of webservers.
 */
final class bfTools
{
    /**
     * We pass the command to run as a simple integer in our encrypted
     * request this is mainly to speed up the decryption process, plus its a
     * single digit(or 2) rather than a huge string to remember :-).
     */
    private $_methods = array(
        1   => 'getCoreHashFailedFileList',
        2   => 'downloadfile',
        3   => 'restorefile',
        4   => 'getSuspectContentFileList',
        5   => 'deleteFile',
        6   => 'checkFTPLayer',
        7   => 'disableFTPLayer',
        8   => 'checkNewDBCredentials',
        9   => 'testDbCredentials',
        10  => 'getFolderPermissions',
        11  => 'setFolderPermissions',
        12  => 'getHiddenFolders',
        13  => 'deleteFolder',
        14  => 'getInstallationFolders',
        15  => 'getRecentlyModified',
        16  => 'getFilePermissions',
        17  => 'setFilePermissions',
        18  => 'getErrorLogs',
        19  => 'getEncrypted',
        20  => 'getUser',
        21  => 'setUser',
        22  => 'setDbPrefix',
        23  => 'setDbCredentials',
        24  => 'getBakTables',
        25  => 'deleteBakTables',
        26  => 'getHtaccessFiles',
        27  => 'setHtaccess',
        28  => 'getUpdatesCount',
        29  => 'getUpdatesDetail',
        30  => 'getDotfiles',
        31  => 'getArchivefiles',
        32  => 'getLargefiles',
        33  => 'fixDbSchema',
        34  => 'getDbSchemaVersion',
        35  => 'checkGoogleFile',
        36  => 'toggleOnline',
        37  => 'getOfflineStatus',
        38  => 'getRobotsFile',
        39  => 'saveRobotsFile',
        40  => 'getTmpfiles',
        41  => 'clearTmpFiles',
        42  => 'getFlufffiles',
        43  => 'clearFlufffiles',
        44  => 'getRenamedToHide',
        45  => 'getPhpinwrongplace',
        46  => 'doExtensionUpgrade',
        47  => 'toggleCache',
        48  => 'getCacheStatus',
        49  => 'checkAkeebaOutputDirectory',
        50  => 'eolsecuritystatus',
        51  => 'applyeolpatch',
        52  => 'getMailerFileList',
        53  => 'getUploaderFileList',
        54  => 'getNonCoreFileList',
        55  => 'saveFile',
        56  => 'getZerobyteFiles',
        57  => 'deleteZerobyteFiles',
        58  => 'getMissingCoreFiles',
        59  => 'restoreAllMissingFiles',
        60  => 'getJoomlaLogTmpConfig',
        61  => 'getActivityLog',
        62  => 'getBFPluginStatus',
        63  => 'getMD5PasswordUsers',
        64  => 'getSessionGCStatus',
        65  => 'setSessionGCStatus',
        66  => 'get2FAPlugins',
        67  => 'enable2FAPlugins',
        68  => 'setLogTmpPaths',
        69  => 'removeLiveSite',
        70  => 'getConfiguredLiveSite',
        71  => 'getSEFConfig',
        72  => 'setSEFConfig',
        73  => 'getAdminFilterFixed',
        74  => 'setAdminFilterFixed',
        75  => 'getPlaintextpasswords',
        76  => 'setPlaintextpasswords',
        77  => 'getUploadsettingsfixed',
        78  => 'setUploadsettingsfixed',
        79  => 'getMailtofrienddisabled',
        80  => 'setMailtofrienddisabled',
        81  => 'getDebugMode',
        82  => 'setDebugMode',
        83  => 'getErrorReporting',
        84  => 'setErrorReporting',
        85  => 'getTemplatePositionDisplay',
        86  => 'setTemplatePositionDisplay',
        87  => 'getCookieSettings',
        88  => 'setCookieSettings',
        89  => 'getSQLFiles',
        90  => 'getCaptchaConfig',
        91  => 'setCaptchaConfig',
        92  => 'doExtensionInstallFromUrl',
        93  => 'getSuperAdmins',
        94  => 'getGroups',
        95  => 'getUseractionlogenabled',
        96  => 'setUseractionlogenabled',
        97  => 'getPrivacyConsentPluginEnabled',
        98  => 'setPrivacyConsentPluginEnabled',
        99  => 'getUseractionlogiplogenabled',
        100 => 'setUseractionlogiplogenabled',
        101 => 'getSystemLogRotationEnabled',
        102 => 'setSystemLogRotationEnabled',
        103 => 'getPurge30Days',
        104 => 'setPurge30Days',
        105 => 'getGzip',
        106 => 'setGzip',
        107 => 'getSessionlifetime',
        108 => 'setSessionlifetime',
        109 => 'getPHPinifiles',
        110 => 'getModifiedfilessincelastaudit',
        111 => 'setAdminHtaccess',
        112 => 'getAdminHtaccess',
        113 => 'getUserRegistration',
        114 => 'setUserRegistration',
        115 => 'getPostInstallMessages',
        999 => 'getDebugLog',
    );

    private $fluffFiles = array(
        '/.drone.yml',
        '/robots.txt.dist',
        '/web.config.txt',
        '/joomla.xml',
        '/build.xml',
        '/LICENSE.txt',
        '/README.txt',
        '/htaccess.txt',
        '/LICENSES.php',
        '/configuration.php-dist',
        '/CHANGELOG.php',
        '/COPYRIGHT.php',
        '/CREDITS.php',
        '/INSTALL.php',
        '/LICENSE.php',
        '/CONTRIBUTING.md',
        '/phpunit.xml.dist',
        '/README.md',
        '/.travis.yml',
        '/travisci-phpunit.xml',
        '/images/banners/osmbanner1.png',
        '/images/banners/osmbanner2.png',
        '/images/banners/shop-ad-books.jpg',
        '/images/banners/shop-ad.jpg',
        '/images/banners/white.png',
        '/images/headers/blue-flower.jpg',
        '/images/headers/maple.jpg',
        '/images/headers/raindrops.jpg',
        '/images/headers/walden-pond.jpg',
        '/images/headers/windows.jpg',
        '/images/joomla_black.gif',
        '/images/joomla_black.png',
        '/images/joomla_green.gif',
        '/images/joomla_logo_black.jpg',
        '/images/powered_by.png',
        '/images/sampledata/fruitshop/apple.jpg',
        '/images/sampledata/fruitshop/bananas_2.jpg',
        '/images/sampledata/fruitshop/fruits.gif',
        '/images/sampledata/fruitshop/tamarind.jpg',
        '/images/sampledata/parks/animals/180px_koala_ag1.jpg',
        '/images/sampledata/parks/animals/180px_wobbegong.jpg',
        '/images/sampledata/parks/animals/200px_phyllopteryx_taeniolatus1.jpg',
        '/images/sampledata/parks/animals/220px_spottedquoll_2005_seanmcclean.jpg',
        '/images/sampledata/parks/animals/789px_spottedquoll_2005_seanmcclean.jpg',
        '/images/sampledata/parks/animals/800px_koala_ag1.jpg',
        '/images/sampledata/parks/animals/800px_phyllopteryx_taeniolatus1.jpg',
        '/images/sampledata/parks/animals/800px_wobbegong.jpg',
        '/images/sampledata/parks/banner_cradle.jpg',
        '/images/sampledata/parks/landscape/120px_pinnacles_western_australia.jpg',
        '/images/sampledata/parks/landscape/120px_rainforest_bluemountainsnsw.jpg',
        '/images/sampledata/parks/landscape/180px_ormiston_pound.jpg',
        '/images/sampledata/parks/landscape/250px_cradle_mountain_seen_from_barn_bluff.jpg',
        '/images/sampledata/parks/landscape/727px_rainforest_bluemountainsnsw.jpg',
        '/images/sampledata/parks/landscape/800px_cradle_mountain_seen_from_barn_bluff.jpg',
        '/images/sampledata/parks/landscape/800px_ormiston_pound.jpg',
        '/images/sampledata/parks/landscape/800px_pinnacles_western_australia.jpg',
        '/images/sampledata/parks/parks.gif',
    );

    /**
     * Pointer to the Joomla Database Object.
     *
     * @var JDatabaseMysql
     */
    private $_db;

    /**
     * Incoming decrypted vars from the request.
     *
     * @var stdClass
     */
    private $_dataObj;

    /**
     * PHP 5 Constructor,
     * I inject the request to the object.
     *
     * @param stdClass $dataObj
     */
    public function __construct($dataObj)
    {
        // init Joomla
        require 'bfInitJoomla.php';

        // Set the request vars
        $this->_dataObj = $dataObj;

        // set the db object
        $this->_db = JFactory::getDBO();
    }

    /**
     * I'm the controller - I run methods based on the request integer.
     */
    public function run()
    {
        if (property_exists($this->_dataObj, 'c')) {
            $c = (int) $this->_dataObj->c;
            if (array_key_exists($c, $this->_methods)) {
                bfLog::log('Calling methd '.$this->_methods[$c]);
                // call the right method
                $this->{$this->_methods[$c]} ();
            } else {
                // Die if an unknown function
                bfEncrypt::reply('error', 'No Such method #err1 - '.$c);
            }
        } else {
            // Die if an unknown function
            bfEncrypt::reply('error', 'No Such method #err2');
        }
    }

    public function getDebugLog()
    {
        bfEncrypt::reply('success', array('data'=>bfLog::getLog()));
    }

    /**
     * Get the post install messages from a Joomla 3+ site.
     */
    public function getPostInstallMessages()
    {
        // bail early if we cannot
        if (!file_exists(JPATH_LIBRARIES.'/fof/include.php')) {
            bfEncrypt::reply('success', array());
        }

        // fire up RAD/fof
        require_once JPATH_LIBRARIES.'/fof/include.php';
        $model = FOFModel::getTmpInstance('Messages', 'PostinstallModel');
        $items = $model->getItemList();

        // load language layer to translate strings
        $lang = JFactory::getLanguage();

        // ensure we only show valid messages
        $model->onProcessList($items);

        $messages = array();

        // translate and compile the messages
        foreach ($items as $item) {
            $lang->load($item->language_extension, JPATH_ADMINISTRATOR, 'en-GB', true);
            $messages[] = array(
                'title' => JText::_($item->title_key),
                'desc'  => JText::_($item->description_key),
            );
        }

        bfEncrypt::reply('success', $messages);
    }

    /**
     * 113
     * Get User Registration Enable/Disable status.
     */
    public function getUserRegistration()
    {
        bfEncrypt::reply('success', array('enabled' => (int) JComponentHelper::getParams('com_users')->get('allowUserRegistration')));
    }

    /**
     * 114
     * Enable User Registration.
     */
    public function setUserRegistration()
    {
        $this->_db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'com_users'");

        $params = \json_decode($this->_db->LoadResult());

        // enabled
        $params->allowUserRegistration = 0;

        $this->_db->setQuery("UPDATE `#__extensions` set params = '".\json_encode($params)."' WHERE `name` = 'com_users'");
        $this->_db->query();

        return $this->getUserRegistration();
    }

    /**
     * 111
     * Enable /administrator/.htaccess restriction on apache.
     */
    public function setAdminHtaccess()
    {
        require 'lib/AdminTools/Model/AdminPassword/AdminPassword.php';

        $p           = new \Akeeba\AdminTools\Admin\Model\AdminPassword();
        $p->username = $this->_dataObj->u;
        $p->password = $this->_dataObj->p;

        if (!$p->protect()) {
            bfEncrypt::reply('error', 'Could not enable administrator .htaccess for some unknown reason :-( ');
        }

        bfEncrypt::reply('success', array(
                'enabled'  => 1,
                'username' => $this->_dataObj->u,
                'password' => $this->_dataObj->p,
            )
        );
    }

    /**
     * 112
     * Enable /administrator/.htaccess restriction on apache.
     */
    public function getAdminHtaccess()
    {
        require 'lib/AdminTools/Model/AdminPassword/AdminPassword.php';

        $obj = new \Akeeba\AdminTools\Admin\Model\AdminPassword();

        bfEncrypt::reply('success', array(
                'enabled' => $obj->isLocked(),
            )
        );
    }

    /**
     * Get the value of $gzip from /configuration.php.
     */
    public function getGzip()
    {
        bfEncrypt::reply('success', array(
                'enabled' => JFactory::getApplication()->getCfg('gzip', '0'),
            )
        );
    }

    /**
     * set the value of $gzip in /configuration.php.
     */
    public function setGzip()
    {
        return $this->_setConfigParam('gzip', 1, 'int');
    }

    /**
     * Get the config for session time.
     */
    public function getSessionlifetime()
    {
        bfEncrypt::reply('success', array(
                'lifetime' => JFactory::getApplication()->getCfg('lifetime', 0),
            )
        );
    }

    /**
     * set the session time to a sensibel recommend default.
     */
    public function setSessionlifetime()
    {
        $this->_setConfigParam('lifetime', 15, 'int');
    }

    /**
     * Get the number of days to delete logs after from the System - User Actions Log.
     *
     * @return int
     */
    public function setPurge30Days()
    {
        $this->_db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'PLG_SYSTEM_ACTIONLOGS'");

        $params = \json_decode($this->_db->LoadResult());

        // enabled
        $params->logDeletePeriod = 30;

        $this->_db->setQuery("UPDATE `#__extensions` set params = '".\json_encode($params)."' WHERE `name` = 'PLG_SYSTEM_ACTIONLOGS'");
        $this->_db->query();

        return $this->getPurge30Days();
    }

    /**
     * 109
     * Gets php.ini and .user.ini files.
     */
    private function getPHPinifiles()
    {
        // make sure we only retrieve a small dataset
        $limitstart = (int) $this->_dataObj->ls;
        $sort       = $this->_dataObj->s;

        if (!$sort) {
            $sort = 'filewithpath';
        }

        if (!in_array($sort, array('filewithpath', 'filemtime'))) {
            die('Invalid Sort');
        }

        if ('filemtime' == $sort) {
            $sort = 'filemtime DESC';
        }

        $limit = (int) $this->_dataObj->limit;

        // Set the query
        $this->_db->setQuery('SELECT id, iscorefile, filewithpath, filemtime, fileperms, `size`, iscorefile from bf_files
                                WHERE filewithpath LIKE "%php.ini%" OR filewithpath LIKE "%.user.ini%"
                                ORDER BY '.$sort.'
                                LIMIT '.(int) $limitstart.', '.$limit);

        // Get an object list of files
        $files = $this->_db->loadObjectList();

        // see how many files there are in total without a limit
        $this->_db->setQuery('SELECT count(*) from bf_files WHERE filewithpath LIKE "%php.ini%" OR filewithpath LIKE "%.user.ini%"');
        $count = $this->_db->loadResult();

        // Only show files that still exist on the hard drive
        $existingFiles = array();
        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                $existingFiles[] = $file;
            } else {
                $this->_db->setQuery(sprintf('DELETE FROM bf_files WHERE filewithpath = "%s"',
                    $file->filewithpath));
                $this->_db->query();

                --$count;
            }
        }

        // return an encrypted reply
        bfEncrypt::reply('success', array(
            'files' => $existingFiles,
            'total' => $count,
        ));
    }

    /**
     * Get the number of days to delete logs after from the System - User Actions Log.
     *
     * @return int
     */
    public function getPurge30Days()
    {
        if (version_compare(JVERSION, '3.9.0', '<')) {
            return false;
        }

        $this->_db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'PLG_SYSTEM_ACTIONLOGS'");

        $params = $this->_db->LoadResult();

        if ('{}' == $params) {
            bfEncrypt::reply('success', array(
                    'days' => null,
                )
            );
        }

        $params = json_decode($params);

        bfEncrypt::reply('success', array(
                'days' => $params->logDeletePeriod,
            )
        );
    }

    /**
     * Joomla 3.9.0+ enable system log rotation.
     *
     * @return mixed
     */
    public function setSystemLogRotationEnabled()
    {
        $this->_db->setQuery("UPDATE `#__extensions` set enabled = 1 WHERE `name` = 'plg_system_logrotation'");
        $this->_db->query();

        return $this->getSystemLogRotationEnabled();
    }

    /**
     * Joomla 3.9.0+ check for system log rotation.
     *
     * @return mixed
     */
    public function getSystemLogRotationEnabled()
    {
        $this->_db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `name` = 'plg_system_logrotation' and enabled = 1");

        bfEncrypt::reply('success', array(
                'enabled' => $this->_db->LoadResult(),
            )
        );
    }

    /**
     * Joomla 3.9.0+ enable IP logging in user action logging.
     *
     * @return mixed
     */
    public function setUseractionlogiplogenabled()
    {
        $this->_db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'com_actionlogs'");

        $params = json_decode($this->_db->LoadResult());

        // enabled
        $params->ip_logging = 1;

        $this->_db->setQuery("UPDATE `#__extensions` set params = '".json_encode($params)."' WHERE `name` = 'com_actionlogs'");
        $this->_db->query();

        return $this->getUseractionlogiplogenabled();
    }

    /**
     * Joomla 3.9.0+ Check for plg_privacy_actionlogs enabled.
     *
     * @return mixed
     */
    public function getUseractionlogiplogenabled()
    {
        $this->_db->setQuery("SELECT params FROM `#__extensions` WHERE `name` = 'com_actionlogs'");

        $params = json_decode($this->_db->LoadResult());

        bfEncrypt::reply('success', array(
                'enabled' => $params->ip_logging,
            )
        );
    }

    /**
     * Joomla 3.9.0+ Check for plg_privacy_actionlogs enabled.
     *
     * @return mixed
     */
    public function setUseractionlogenabled()
    {
        $this->_db->setQuery("UPDATE `#__extensions` set enabled = 1 WHERE `name` = 'PLG_ACTIONLOG_JOOMLA'");
        $this->_db->query();
        $this->_db->setQuery("UPDATE `#__extensions` set enabled = 1 WHERE `name` = 'PLG_SYSTEM_ACTIONLOGS'");
        $this->_db->query();

        return $this->getUseractionlogenabled();
    }

    /**
     * Joomla 3.9.0+ Check for plg_privacy_actionlogs enabled.
     *
     * @return mixed
     */
    public function getUseractionlogenabled()
    {
        $this->_db->setQuery("SELECT count(*) FROM `#__extensions` WHERE (`name` = 'PLG_ACTIONLOG_JOOMLA' or `name` = 'PLG_SYSTEM_ACTIONLOGS') and enabled = 1");

        bfEncrypt::reply('success', array(
                'enabled' => 2 == $this->_db->LoadResult() ? 1 : 0,
            )
        );
    }

    /**
     * Joomla 3.9.0+ Check for plg_system_privacyconsent enabled.
     *
     * @return mixed
     */
    public function setPrivacyConsentPluginEnabled()
    {
        $this->_db->setQuery("UPDATE `#__extensions` set enabled = 1 WHERE `name` = 'plg_system_privacyconsent'");
        $this->_db->query();

        return $this->getUseractionlogenabled();
    }

    /**
     * Joomla 3.9.0+ Check for plg_system_privacyconsent enabled.
     *
     * @return mixed
     */
    public function getPrivacyConsentPluginEnabled()
    {
        $this->_db->setQuery("SELECT count(*) FROM `#__extensions` WHERE `name` = 'plg_system_privacyconsent' and enabled = 1");

        bfEncrypt::reply('success', array(
                'enabled' => $this->_db->LoadResult(),
            )
        );
    }

    /**
     * Check several EOL files for security patches.
     */
    public function eolsecuritystatus()
    {
        $data = array();

        /**
         * Joomla 1,5 & 2.5 Series
         * [20151201] - Core - Remote Code Execution Vulnerability.
         *
         * @see    http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-8562
         * @secure md5 debug.php    Joomla 2.5.x    54a2f22406d8ee4b281d1a4543cb072b
         * @secure md5 session.php  Joomla 2.5.x    e9ac6f13100536eefa9241191c85c4b0
         * @secure md5 session.php  Joomla 1.5.x    63651a22d38b69f66959199955c5490c
         */
        $file  = JPATH_BASE.'/libraries/joomla/session/session.php';
        $file2 = JPATH_BASE.'/plugins/system/debug/debug.php';

        if (file_exists($file)) {
            $data['CVE20158562']['session'] = md5_file($file);
        } else {
            $data['CVE20158562']['session'] = 'NON_EXIST';
        }

        if (file_exists($file2)) {
            $data['CVE20158562']['debug'] = md5_file($file2);
        } else {
            $data['CVE20158562']['debug'] = 'NON_EXIST';
        }

        /**
         * Joomla 1,5.xxx.
         *
         * @see    http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=31626
         * @secure md5 media.php 3de2ea3338d49956b5dabf3a3fa1200d
         */
        $file = JPATH_BASE.'/administrator/components/com_media/helpers/media.php';

        if (file_exists($file)) {
            $data['fileupload_15']['media'] = md5_file($file);
        } else {
            $data['fileupload_15']['media'] = 'NON_EXIST';
        }

        /**
         * Joomla 1.5.xxx.
         *
         * @see    http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=31626
         * @secure md5 file.php 0eabdf91e2c7a26493eeb3dbe7a3fb39
         */
        $file = JPATH_BASE.'/libraries/joomla/filesystem/file.php';

        if (file_exists($file)) {
            $data['fileupload_15']['file'] = md5_file($file);
        } else {
            $data['fileupload_15']['file'] = 'NON_EXIST';
        }

        bfEncrypt::reply('success', array(
            'data' => $data,
        ));
    }

    public function applyeolpatch()
    {
        $i            = 0;
        $filesToPatch = array();

        if (preg_match('/^1\.5/', JVERSION)) {
            $filesToPatch[] = array(
                'source'      => 'https://cdn.myjoomla.com/public/patchfile/1',
                'destination' => JPATH_BASE.'/libraries/joomla/filesystem/file.php',
            );
            $filesToPatch[] = array(
                'source'      => 'https://cdn.myjoomla.com/public/patchfile/2',
                'destination' => JPATH_BASE.'/administrator/components/com_media/helpers/media.php',
            );
            $filesToPatch[] = array(
                'source'      => 'https://cdn.myjoomla.com/public/patchfile/3',
                'destination' => JPATH_BASE.'/libraries/joomla/session/session.php',
            );
        } elseif (preg_match('/^2\.5/', JVERSION)) {
            $filesToPatch[] = array(
                'source'      => 'https://cdn.myjoomla.com/public/patchfile/4',
                'destination' => JPATH_BASE.'/libraries/joomla/session/session.php',
            );
            $filesToPatch[] = array(
                'source'      => 'https://cdn.myjoomla.com/public/patchfile/5',
                'destination' => JPATH_BASE.'/plugins/system/debug/debug.php',
            );
        }

        foreach ($filesToPatch as $fileToPatch) {
            $source = base64_decode(file_get_contents($fileToPatch['source']));

            if (!is_writable($fileToPatch['destination'])) {
                bfEncrypt::reply('error', array(
                    'msg' => 'File NOT patched as it is unwritable: '.$fileToPatch['destination'],
                ));
            }

            if (!$source) {
                bfEncrypt::reply('error', array(
                    'msg' => 'File NOT patched as no source for it: '.$fileToPatch['destination'],
                ));
            }

            if (file_put_contents($fileToPatch['destination'], $source)) {
                ++$i;
            } else {
                bfEncrypt::reply('error', array(
                    'msg' => 'File NOT patched - no idea why :-( we coult not write to the file ',
                ));
            }

            unset($source);
        }

        bfEncrypt::reply('success', array(
            'msg' => $i.' File(s) patched!',
        ));
    }

    /**
     * Load Flash Upload Settings from params from com_media without using a helper. and then remove swf and application/x-shockwave-flash.
     */
    public function setUploadsettingsfixed()
    {
        $this->_db->setQuery("select params from #__extensions where element = 'com_media'");
        $params = json_decode($this->_db->LoadResult());

        $items = explode(',', $params->upload_extensions);
        foreach ($items as $k => $item) {
            if ('swf' == strtolower(trim($item))) {
                unset($items[$k]);
            }
        }
        $params->upload_extensions = implode(',', $items);

        $items = explode(',', $params->upload_mime);
        foreach ($items as $k => $item) {
            if ('application/x-shockwave-flash' == strtolower(trim($item))) {
                unset($items[$k]);
            }
        }
        $params->upload_mime = implode(',', $items);
        $sql                 = sprintf("UPDATE #__extensions set `params` = '%s' WHERE `element` = 'com_media'", json_encode($params));
        $this->_db->setQuery($sql);
        $this->_db->query();

        $this->getUploadsettingsfixed();
    }

    /**
     * Load Flash Upload Settings from params from com_media without using a helper.
     */
    public function getUploadsettingsfixed()
    {
        $this->_db->setQuery("select params from #__extensions where element = 'com_media'");
        $params = json_decode($this->_db->LoadResult());
        if (
            !preg_match('/swf/ism', $params->upload_extensions)
            &&
            !preg_match('/application\/x-shockwave-flash/ism', $params->upload_mime)
        ) {
            bfEncrypt::reply('success', array('uploadsettingsfixed' => 1));
        } else {
            bfEncrypt::reply('success', array('uploadsettingsfixed' => 0));
        }
    }

    /**
     * Method to delete a named file when we know its id.
     */
    private function deleteFile()
    {
        // Get the filewithpath based on the id
        $this->_db->setQuery('SELECT filewithpath from bf_files WHERE id = '.(int) $this->_dataObj->file_id);
        $filewithpath = $this->_db->loadResult();

        // check that the file we got form the database matches to the path we think it should be
        if ($this->_dataObj->filewithpath != $filewithpath) {
            bfEncrypt::reply('failure', array(
                'msg' => 'File Not matching: '.$this->_dataObj->filewithpath.' !== '.$filewithpath,
            ));
        }

        // If the file doesnt exist then remove from cache and reply
        if (!file_exists(JPATH_BASE.$filewithpath)) {
            $this->_db->setQuery('DELETE FROM bf_files WHERE id = '.(int) $this->_dataObj->file_id);
            $this->_db->query();
            bfEncrypt::reply('failure', array(
                'msg' => 'File doesn\'t exist: '.$filewithpath,
            ));
        }

        // Attempt to force deletion
        if (!is_writable(JPATH_BASE.$filewithpath)) {
            @chmod(JPATH_BASE.$filewithpath, 0777);
        }

        // delete the file, making sure we prefix with a path
        if (@unlink(JPATH_BASE.$filewithpath)) {
            $this->_db->setQuery('DELETE FROM bf_files WHERE id = '.(int) $this->_dataObj->file_id);
            $this->_db->query();

            // File deleted - say yes
            bfEncrypt::reply('success', array(
                'msg' => 'File deleted: '.$filewithpath,
            ));
        } else {
            // File deleted - say no
            bfEncrypt::reply('failure', array(
                'msg' => 'File Not Deleted: '.$filewithpath,
            ));
        }
    }

    /**
     * I delete a folder.
     */
    private function deleteFolder()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        // init our return msg
        $msg = array();

        // hidden or normal - needed for ALL deletes
        $type = $this->_dataObj->type;

        // switch on type
        if ('hidden' == $type) {
            // get the folders cache id
            $folder_id = $this->_dataObj->fid;

            // init
            $msgToReturn                    = array();
            $msgToReturn['deleted_files']   = 0;
            $msgToReturn['deleted_folders'] = 0;
            $msgToReturn['left']            = 0;

            // Do we want to delete all hidden folders?
            if ('ALL' == $folder_id) { // All meaning all hidden folders, not ALL folders in our db!!
                $this->_dataObj->ls    = 0;
                $this->_dataObj->limit = 999999999;

                // get all the hidden folders
                $folders = $this->getHiddenFolders(true);
                bfLog::log('Deleting this many folders : '.count($folders));

                // foreach hidden folder, delete that hidden folder recursivly
                foreach ($folders as $folder) {
                    // delete recursive
                    bfLog::log('Deleting folder: '.JPATH_BASE.$folder->folderwithpath);
                    $msg = Bf_Filesystem::deleteRecursive(JPATH_BASE.$folder->folderwithpath, true, $msg);

                    $this->_db->setQuery('DELETE FROM bf_folders WHERE folderwithpath LIKE "'.$folder->folderwithpath.'%"');
                    $this->_db->loadResult();
                    $this->_db->setQuery('DELETE FROM bf_files WHERE filewithpath LIKE "'.$folder->folderwithpath.'%"');
                    $this->_db->loadResult();

                    // oh dear we failed
                    if ('failure' == $msg['result']) {
                        $msgToReturn                    = array();
                        $msgToReturn['deleted_files']   = count(@$msg['deleted_files']);
                        $msgToReturn['deleted_folders'] = count(@$msg['deleted_folders']);
                        $msgToReturn['left']            = $this->getHiddenFolders(true);

                        // send back the error message
                        bfEncrypt::reply('failure', array(
                            'msg' => 'Problem!: '.json_encode($msgToReturn),
                        ));
                    }
                }
            } else {
                // select the folder to delete
                $this->_db->setQuery('SELECT folderwithpath FROM bf_folders WHERE id = '.(int) $folder_id);
                $folderwithpath = $this->_db->loadResult();

                // if the folder is not there
                if (!$folderwithpath) {
                    bfEncrypt::reply('failure', array(
                        'msg' => 'Folder Not Found #msg2#: '.$folderwithpath,
                    ));
                }

                $msg = Bf_Filesystem::deleteRecursive(JPATH_BASE.$folderwithpath, true, $msg);
            }

            // if we deleted some folders
            if (count($msg['deleted_folders'])) {
                foreach ($msg['deleted_folders'] as $folder) {
                    $fwp = str_replace('//', '/', str_replace(JPATH_BASE, '', $folder));

                    $sql = "DELETE FROM bf_folders where folderwithpath = '".$fwp."'";

                    $this->_db->setQuery($sql);
                    $this->_db->query();
                }
            }

            // if we deleted some files
            if (count($msg['deleted_files'])) {
                foreach ($msg['deleted_files'] as $file) {
                    $fwp = str_replace('//', '/', str_replace(JPATH_BASE, '', $file));

                    $sql = "DELETE FROM bf_files where filewithpath = '".$fwp."'";
                    $this->_db->setQuery($sql);
                    $this->_db->query();
                }
            }

            // reply back with our warning or success message
            $msgToReturn                    = array();
            $msgToReturn['deleted_files']   = count($msg['deleted_files']);
            $msgToReturn['deleted_folders'] = count($msg['deleted_folders']);
            $msgToReturn['left']            = count($this->getHiddenFolders(true));

            bfEncrypt::reply('success', array(
                'msg' => json_encode($msgToReturn),
            ));
        }

        if ($type = 'deleteinstallation') {
            $folders = $this->getFolders(JPATH_BASE);

            foreach ($folders as $folder) {
                if (preg_match('/installation|installation.old|docs\/installation|install|installation.bak|installation.old|installation.backup|installation.delete/i', $folder)) {
                    $installationFolders[] = $folder;
                }
            }

            foreach ($installationFolders as $folderwithpath) {
                bfLog::log('Deleting folder: '.$folderwithpath);
                $msg = Bf_Filesystem::deleteRecursive(JPATH_BASE.$folderwithpath, true, $msg);
            }

            bfEncrypt::reply('success', array(
                'msg' => 'ok',
            ));
        }
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getHiddenFolders($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;

        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }
        $this->_db->setQuery('SELECT * FROM bf_folders WHERE folderwithpath LIKE "%/.%" LIMIT '.(int) $limitstart.', '.$limit);
        $folders = $this->_db->loadObjectList();

        if (true === $internal) {
            return $folders;
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_folders WHERE folderwithpath LIKE "%/.%"');
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $folders,
            'total' => $count,
        ));
    }

    /**
     * Function taken from Akeeba filesystem.php.
     *
     * Akeeba Engine
     * The modular PHP5 site backup engine
     *
     * @copyright Copyright (c)2009 Nicholas K. Dionysopoulos
     * @license   GNU GPL version 3 or, at your option, any later version
     *
     * @version   Id: scanner.php 158 2010-06-10 08:46:49Z nikosdion
     */
    private function getFolders($folder)
    {
        // Initialize variables
        $arr   = array();
        $false = false;

        $folder = trim($folder);

        if (!is_dir($folder) && !is_dir($folder.DIRECTORY_SEPARATOR) || is_link($folder.DIRECTORY_SEPARATOR) || is_link($folder) || !$folder) {
            return $false;
        }

        if (@file_exists($folder.DIRECTORY_SEPARATOR.'.myjoomla.ignore.folder')) {
            return array();
        }

        $handle = @opendir($folder);
        if (false === $handle) {
            $handle = @opendir($folder.DIRECTORY_SEPARATOR);
        }
        // If directory is not accessible, just return FALSE
        if (false === $handle) {
            return $false;
        }

        while ((false !== ($file = @readdir($handle)))) {
            if (('.' != $file) && ('..' != $file) && (null != trim($file))) {
                $ds    = ('' == $folder) || (DIRECTORY_SEPARATOR == $folder) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) ? '' : DIRECTORY_SEPARATOR;
                $dir   = trim($folder.$ds.$file);
                $isDir = @is_dir($dir);
                if ($isDir) {
                    $arr[] = $this->cleanupFileFolderName(str_replace(JPATH_BASE, '', $folder.DIRECTORY_SEPARATOR.$file));
                }
            }
        }
        @closedir($handle);

        return $arr;
    }

    /**
     * Clean up a string, a path name.
     *
     * @param string $str
     *
     * @return string
     */
    private function cleanupFileFolderName($str)
    {
        $str = str_replace('////', '/', $str);
        $str = str_replace('///', '/', $str);
        $str = str_replace('//', '/', $str);
        $str = str_replace('\\/', '/', $str);
        $str = str_replace('\\t', '/t', $str);
        $str = str_replace("\/", '/', $str);

        return addslashes($str);
    }

    /**
     * I get the number of core files that failed the hash checking.
     */
    private function getCoreHashFailedFileList()
    {
        // set up the limit and limit start for the SQL
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        $this->_db->setQuery('SELECT id, filewithpath, filemtime, fileperms FROM bf_files WHERE hashfailed = 1 LIMIT '.$limitstart.', '.$limit);

        // Get the files from the cache
        $files = $this->_db->loadObjectList();

        // get the count as well, for pagination
        $this->_db->setQuery('SELECT count(*) from bf_files WHERE hashfailed = 1');
        $count = $this->_db->loadResult();

        // send back the totals
        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * I get list of database tables that begin with bak_.
     */
    private function deleteBakTables()
    {
        $tables = $this->getBakTables(true);

        // for all the bak tables
        foreach ($tables as $table) {
            // compose the sql query
            $this->_db->setQuery('DROP TABLE '.$table[0]);

            // delete the bak_tables
            $this->_db->query();
        }

        $count = count($tables);

        // send back the totals
        bfEncrypt::reply('success', array(
            'tables' => $tables,
            'total'  => $count,
        ));
    }

    /**
     * I get list of database tables that begin with bak_.
     */
    private function getBakTables($internal = false)
    {
        // Get the database name
        $config = JFactory::getApplication();
        $dbname = $config->getCfg('db', '');

        // compose the sql query
        $this->_db->setQuery("SHOW TABLES WHERE `Tables_in_{$dbname}` like 'bak_%'");

        // Get the bak_tables
        $tables = $this->_db->loadRowList();

        // return array if we are internally calling this method
        if (true === $internal) {
            return $tables;
        }

        // count them
        $count = count($tables);

        // send back the totals
        bfEncrypt::reply('success', array(
            'tables' => $tables,
            'total'  => $count,
        ));
    }

    /**
     * get the value of the $live_site var from configuration.php.
     */
    private function getConfiguredLiveSite()
    {
        // send back the totals
        bfEncrypt::reply('success', array(
            'live_site' => JFactory::getApplication()->getCfg('live_site', ''),
        ));
    }

    /**
     * Get a list of folders with 777 permissions.
     */
    private function getFolderPermissions()
    {
        // set up the limit and the limitstart SQL
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        $this->_db->setQuery('SELECT `id`, `folderwithpath`, `folderinfo` from bf_folders WHERE folderinfo IN ("777", "351", "311") LIMIT '.$limitstart.', '.$limit);

        // get the files
        $files = $this->_db->loadObjectList();

        // get the count for pagination
        $this->_db->setQuery('SELECT count(*) from bf_folders WHERE `folderinfo` IN ("777", "351", "311")');
        $count = $this->_db->loadResult();

        // send back the totals
        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * Get a list of files with 777 permissions.
     */
    private function getFilePermissions()
    {
        // set up the limit and the limitstart SQL
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        $this->_db->setQuery('SELECT id, filewithpath, fileperms from bf_files WHERE fileperms = "0777" OR fileperms = "777" LIMIT '.(int) $limitstart.', '.$limit);

        // get the files
        $files = $this->_db->loadObjectList();

        // get the count for pagination
        $this->_db->setQuery('SELECT count(*) from bf_files WHERE fileperms = "0777" OR fileperms = "777"');
        $count = $this->_db->loadResult();

        // send back the totals
        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * Set the permissions on files that have 777 perms to be 644.
     */
    private function setFilePermissions()
    {
        $fixed  = 0;
        $errors = 0;

        $this->_db->setQuery('SELECT id, filewithpath from bf_files WHERE fileperms = "0777" OR fileperms = "777"');
        $files = $this->_db->loadObjectList();
        foreach ($files as $file) {
            if (@chmod(JPATH_BASE.$file->filewithpath, 0644)) {
                ++$fixed;
                $this->_db->setQuery('UPDATE bf_files SET fileperms = "0644" WHERE id = "'.(int) $file->id.'"');
                $this->_db->query();
            } else {
                ++$errors;
            }
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_folders WHERE folderinfo LIKE "%777%"');
        $folders_777 = $this->_db->LoadResult();

        $res           = new stdClass();
        $res->errors   = $errors;
        $res->fixed    = $fixed;
        $res->leftover = $folders_777;

        bfEncrypt::reply('success', $res);
    }

    /**
     * Return the list of files that have been flagged as containing mail commands or text.
     */
    private function getUploaderFileList()
    {
        // make sure we only retrieve a small dataset
        $limitstart = (int) $this->_dataObj->ls;
        $sort       = $this->_dataObj->s;

        if (!$sort) {
            $sort = 'filewithpath';
        }

        if (!in_array($sort, array('filewithpath', 'filemtime'))) {
            die('Invalid Sort');
        }

        if ('filemtime' == $sort) {
            $sort = 'filemtime DESC';
        }

        $limit = (int) $this->_dataObj->limit;

        // Set the query
        $this->_db->setQuery('SELECT id, iscorefile, filewithpath, filemtime, fileperms, `size`, iscorefile from bf_files
                                WHERE uploader = 1
                                ORDER BY '.$sort.'
                                LIMIT '.(int) $limitstart.', '.$limit);

        // Get an object list of files
        $files = $this->_db->loadObjectList();

        // see how many files there are in total without a limit
        $this->_db->setQuery('SELECT count(*) from bf_files WHERE uploader = 1');
        $count = $this->_db->loadResult();

        // Only show files that still exist on the hard drive
        $existingFiles = array();
        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                $existingFiles[] = $file;
            } else {
                $this->_db->setQuery(sprintf('DELETE FROM bf_files WHERE filewithpath = "%s"',
                    $file->filewithpath));
                $this->_db->query();

                --$count;
            }
        }

        // return an encrypted reply
        bfEncrypt::reply('success', array(
            'files' => $existingFiles,
            'total' => $count,
        ));
    }

    /**
     * Return the list of files that have been flagged as containing mail commands or text.
     */
    private function getMailerFileList()
    {
        // make sure we only retrieve a small dataset
        $limitstart = (int) $this->_dataObj->ls;
        $sort       = $this->_dataObj->s;

        if (!$sort) {
            $sort = 'filewithpath';
        }

        if (!in_array($sort, array('filewithpath', 'filemtime'))) {
            die('Invalid Sort');
        }

        if ('filemtime' == $sort) {
            $sort = 'filemtime DESC';
        }

        $limit = (int) $this->_dataObj->limit;

        // Set the query
        $this->_db->setQuery('SELECT id, iscorefile, filewithpath, filemtime, fileperms, `size`, iscorefile from bf_files
                                WHERE mailer = 1
                                ORDER BY '.$sort.'
                                LIMIT '.(int) $limitstart.', '.$limit);

        // Get an object list of files
        $files = $this->_db->loadObjectList();

        // see how many files there are in total without a limit
        $this->_db->setQuery('SELECT count(*) from bf_files WHERE mailer = 1');
        $count = $this->_db->loadResult();

        // Only show files that still exist on the hard drive
        $existingFiles = array();
        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                $existingFiles[] = $file;
            } else {
                $this->_db->setQuery(sprintf('DELETE FROM bf_files WHERE filewithpath = "%s"',
                    $file->filewithpath));
                $this->_db->query();

                --$count;
            }
        }

        // return an encrypted reply
        bfEncrypt::reply('success', array(
            'files' => $existingFiles,
            'total' => $count,
        ));
    }

    /**
     * Return the list of files that have been flagged as containing patterns that match our suspect patterns
     * These maybe false positives for suspect content, but might be examples of bad code standards like using
     * ../../../ or eval() method.
     */
    private function getSuspectContentFileList()
    {
        // make sure we only retrieve a small dataset
        $limitstart = (int) $this->_dataObj->ls;
        $sort       = $this->_dataObj->s;

        if (!$sort) {
            $sort = 'filewithpath';
        }

        if (!in_array($sort, array('filewithpath', 'filemtime'))) {
            die('Invalid Sort');
        }

        if ('filemtime' == $sort) {
            $sort = 'filemtime DESC';
        }

        $limit = (int) $this->_dataObj->limit;

        // Set the query
        $this->_db->setQuery('SELECT id, iscorefile, filewithpath, filemtime, fileperms, `size`, iscorefile, hacked, currenthash from bf_files
                                WHERE suspectcontent = 1 OR hacked = 1
                                ORDER BY '.$sort.'
                                LIMIT '.(int) $limitstart.', '.$limit);

        // Get an object list of files
        $files = $this->_db->loadObjectList();

        // see how many files there are in total without a limit
        $this->_db->setQuery('SELECT count(*) from bf_files WHERE suspectcontent = 1 OR hacked = 1');
        $count = $this->_db->loadResult();

        // Only show files that still exist on the hard drive
        $existingFiles = array();
        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                $existingFiles[] = $file;
            } else {
                $this->_db->setQuery(sprintf('DELETE FROM bf_files WHERE filewithpath = "%s"',
                    $file->filewithpath));
                $this->_db->query();

                --$count;
            }
        }

        // return an encrypted reply
        bfEncrypt::reply('success', array(
            'files' => $existingFiles,
            'total' => $count,
        ));
    }

    /**
     * Get SQL files found.
     */
    private function getSQLFiles()
    {
        // make sure we only retrieve a small dataset
        $limitstart = (int) $this->_dataObj->ls;
        $sort       = $this->_dataObj->s;

        if (!$sort) {
            $sort = 'filewithpath';
        }

        if (!in_array($sort, array('filewithpath', 'filemtime'))) {
            die('Invalid Sort');
        }

        if ('filemtime' == $sort) {
            $sort = 'filemtime DESC';
        }

        $limit = (int) $this->_dataObj->limit;

        // Set the query
        $this->_db->setQuery('SELECT * FROM bf_files WHERE 
        (
        (filewithpath LIKE \'%.sql\' or filewithpath LIKE \'%sql/site.%\')
        and 
        (iscorefile = 0 or iscorefile is null)
        )
                                ORDER BY '.$sort.'
                                LIMIT '.(int) $limitstart.', '.$limit);

        // Get an object list of files
        $files = $this->_db->loadObjectList();

        // see how many files there are in total without a limit
        $this->_db->setQuery('SELECT count(*)  FROM bf_files WHERE 
        (
        (filewithpath LIKE \'%.sql\' or filewithpath LIKE \'%sql/site.%\')
        and 
        (iscorefile = 0 or iscorefile is null)
        )');
        $count = $this->_db->loadResult();

        // Only show files that still exist on the hard drive
        $existingFiles = array();
        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                $existingFiles[] = $file;
            } else {
                $this->_db->setQuery(sprintf('DELETE FROM bf_files WHERE filewithpath = "%s"',
                    $file->filewithpath));
                $this->_db->query();

                --$count;
            }
        }

        // return an encrypted reply
        bfEncrypt::reply('success', array(
            'files' => $existingFiles,
            'total' => $count,
        ));
    }

    /**
     * Return the list of files that have been flagged as containing patterns that match our suspect patterns
     * These maybe false positives for suspect content, but might be examples of bad code standards like using
     * ../../../ or eval() method.
     */
    private function getNonCoreFileList()
    {
        // make sure we only retrieve a small dataset
        $limitstart = (int) $this->_dataObj->ls;
        $sort       = $this->_dataObj->s;

        if (!$sort) {
            $sort = 'filewithpath';
        }

        if (!in_array($sort, array('filewithpath', 'filemtime'))) {
            die('Invalid Sort');
        }

        if ('filemtime' == $sort) {
            $sort = 'filemtime DESC';
        }

        $limit = (int) $this->_dataObj->limit;

        // Set the query
        $this->_db->setQuery('SELECT id, iscorefile, filewithpath, filemtime, fileperms, `size`, iscorefile from bf_files
                                WHERE iscorefile IS NULL
                                ORDER BY '.$sort.'
                                LIMIT '.(int) $limitstart.', '.$limit);

        // Get an object list of files
        $files = $this->_db->loadObjectList();

        // see how many files there are in total without a limit
        $this->_db->setQuery('SELECT count(*) from bf_files WHERE iscorefile IS NULL');
        $count = $this->_db->loadResult();

        // Only show files that still exist on the hard drive
        $existingFiles = array();
        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                $existingFiles[] = $file;
            } else {
                $this->_db->setQuery(sprintf('DELETE FROM bf_files WHERE filewithpath = "%s"',
                    $file->filewithpath));
                $this->_db->query();

                --$count;
            }
        }

        // return an encrypted reply
        bfEncrypt::reply('success', array(
            'files' => $existingFiles,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getInstallationFolders($internal = false)
    {
        $folders = $this->getFolders(JPATH_BASE);
        foreach ($folders as $folder) {
            if (preg_match('/installation|installation.old|docs\/installation|install|installation.bak|installation.old|installation.backup|installation.delete/i', $folder)) {
                $installationFolders[] = $folder;
            }
        }

        bfEncrypt::reply('success', array(
            'files' => $installationFolders,
            'total' => count($installationFolders),
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getRecentlyModified($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = "SELECT * FROM bf_files WHERE filemtime > '".strtotime('-3 days', time())."' ORDER BY filemtime DESC LIMIT ".(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery("SELECT count(*) FROM bf_files WHERE filemtime > '".strtotime('-3 days', time())."'");
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getHtaccessFiles($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = "SELECT * FROM bf_files WHERE filewithpath LIKE '%/.htaccess' ORDER BY filewithpath DESC LIMIT ".(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery("SELECT count(*) FROM bf_files WHERE filewithpath LIKE '%/.htaccess'");
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getLargefiles($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        $order      = $this->_dataObj->orderby;

        if (!in_array($order, array('filewithpath', 'filemtime', 'size'))) {
            $order = 'filewithpath';
        }

        if (!$limitstart) {
            $limitstart = 0;
        }

        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files WHERE SIZE > 2097152 ORDER BY '.$order.' DESC LIMIT '.(int) $limitstart.', '.$limit;

        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT COUNT(*) FROM bf_files WHERE SIZE > 2097152');
        $count = (int) $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getArchivefiles($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files WHERE
        filewithpath LIKE "%.zip"
        OR filewithpath LIKE "%.tar"
        OR filewithpath LIKE "%.tar.gz"
        OR filewithpath LIKE "%.bz2"
        OR filewithpath LIKE "%.gzip"
        OR filewithpath LIKE "%.bzip2" ORDER BY filemtime DESC LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_files WHERE
        filewithpath LIKE "%.zip"
        OR filewithpath LIKE "%.tar"
        OR filewithpath LIKE "%.tar.gz"
        OR filewithpath LIKE "%.bz2"
        OR filewithpath LIKE "%.gzip"
        OR filewithpath LIKE "%.bzip2"');
        $count = (int) $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getPhpinwrongplace($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files AS b WHERE filewithpath REGEXP "^/images/.*\.php$" ORDER BY filemtime DESC LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $count = (int) count($files);

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getTmpfiles($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files WHERE
        filewithpath LIKE "/tmp%"
        AND
                filewithpath != "/tmp/index.html"
        ORDER BY filemtime DESC LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_files WHERE
        filewithpath LIKE "/tmp%"
        AND
                filewithpath != "/tmp/index.html"
        ORDER BY filemtime');
        $count = (int) $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    private function clearFluffFiles()
    {
        require 'bfFilesystem.php';

        foreach ($this->fluffFiles as $file) {
            // ensure we are based correctly
            $fileWithPath = JPATH_BASE.$file;

            // Remove File.
            unlink($fileWithPath);
        }

        $this->getFlufffiles(true);
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getFlufffiles($internal = false)
    {
        $files               = array();
        $files['present']    = array();
        $files['notpresent'] = array();

        foreach ($this->fluffFiles as $file) {
            // ensure we are based correctly
            $fileWithPath = JPATH_BASE.$file;

            // determine if the file is present or not
            if (@file_exists($fileWithPath)) { //@ to avoid any nasty warnings
                $files['present'][] = $file;
            } else {
                $files['notpresent'][] = $file;
            }
        }

        bfEncrypt::reply('success', array(
            'total' => count($files['present']),
            'files' => $files,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getRenamedToHide($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files WHERE
                                filewithpath LIKE "%.backup%"
                                OR
                                filewithpath LIKE "%.bak%"
                                OR
                                filewithpath LIKE "%.old%"
                                ORDER BY filemtime DESC LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_files WHERE
                                filewithpath LIKE "%.backup%"
                                OR
                                filewithpath LIKE "%.bak%"
                                OR
                                filewithpath LIKE "%.old%"');
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    private function clearTmpFiles()
    {
        require 'bfFilesystem.php';

        $filesAndFolders = Bf_Filesystem::readDirectory(JPATH_ROOT.'/tmp', '.', true);

        foreach ($filesAndFolders as $pointer) {
            $pointer = JPATH_ROOT.'/tmp/'.$pointer;

            if (is_dir($pointer)) {
                bfLog::log('Deleting '.$pointer);
                Bf_Filesystem::deleteRecursive($pointer, true);
            } else {
                bfLog::log('Deleting '.$pointer);
                unlink($pointer);
            }
        }

        file_put_contents(JPATH_ROOT.'/tmp/index.html', '<html><body bgcolor="#FFFFFF"></body></html> ');

        $sql = 'DELETE FROM bf_files WHERE
                  filewithpath LIKE "/tmp%"
                    AND
                  filewithpath != "/tmp/index.html"';
        $this->_db->setQuery($sql);
        $this->_db->query();

        bfEncrypt::reply('success', array(
            'res' => true,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getDotfiles($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files WHERE filewithpath LIKE "%/.%" ORDER BY filemtime DESC LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_files WHERE filewithpath LIKE "%/.%"');
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * Find files which have zero bytes (no content) as they just litter the webspace
     * and run up inode counts. Joomla doesnt rely on zero byte files, we have seen "other hack cleanup companies"
     * litter the webspace with zero byte files and so this tool deletes those too.
     *
     * @param bool $internal
     *
     * @return mixed
     */
    private function getZerobyteFiles($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files WHERE size = 0 ORDER BY filemtime DESC LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_files WHERE size = 0');
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * Restore core files from a trusted source.
     *
     * This source (corefiles.myjoomla.io) is checked hourly for integrity, if you are concerned about MITM Attacks, well, if your server
     * is compromised enough for a MITM Attack then you have bigger issues, plus this is how Joomla updates happen
     * anyway so no additional security issues are created with this code!
     */
    private function restoreAllMissingFiles()
    {
        $url         = 'https://corefiles.myjoomla.io/%s%s?raw';
        $restored    = 0;
        $notRestored = 0;

        // Crappy Servers Alert!
        @set_time_limit(3600);

        $files = $this->getMissingCoreFiles(true);
        foreach ($files as $file) {
            $downloadUrl = sprintf($url, JVERSION, $file->filewithpath);

            $restoreToFile = JPATH_BASE.$file->filewithpath;

            // check folder and path to folder exists
            $folder = dirname($restoreToFile);
            if (!file_exists($folder)) {
                @mkdir($folder, 0755, true);
            }

            $content = file_get_contents($downloadUrl);

            if ($content && file_exists($folder) && file_put_contents($restoreToFile, $content)) {
                // Set correct permissions @ for crappy servers
                @chmod($restoreToFile, 0644);

                // Update the cache database tables so we dont have to run a new audit right away
                $sql = "INSERT INTO `bf_files` 
                (`id`, `filewithpath`, `fileperms`, `filemtime`, `toggler`, `currenthash`, `lasthash`, `iscorefile`, `hashfailed`, `hashchanged`, `hacked`, `suspectcontent`, `falsepositive`, `mailer`, `uploader`, `encrypted`, `queued`, `size`)
                VALUES
                (NULL, '%s', '0644', '%s', NULL, '%s', '%s', 1, NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, %s)";

                $sql = sprintf($sql, $file->filewithpath, time(), md5_file($restoreToFile), md5_file($restoreToFile), filesize($restoreToFile));
                $this->_db->setQuery($sql);
                $this->_db->query();

                ++$restored;
            } else {
                ++$notRestored;
            }
        }

        bfEncrypt::reply('success', array(
            'total'       => count($files),
            'restored'    => $restored,
            'notrestored' => $notRestored,
        ));
    }

    private function getMissingCoreFiles($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = " FROM `bf_core_hashes`
                    WHERE filewithpath NOT IN (
                        SELECT filewithpath from bf_files
                    )
                    AND filewithpath NOT LIKE '/installation/%'
                    AND filewithpath != '/robots.txt.dist'
                    AND filewithpath != '/administrator/manifests/packages/pkg_weblinks.xml'
                    AND filewithpath != '/'
                    AND filewithpath != '/robots.txt.dist'
                    AND filewithpath != '/web.config.txt'
                    AND filewithpath != '/joomla.xml'
                    AND filewithpath != '/build.xml'
                    AND filewithpath != '/LICENSE.txt'
                    AND filewithpath != '/README.txt'
                    AND filewithpath != '/htaccess.txt'
                    AND filewithpath != '/LICENSES.php'
                    AND filewithpath != '/configuration.php-dist'
                    AND filewithpath != '/CHANGELOG.php'
                    AND filewithpath != '/COPYRIGHT.php'
                    AND filewithpath != '/CREDITS.php'
                    AND filewithpath != '/INSTALL.php'
                    AND filewithpath != '/LICENSE.php'
                    AND filewithpath != '/CONTRIBUTING.md'
                    AND filewithpath != '/phpunit.xml.dist'
                    AND filewithpath != '/.drone.yml'
                    AND filewithpath != '/README.md'
                    AND filewithpath != '/.travis.yml'
                    AND filewithpath != '/travisci-phpunit.xml'
                    AND filewithpath != '/images/banners/osmbanner1.png'
                    AND filewithpath != '/images/banners/osmbanner2.png'
                    AND filewithpath != '/images/banners/shop-ad-books.jpg'
                    AND filewithpath != '/images/banners/shop-ad.jpg'
                    AND filewithpath != '/images/banners/white.png'
                    AND filewithpath != '/images/headers/blue-flower.jpg'
                    AND filewithpath != '/images/headers/maple.jpg'
                    AND filewithpath != '/images/headers/raindrops.jpg'
                    AND filewithpath != '/images/headers/walden-pond.jpg'
                    AND filewithpath != '/images/headers/windows.jpg'
                    AND filewithpath != '/images/joomla_black.gif'
                    AND filewithpath != '/images/joomla_black.png'
                    AND filewithpath != '/images/joomla_green.gif'
                    AND filewithpath != '/images/joomla_logo_black.jpg'
                    AND filewithpath != '/images/powered_by.png'
                    AND filewithpath != '/images/sampledata/fruitshop/apple.jpg'
                    AND filewithpath != '/images/sampledata/fruitshop/bananas_2.jpg'
                    AND filewithpath != '/images/sampledata/fruitshop/fruits.gif'
                    AND filewithpath != '/images/sampledata/fruitshop/tamarind.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/180px_koala_ag1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/180px_wobbegong.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/200px_phyllopteryx_taeniolatus1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/220px_spottedquoll_2005_seanmcclean.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/789px_spottedquoll_2005_seanmcclean.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/800px_koala_ag1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/800px_phyllopteryx_taeniolatus1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/800px_wobbegong.jpg'
                    AND filewithpath != '/images/sampledata/parks/banner_cradle.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/120px_pinnacles_western_australia.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/120px_rainforest_bluemountainsnsw.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/180px_ormiston_pound.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/250px_cradle_mountain_seen_from_barn_bluff.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/727px_rainforest_bluemountainsnsw.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/800px_cradle_mountain_seen_from_barn_bluff.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/800px_ormiston_pound.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/800px_pinnacles_western_australia.jpg'
                    AND filewithpath != '/images/sampledata/parks/parks.gif' ORDER BY filewithpath DESC ";

        $limitIt = 'LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery('SELECT * '.$sql.$limitIt);
        $files = $this->_db->LoadObjectList();

        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                unset($files[$k]);
            }
        }

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT count(*) '.$sql.$limitIt);
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * Tool57
     * Delete files which have zero bytes (no content) as they just litter the webspace
     * and run up inode counts. Joomla doesnt rely on zero byte files, we have seen "other hack cleanup companies"
     * litter the webspace with zero byte files and so this tool deletes those too.
     */
    private function deleteZerobyteFiles()
    {
        $sql = 'SELECT filewithpath FROM bf_files WHERE size = 0';
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        $filesDeleted = array();
        $count        = 0;

        foreach ($files as $file) {
            $fullFilePath = JPATH_BASE.$file->filewithpath;
            if (@unlink($fullFilePath)) {
                ++$count;
                $filesDeleted[] = $file->filewithpath;

                $sql = sprintf('DELETE FROM bf_files WHERE filewithpath = " % s"', $file->filewithpath);
                $this->_db->setQuery($sql);
                $this->_db->query();
            }
        }

        bfEncrypt::reply('success', array(
            'files' => $filesDeleted,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getEncrypted($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;
        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999';
        }

        $sql = 'SELECT * FROM bf_files WHERE encrypted = 1 ORDER BY filemtime DESC LIMIT '.(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_files WHERE encrypted = 1');
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return JUser|mixed|object
     */
    private function getUser($internal = false)
    {
        switch ($this->_dataObj->searchfield) {
            case 'username':
                $sql = "SELECT * FROM #__users WHERE username = '%s'";
                $sql = sprintf($sql, $this->_dataObj->searchvalue);
                $this->_db->setQuery($sql);
                $row = $this->_db->loadObject();
                break;
            case 'id':
                $row = new JUser();
                $row->load((int) $this->_dataObj->searchvalue);
                break;
        }

        if ($row->id) {
            // NEVER let the users password leave the remote site
            $row->password = '**REMOVED**';
        }

        if (true === $internal) {
            return $row;
        }

        bfEncrypt::reply('success', array(
            'user' => $row,
        ));
    }

    /**
     * remove £live_site from the configuration.php.
     *
     * @throws exception Exception
     */
    private function removeLiveSite()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        try {
            $config = JFactory::getConfig();

            if (version_compare(JVERSION, '3.0', 'ge')) {
                $config->set('live_site', '');
            } else {
                $config->setValue('config.live_site', '');
            }

            $newConfig = $config->toString('PHP', array(
                'class'      => 'JConfig',
                'closingtag' => false,
            ));

            // On some occasions, Joomla! 1.6 ignores the configuration and
            // produces "class c". Let's fix this!
            $newConfig = str_replace('class c {', 'class JConfig {', $newConfig);
            $newConfig = str_replace('namespace c;', '', $newConfig);

            // Try to write out the configuration.php
            $filename = JPATH_ROOT.DIRECTORY_SEPARATOR.'configuration.php';
            $result   = Bf_Filesystem::_write($filename, $newConfig);
            if (false !== $result) {
                bfEncrypt::reply('success', array());
            } else {
                bfEncrypt::reply(bfReply::ERROR, array(
                    'msg' => 'Could Not Save Config',
                ));
            }
        } catch (Exception $e) {
            bfEncrypt::reply(bfReply::ERROR, array(
                'msg' => $e->getMessage(),
            ));
        }
    }

    /**
     * set the log_path and tmp_path to sane defaults.
     *
     * @throws exception Exception
     */
    private function setLogTmpPaths()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        try {
            // sane and recommended defaults
            $logpath = JPATH_ROOT.DIRECTORY_SEPARATOR.'administrator/logs';
            $tmpath  = JPATH_ROOT.DIRECTORY_SEPARATOR.'tmp';

            // force creation and set sane permissions
            @mkdir($logpath);
            @mkdir($tmpath);
            @chmod($logpath, 0755);
            @chmod($tmpath, 0755);

            $config = JFactory::getConfig();

            if (version_compare(JVERSION, '3.0', 'ge')) {
                $config->set('log_path', $logpath);
                $config->set('tmp_path', $tmpath);
            } else {
                $config->setValue('config.log_path', $logpath);
                $config->setValue('config.tmp_path', $tmpath);
            }

            $newConfig = $config->toString('PHP', array(
                'class'      => 'JConfig',
                'closingtag' => false,
            ));

            // On some occasions, Joomla! 1.6 ignores the configuration and
            // produces "class c". Let's fix this!
            $newConfig = str_replace('class c {', 'class JConfig {', $newConfig);
            $newConfig = str_replace('namespace c;', '', $newConfig);

            // Try to write out the configuration.php
            $filename = JPATH_ROOT.DIRECTORY_SEPARATOR.'configuration.php';
            $result   = Bf_Filesystem::_write($filename, $newConfig);
            if (false !== $result) {
                bfEncrypt::reply('success', array(
                    'log_path'    => $logpath,
                    'tmp_path'    => $tmpath,
                    'config_file' => $filename,
                ));
            } else {
                bfEncrypt::reply(bfReply::ERROR, array(
                    'msg' => 'Could Not Save Config',
                ));
            }
        } catch (Exception $e) {
            bfEncrypt::reply(bfReply::ERROR, array(
                'msg' => $e->getMessage(),
            ));
        }
    }

    /**
     * Enable SEF and SEF Rewrite.
     */
    private function setSEFConfig()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        try {
            $config = JFactory::getConfig();

            // Our sane defaults
            $sef         = 1;
            $sef_rewrite = 1;
            $sef_suffix  = 0;

            if (version_compare(JVERSION, '3.0', 'ge')) {
                $config->set('sef', $sef);
                $config->set('sef_rewrite', $sef_rewrite);
                $config->set('sef_suffix', $sef_suffix);
            } else {
                $config->setValue('config.sef', $sef);
                $config->setValue('config.sef_rewrite', $sef_rewrite);
                $config->setValue('config.sef_suffix', $sef_suffix);
            }

            $newConfig = $config->toString('PHP', array(
                'class'      => 'JConfig',
                'closingtag' => false,
            ));

            // On some occasions, Joomla! 1.6 ignores the configuration and
            // produces "class c". Let's fix this!
            $newConfig = str_replace('class c {', 'class JConfig {', $newConfig);
            $newConfig = str_replace('namespace c;', '', $newConfig);

            // Try to write out the configuration.php
            $filename = JPATH_ROOT.DIRECTORY_SEPARATOR.'configuration.php';
            $result   = Bf_Filesystem::_write($filename, $newConfig);
            if (false !== $result) {
                bfEncrypt::reply('success', $this->getSEFConfig());
            } else {
                bfEncrypt::reply(bfReply::ERROR, array(
                    'msg' => 'Could Not Save Config',
                ));
            }
        } catch (Exception $e) {
            bfEncrypt::reply(bfReply::ERROR, array(
                'msg' => $e->getMessage(),
            ));
        }
    }

    /**
     * Get the settings for the SEF from Joomla Global Config.
     *
     * public $sef = '1';
     * public $sef_rewrite = '0';
     * public $sef_suffix = '0';
     */
    private function getSEFConfig()
    {
        $config = JFactory::getConfig();

        if (version_compare(JVERSION, '3.0', 'ge')) {
            $data = array(
                'sef'         => $config->get('sef'),
                'sef_rewrite' => $config->get('sef_rewrite'),
                'sef_suffix'  => $config->get('sef_suffix'),
            );
        } else {
            $data = array(
                'sef'         => $config->getValue('config.sef'),
                'sef_rewrite' => $config->getValue('config.sef_rewrite'),
                'sef_suffix'  => $config->getValue('config.sef_suffix'),
            );
        }

        bfEncrypt::reply('success', $data);
    }

    /**
     * Set Cookie Settings right.
     */
    private function setCookieSettings()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        try {
            $config = JFactory::getConfig();

            if (version_compare(JVERSION, '3.0', 'ge')) {
                $config->set('cookie_domain', '');
                $config->set('cookie_path', '');
            } else {
                $config->setValue('config.cookie_domain', '');
                $config->setValue('config.cookie_path', '');
            }

            $newConfig = $config->toString('PHP', array(
                'class'      => 'JConfig',
                'closingtag' => false,
            ));

            // On some occasions, Joomla! 1.6 ignores the configuration and
            // produces "class c". Let's fix this!
            $newConfig = str_replace('class c {', 'class JConfig {', $newConfig);
            $newConfig = str_replace('namespace c;', '', $newConfig);

            // Try to write out the configuration.php
            $filename = JPATH_ROOT.DIRECTORY_SEPARATOR.'configuration.php';
            $result   = Bf_Filesystem::_write($filename, $newConfig);
            if (false !== $result) {
                bfEncrypt::reply('success', $this->getCookieSettings());
            } else {
                bfEncrypt::reply(bfReply::ERROR, array(
                    'msg' => 'Could Not Save Config',
                ));
            }
        } catch (Exception $e) {
            bfEncrypt::reply(bfReply::ERROR, array(
                'msg' => $e->getMessage(),
            ));
        }
    }

    /**
     * Get the settings for the cookie from config.
     *
     * public $cookie_domain
     * public $cookie_path
     */
    private function getCookieSettings()
    {
        $config = JFactory::getConfig();

        if (version_compare(JVERSION, '3.0', 'ge')) {
            $data = array(
                'cookie_domain' => $config->get('cookie_domain'),
                'cookie_path'   => $config->get('cookie_path'),
            );
        } else {
            $data = array(
                'cookie_domain' => $config->getValue('config.cookie_domain'),
                'cookie_path'   => $config->getValue('config.cookie_path'),
            );
        }

        bfEncrypt::reply('success', $data);
    }

    /**
     * @throws exception Exception
     */
    private function setDbPrefix()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        $prefix = $this->_dataObj->prefix;
        try {
            $prefix = $this->_validateDbPrefix($prefix);

            /**
             * Performs the actual schema change.
             *
             * @param $prefix string
             *                The new prefix
             *
             * @return bool False if the schema could not be changed
             *
             * @copyright Copyright (c)2010-2011 Nicholas K. Dionysopoulos
             * @license   GNU General Public License version 3, or later
             */
            $config = JFactory::getConfig();
            if (version_compare(JVERSION, '3.0', 'ge')) {
                $oldprefix = $config->get('dbprefix', '');
                $dbname    = $config->get('db', '');
            } else {
                $oldprefix = $config->getValue('config.dbprefix', '');
                $dbname    = $config->getValue('config.db', '');
            }

            $db  = $this->_db;
            $sql = "SHOW TABLES WHERE `Tables_in_{$dbname}` like '{$oldprefix}%'";
            $db->setQuery($sql);

            if (version_compare(JVERSION, '3.0', 'ge')) {
                $oldTables = $db->loadColumn();
            } else {
                $oldTables = $db->loadResultArray();
            }

            if (empty($oldTables)) {
                throw new Exception('Could not find any tables with the old prefix to change to the new prefix');
            }

            foreach ($oldTables as $table) {
                $newTable = $prefix.substr($table, strlen($oldprefix));
                $sql      = "RENAME TABLE `$table` TO `$newTable`";
                $db->setQuery($sql);
                if (!$db->query()) {
                    // Something went wrong; I am pulling the plug and hope for
                    // the best
                    throw new Exception('Something went wrong; I am pulling the plug and hope for the best - Contact our support URGENTLY');
                }
            }

            /**
             * Updates the configuration.php file with the given prefix.
             *
             * @param $prefix string
             *                The prefix to write to the configuration.php file
             *
             * @return bool False if writing to the file was not possible
             *
             * @copyright Copyright (c)2010-2011 Nicholas K. Dionysopoulos
             * @license   GNU General Public License version 3, or later
             */
            // Load the configuration and replace the db prefix
            $config = JFactory::getConfig();
            if (version_compare(JVERSION, '3.0', 'ge')) {
                $oldprefix = $config->get('dbprefix', $prefix);
            } else {
                $oldprefix = $config->getValue('config.dbprefix', $prefix);
            }
            if (version_compare(JVERSION, '3.0', 'ge')) {
                $config->set('dbprefix', $prefix);
            } else {
                $config->setValue('config.dbprefix', $prefix);
            }

            $newConfig = $config->toString('PHP', array(
                'class'      => 'JConfig',
                'closingtag' => false,
            ));

            // On some occasions, Joomla! 1.6 ignores the configuration and
            // produces "class c". Let's fix this!
            $newConfig = str_replace('class c {', 'class JConfig {', $newConfig);
            $newConfig = str_replace('namespace c;', '', $newConfig);

            if (version_compare(JVERSION, '3.0', 'ge')) {
                $config->set('dbprefix', $oldprefix);
            } else {
                $config->setValue('config.dbprefix', $oldprefix);
            }

            // Try to write out the configuration.php
            $filename = JPATH_ROOT.DIRECTORY_SEPARATOR.'configuration.php';
            $result   = Bf_Filesystem::_write($filename, $newConfig);
            if (false !== $result) {
                bfEncrypt::reply('success', array(
                    'prefix' => $prefix,
                ));
            } else {
                bfEncrypt::reply(bfReply::ERROR, array(
                    'msg' => 'Could Not Save Config',
                ));
            }
        } catch (Exception $e) {
            bfEncrypt::reply(bfReply::ERROR, array(
                'msg' => $e->getMessage(),
            ));
        }
    }

    /**
     * Validates a prefix.
     * The prefix must be 3-6 lowercase characters followed by
     * an underscore and must not alrady exist in the current database. It must
     * also not be jos_ or bak_.
     *
     * @param $prefix string
     *                The prefix to check
     *
     * @return string bool validated prefix or false if the prefix is invalid
     *
     * @throws exception
     *
     * @copyright Copyright (c)2010-2011 Nicholas K. Dionysopoulos
     */
    private function _validateDbPrefix($prefix)
    {
        // Check that the prefix is not jos_ or bak_
        if (('jos_' == $prefix) || ('bak_' == $prefix)) {
            throw new exception('Cannot be a standard prefix like jos_ or bak_');
        }

        // Check that we're not trying to reuse the same prefix
        $config = JFactory::getConfig();
        if (version_compare(JVERSION, '3.0', 'ge')) {
            $oldprefix = $config->get('dbprefix', '');
        } else {
            $oldprefix = $config->getValue('config.dbprefix', '');
        }
        if ($prefix == $oldprefix) {
            throw new exception('Cannot be the same as existing prefix');
        }

        // Check the length
        $pLen = strlen($prefix);
        if (($pLen < 4) || ($pLen > 6)) {
            throw new exception('Prefix must be between 4 and 6 chars');
        }

        // Check that the prefix ends with an underscore
        if ('_' != substr($prefix, -1)) {
            throw new exception('Prefix must end with an underscore');
        }

        // Check that the part before the underscore is lowercase letters
        $valid = preg_match('/[\w]_/i', $prefix);
        if (0 === $valid) {
            throw new exception('Prefix must be all lowercase');
        }

        // Turn the prefix into lowercase
        $prefix = strtolower($prefix);

        // Check if the prefix already exists in the database
        $db = $this->_db;
        if (version_compare(JVERSION, '3.0', 'ge')) {
            $dbname = $config->get('db', '');
        } else {
            $dbname = $config->getValue('config.db', '');
        }
        $sql = "SHOW TABLES WHERE `Tables_in_{$dbname}` like '{$prefix}%'";
        $db->setQuery($sql);
        if (version_compare(JVERSION, '3.0', 'ge')) {
            $existing_tables = $db->loadColumn();
        } else {
            $existing_tables = $db->loadResultArray();
        }
        if (count($existing_tables)) {
            // Sometimes we have false alerts, e.g. a prefix of dev_ will match
            // tables starting with dev15_ or dev16_
            $realCount = 0;
            foreach ($existing_tables as $check) {
                if (substr($check, 0, $pLen) == $prefix) {
                    ++$realCount;
                    break;
                }
            }
            if ($realCount) {
                throw new exception('Prefix already exists in the database');
            }
        }

        return $prefix;
    }

    /**
     * Update details of a user, including a hashed password.
     *
     * @todo Not sure this is ever called anymore (April 2018)
     */
    private function setUser()
    {
        $email    = $this->_dataObj->email;
        $pass     = $this->_dataObj->password;
        $username = $this->_dataObj->username;
        $where    = $this->_dataObj->where;

        if (!$email || !$pass || !$username || !$where) {
            bfEncrypt::reply('failure', array(
                'msg' => 'Not all required parts set',
            ));
        }

        $sql = 'UPDATE #__users SET username="%s", password="%s", email ="%s" WHERE %s';
        $sql = sprintf($sql, $username, $pass, $email, $where);
        $this->_db->setQuery($sql);
        $id = $this->_db->query();

        bfEncrypt::reply('success', array(
            'usersaved' => $id,
        ));
    }

    /**
     * @param bool $internal
     *
     * @return array|mixed
     */
    private function getErrorLogs($internal = false)
    {
        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;

        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '9999999999999999'; //pah
        }

        $sql = "SELECT * FROM bf_files WHERE filewithpath LIKE '%error_log' ORDER BY filemtime DESC LIMIT ".(int) $limitstart.', '.$limit;
        $this->_db->setQuery($sql);
        $files = $this->_db->LoadObjectList();

        if (true === $internal) {
            return $files;
        }

        $this->_db->setQuery("SELECT count(*) FROM bf_files WHERE filewithpath LIKE '%error_log'");
        $count = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'files' => $files,
            'total' => $count,
        ));
    }

    /**
     * Save the robots.txt file.
     */
    private function saveRobotsFile()
    {
        if (file_put_contents(JPATH_BASE.'/robots.txt', base64_decode($this->_dataObj->filecontents))) {
            bfEncrypt::reply('success', array(
                'msg' => 'File saved!',
            ));
        } else {
            bfEncrypt::reply('error', array(
                'msg' => 'File could not be saved!',
            ));
        }
    }

    /**
     * ok ok I know this looks bad, it probably is, but this allows a subscriber to edit a file on
     * myJoomla.com and then save the contents back to myJoomla.com.
     *
     * In order to get to this method a lot of security jumps have to have gone through already
     *
     * Its not as insecure as first seen... promise :)
     */
    private function saveFile()
    {
        require 'bfFilesystem.php';

        if (!$this->_dataObj->filename || !$this->_dataObj->filecontents) {
            bfEncrypt::reply('error', array(
                'msg' => 'No file name or file contents were provided!',
            ));
        }

        if (file_exists(JPATH_BASE.$this->_dataObj->filename) && !is_writable(JPATH_BASE.$this->_dataObj->filename)) {
            bfEncrypt::reply('error', array(
                'msg' => 'File not saved - as file is unwritable!',
            ));
        }

        if (!file_exists(dirname(JPATH_BASE.$this->_dataObj->filename))) {
            if (!@mkdir(dirname(JPATH_BASE.$this->_dataObj->filename), 0755, true)) {
                bfEncrypt::reply('error', array(
                    'msg' => 'File not saved - could not create folder paths!',
                ));
            }
        }

        $content = base64_decode($this->_dataObj->filecontents);

        if (!$content) {
            bfEncrypt::reply('error', array(
                'msg' => 'File not saved - as no content sent to save into the file!',
            ));
        }

        if (@Bf_Filesystem::_write(JPATH_BASE.$this->_dataObj->filename, $content)) {
            bfEncrypt::reply('success', array(
                'msg' => 'File saved!',
            ));
        } else {
            bfEncrypt::reply('error', array(
                'msg' => 'No idea why, but file content could not be saved to '.JPATH_BASE.$this->_dataObj->filename,
            ));
        }
    }

    /**
     * get the contents of the robots.txt only if it exists in the cache tables.
     */
    private function getRobotsFile()
    {
        $this->_db->setQuery('SELECT id from bf_files WHERE filewithpath = "/robots.txt"');
        $id = $this->_db->loadResult();
        if (!$id) {
            $obj               = new stdclass();
            $obj->filename     = '';
            $obj->filemd5      = md5('');
            $obj->filewithpath = '';
            $obj->filecontents = base64_encode('Could not load content for your own security, run a full audit before attempting to edit file content with myJoomla.com');
            $obj->filesize     = 0;
            $obj->basepath     = JPATH_BASE;
            $obj->writeable    = 0;

            bfEncrypt::reply('success', array(
                'file' => $obj,
            ));
        }
        $this->downloadfile($id);
    }

    /**
     * @param null $file_id
     */
    private function downloadfile($file_id = null)
    {
        if (null === $file_id) {
            $file_id = (int) $this->_dataObj->f;
        }

        $this->_db->setQuery('SELECT filewithpath from bf_files WHERE id = '.$file_id);

        $filename     = $this->_db->loadResult();
        $filewithpath = JPATH_BASE.$filename;

        if (file_exists($filewithpath)) {
            $contents              = file_get_contents($filewithpath);
            $contentsbase64_encode = base64_encode($contents);
            $obj                   = new stdclass();
            $obj->filename         = $filename;
            $obj->filemd5          = md5($contents);
            $obj->filewithpath     = $filewithpath;
            $obj->filecontents     = $contentsbase64_encode;
            $obj->filesize         = filesize($filewithpath);
            $obj->basepath         = JPATH_BASE;
            $obj->writeable        = is_writable($filewithpath);

            bfEncrypt::reply('success', array(
                'file' => $obj,
            ));
        } else {
            bfEncrypt::reply('error', array(
                'msg' => 'File No Longer Exists!',
            ));
        }
    }

    private function restorefile()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        // get the cached data on the file
        $this->_db->setQuery('SELECT filewithpath FROM bf_files WHERE id = '.$this->_dataObj->fileid);
        $file_to_restore_nopath = $this->_db->loadResult();
        $file_to_restore        = JPATH_BASE.$file_to_restore_nopath;

        $new_file_contents = base64_decode($this->_dataObj->filecontents);
        $new_md5           = md5($new_file_contents);
        if ($new_md5 !== $this->_dataObj->md5) {
            bfEncrypt::reply('failure', 'MD5 Check 1 Failed');
        }

        $this->_db->setQuery('SELECT hash FROM bf_core_hashes WHERE filewithpath = "'.$file_to_restore_nopath.'"');
        $core_md5 = $this->_db->loadResult();
        if ($core_md5 !== $this->_dataObj->md5) {
            bfEncrypt::reply('failure', 'MD5 Check 2 Failed');
        }

        $backup = file_get_contents($file_to_restore);
        Bf_Filesystem::_write($file_to_restore, $new_file_contents);

        if (md5_file($file_to_restore) !== $this->_dataObj->md5) {
            Bf_Filesystem::_write($file_to_restore, $backup);
            bfEncrypt::reply('failure', 'MD5 Check 3 Failed');
        }

        $this->_db->setQuery("UPDATE bf_files SET suspectcontent = 0 , hashfailed = 0 where filewithpath = '".$file_to_restore_nopath."'");
        $this->_db->query();

        bfEncrypt::reply('success', 'Restored OK');
    }

    private function checkFTPLayer()
    {
        $config     = JFactory::getApplication();
        $ftp_pass   = $config->getCfg('ftp_pass', '');
        $ftp_user   = $config->getCfg('ftp_user', '');
        $ftp_enable = $config->getCfg('ftp_enable', '');
        $ftp_host   = $config->getCfg('ftp_host', '');
        $ftp_root   = $config->getCfg('ftp_root', '');
        if ($ftp_pass || $ftp_user || '1' == $ftp_enable || $ftp_host || $ftp_root) {
            bfEncrypt::reply('success', 1);
        } else {
            bfEncrypt::reply('success', 0);
        }
    }

    private function disableFTPLayer()
    {
        $config      = JFactory::getApplication();
        $config_file = JPATH_BASE.'/configuration.php';

        $ftp_pass   = $config->getCfg('ftp_pass', '');
        $ftp_user   = $config->getCfg('ftp_user', '');
        $ftp_enable = $config->getCfg('ftp_enable', '');
        $ftp_host   = $config->getCfg('ftp_host', '');
        $ftp_root   = $config->getCfg('ftp_root', '');

        $config_txt = file_get_contents(JPATH_BASE.'/configuration.php');
        $config_txt = str_replace("\$ftp_enable = '1';", "\$ftp_enable = '0';", $config_txt);
        $config_txt = str_replace("\$ftp_pass = '".$ftp_pass."';", "\$ftp_pass = '';", $config_txt);
        $config_txt = str_replace("\$ftp_user = '".$ftp_user."';", "\$ftp_user = '';", $config_txt);
        $config_txt = str_replace("\$ftp_host = '".$ftp_host."';", "\$ftp_host = '';", $config_txt);
        $config_txt = str_replace("\$ftp_root = '".$ftp_root."';", "\$ftp_root = '';", $config_txt);

        @chmod($config_file, 0777);
        if (file_put_contents($config_file, $config_txt)) {
            @chmod($config_file, 0644);
            bfEncrypt::reply('success', 1);
        } else {
            bfEncrypt::reply('failure', 'Could not write configuration.php to '.$config_file);
        }
    }

    private function setFolderPermissions()
    {
        $fixed  = 0;
        $errors = 0;

        $this->_db->setQuery('SELECT id, folderwithpath from bf_folders WHERE folderinfo = "777"');
        $folders = $this->_db->loadObjectList();
        foreach ($folders as $folder) {
            if (@chmod(JPATH_BASE.$folder->folderwithpath, 0755)) {
                ++$fixed;
                $this->_db->setQuery('UPDATE bf_folders SET folderinfo = "755" WHERE id = "'.(int) $folder->id.'" AND folderinfo = "777"');
                $this->_db->query();
            } else {
                ++$errors;
            }
        }

        $this->_db->setQuery('SELECT count(*) FROM bf_folders WHERE folderinfo LIKE "%777%"');
        $folders_777 = $this->_db->LoadResult();

        $res           = new stdClass();
        $res->errors   = $errors;
        $res->fixed    = $fixed;
        $res->leftover = $folders_777;

        bfEncrypt::reply('success', $res);
    }

    /**
     * I do some sanity checks then enable .htaccess.
     */
    private function setHtaccess()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        // init bfDatabase

        // To
        $htaccess = JPATH_BASE.DIRECTORY_SEPARATOR.'.htaccess';

        // From
        $htaccesstxt = JPATH_BASE.DIRECTORY_SEPARATOR.'htaccess.txt';

        $res = new stdClass();
        if (file_exists($htaccess)) {
            $res->result = 'ERROR';
            $res->msg    = '.htaccess file already exists!';
            bfEncrypt::reply(bfReply::SUCCESS, $res);
        }

        if (!file_exists($htaccesstxt)) {
            $res->result = 'ERROR';
            $res->msg    = 'htaccess.txt file not found, cannot proceed';
            bfEncrypt::reply(bfReply::SUCCESS, $res);
        }

        // Test we are on apache
        if (!preg_match('/Apache|LiteSpeed/i', $_SERVER['SERVER_SOFTWARE'])) {
            $res->result = 'ERROR';
            $res->msg    = 'Server reported its not running Apache/LiteSpeed, but is running '.$_SERVER['SERVER_SOFTWARE'];
            bfEncrypt::reply(bfReply::SUCCESS, $res);
        }

        $didItWork = Bf_Filesystem::_write($htaccess, file_get_contents($htaccesstxt));

        if (false == $didItWork) {
            $res->result = 'ERROR';
            $res->msg    = 'Could not copy htaccess.txt to .htaccess';
            bfEncrypt::reply(bfReply::SUCCESS, $res);
        }

        $res->result = 'SUCCESS';
        $res->msg    = '.htaccess enabled! - Go and test your site!';
        bfEncrypt::reply(bfReply::SUCCESS, $res);
    }

    /**
     * I set the new database credentials in /configuration.php after some testing.
     */
    private function setDbCredentials()
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        $password = $this->_dataObj->p;
        $user     = $this->_dataObj->u;

        $res = $this->testDbCredentials(true);
        if ('error' == $res->result) {
            bfEncrypt::reply(bfReply::ERROR, $res);
        }
        /**
         * Updates the configuration.php file with the given prefix
         * (some code from below).
         *
         * @param $prefix string
         *                The prefix to write to the configuration.php file
         *
         * @return bool False if writing to the file was not possible
         *
         * @copyright Copyright (c)2010-2011 Nicholas K. Dionysopoulos
         * @license   GNU General Public License version 3, or later
         */
        // Load the configuration and replace the db prefix
        $config = JFactory::getConfig();
        if (version_compare(JVERSION, '3.0', 'ge')) {
            $olduser     = $config->get('user');
            $oldpassword = $config->get('password');
            $host        = $config->get('host');
        } else {
            $olduser     = $config->getValue('config.user');
            $oldpassword = $config->getValue('configpassword');
            $host        = $config->getValue('host');
        }

        if (version_compare(JVERSION, '3.0', 'ge')) {
            $config->set('user', $user);
            $config->set('password', $password);
        } else {
            $config->setValue('config.user', $user);
            $config->setValue('config.password', $password);
        }

        $newConfig = $config->toString('PHP', 'config', array(
            'class' => 'JConfig',
        ));

        // On some occasions, Joomla! 1.6 ignores the configuration and
        // produces "class c". Let's fix this!
        $newConfig = str_replace('class c {', 'class JConfig {', $newConfig);

        // Try to write out the configuration.php
        $filename = JPATH_ROOT.DIRECTORY_SEPARATOR.'configuration.php';
        $result   = Bf_Filesystem::_write($filename, $newConfig);

        // reconnect db! to use new credentials
        $newConnectionOptions['user']     = $user;
        $newConnectionOptions['password'] = $password;
        $newConnectionOptions['host']     = $host;

        // make new db connection
        $db = JDatabase::getInstance($newConnectionOptions);
        $db->setQuery('SHOW DATABASES  where `Database` NOT IN ("test", "information_schema", "mysql")');
        $dbs_visible = count($db->loadObjectList());

        if (false !== $result) {
            bfEncrypt::reply('success', array(
                'msg'         => 'Config saved!',
                'dbs_visible' => $dbs_visible,
            ));
        } else {
            bfEncrypt::reply(bfReply::ERROR, array(
                'msg' => 'Could Not Save Config',
            ));
        }
    }

    /**
     * @param bool $internal
     *
     * @return stdClass
     */
    private function testDbCredentials($internal = false)
    {
        try {
            $config = JFactory::getApplication();

            $pass = $this->_dataObj->p;
            $user = $this->_dataObj->u;

            $host = $config->getCfg('host', '');
            $db   = $config->getCfg('db', '');

            if (function_exists('mysql_connect')) {
                $link = @mysql_connect($host, $user, $pass);
            } else {
                $link = @mysqli_connect($host, $user, $pass);
            }

            $msg = new stdClass();

            if (!$link) {
                if (function_exists('mysql_connect')) {
                    $msg->msg = trim(mysql_error().' Could not connect to mysql server with supplied credentials');
                } else {
                    $msg->msg = trim(mysqli_error().' Could not connect to mysql server with supplied credentials');
                }
                $msg->result = 'error';
                if (true === $internal) {
                    return $msg;
                }
                bfEncrypt::reply('success', $msg);
            }

            if (function_exists('mysql_connect')) {
                if (!@mysql_select_db($db, $link)) {
                    $msg->msg    = trim(mysql_error().' Mysql User exists, but has no access to the database');
                    $msg->result = 'error';
                    if (true === $internal) {
                        return $msg;
                    }
                    bfEncrypt::reply('success', $msg);
                }
            } else {
                if (!@mysqli_select_db($link, $db)) {
                    $msg->msg    = trim(mysqli_error().' Mysql User exists, but has no access to the database');
                    $msg->result = 'error';
                    if (true === $internal) {
                        return $msg;
                    }
                    bfEncrypt::reply('success', $msg);
                }
            }

            $msg->result = 'success';
            if (true === $internal) {
                return $msg;
            }

            bfEncrypt::reply('success', $msg);
        } catch (Exception $e) {
            bfEncrypt::reply('error', 'exception: '.$e->getMessage());
        }
    }

    private function getUpdatesCount()
    {
        require 'bfUpdates.php';

        $bfUpdates = new bfUpdates();

        bfEncrypt::reply('success', array(
            'count' => $bfUpdates->getupdates(true),
        ));
    }

    private function getUpdatesDetail()
    {
        @ob_start();
        @set_time_limit(60);
        require 'bfUpdates.php';

        $bfUpdates = new bfUpdates();
        $updates   = $bfUpdates->getupdates(false, $this->_dataObj->d);

        @ob_clean();

        bfEncrypt::reply('success', array(
            'current_joomla_version' => JVERSION,
            'availableUpdates'       => $updates['updates'],
            'updateSites'            => $updates['sites'],
        ));
    }

    /**
     * Fix Db Schema version in the db.
     *
     * @since 20130929
     */
    private function fixDbSchema()
    {
        require JPATH_ADMINISTRATOR.'/components/com_installer/models/database.php';
        $model = new InstallerModelDatabase();
        $model->fix();

        $changeSet = $model->getItems();
        bfEncrypt::reply('success', array(
            'latest'        => $changeSet->getSchema(),
            'current'       => $model->getSchemaVersion(),
            'schema_errors' => $model->getItems()->check(),
        ));
    }

    /**
     * Return the DB schema.
     *
     * @since 20130929
     */
    private function getDbSchemaVersion()
    {
        require JPATH_ADMINISTRATOR.'/components/com_installer/models/database.php';
        $model     = new InstallerModelDatabase();
        $changeSet = $model->getItems();
        bfEncrypt::reply('success', array(
            'latest'        => $changeSet->getSchema(),
            'current'       => $model->getSchemaVersion(),
            'schema_errors' => $model->getItems()
                ->check(),
        ));
    }

    private function checkGoogleFile()
    {
        $found = false;
        $files = scandir(JPATH_BASE);
        foreach ($files as $file) {
            if (preg_match('/google.*\.html/', $file)) {
                $found = true;
            }
        }
        bfEncrypt::reply('success', array(
            'found' => $found,
        ));
    }

    private function toggleOnline()
    {
        return $this->_setConfigParam('offline', $this->_dataObj->status, 'int');
    }

    /**
     * Generic function for updating the configuration.php file.
     *
     * @param $param string
     * @param $value string|int
     */
    private function _setConfigParam($param, $value, $type = 'int')
    {
        // Require more complex methods for dealing with files
        require 'bfFilesystem.php';

        if ('int' == $type && !is_int($value)) {
            if ('true' == $value) {
                $value = 1;
            } elseif ('false' == $value) {
                $value = 0;
            } else {
                $value = 0;
            }
        }

        $config = JFactory::getConfig();

        if (version_compare(JVERSION, '3.0', 'ge')) {
            $config->set($param, $value);
        } else {
            $config->setValue('config.'.$param, $value);
        }

        $newConfig = $config->toString('PHP', array(
            'class' => 'JConfig',
        ));

        /**
         * On some occasions, Joomla! 1.6+ ignores the configuration and
         * produces "class c". Let's fix this!
         */
        $newConfig = str_replace('class c {', 'class JConfig {', $newConfig);
        $newConfig = str_replace('namespace c;', '', $newConfig);

        // Set the correct location of the file
        $filename = JPATH_ROOT.DIRECTORY_SEPARATOR.'configuration.php';

        // Try to write out the configuration.php
        $result = Bf_Filesystem::_write($filename, $newConfig);

        if (false !== $result) {
            bfEncrypt::reply('success', array(
                $param => $value,
            ));
        } else {
            bfEncrypt::reply(bfReply::ERROR, array(
                'msg' => 'Could Not Save Config value for '.$param,
            ));
        }
    }

    private function toggleCache()
    {
        return $this->_setConfigParam('caching', $this->_dataObj->status, 'int');
    }

    private function getOfflineStatus()
    {
        bfEncrypt::reply('success', array(
            'offline' => JFactory::getApplication()->getCfg('offline'),
        ));
    }

    private function getCacheStatus()
    {
        bfEncrypt::reply('success', array(
            'caching' => JFactory::getApplication()->getCfg('caching'),
        ));
    }

    /**
     * Install an extension from Url.
     */
    private function doExtensionInstallFromUrl()
    {
        ob_start();
        // Load up as much of Joomla as we need
        require 'bfExtensions.php';
        $ext = new bfExtensions($this->_dataObj);
        $ext->installExtensionFromUrl();
    }

    private function doExtensionUpgrade()
    {
        ob_start();

        // Load up as much of Joomla as we need
        require 'bfExtensions.php';

        $app = JFactory::getApplication('Myjoomla');

        // Support crappy extensions like OSMap that implement their own license manager via plugins
        JPluginHelper::importPlugin('system');

        // init reply to myJoomla.com
        $result             = array();
        $result['messages'] = array();

        // which row in the _updates table should we use
        $this->_db->setQuery('SELECT update_id from #__updates WHERE extension_id = "'.$this->_dataObj->eid.'"');
        $extension_row_id = $this->_db->loadResult();

        // Do the update
        $ext              = new bfExtensions();
        $result['result'] = $ext->doUpdate($extension_row_id);

        // Grab any error messages

        $result['messages'] = $app->getMessageQueue();

        // translate messages
        $lang = JFactory::getLanguage();
        $lang->load('com_installer', JPATH_ADMINISTRATOR, 'en-GB', true);
        $lang->load('lib_joomla', JPATH_ADMINISTRATOR, 'en-GB', true);

        if (count($result['messages'])) {
            foreach ($result['messages'] as &$msg) {
                $msg['message'] = JText::_($msg['message']);
            }
        }

        bfEncrypt::reply('success', array(
            'result' => $result,
        ));
    }

    private function checkAkeebaOutputDirectory()
    {
        try {
            // If using PHP 5.2 then ABORT as Akeeba stuff needs newer PHP version
            if (version_compare(PHP_VERSION, '5.3.0', '<')) {
                throw new Exception('PHP version below 5.3.0 so Akeeba Will Not Work!');
            } else {
                require 'bfPHPFiveThreePlusOnly.php';
            }

            // Check Akeeba Installed - Prerequisite
            if (!file_exists(JPATH_SITE.'/libraries/f0f/include.php')
                || !file_exists(JPATH_SITE.'/administrator/components/com_akeeba/engine/Factory.php')
                || !file_exists(JPATH_SITE.'/administrator/components/com_akeeba/engine/serverkey.php')
            ) {
                bfEncrypt::reply('success', array(
                    'paths' => array(),
                ));
            }

            $returnData = array();

            if (!defined('AKEEBAENGINE')) {
                define('AKEEBAENGINE', 1);
            }

            require_once JPATH_SITE.'/libraries/f0f/include.php';
            require_once JPATH_SITE.'/administrator/components/com_akeeba/engine/Factory.php';

            $serverKeyFile = JPATH_BASE.'/administrator/components/com_akeeba/engine/serverkey.php';
            if (!defined('AKEEBA_SERVERKEY') && file_exists($serverKeyFile)) {
                include $serverKeyFile;
            }

            // Get the list of profiles
            $profileList = F0FModel::getTmpInstance('Profiles', 'AkeebaModel')->getProfilesList();

            // for each profile
            foreach ($profileList as $config) {
                // if encrypted
                if ('###AES128###' == substr($config->configuration, 0, 12)) {
                    $php53 = new bfPHPFiveThreePlusOnly();

                    $config->configuration = $php53->getAkeebaConfig($config->configuration);
                }

                // Convert ini to useable array
                $data = parse_ini_string($config->configuration, true);

                // find the folder
                $dir = $data['akeeba']['basic.output_directory'];

                $returnData[] = array('path' => $dir,
                    'is_writable'            => is_writable($dir),
                    'file_exists'            => file_exists($dir), );
            }

            bfEncrypt::reply('success', array(
                'paths' => $returnData,
            ));
        } catch (Exception $e) {
            bfEncrypt::reply('error', array(
                'msg' => $e->getMessage(),
            ));
        }
    }

    /**
     * return a value from the config.
     */
    private function getDebugMode()
    {
        $config = JFactory::getConfig();

        $data = array(
            'debug' => $config->get('debug'),
        );

        bfEncrypt::reply('success', array(
            'debug' => $data,
        ));
    }

    /**
     * set a value to the config.
     */
    private function setDebugMode()
    {
        return $this->_setConfigParam('debug', 'false', 'int');
    }

    /**
     * return a value from the config.
     */
    private function getErrorReporting()
    {
        $config = JFactory::getConfig();

        $data = array(
            'error_reporting' => $config->get('error_reporting'),
        );

        bfEncrypt::reply('success', array(
            'error_reporting' => $data,
        ));
    }

    /**
     * set a value to the config.
     */
    private function setErrorReporting()
    {
        return $this->_setConfigParam('error_reporting', 'none', 'string');
    }

    /**
     * return the main configuration.php without sensitive information
     * like passwords.
     */
    private function getJoomlaLogTmpConfig()
    {
        $config = JFactory::getConfig();

        $data = array(
            'log_path' => $config->get('log_path'),
            'tmp_path' => $config->get('tmp_path'),
            'base'     => JPATH_BASE,
        );

        bfEncrypt::reply('success', array(
            'paths' => $data,
        ));
    }

    /**
     * Get the User Actions Log.
     *
     * Joomla 3.9.0 implemented a User Action Log which basically replicates what we used to do
     * So now we load data from their log and not ours :-) Saves duplicating our efforts!
     */
    private function getActivityLog()
    {
        if (!class_exists('bfActivitylog')) {
            require_once 'bfActivitylog.php';
        }

        $inst = bfActivitylog::getInstance();
        $inst->ensureTableCreated();

        $limitstart = (int) $this->_dataObj->ls;
        $limit      = (int) $this->_dataObj->limit;

        if (!$limitstart) {
            $limitstart = 0;
        }
        if (!$limit) {
            $limit = '100';
        }

        if (version_compare(JVERSION, '3.9.0', '>=')) {
            // Manipulate the base Uri in the Joomla Stack to provide compatibility with some 3pd extensions like ACL Manager!
            try {
                $uri = \Joomla\CMS\Uri\Uri::getInstance();

                $reflection   = new \ReflectionClass($uri);
                $baseProperty = $reflection->getProperty('base');
                $baseProperty->setAccessible(true);
                $base           = $baseProperty->getValue();
                $base['prefix'] = $uri->toString(array('scheme', 'host'));
                $base['path']   = '/';
                $baseProperty->setValue($base);
            } catch (ReflectionException $e) {
            }

            JLoader::register('ActionlogsModelActionlogs', JPATH_ADMINISTRATOR.'/components/com_actionlogs/models/actionlogs.php');
            JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR.'/components/com_actionlogs/helpers/actionlogs.php');

            $model = JModelLegacy::getInstance('Actionlogs', 'ActionlogsModel', array('ignore_request' => true));

            // Set the Start and Limit
            $model->setState('list.start', $limitstart);
            $model->setState('list.limit', $limit);
            $model->setState('list.ordering', 'a.id');
            $model->setState('list.direction', 'DESC');

            $rows = $model->getItems();

            // Load all language files needed
            ActionlogsHelper::loadActionLogPluginsLanguage();
            $lang = JFactory::getLanguage();
            $lang->load('com_privacy', JPATH_ADMINISTRATOR, null, false, true);
            $lang->load('plg_system_actionlogs', JPATH_ADMINISTRATOR, null, false, true);
            $lang->load('plg_system_privacyconsent', JPATH_ADMINISTRATOR, null, false, true);

            // manipulate data to push to myJoomla.com
            foreach ($rows as $row) {
                $row->what   = ActionlogsHelper::getHumanReadableLogMessage($row);
                $row->ip     = $row->ip_address;
                $row->when   = $row->log_date;
                $row->who_id = $row->user_id;
                $row->source = 'core_user_action_log';
            }
        } else {
            // Before Joomla 3.9.0
            $this->_db->setQuery('SELECT * from bf_activitylog ORDER by id DESC LIMIT '.$limitstart.', '.$limit);
            $rows = $this->_db->loadObjectList();
        }

        bfEncrypt::reply('success', $rows ?: array());
    }

    /**
     * enable/disable and get status of our plugin.
     */
    private function getBFPluginStatus()
    {
        switch ($this->_dataObj->action) {
            case 'enable':

                if (version_compare(JVERSION, '3.9.0', '>=')) {
                    $this->_db->setQuery("UPDATE `#__extensions` set enabled = 1 WHERE `name` = 'PLG_ACTIONLOG_JOOMLA'");
                    $this->_db->query();
                    $this->_db->setQuery("UPDATE `#__extensions` set enabled = 1 WHERE `name` = 'PLG_SYSTEM_ACTIONLOGS'");
                    $this->_db->query();
                }

                $this->_db->setQuery('UPDATE `#__extensions` SET enabled = 1 WHERE element = "bfnetwork"');
                $this->_db->query();
                break;
            case 'disable':
                $this->_db->setQuery('UPDATE `#__extensions` SET enabled = 0 WHERE element = "bfnetwork"');
                $this->_db->query();
                break;
        }

        $this->_db->setQuery('SELECT enabled FROM #__extensions WHERE element = "bfnetwork"');
        $result = $this->_db->loadResult();
        bfEncrypt::reply('success', $result);
    }

    /**
     * get the list of users that have a 32 char password hash - e.g md5.
     */
    private function getMD5PasswordUsers()
    {
        $this->_db->setQuery('SELECT id, username, name, password FROM #__users WHERE CHAR_LENGTH(password) = 32');
        $result = $this->_db->loadObjectList();
        bfEncrypt::reply('success', $result);
    }

    /**
     * Check the session gc plugin in Joomla 3.
     */
    private function setSessionGCStatus()
    {
        $this->_db->setQuery("update #__extensions set enabled = 1 where name = 'plg_system_sessiongc'");
        $this->_db->query();

        bfEncrypt::reply('success', array(
            'status' => $this->getSessionGCStatus(),
        ));
    }

    /**
     * Check the session gc plugin in Joomla 3.
     */
    private function getSessionGCStatus()
    {
        $res = 2;

        // Session GC
        $this->_db->setQuery("select count(*) from #__extensions where name = 'plg_system_sessiongc'");
        $hasSessionGcPlugin = $this->_db->LoadResult();

        if ($hasSessionGcPlugin) {
            $this->_db->setQuery("select enabled from #__extensions where name = 'plg_system_sessiongc'");
            $res = $this->_db->LoadResult();
        }

        bfEncrypt::reply('success', array(
            'status' => $res,
        ));
    }

    /**
     * Get the 2FA plugins.
     */
    private function enable2FAPlugins()
    {
        $this->_db->setQuery("UPDATE `#__extensions` SET enabled = 1 WHERE `folder` = 'twofactorauth'");
        $this->_db->LoadResult();

        $this->get2FAPlugins();
    }

    /**
     * Get the 2FA plugins.
     */
    private function get2FAPlugins()
    {
        $this->_db->setQuery("SELECT * FROM `#__extensions` WHERE `folder` = 'twofactorauth'");
        $res = $this->_db->loadObjectList();

        bfEncrypt::reply('success', $res);
    }

    /**
     * set params from com_config without using a helper.
     */
    private function setAdminFilterFixed()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE `element` = 'com_config'");
        $params                            = json_decode($this->_db->LoadResult());
        $params->filters->{7}->filter_type = 'BL';
        $this->_db->setQuery(sprintf("UPDATE #__extensions set `params` = '%s' WHERE `element` = 'com_config'", json_encode($params)));
        $this->_db->query();

        return $this->getAdminFilterFixed();
    }

    /**
     * Load params from com_config without using a helper.
     */
    private function getAdminFilterFixed()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE element = 'com_config'");
        $params = json_decode($this->_db->LoadResult());

        bfEncrypt::reply('success', $params->filters->{7});
    }

    /**
     * set params from com_config without using a helper.
     */
    private function setPlaintextpasswords()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE `element` = 'com_users'");
        $params               = json_decode($this->_db->LoadResult());
        $params->sendpassword = '0';
        $this->_db->setQuery(sprintf("UPDATE #__extensions set `params` = '%s' WHERE `element` = 'com_users'", json_encode($params)));
        $this->_db->query();

        $this->getPlaintextpasswords();
    }

    /**
     * Load params from com_config without using a helper.
     */
    private function getPlaintextpasswords()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE element = 'com_users'");
        $params = json_decode($this->_db->LoadResult());

        bfEncrypt::reply('success', array('sendpassword' => $params->sendpassword));
    }

    /**
     * set params from com_content without using a helper.
     */
    private function setMailtofrienddisabled()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE `element` = 'com_content'");
        $params                  = json_decode($this->_db->LoadResult());
        $params->show_email_icon = '0';
        $this->_db->setQuery(sprintf("UPDATE #__extensions set `params` = '%s' WHERE `element` = 'com_content'", json_encode($params)));
        $this->_db->query();

        $this->getMailtofrienddisabled();
    }

    /**
     * Load params from com_content without using a helper.
     */
    private function getMailtofrienddisabled()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE element = 'com_content'");
        $params = json_decode($this->_db->LoadResult());

        bfEncrypt::reply('success', array('show_email_icon' => $params->show_email_icon));
    }

    /**
     * set params from com_templates without using a helper.
     */
    private function setTemplatePositionDisplay()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE `element` = 'com_templates'");
        $params                             = json_decode($this->_db->LoadResult());
        $params->template_positions_display = '0';
        $this->_db->setQuery(sprintf("UPDATE #__extensions set `params` = '%s' WHERE `element` = 'com_templates'", json_encode($params)));
        $this->_db->query();

        $this->getTemplatePositionDisplay();
    }

    /**
     * Load params from com_templates without using a helper.
     */
    private function getTemplatePositionDisplay()
    {
        $this->_db->setQuery("SELECT `params` from #__extensions WHERE element = 'com_templates'");
        $params = json_decode($this->_db->LoadResult());

        bfEncrypt::reply('success', array('template_positions_display' => $params->template_positions_display));
    }

    /**
     * Get the configuration of the google recaptcha plugin and global config.
     */
    private function getCaptchaConfig()
    {
        $config = JFactory::getApplication();

        $this->_db->setQuery("SELECT enabled FROM #__extensions WHERE name ='plg_captcha_recaptcha'");
        $enabled = $this->_db->loadResult();

        $this->_db->setQuery("SELECT params FROM #__extensions WHERE name ='plg_captcha_recaptcha'");
        $keyed = $this->_db->loadResult();

        bfEncrypt::reply('success', array(
            'enabled'    => $enabled,
            'configured' => $config->getCfg('captcha', ''),
            'keys'       => json_decode($keyed),
        ));
    }

    /**
     * Set the configuration of the google recaptcha plugin and global config.
     */
    private function setCaptchaConfig()
    {
        $this->_db->setQuery(sprintf("UPDATE #__extensions 
        SET 
        enabled = 1,
        params = '{\"version\":\"2.0\",\"public_key\":\"%s\",\"private_key\":\"%s\",\"theme\":\"clean\",\"theme2\":\"light\",\"size\":\"normal\"}' 
        WHERE name ='plg_captcha_recaptcha'",
            $this->_dataObj->site_key,
            $this->_dataObj->secret_key
        ));
        $this->_db->query();

        $this->_setConfigParam('captcha', 'recaptcha', 'string');
    }

    /**
     * get the list of ACL Groups.
     */
    private function getGroups()
    {
        $this->_db->setQuery('select id, title from #__usergroups');

        bfEncrypt::reply('success', array(
            'groups' => $this->_db->loadObjectList(),
        ));
    }

    /**
     * get the list of super admins.
     */
    private function getSuperAdmins()
    {
        $this->_db->setQuery('select id, name, username from #__users as u
                        left join #__user_usergroup_map as m on u.id = m.user_id
                        where m.group_id = '.(int) $this->_dataObj->groupid);

        bfEncrypt::reply('success', array(
            'users' => $this->_db->loadObjectList(),
        ));
    }

    /**
     * 110
     * Identify Files That Existed In Last Audit, And Modified Before This Audit.
     */
    private function getModifiedfilessincelastaudit()
    {
        $limitstart = (int) $this->_dataObj->ls;
        $sort       = $this->_dataObj->s;

        if (!$sort) {
            $sort = 'filewithpath';
        }

        if (!in_array($sort, array('filewithpath', 'filemtime'))) {
            die('Invalid Sort');
        }

        if ('filemtime' === $sort) {
            $sort = 'filemtime DESC';
        }

        $limit = (int) $this->_dataObj->limit;

        // Set the query
        $this->_db->setQuery('SELECT new.id, new.iscorefile, new.filewithpath, new.filemtime, new.fileperms, new.`size`, new.iscorefile from bf_files  as new
                              LEFT JOIN bf_files_last as old ON old.filewithpath = new.filewithpath
                              WHERE old.currenthash != new.currenthash
                              ORDER BY '.$sort.'
                              LIMIT '.$limitstart.', '.$limit);

        // Get an object list of files
        $files = $this->_db->loadObjectList();

        // see how many files there are in total without a limit
        $sql = 'select count(*) from `bf_files` as new
                  LEFT JOIN bf_files_last as old ON old.filewithpath = new.filewithpath
                  WHERE old.currenthash != new.currenthash';

        $this->_db->setQuery($sql);
        $count = $this->_db->loadResult();

        // Only show files that still exist on the hard drive
        $existingFiles = array();
        foreach ($files as $k => $file) {
            if (file_exists(JPATH_BASE.$file->filewithpath)) {
                $existingFiles[] = $file;
            } else {
                $this->_db->setQuery(sprintf('DELETE FROM bf_files WHERE filewithpath = "%s"',
                    $file->filewithpath));
                $this->_db->query();

                --$count;
            }
        }

        // return an encrypted reply
        bfEncrypt::reply('success', array(
            'files' => $existingFiles,
            'total' => $count,
        ));
    }
}

// init this class
$securityController = new bfTools($dataObj);

// Run the tool method
$securityController->run();
PK��#]�fl��.system/bfnetwork/bfnetwork/Math/BigInteger.phpnu�[���<?php
/**
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license GNU General Public License version 3 or later
 *
 * @see https://myJoomla.com/
 *
 * @author Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
/**
 * Pure-PHP arbitrary precision integer arithmetic library.
 *
 * Supports base-2, base-10, base-16, and base-256 numbers.  Uses the GMP or BCMath extensions, if available,
 * and an internal implementation, otherwise.
 *
 * PHP versions 4 and 5
 *
 * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
 * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
 *
 * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
 * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction.  Because the largest possible
 * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
 * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
 * used.  As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
 * which only supports integers.  Although this fact will slow this library down, the fact that such a high
 * base is being used should more than compensate.
 *
 * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format.  ie.
 * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
 *
 * Useful resources are as follows:
 *
 *  - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
 *  - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
 *  - Java's BigInteger classes.  See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
 *
 * Here's an example of how to use this library:
 * <code>
 * <?php
 *    include 'Math/BigInteger.php';
 *
 *    $a = new Math_BigInteger(2);
 *    $b = new Math_BigInteger(3);
 *
 *    $c = $a->add($b);
 *
 *    echo $c->toString(); // outputs 5
 * ?>
 * </code>
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category  Math
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2006 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 * @see      http://pear.php.net/package/Math_BigInteger
 */

/**#@+
 * Reduction constants
 *
 * @access private
 * @see Math_BigInteger::_reduce()
 */
/**
 * @see Math_BigInteger::_montgomery()
 * @see Math_BigInteger::_prepMontgomery()
 */
define('MATH_BIGINTEGER_MONTGOMERY', 0);
/*
 * @see Math_BigInteger::_barrett()
 */
define('MATH_BIGINTEGER_BARRETT', 1);
/*
 * @see Math_BigInteger::_mod2()
 */
define('MATH_BIGINTEGER_POWEROF2', 2);
/*
 * @see Math_BigInteger::_remainder()
 */
define('MATH_BIGINTEGER_CLASSIC', 3);
/*
 * @see Math_BigInteger::__clone()
 */
define('MATH_BIGINTEGER_NONE', 4);
/**#@-*/

/**#@+
 * Array constants
 *
 * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
 * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
 *
 * @access private
 */
/*
 * $result[MATH_BIGINTEGER_VALUE] contains the value.
 */
define('MATH_BIGINTEGER_VALUE', 0);
/*
 * $result[MATH_BIGINTEGER_SIGN] contains the sign.
 */
define('MATH_BIGINTEGER_SIGN', 1);
/**#@-*/

/**#@+
 * @access private
 * @see Math_BigInteger::_montgomery()
 * @see Math_BigInteger::_barrett()
 */
/*
 * Cache constants
 *
 * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
 */
define('MATH_BIGINTEGER_VARIABLE', 0);
/*
 * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
 */
define('MATH_BIGINTEGER_DATA', 1);
/**#@-*/

/**#@+
 * Mode constants.
 *
 * @access private
 * @see Math_BigInteger::Math_BigInteger()
 */
/*
 * To use the pure-PHP implementation
 */
define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
/*
 * To use the BCMath library
 *
 * (if enabled; otherwise, the internal implementation will be used)
 */
define('MATH_BIGINTEGER_MODE_BCMATH', 2);
/*
 * To use the GMP library
 *
 * (if present; otherwise, either the BCMath or the internal implementation will be used)
 */
define('MATH_BIGINTEGER_MODE_GMP', 3);
/**#@-*/

/*
 * Karatsuba Cutoff
 *
 * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
 *
 * @access private
 */
define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);

/**
 * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
 * numbers.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Math_BigInteger
{
    /**
     * Holds the BigInteger's value.
     *
     * @var array
     */
    public $value;

    /**
     * Holds the BigInteger's magnitude.
     *
     * @var bool
     */
    public $is_negative = false;

    /**
     * Random number generator function.
     *
     * @see setRandomGenerator()
     */
    public $generator = 'mt_rand';

    /**
     * Precision.
     *
     * @see setPrecision()
     */
    public $precision = -1;

    /**
     * Precision Bitmask.
     *
     * @see setPrecision()
     */
    public $bitmask = false;

    /**
     * Mode independent value used for serialization.
     *
     * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
     * a variable that'll be serializable regardless of whether or not extensions are being used.  Unlike $this->value,
     * however, $this->hex is only calculated when $this->__sleep() is called.
     *
     * @see __sleep()
     * @see __wakeup()
     *
     * @var string
     */
    public $hex;

    /**
     * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
     *
     * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
     * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('0x32', 16); // 50 in base-16
     *
     *    echo $a->toString(); // outputs 50
     * ?>
     * </code>
     *
     * @param optional         $x    base-10 number or base-$base number if $base set
     * @param optional integer $base
     *
     * @return Math_BigInteger
     */
    public function __construct($x = 0, $base = 10)
    {
        if (!defined('MATH_BIGINTEGER_MODE')) {
            switch (true) {
                case extension_loaded('gmp'):
                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
                    break;
                case extension_loaded('bcmath'):
                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
                    break;
                default:
                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
            }
        }

        if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
            // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
            ob_start();
            @phpinfo();
            $content = ob_get_contents();
            ob_end_clean();

            preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);

            $versions = array();
            if (!empty($matches[1])) {
                for ($i = 0; $i < count($matches[1]); ++$i) {
                    $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));

                    // Remove letter part in OpenSSL version
                    if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
                        $versions[$matches[1][$i]] = $fullVersion;
                    } else {
                        $versions[$matches[1][$i]] = $m[0];
                    }
                }
            }

            // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
            switch (true) {
                case !isset($versions['Header']):
                case !isset($versions['Library']):
                case $versions['Header'] == $versions['Library']:
                    define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
                    break;
                default:
                    define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
            }
        }

        if (!defined('PHP_INT_SIZE')) {
            define('PHP_INT_SIZE', 4);
        }

        if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
            switch (PHP_INT_SIZE) {
                case 8: // use 64-bit integers if int size is 8 bytes
                    define('MATH_BIGINTEGER_BASE', 31);
                    define('MATH_BIGINTEGER_BASE_FULL', 0x80000000);
                    define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF);
                    define('MATH_BIGINTEGER_MSB', 0x40000000);
                    // 10**9 is the closest we can get to 2**31 without passing it
                    define('MATH_BIGINTEGER_MAX10', 1000000000);
                    define('MATH_BIGINTEGER_MAX10_LEN', 9);
                    // the largest digit that may be used in addition / subtraction
                    define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
                    break;
                //case 4: // use 64-bit floats if int size is 4 bytes
                default:
                    define('MATH_BIGINTEGER_BASE', 26);
                    define('MATH_BIGINTEGER_BASE_FULL', 0x4000000);
                    define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF);
                    define('MATH_BIGINTEGER_MSB', 0x2000000);
                    // 10**7 is the closest to 2**26 without passing it
                    define('MATH_BIGINTEGER_MAX10', 10000000);
                    define('MATH_BIGINTEGER_MAX10_LEN', 7);
                    // the largest digit that may be used in addition / subtraction
                    // we do pow(2, 52) instead of using 4503599627370496 directly because some
                    // PHP installations will truncate 4503599627370496.
                    define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
            }
        }

        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                switch (true) {
                    case is_resource($x) && 'GMP integer' == get_resource_type($x):
                        // PHP 5.6 switched GMP from using resources to objects
                    case is_object($x) && 'GMP' == get_class($x):
                        $this->value = $x;

                        return;
                }
                $this->value = gmp_init(0);
                break;
            case MATH_BIGINTEGER_MODE_BCMATH:
                $this->value = '0';
                break;
            default:
                $this->value = array();
        }

        // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
        // '0' is the only value like this per http://php.net/empty
        if (empty($x) && (256 != abs($base) || '0' !== $x)) {
            return;
        }

        switch ($base) {
            case -256:
                if (ord($x[0]) & 0x80) {
                    $x                 = ~$x;
                    $this->is_negative = true;
                }
                // no break
            case  256:
                switch (MATH_BIGINTEGER_MODE) {
                    case MATH_BIGINTEGER_MODE_GMP:
                        $sign        = $this->is_negative ? '-' : '';
                        $this->value = gmp_init($sign.'0x'.bin2hex($x));
                        break;
                    case MATH_BIGINTEGER_MODE_BCMATH:
                        // round $len to the nearest 4 (thanks, DavidMJ!)
                        $len = (strlen($x) + 3) & 0xFFFFFFFC;

                        $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);

                        for ($i = 0; $i < $len; $i += 4) {
                            $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
                            $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
                        }

                        if ($this->is_negative) {
                            $this->value = '-'.$this->value;
                        }

                        break;
                    // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
                    default:
                        while (strlen($x)) {
                            $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
                        }
                }

                if ($this->is_negative) {
                    if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
                        $this->is_negative = false;
                    }
                    $temp        = $this->add(new Math_BigInteger('-1'));
                    $this->value = $temp->value;
                }
                break;
            case  16:
            case -16:
                if ($base > 0 && '-' == $x[0]) {
                    $this->is_negative = true;
                    $x                 = substr($x, 1);
                }

                $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);

                $is_negative = false;
                if ($base < 0 && hexdec($x[0]) >= 8) {
                    $this->is_negative = $is_negative = true;
                    $x                 = bin2hex(~pack('H*', $x));
                }

                switch (MATH_BIGINTEGER_MODE) {
                    case MATH_BIGINTEGER_MODE_GMP:
                        $temp              = $this->is_negative ? '-0x'.$x : '0x'.$x;
                        $this->value       = gmp_init($temp);
                        $this->is_negative = false;
                        break;
                    case MATH_BIGINTEGER_MODE_BCMATH:
                        $x                 = (strlen($x) & 1) ? '0'.$x : $x;
                        $temp              = new Math_BigInteger(pack('H*', $x), 256);
                        $this->value       = $this->is_negative ? '-'.$temp->value : $temp->value;
                        $this->is_negative = false;
                        break;
                    default:
                        $x           = (strlen($x) & 1) ? '0'.$x : $x;
                        $temp        = new Math_BigInteger(pack('H*', $x), 256);
                        $this->value = $temp->value;
                }

                if ($is_negative) {
                    $temp        = $this->add(new Math_BigInteger('-1'));
                    $this->value = $temp->value;
                }
                break;
            case  10:
            case -10:
                // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
                // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
                // [^-0-9].*: find any non-numeric characters and then any characters that follow that
                $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);

                switch (MATH_BIGINTEGER_MODE) {
                    case MATH_BIGINTEGER_MODE_GMP:
                        $this->value = gmp_init($x);
                        break;
                    case MATH_BIGINTEGER_MODE_BCMATH:
                        // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
                        // results then doing it on '-1' does (modInverse does $x[0])
                        $this->value = '-' === $x ? '0' : (string) $x;
                        break;
                    default:
                        $temp = new Math_BigInteger();

                        $multiplier        = new Math_BigInteger();
                        $multiplier->value = array(MATH_BIGINTEGER_MAX10);

                        if ('-' == $x[0]) {
                            $this->is_negative = true;
                            $x                 = substr($x, 1);
                        }

                        $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
                        while (strlen($x)) {
                            $temp = $temp->multiply($multiplier);
                            $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
                            $x    = substr($x, MATH_BIGINTEGER_MAX10_LEN);
                        }

                        $this->value = $temp->value;
                }
                break;
            case  2: // base-2 support originally implemented by Lluis Pamies - thanks!
            case -2:
                if ($base > 0 && '-' == $x[0]) {
                    $this->is_negative = true;
                    $x                 = substr($x, 1);
                }

                $x = preg_replace('#^([01]*).*#', '$1', $x);
                $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);

                $str = '0x';
                while (strlen($x)) {
                    $part = substr($x, 0, 4);
                    $str .= dechex(bindec($part));
                    $x = substr($x, 4);
                }

                if ($this->is_negative) {
                    $str = '-'.$str;
                }

                $temp              = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
                $this->value       = $temp->value;
                $this->is_negative = $temp->is_negative;

                break;
            default:
                // base not supported, so we'll let $this == 0
        }
    }

    /**
     * Converts bytes to 32-bit integers.
     *
     * @param string $x
     *
     * @return int
     */
    public function _bytes2int($x)
    {
        $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));

        return $temp['int'];
    }

    /**
     * Logical Right Shift.
     *
     * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
     *
     * @param $x String
     * @param $shift Integer
     *
     * @return string
     */
    public function _base256_rshift(&$x, $shift)
    {
        if (0 == $shift) {
            $x = ltrim($x, chr(0));

            return '';
        }

        $num_bytes = $shift >> 3; // eg. floor($shift/8)
        $shift &= 7; // eg. $shift % 8

        $remainder = '';
        if ($num_bytes) {
            $start     = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
            $remainder = substr($x, $start);
            $x         = substr($x, 0, -$num_bytes);
        }

        $carry       = 0;
        $carry_shift = 8 - $shift;
        for ($i = 0; $i < strlen($x); ++$i) {
            $temp  = (ord($x[$i]) >> $shift) | $carry;
            $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
            $x[$i] = chr($temp);
        }
        $x = ltrim($x, chr(0));

        $remainder = chr($carry >> $carry_shift).$remainder;

        return ltrim($remainder, chr(0));
    }

    /**
     * Adds two BigIntegers.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('10');
     *    $b = new Math_BigInteger('20');
     *
     *    $c = $a->add($b);
     *
     *    echo $c->toString(); // outputs 30
     * ?>
     * </code>
     *
     * @param Math_BigInteger $y
     *
     * @return Math_BigInteger
     *
     * @internal Performs base-2**52 addition
     */
    public function add($y)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp        = new Math_BigInteger();
                $temp->value = gmp_add($this->value, $y->value);

                return $this->_normalize($temp);
            case MATH_BIGINTEGER_MODE_BCMATH:
                $temp        = new Math_BigInteger();
                $temp->value = bcadd($this->value, $y->value, 0);

                return $this->_normalize($temp);
        }

        $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);

        $result              = new Math_BigInteger();
        $result->value       = $temp[MATH_BIGINTEGER_VALUE];
        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];

        return $this->_normalize($result);
    }

    /**
     * Normalize.
     *
     * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
     *
     * @param Math_BigInteger
     *
     * @return Math_BigInteger
     *
     * @see _trim()
     */
    public function _normalize($result)
    {
        $result->precision = $this->precision;
        $result->bitmask   = $this->bitmask;

        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                if (!empty($result->bitmask->value)) {
                    $result->value = gmp_and($result->value, $result->bitmask->value);
                }

                return $result;
            case MATH_BIGINTEGER_MODE_BCMATH:
                if (!empty($result->bitmask->value)) {
                    $result->value = bcmod($result->value, $result->bitmask->value);
                }

                return $result;
        }

        $value = &$result->value;

        if (!count($value)) {
            return $result;
        }

        $value = $this->_trim($value);

        if (!empty($result->bitmask->value)) {
            $length = min(count($value), count($this->bitmask->value));
            $value  = array_slice($value, 0, $length);

            for ($i = 0; $i < $length; ++$i) {
                $value[$i] = $value[$i] & $this->bitmask->value[$i];
            }
        }

        return $result;
    }

    /**
     * Trim.
     *
     * Removes leading zeros
     *
     * @param array $value
     *
     * @return Math_BigInteger
     */
    public function _trim($value)
    {
        for ($i = count($value) - 1; $i >= 0; --$i) {
            if ($value[$i]) {
                break;
            }
            unset($value[$i]);
        }

        return $value;
    }

    /**
     * Performs addition.
     *
     * @param array $x_value
     * @param bool  $x_negative
     * @param array $y_value
     * @param bool  $y_negative
     *
     * @return array
     */
    public function _add($x_value, $x_negative, $y_value, $y_negative)
    {
        $x_size = count($x_value);
        $y_size = count($y_value);

        if (0 == $x_size) {
            return array(
                MATH_BIGINTEGER_VALUE => $y_value,
                MATH_BIGINTEGER_SIGN  => $y_negative,
            );
        } elseif (0 == $y_size) {
            return array(
                MATH_BIGINTEGER_VALUE => $x_value,
                MATH_BIGINTEGER_SIGN  => $x_negative,
            );
        }

        // subtract, if appropriate
        if ($x_negative != $y_negative) {
            if ($x_value == $y_value) {
                return array(
                    MATH_BIGINTEGER_VALUE => array(),
                    MATH_BIGINTEGER_SIGN  => false,
                );
            }

            $temp                       = $this->_subtract($x_value, false, $y_value, false);
            $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
                $x_negative : $y_negative;

            return $temp;
        }

        if ($x_size < $y_size) {
            $size  = $x_size;
            $value = $y_value;
        } else {
            $size  = $y_size;
            $value = $x_value;
        }

        $value[count($value)] = 0; // just in case the carry adds an extra digit

        $carry = 0;
        for ($i = 0, $j = 1; $j < $size; $i += 2, $j += 2) {
            $sum   = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
            $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
            $sum   = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;

            $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);

            $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
            $value[$j] = $temp;
        }

        if ($j == $size) { // ie. if $y_size is odd
            $sum       = $x_value[$i] + $y_value[$i] + $carry;
            $carry     = $sum >= MATH_BIGINTEGER_BASE_FULL;
            $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
            ++$i; // ie. let $i = $j since we've just done $value[$i]
        }

        if ($carry) {
            for (; MATH_BIGINTEGER_MAX_DIGIT == $value[$i]; ++$i) {
                $value[$i] = 0;
            }
            ++$value[$i];
        }

        return array(
            MATH_BIGINTEGER_VALUE => $this->_trim($value),
            MATH_BIGINTEGER_SIGN  => $x_negative,
        );
    }

    /**
     * Performs subtraction.
     *
     * @param array $x_value
     * @param bool  $x_negative
     * @param array $y_value
     * @param bool  $y_negative
     *
     * @return array
     */
    public function _subtract($x_value, $x_negative, $y_value, $y_negative)
    {
        $x_size = count($x_value);
        $y_size = count($y_value);

        if (0 == $x_size) {
            return array(
                MATH_BIGINTEGER_VALUE => $y_value,
                MATH_BIGINTEGER_SIGN  => !$y_negative,
            );
        } elseif (0 == $y_size) {
            return array(
                MATH_BIGINTEGER_VALUE => $x_value,
                MATH_BIGINTEGER_SIGN  => $x_negative,
            );
        }

        // add, if appropriate (ie. -$x - +$y or +$x - -$y)
        if ($x_negative != $y_negative) {
            $temp                       = $this->_add($x_value, false, $y_value, false);
            $temp[MATH_BIGINTEGER_SIGN] = $x_negative;

            return $temp;
        }

        $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);

        if (!$diff) {
            return array(
                MATH_BIGINTEGER_VALUE => array(),
                MATH_BIGINTEGER_SIGN  => false,
            );
        }

        // switch $x and $y around, if appropriate.
        if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
            $temp    = $x_value;
            $x_value = $y_value;
            $y_value = $temp;

            $x_negative = !$x_negative;

            $x_size = count($x_value);
            $y_size = count($y_value);
        }

        // at this point, $x_value should be at least as big as - if not bigger than - $y_value

        $carry = 0;
        for ($i = 0, $j = 1; $j < $y_size; $i += 2, $j += 2) {
            $sum   = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
            $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
            $sum   = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;

            $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);

            $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
            $x_value[$j] = $temp;
        }

        if ($j == $y_size) { // ie. if $y_size is odd
            $sum         = $x_value[$i] - $y_value[$i] - $carry;
            $carry       = $sum < 0;
            $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
            ++$i;
        }

        if ($carry) {
            for (; !$x_value[$i]; ++$i) {
                $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
            }
            --$x_value[$i];
        }

        return array(
            MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
            MATH_BIGINTEGER_SIGN  => $x_negative,
        );
    }

    /**
     * Compares two numbers.
     *
     * @param array $x_value
     * @param bool  $x_negative
     * @param array $y_value
     * @param bool  $y_negative
     *
     * @return int
     *
     * @see compare()
     */
    public function _compare($x_value, $x_negative, $y_value, $y_negative)
    {
        if ($x_negative != $y_negative) {
            return (!$x_negative && $y_negative) ? 1 : -1;
        }

        $result = $x_negative ? -1 : 1;

        if (count($x_value) != count($y_value)) {
            return (count($x_value) > count($y_value)) ? $result : -$result;
        }
        $size = max(count($x_value), count($y_value));

        $x_value = array_pad($x_value, $size, 0);
        $y_value = array_pad($y_value, $size, 0);

        for ($i = count($x_value) - 1; $i >= 0; --$i) {
            if ($x_value[$i] != $y_value[$i]) {
                return ($x_value[$i] > $y_value[$i]) ? $result : -$result;
            }
        }

        return 0;
    }

    /**
     * Multiplies two BigIntegers.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('10');
     *    $b = new Math_BigInteger('20');
     *
     *    $c = $a->multiply($b);
     *
     *    echo $c->toString(); // outputs 200
     * ?>
     * </code>
     *
     * @param Math_BigInteger $x
     *
     * @return Math_BigInteger
     */
    public function multiply($x)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp        = new Math_BigInteger();
                $temp->value = gmp_mul($this->value, $x->value);

                return $this->_normalize($temp);
            case MATH_BIGINTEGER_MODE_BCMATH:
                $temp        = new Math_BigInteger();
                $temp->value = bcmul($this->value, $x->value, 0);

                return $this->_normalize($temp);
        }

        $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);

        $product              = new Math_BigInteger();
        $product->value       = $temp[MATH_BIGINTEGER_VALUE];
        $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];

        return $this->_normalize($product);
    }

    /**
     * Performs multiplication.
     *
     * @param array $x_value
     * @param bool  $x_negative
     * @param array $y_value
     * @param bool  $y_negative
     *
     * @return array
     */
    public function _multiply($x_value, $x_negative, $y_value, $y_negative)
    {
        //if ( $x_value == $y_value ) {
        //    return array(
        //        MATH_BIGINTEGER_VALUE => $this->_square($x_value),
        //        MATH_BIGINTEGER_SIGN => $x_sign != $y_value
        //    );
        //}

        $x_length = count($x_value);
        $y_length = count($y_value);

        if (!$x_length || !$y_length) { // a 0 is being multiplied
            return array(
                MATH_BIGINTEGER_VALUE => array(),
                MATH_BIGINTEGER_SIGN  => false,
            );
        }

        return array(
            MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
                $this->_trim($this->_regularMultiply($x_value, $y_value)) :
                $this->_trim($this->_karatsuba($x_value, $y_value)),
            MATH_BIGINTEGER_SIGN => $x_negative != $y_negative,
        );
    }

    /**
     * Performs long multiplication on two BigIntegers.
     *
     * Modeled after 'multiply' in MutableBigInteger.java.
     *
     * @param array $x_value
     * @param array $y_value
     *
     * @return array
     */
    public function _regularMultiply($x_value, $y_value)
    {
        $x_length = count($x_value);
        $y_length = count($y_value);

        if (!$x_length || !$y_length) { // a 0 is being multiplied
            return array();
        }

        if ($x_length < $y_length) {
            $temp    = $x_value;
            $x_value = $y_value;
            $y_value = $temp;

            $x_length = count($x_value);
            $y_length = count($y_value);
        }

        $product_value = $this->_array_repeat(0, $x_length + $y_length);

        // the following for loop could be removed if the for loop following it
        // (the one with nested for loops) initially set $i to 0, but
        // doing so would also make the result in one set of unnecessary adds,
        // since on the outermost loops first pass, $product->value[$k] is going
        // to always be 0

        $carry = 0;

        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
            $temp              = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
            $carry             = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
        }

        $product_value[$j] = $carry;

        // the above for loop is what the previous comment was talking about.  the
        // following for loop is the "one with nested for loops"
        for ($i = 1; $i < $y_length; ++$i) {
            $carry = 0;

            for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
                $temp              = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
                $carry             = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
                $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
            }

            $product_value[$k] = $carry;
        }

        return $product_value;
    }

    /**
     * Array Repeat.
     *
     * @param $input Array
     * @param $multiplier mixed
     *
     * @return array
     */
    public function _array_repeat($input, $multiplier)
    {
        return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
    }

    /**
     * Performs Karatsuba multiplication on two BigIntegers.
     *
     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
     *
     * @param array $x_value
     * @param array $y_value
     *
     * @return array
     */
    public function _karatsuba($x_value, $y_value)
    {
        $m = min(count($x_value) >> 1, count($y_value) >> 1);

        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
            return $this->_regularMultiply($x_value, $y_value);
        }

        $x1 = array_slice($x_value, $m);
        $x0 = array_slice($x_value, 0, $m);
        $y1 = array_slice($y_value, $m);
        $y0 = array_slice($y_value, 0, $m);

        $z2 = $this->_karatsuba($x1, $y1);
        $z0 = $this->_karatsuba($x0, $y0);

        $z1   = $this->_add($x1, false, $x0, false);
        $temp = $this->_add($y1, false, $y0, false);
        $z1   = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
        $temp = $this->_add($z2, false, $z0, false);
        $z1   = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);

        $z2                        = array_merge(array_fill(0, 2 * $m, 0), $z2);
        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);

        $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
        $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);

        return $xy[MATH_BIGINTEGER_VALUE];
    }

    /**
     * Converts 32-bit integers to bytes.
     *
     * @param int $x
     *
     * @return string
     */
    public function _int2bytes($x)
    {
        return ltrim(pack('N', $x), chr(0));
    }

    /**
     * Converts a BigInteger to a bit string (eg. base-2).
     *
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
     * saved as two's compliment.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('65');
     *
     *    echo $a->toBits(); // outputs '1000001'
     * ?>
     * </code>
     *
     * @param bool $twos_compliment
     *
     * @return string
     *
     * @internal Converts a base-2**26 number to base-2**2
     */
    public function toBits($twos_compliment = false)
    {
        $hex  = $this->toHex($twos_compliment);
        $bits = '';
        for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i -= 8) {
            $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT).$bits;
        }
        if ($start) { // hexdec('') == 0
            $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT).$bits;
        }
        $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');

        if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
            return '0'.$result;
        }

        return $result;
    }

    /**
     * Converts a BigInteger to a hex string (eg. base-16)).
     *
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
     * saved as two's compliment.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('65');
     *
     *    echo $a->toHex(); // outputs '41'
     * ?>
     * </code>
     *
     * @param bool $twos_compliment
     *
     * @return string
     *
     * @internal Converts a base-2**26 number to base-2**8
     */
    public function toHex($twos_compliment = false)
    {
        return bin2hex($this->toBytes($twos_compliment));
    }

    /**
     * Converts a BigInteger to a byte string (eg. base-256).
     *
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
     * saved as two's compliment.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('65');
     *
     *    echo $a->toBytes(); // outputs chr(65)
     * ?>
     * </code>
     *
     * @param bool $twos_compliment
     *
     * @return string
     *
     * @internal Converts a base-2**26 number to base-2**8
     */
    public function toBytes($twos_compliment = false)
    {
        if ($twos_compliment) {
            $comparison = $this->compare(new Math_BigInteger());
            if (0 == $comparison) {
                return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
            }

            $temp  = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
            $bytes = $temp->toBytes();

            if (empty($bytes)) { // eg. if the number we're trying to convert is -1
                $bytes = chr(0);
            }

            if (ord($bytes[0]) & 0x80) {
                $bytes = chr(0).$bytes;
            }

            return $comparison < 0 ? ~$bytes : $bytes;
        }

        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                if (0 == gmp_cmp($this->value, gmp_init(0))) {
                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
                }

                $temp = gmp_strval(gmp_abs($this->value), 16);
                $temp = (strlen($temp) & 1) ? '0'.$temp : $temp;
                $temp = pack('H*', $temp);

                return $this->precision > 0 ?
                    substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
                    ltrim($temp, chr(0));
            case MATH_BIGINTEGER_MODE_BCMATH:
                if ('0' === $this->value) {
                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
                }

                $value   = '';
                $current = $this->value;

                if ('-' == $current[0]) {
                    $current = substr($current, 1);
                }

                while (bccomp($current, '0', 0) > 0) {
                    $temp    = bcmod($current, '16777216');
                    $value   = chr($temp >> 16).chr($temp >> 8).chr($temp).$value;
                    $current = bcdiv($current, '16777216', 0);
                }

                return $this->precision > 0 ?
                    substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
                    ltrim($value, chr(0));
        }

        if (!count($this->value)) {
            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
        }
        $result = $this->_int2bytes($this->value[count($this->value) - 1]);

        $temp = $this->copy();

        for ($i = count($temp->value) - 2; $i >= 0; --$i) {
            $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
            $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
        }

        return $this->precision > 0 ?
            str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
            $result;
    }

    /**
     * Compares two numbers.
     *
     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is
     * demonstrated thusly:
     *
     * $x  > $y: $x->compare($y)  > 0
     * $x  < $y: $x->compare($y)  < 0
     * $x == $y: $x->compare($y) == 0
     *
     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
     *
     * @param Math_BigInteger $y
     *
     * @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal
     *
     * @see equals()
     *
     * @internal could return $this->subtract($x), but that's not as fast as what we do do
     */
    public function compare($y)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                return gmp_cmp($this->value, $y->value);
            case MATH_BIGINTEGER_MODE_BCMATH:
                return bccomp($this->value, $y->value, 0);
        }

        return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
    }

    /**
     * Copy an object.
     *
     * PHP5 passes objects by reference while PHP4 passes by value.  As such, we need a function to guarantee
     * that all objects are passed by value, when appropriate.  More information can be found here:
     *
     * {@link http://php.net/language.oop5.basic#51624}
     *
     * @see __clone()
     *
     * @return Math_BigInteger
     */
    public function copy()
    {
        $temp              = new Math_BigInteger();
        $temp->value       = $this->value;
        $temp->is_negative = $this->is_negative;
        $temp->generator   = $this->generator;
        $temp->precision   = $this->precision;
        $temp->bitmask     = $this->bitmask;

        return $temp;
    }

    /**
     * Logical Left Shift.
     *
     * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
     *
     * @param $x String
     * @param $shift Integer
     *
     * @return string
     */
    public function _base256_lshift(&$x, $shift)
    {
        if (0 == $shift) {
            return;
        }

        $num_bytes = $shift >> 3; // eg. floor($shift/8)
        $shift &= 7; // eg. $shift % 8

        $carry = 0;
        for ($i = strlen($x) - 1; $i >= 0; --$i) {
            $temp  = ord($x[$i]) << $shift | $carry;
            $x[$i] = chr($temp);
            $carry = $temp >> 8;
        }
        $carry = (0 != $carry) ? chr($carry) : '';
        $x     = $carry.$x.str_repeat(chr(0), $num_bytes);
    }

    /**
     *  __toString() magic method.
     *
     * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
     * toString().
     *
     * @internal Implemented per a suggestion by Techie-Michael - thanks!
     */
    public function __toString()
    {
        return $this->toString();
    }

    /**
     * Converts a BigInteger to a base-10 number.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('50');
     *
     *    echo $a->toString(); // outputs 50
     * ?>
     * </code>
     *
     * @return string
     *
     * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
     */
    public function toString()
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                return gmp_strval($this->value);
            case MATH_BIGINTEGER_MODE_BCMATH:
                if ('0' === $this->value) {
                    return '0';
                }

                return ltrim($this->value, '0');
        }

        if (!count($this->value)) {
            return '0';
        }

        $temp              = $this->copy();
        $temp->is_negative = false;

        $divisor        = new Math_BigInteger();
        $divisor->value = array(MATH_BIGINTEGER_MAX10);
        $result         = '';
        while (count($temp->value)) {
            list($temp, $mod) = $temp->divide($divisor);
            $result           = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT).$result;
        }
        $result = ltrim($result, '0');
        if (empty($result)) {
            $result = '0';
        }

        if ($this->is_negative) {
            $result = '-'.$result;
        }

        return $result;
    }

    /**
     * Divides two BigIntegers.
     *
     * Returns an array whose first element contains the quotient and whose second element contains the
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
     * and the divisor (basically, the "common residue" is the first positive modulo).
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('10');
     *    $b = new Math_BigInteger('20');
     *
     *    list($quotient, $remainder) = $a->divide($b);
     *
     *    echo $quotient->toString(); // outputs 0
     *    echo "\r\n";
     *    echo $remainder->toString(); // outputs 10
     * ?>
     * </code>
     *
     * @param Math_BigInteger $y
     *
     * @return array
     *
     * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
     */
    public function divide($y)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $quotient  = new Math_BigInteger();
                $remainder = new Math_BigInteger();

                list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);

                if (gmp_sign($remainder->value) < 0) {
                    $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
                }

                return array($this->_normalize($quotient), $this->_normalize($remainder));
            case MATH_BIGINTEGER_MODE_BCMATH:
                $quotient  = new Math_BigInteger();
                $remainder = new Math_BigInteger();

                $quotient->value  = bcdiv($this->value, $y->value, 0);
                $remainder->value = bcmod($this->value, $y->value);

                if ('-' == $remainder->value[0]) {
                    $remainder->value = bcadd($remainder->value, '-' == $y->value[0] ? substr($y->value, 1) : $y->value, 0);
                }

                return array($this->_normalize($quotient), $this->_normalize($remainder));
        }

        if (1 == count($y->value)) {
            list($q, $r)           = $this->_divide_digit($this->value, $y->value[0]);
            $quotient              = new Math_BigInteger();
            $remainder             = new Math_BigInteger();
            $quotient->value       = $q;
            $remainder->value      = array($r);
            $quotient->is_negative = $this->is_negative != $y->is_negative;

            return array($this->_normalize($quotient), $this->_normalize($remainder));
        }

        static $zero;
        if (!isset($zero)) {
            $zero = new Math_BigInteger();
        }

        $x = $this->copy();
        $y = $y->copy();

        $x_sign = $x->is_negative;
        $y_sign = $y->is_negative;

        $x->is_negative = $y->is_negative = false;

        $diff = $x->compare($y);

        if (!$diff) {
            $temp              = new Math_BigInteger();
            $temp->value       = array(1);
            $temp->is_negative = $x_sign != $y_sign;

            return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
        }

        if ($diff < 0) {
            // if $x is negative, "add" $y.
            if ($x_sign) {
                $x = $y->subtract($x);
            }

            return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
        }

        // normalize $x and $y as described in HAC 14.23 / 14.24
        $msb = $y->value[count($y->value) - 1];
        for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
            $msb <<= 1;
        }
        $x->_lshift($shift);
        $y->_lshift($shift);
        $y_value = &$y->value;

        $x_max = count($x->value) - 1;
        $y_max = count($y->value) - 1;

        $quotient       = new Math_BigInteger();
        $quotient_value = &$quotient->value;
        $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);

        static $temp, $lhs, $rhs;
        if (!isset($temp)) {
            $temp = new Math_BigInteger();
            $lhs  = new Math_BigInteger();
            $rhs  = new Math_BigInteger();
        }
        $temp_value = &$temp->value;
        $rhs_value  = &$rhs->value;

        // $temp = $y << ($x_max - $y_max-1) in base 2**26
        $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);

        while ($x->compare($temp) >= 0) {
            // calculate the "common residue"
            ++$quotient_value[$x_max - $y_max];
            $x     = $x->subtract($temp);
            $x_max = count($x->value) - 1;
        }

        for ($i = $x_max; $i >= $y_max + 1; --$i) {
            $x_value  = &$x->value;
            $x_window = array(
                isset($x_value[$i]) ? $x_value[$i] : 0,
                isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
                isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0,
            );
            $y_window = array(
                $y_value[$y_max],
                ($y_max > 0) ? $y_value[$y_max - 1] : 0,
            );

            $q_index = $i - $y_max - 1;
            if ($x_window[0] == $y_window[0]) {
                $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
            } else {
                $quotient_value[$q_index] = $this->_safe_divide(
                    $x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1],
                    $y_window[0]
                );
            }

            $temp_value = array($y_window[1], $y_window[0]);

            $lhs->value = array($quotient_value[$q_index]);
            $lhs        = $lhs->multiply($temp);

            $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);

            while ($lhs->compare($rhs) > 0) {
                --$quotient_value[$q_index];

                $lhs->value = array($quotient_value[$q_index]);
                $lhs        = $lhs->multiply($temp);
            }

            $adjust     = $this->_array_repeat(0, $q_index);
            $temp_value = array($quotient_value[$q_index]);
            $temp       = $temp->multiply($y);
            $temp_value = &$temp->value;
            $temp_value = array_merge($adjust, $temp_value);

            $x = $x->subtract($temp);

            if ($x->compare($zero) < 0) {
                $temp_value = array_merge($adjust, $y_value);
                $x          = $x->add($temp);

                --$quotient_value[$q_index];
            }

            $x_max = count($x_value) - 1;
        }

        // unnormalize the remainder
        $x->_rshift($shift);

        $quotient->is_negative = $x_sign != $y_sign;

        // calculate the "common residue", if appropriate
        if ($x_sign) {
            $y->_rshift($shift);
            $x = $y->subtract($x);
        }

        return array($this->_normalize($quotient), $this->_normalize($x));
    }

    /**
     * Divides a BigInteger by a regular integer.
     *
     * abc / x = a00 / x + b0 / x + c / x
     *
     * @param array $dividend
     * @param array $divisor
     *
     * @return array
     */
    public function _divide_digit($dividend, $divisor)
    {
        $carry  = 0;
        $result = array();

        for ($i = count($dividend) - 1; $i >= 0; --$i) {
            $temp       = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
            $result[$i] = $this->_safe_divide($temp, $divisor);
            $carry      = (int) ($temp - $divisor * $result[$i]);
        }

        return array($result, $carry);
    }

    /**
     * Single digit division.
     *
     * Even if int64 is being used the division operator will return a float64 value
     * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
     * have the precision of int64 this is a problem so, when int64 is being used,
     * we'll guarantee that the dividend is divisible by first subtracting the remainder.
     *
     * @param int $x
     * @param int $y
     *
     * @return int
     */
    public function _safe_divide($x, $y)
    {
        if (MATH_BIGINTEGER_BASE === 26) {
            return (int) ($x / $y);
        }

        // MATH_BIGINTEGER_BASE === 31
        return ($x - ($x % $y)) / $y;
    }

    /**
     * Subtracts two BigIntegers.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('10');
     *    $b = new Math_BigInteger('20');
     *
     *    $c = $a->subtract($b);
     *
     *    echo $c->toString(); // outputs -10
     * ?>
     * </code>
     *
     * @param Math_BigInteger $y
     *
     * @return Math_BigInteger
     *
     * @internal Performs base-2**52 subtraction
     */
    public function subtract($y)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp        = new Math_BigInteger();
                $temp->value = gmp_sub($this->value, $y->value);

                return $this->_normalize($temp);
            case MATH_BIGINTEGER_MODE_BCMATH:
                $temp        = new Math_BigInteger();
                $temp->value = bcsub($this->value, $y->value, 0);

                return $this->_normalize($temp);
        }

        $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);

        $result              = new Math_BigInteger();
        $result->value       = $temp[MATH_BIGINTEGER_VALUE];
        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];

        return $this->_normalize($result);
    }

    /**
     * Logical Left Shift.
     *
     * Shifts BigInteger's by $shift bits.
     *
     * @param int $shift
     */
    public function _lshift($shift)
    {
        if (0 == $shift) {
            return;
        }

        $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
        $shift %= MATH_BIGINTEGER_BASE;
        $shift = 1 << $shift;

        $carry = 0;

        for ($i = 0; $i < count($this->value); ++$i) {
            $temp            = $this->value[$i] * $shift + $carry;
            $carry           = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
        }

        if ($carry) {
            $this->value[count($this->value)] = $carry;
        }

        while ($num_digits--) {
            array_unshift($this->value, 0);
        }
    }

    /**
     * Logical Right Shift.
     *
     * Shifts BigInteger's by $shift bits.
     *
     * @param int $shift
     */
    public function _rshift($shift)
    {
        if (0 == $shift) {
            return;
        }

        $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
        $shift %= MATH_BIGINTEGER_BASE;
        $carry_shift = MATH_BIGINTEGER_BASE - $shift;
        $carry_mask  = (1 << $shift) - 1;

        if ($num_digits) {
            $this->value = array_slice($this->value, $num_digits);
        }

        $carry = 0;

        for ($i = count($this->value) - 1; $i >= 0; --$i) {
            $temp            = $this->value[$i] >> $shift | $carry;
            $carry           = ($this->value[$i] & $carry_mask) << $carry_shift;
            $this->value[$i] = $temp;
        }

        $this->value = $this->_trim($this->value);
    }

    /**
     * __clone() magic method.
     *
     * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
     * directly in PHP5.  You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
     * only syntax of $y = clone $x.  As such, if you're trying to write an application that works on both PHP4 and PHP5,
     * call Math_BigInteger::copy(), instead.
     *
     * @see copy()
     *
     * @return Math_BigInteger
     */
    public function __clone()
    {
        return $this->copy();
    }

    /**
     *  __sleep() magic method.
     *
     * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
     *
     * @see __wakeup()
     */
    public function __sleep()
    {
        $this->hex = $this->toHex(true);
        $vars      = array('hex');
        if ('mt_rand' != $this->generator) {
            $vars[] = 'generator';
        }
        if ($this->precision > 0) {
            $vars[] = 'precision';
        }

        return $vars;
    }

    /**
     *  __wakeup() magic method.
     *
     * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
     *
     * @see __sleep()
     */
    public function __wakeup()
    {
        $temp              = new Math_BigInteger($this->hex, -16);
        $this->value       = $temp->value;
        $this->is_negative = $temp->is_negative;
        $this->setRandomGenerator($this->generator);
        if ($this->precision > 0) {
            // recalculate $this->bitmask
            $this->setPrecision($this->precision);
        }
    }

    /**
     * Set random number generator function.
     *
     * This function is deprecated.
     *
     * @param string $generator
     */
    public function setRandomGenerator($generator)
    {
    }

    /**
     * Set Precision.
     *
     * Some bitwise operations give different results depending on the precision being used.  Examples include left
     * shift, not, and rotates.
     *
     * @param int $bits
     */
    public function setPrecision($bits)
    {
        $this->precision = $bits;
        if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH) {
            $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1).str_repeat(chr(0xFF), $bits >> 3), 256);
        } else {
            $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
        }

        $temp        = $this->_normalize($this);
        $this->value = $temp->value;
    }

    /**
     * Performs modular exponentiation.
     *
     * Alias for Math_BigInteger::modPow()
     *
     * @param Math_BigInteger $e
     * @param Math_BigInteger $n
     *
     * @return Math_BigInteger
     */
    public function powMod($e, $n)
    {
        return $this->modPow($e, $n);
    }

    /**
     * Performs modular exponentiation.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger('10');
     *    $b = new Math_BigInteger('20');
     *    $c = new Math_BigInteger('30');
     *
     *    $c = $a->modPow($b, $c);
     *
     *    echo $c->toString(); // outputs 10
     * ?>
     * </code>
     *
     * @param Math_BigInteger $e
     * @param Math_BigInteger $n
     *
     * @return Math_BigInteger
     *
     * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
     *    and although the approach involving repeated squaring does vastly better, it, too, is impractical
     *    for our purposes.  The reason being that division - by far the most complicated and time-consuming
     *    of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
     *
     *    Modular reductions resolve this issue.  Although an individual modular reduction takes more time
     *    then an individual division, when performed in succession (with the same modulo), they're a lot faster.
     *
     *    The two most commonly used modular reductions are Barrett and Montgomery reduction.  Montgomery reduction,
     *    although faster, only works when the gcd of the modulo and of the base being used is 1.  In RSA, when the
     *    base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
     *    the product of two odd numbers is odd), but what about when RSA isn't used?
     *
     *    In contrast, Barrett reduction has no such constraint.  As such, some bigint implementations perform a
     *    Barrett reduction after every operation in the modpow function.  Others perform Barrett reductions when the
     *    modulo is even and Montgomery reductions when the modulo is odd.  BigInteger.java's modPow method, however,
     *    uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
     *    the other, a power of two - and recombine them, later.  This is the method that this modPow function uses.
     *    {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
     */
    public function modPow($e, $n)
    {
        $n = false !== $this->bitmask && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();

        if ($e->compare(new Math_BigInteger()) < 0) {
            $e = $e->abs();

            $temp = $this->modInverse($n);
            if (false === $temp) {
                return false;
            }

            return $this->_normalize($temp->modPow($e, $n));
        }

        if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP) {
            $temp        = new Math_BigInteger();
            $temp->value = gmp_powm($this->value, $e->value, $n->value);

            return $this->_normalize($temp);
        }

        if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
            list(, $temp) = $this->divide($n);

            return $temp->modPow($e, $n);
        }

        if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
            $components = array(
                'modulus'        => $n->toBytes(true),
                'publicExponent' => $e->toBytes(true),
            );

            $components = array(
                'modulus'        => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
                'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent']),
            );

            $RSAPublicKey = pack('Ca*a*a*',
                48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
                $components['modulus'], $components['publicExponent']
            );

            $rsaOID       = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
            $RSAPublicKey = chr(0).$RSAPublicKey;
            $RSAPublicKey = chr(3).$this->_encodeASN1Length(strlen($RSAPublicKey)).$RSAPublicKey;

            $encapsulated = pack('Ca*a*',
                48, $this->_encodeASN1Length(strlen($rsaOID.$RSAPublicKey)), $rsaOID.$RSAPublicKey
            );

            $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n".
                chunk_split(base64_encode($encapsulated)).
                '-----END PUBLIC KEY-----';

            $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);

            if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
                return new Math_BigInteger($result, 256);
            }
        }

        if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) {
            $temp        = new Math_BigInteger();
            $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);

            return $this->_normalize($temp);
        }

        if (empty($e->value)) {
            $temp        = new Math_BigInteger();
            $temp->value = array(1);

            return $this->_normalize($temp);
        }

        if ($e->value == array(1)) {
            list(, $temp) = $this->divide($n);

            return $this->_normalize($temp);
        }

        if ($e->value == array(2)) {
            $temp         = new Math_BigInteger();
            $temp->value  = $this->_square($this->value);
            list(, $temp) = $temp->divide($n);

            return $this->_normalize($temp);
        }

        return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));

        // the following code, although not callable, can be run independently of the above code
        // although the above code performed better in my benchmarks the following could might
        // perform better under different circumstances. in lieu of deleting it it's just been
        // made uncallable

        // is the modulo odd?
        if ($n->value[0] & 1) {
            return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
        }
        // if it's not, it's even

        // find the lowest set bit (eg. the max pow of 2 that divides $n)
        for ($i = 0; $i < count($n->value); ++$i) {
            if ($n->value[$i]) {
                $temp = decbin($n->value[$i]);
                $j    = strlen($temp) - strrpos($temp, '1') - 1;
                $j += 26 * $i;
                break;
            }
        }
        // at this point, 2^$j * $n/(2^$j) == $n

        $mod1 = $n->copy();
        $mod1->_rshift($j);
        $mod2        = new Math_BigInteger();
        $mod2->value = array(1);
        $mod2->_lshift($j);

        $part1 = ($mod1->value != array(1)) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
        $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);

        $y1 = $mod2->modInverse($mod1);
        $y2 = $mod1->modInverse($mod2);

        $result = $part1->multiply($mod2);
        $result = $result->multiply($y1);

        $temp = $part2->multiply($mod1);
        $temp = $temp->multiply($y2);

        $result         = $result->add($temp);
        list(, $result) = $result->divide($n);

        return $this->_normalize($result);
    }

    /**
     * Absolute value.
     *
     * @return Math_BigInteger
     */
    public function abs()
    {
        $temp = new Math_BigInteger();

        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp->value = gmp_abs($this->value);
                break;
            case MATH_BIGINTEGER_MODE_BCMATH:
                $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
                break;
            default:
                $temp->value = $this->value;
        }

        return $temp;
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger(30);
     *    $b = new Math_BigInteger(17);
     *
     *    $c = $a->modInverse($b);
     *    echo $c->toString(); // outputs 4
     *
     *    echo "\r\n";
     *
     *    $d = $a->multiply($c);
     *    list(, $d) = $d->divide($b);
     *    echo $d; // outputs 1 (as per the definition of modular inverse)
     * ?>
     * </code>
     *
     * @param Math_BigInteger $n
     *
     * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise
     *
     * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
     */
    public function modInverse($n)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp        = new Math_BigInteger();
                $temp->value = gmp_invert($this->value, $n->value);

                return (false === $temp->value) ? false : $this->_normalize($temp);
        }

        static $zero, $one;
        if (!isset($zero)) {
            $zero = new Math_BigInteger();
            $one  = new Math_BigInteger(1);
        }

        // $x mod -$n == $x mod $n.
        $n = $n->abs();

        if ($this->compare($zero) < 0) {
            $temp = $this->abs();
            $temp = $temp->modInverse($n);

            return $this->_normalize($n->subtract($temp));
        }

        extract($this->extendedGCD($n));

        if (!$gcd->equals($one)) {
            return false;
        }

        $x = $x->compare($zero) < 0 ? $x->add($n) : $x;

        return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
    }

    /**
     * Calculates the greatest common divisor and Bezout's identity.
     *
     * Say you have 693 and 609.  The GCD is 21.  Bezout's identity states that there exist integers x and y such that
     * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which
     * combination is returned is dependant upon which mode is in use.  See
     * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger(693);
     *    $b = new Math_BigInteger(609);
     *
     *    extract($a->extendedGCD($b));
     *
     *    echo $gcd->toString() . "\r\n"; // outputs 21
     *    echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
     * ?>
     * </code>
     *
     * @param Math_BigInteger $n
     *
     * @return Math_BigInteger
     *
     * @internal Calculates the GCD using the binary xGCD algorithim described in
     *    {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}.  As the text above 14.61 notes,
     *    the more traditional algorithim requires "relatively costly multiple-precision divisions".
     */
    public function extendedGCD($n)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                extract(gmp_gcdext($this->value, $n->value));

                return array(
                    'gcd' => $this->_normalize(new Math_BigInteger($g)),
                    'x'   => $this->_normalize(new Math_BigInteger($s)),
                    'y'   => $this->_normalize(new Math_BigInteger($t)),
                );
            case MATH_BIGINTEGER_MODE_BCMATH:
                // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
                // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway.  as is,
                // the basic extended euclidean algorithim is what we're using.

                $u = $this->value;
                $v = $n->value;

                $a = '1';
                $b = '0';
                $c = '0';
                $d = '1';

                while (0 != bccomp($v, '0', 0)) {
                    $q = bcdiv($u, $v, 0);

                    $temp = $u;
                    $u    = $v;
                    $v    = bcsub($temp, bcmul($v, $q, 0), 0);

                    $temp = $a;
                    $a    = $c;
                    $c    = bcsub($temp, bcmul($a, $q, 0), 0);

                    $temp = $b;
                    $b    = $d;
                    $d    = bcsub($temp, bcmul($b, $q, 0), 0);
                }

                return array(
                    'gcd' => $this->_normalize(new Math_BigInteger($u)),
                    'x'   => $this->_normalize(new Math_BigInteger($a)),
                    'y'   => $this->_normalize(new Math_BigInteger($b)),
                );
        }

        $y        = $n->copy();
        $x        = $this->copy();
        $g        = new Math_BigInteger();
        $g->value = array(1);

        while (!(($x->value[0] & 1) || ($y->value[0] & 1))) {
            $x->_rshift(1);
            $y->_rshift(1);
            $g->_lshift(1);
        }

        $u = $x->copy();
        $v = $y->copy();

        $a = new Math_BigInteger();
        $b = new Math_BigInteger();
        $c = new Math_BigInteger();
        $d = new Math_BigInteger();

        $a->value = $d->value = $g->value = array(1);
        $b->value = $c->value = array();

        while (!empty($u->value)) {
            while (!($u->value[0] & 1)) {
                $u->_rshift(1);
                if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) {
                    $a = $a->add($y);
                    $b = $b->subtract($x);
                }
                $a->_rshift(1);
                $b->_rshift(1);
            }

            while (!($v->value[0] & 1)) {
                $v->_rshift(1);
                if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) {
                    $c = $c->add($y);
                    $d = $d->subtract($x);
                }
                $c->_rshift(1);
                $d->_rshift(1);
            }

            if ($u->compare($v) >= 0) {
                $u = $u->subtract($v);
                $a = $a->subtract($c);
                $b = $b->subtract($d);
            } else {
                $v = $v->subtract($u);
                $c = $c->subtract($a);
                $d = $d->subtract($b);
            }
        }

        return array(
            'gcd' => $this->_normalize($g->multiply($v)),
            'x'   => $this->_normalize($c),
            'y'   => $this->_normalize($d),
        );
    }

    /**
     * DER-encode an integer.
     *
     * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
     *
     * @see modPow()
     *
     * @param int $length
     *
     * @return string
     */
    public function _encodeASN1Length($length)
    {
        if ($length <= 0x7F) {
            return chr($length);
        }

        $temp = ltrim(pack('N', $length), chr(0));

        return pack('Ca*', 0x80 | strlen($temp), $temp);
    }

    /**
     * Performs squaring.
     *
     * @param array $x
     *
     * @return array
     */
    public function _square($x = false)
    {
        return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
            $this->_trim($this->_baseSquare($x)) :
            $this->_trim($this->_karatsubaSquare($x));
    }

    /**
     * Performs traditional squaring on two BigIntegers.
     *
     * Squaring can be done faster than multiplying a number by itself can be.  See
     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
     *
     * @param array $value
     *
     * @return array
     */
    public function _baseSquare($value)
    {
        if (empty($value)) {
            return array();
        }
        $square_value = $this->_array_repeat(0, 2 * count($value));

        for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
            $i2 = $i << 1;

            $temp              = $square_value[$i2] + $value[$i] * $value[$i];
            $carry             = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);

            // note how we start from $i+1 instead of 0 as we do in multiplication.
            for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
                $temp             = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
                $carry            = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
                $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
            }

            // the following line can yield values larger 2**15.  at this point, PHP should switch
            // over to floats.
            $square_value[$i + $max_index + 1] = $carry;
        }

        return $square_value;
    }

    /**
     * Performs Karatsuba "squaring" on two BigIntegers.
     *
     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
     *
     * @param array $value
     *
     * @return array
     */
    public function _karatsubaSquare($value)
    {
        $m = count($value) >> 1;

        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
            return $this->_baseSquare($value);
        }

        $x1 = array_slice($value, $m);
        $x0 = array_slice($value, 0, $m);

        $z2 = $this->_karatsubaSquare($x1);
        $z0 = $this->_karatsubaSquare($x0);

        $z1   = $this->_add($x1, false, $x0, false);
        $z1   = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
        $temp = $this->_add($z2, false, $z0, false);
        $z1   = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);

        $z2                        = array_merge(array_fill(0, 2 * $m, 0), $z2);
        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);

        $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
        $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);

        return $xx[MATH_BIGINTEGER_VALUE];
    }

    /**
     * Sliding Window k-ary Modular Exponentiation.
     *
     * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}.  In a departure from those algorithims,
     * however, this function performs a modular reduction after every multiplication and squaring operation.
     * As such, this function has the same preconditions that the reductions being used do.
     *
     * @param Math_BigInteger $e
     * @param Math_BigInteger $n
     * @param int             $mode
     *
     * @return Math_BigInteger
     */
    public function _slidingWindow($e, $n, $mode)
    {
        static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
        //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1

        $e_value  = $e->value;
        $e_length = count($e_value) - 1;
        $e_bits   = decbin($e_value[$e_length]);
        for ($i = $e_length - 1; $i >= 0; --$i) {
            $e_bits .= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);
        }

        $e_length = strlen($e_bits);

        // calculate the appropriate window size.
        // $window_size == 3 if $window_ranges is between 25 and 81, for example.
        for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);

        $n_value = $n->value;

        // precompute $this^0 through $this^$window_size
        $powers    = array();
        $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
        $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);

        // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
        // in a 1.  ie. it's supposed to be odd.
        $temp = 1 << ($window_size - 1);
        for ($i = 1; $i < $temp; ++$i) {
            $i2              = $i << 1;
            $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
        }

        $result = array(1);
        $result = $this->_prepareReduce($result, $n_value, $mode);

        for ($i = 0; $i < $e_length;) {
            if (!$e_bits[$i]) {
                $result = $this->_squareReduce($result, $n_value, $mode);
                ++$i;
            } else {
                for ($j = $window_size - 1; $j > 0; --$j) {
                    if (!empty($e_bits[$i + $j])) {
                        break;
                    }
                }

                for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
                    $result = $this->_squareReduce($result, $n_value, $mode);
                }

                $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);

                $i += $j + 1;
            }
        }

        $temp        = new Math_BigInteger();
        $temp->value = $this->_reduce($result, $n_value, $mode);

        return $temp;
    }

    /**
     * Modular reduction preperation.
     *
     * @see _slidingWindow()
     *
     * @param array $x
     * @param array $n
     * @param int   $mode
     *
     * @return array
     */
    public function _prepareReduce($x, $n, $mode)
    {
        if (MATH_BIGINTEGER_MONTGOMERY == $mode) {
            return $this->_prepMontgomery($x, $n);
        }

        return $this->_reduce($x, $n, $mode);
    }

    /**
     * Prepare a number for use in Montgomery Modular Reductions.
     *
     * @see _montgomery()
     * @see _slidingWindow()
     *
     * @param array $x
     * @param array $n
     *
     * @return array
     */
    public function _prepMontgomery($x, $n)
    {
        $lhs        = new Math_BigInteger();
        $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
        $rhs        = new Math_BigInteger();
        $rhs->value = $n;

        list(, $temp) = $lhs->divide($rhs);

        return $temp->value;
    }

    /**
     * Modular reduction.
     *
     * For most $modes this will return the remainder.
     *
     * @see _slidingWindow()
     *
     * @param array $x
     * @param array $n
     * @param int   $mode
     *
     * @return array
     */
    public function _reduce($x, $n, $mode)
    {
        switch ($mode) {
            case MATH_BIGINTEGER_MONTGOMERY:
                return $this->_montgomery($x, $n);
            case MATH_BIGINTEGER_BARRETT:
                return $this->_barrett($x, $n);
            case MATH_BIGINTEGER_POWEROF2:
                $lhs        = new Math_BigInteger();
                $lhs->value = $x;
                $rhs        = new Math_BigInteger();
                $rhs->value = $n;

                return $x->_mod2($n);
            case MATH_BIGINTEGER_CLASSIC:
                $lhs          = new Math_BigInteger();
                $lhs->value   = $x;
                $rhs          = new Math_BigInteger();
                $rhs->value   = $n;
                list(, $temp) = $lhs->divide($rhs);

                return $temp->value;
            case MATH_BIGINTEGER_NONE:
                return $x;
            default:
                // an invalid $mode was provided
        }
    }

    /**
     * Montgomery Modular Reduction.
     *
     * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
     * improved upon (basically, by using the comba method).  gcd($n, 2) must be equal to one for this function
     * to work correctly.
     *
     * @see _prepMontgomery()
     * @see _slidingWindow()
     *
     * @param array $x
     * @param array $n
     *
     * @return array
     */
    public function _montgomery($x, $n)
    {
        static $cache = array(
            MATH_BIGINTEGER_VARIABLE => array(),
            MATH_BIGINTEGER_DATA     => array(),
        );

        if (false === ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE]))) {
            $key                               = count($cache[MATH_BIGINTEGER_VARIABLE]);
            $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
            $cache[MATH_BIGINTEGER_DATA][]     = $this->_modInverse67108864($n);
        }

        $k = count($n);

        $result = array(MATH_BIGINTEGER_VALUE => $x);

        for ($i = 0; $i < $k; ++$i) {
            $temp   = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
            $temp   = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
            $temp   = $this->_regularMultiply(array($temp), $n);
            $temp   = array_merge($this->_array_repeat(0, $i), $temp);
            $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
        }

        $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);

        if ($this->_compare($result, false, $n, false) >= 0) {
            $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
        }

        return $result[MATH_BIGINTEGER_VALUE];
    }

    /**
     * Modular Inverse of a number mod 2**26 (eg. 67108864).
     *
     * Based off of the bnpInvDigit function implemented and justified in the following URL:
     *
     * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
     *
     * The following URL provides more info:
     *
     * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
     *
     * As for why we do all the bitmasking...  strange things can happen when converting from floats to ints. For
     * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
     * int(-2147483648).  To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
     * auto-converted to floats.  The outermost bitmask is present because without it, there's no guarantee that
     * the "residue" returned would be the so-called "common residue".  We use fmod, in the last step, because the
     * maximum possible $x is 26 bits and the maximum $result is 16 bits.  Thus, we have to be able to handle up to
     * 40 bits, which only 64-bit floating points will support.
     *
     * Thanks to Pedro Gimeno Fortea for input!
     *
     * @see _montgomery()
     *
     * @param array $x
     *
     * @return int
     */
    public function _modInverse67108864($x) // 2**26 == 67,108,864
    {
        $x      = -$x[0];
        $result = $x & 0x3; // x**-1 mod 2**2
        $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
        $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
        $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
        $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
        return $result & MATH_BIGINTEGER_MAX_DIGIT;
    }

    /**
     * Barrett Modular Reduction.
     *
     * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information.  Modified slightly,
     * so as not to require negative numbers (initially, this script didn't support negative numbers).
     *
     * Employs "folding", as described at
     * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}.  To quote from
     * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
     *
     * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
     * usable on account of (1) its not using reasonable radix points as discussed in
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
     * radix points, it only works when there are an even number of digits in the denominator.  The reason for (2) is that
     * (x >> 1) + (x >> 1) != x / 2 + x / 2.  If x is even, they're the same, but if x is odd, they're not.  See the in-line
     * comments for details.
     *
     * @see _slidingWindow()
     *
     * @param array $n
     * @param array $m
     *
     * @return array
     */
    public function _barrett($n, $m)
    {
        static $cache = array(
            MATH_BIGINTEGER_VARIABLE => array(),
            MATH_BIGINTEGER_DATA     => array(),
        );

        $m_length = count($m);

        // if ($this->_compare($n, $this->_square($m)) >= 0) {
        if (count($n) > 2 * $m_length) {
            $lhs          = new Math_BigInteger();
            $rhs          = new Math_BigInteger();
            $lhs->value   = $n;
            $rhs->value   = $m;
            list(, $temp) = $lhs->divide($rhs);

            return $temp->value;
        }

        // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
        if ($m_length < 5) {
            return $this->_regularBarrett($n, $m);
        }

        // n = 2 * m.length

        if (false === ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE]))) {
            $key                               = count($cache[MATH_BIGINTEGER_VARIABLE]);
            $cache[MATH_BIGINTEGER_VARIABLE][] = $m;

            $lhs         = new Math_BigInteger();
            $lhs_value   = &$lhs->value;
            $lhs_value   = $this->_array_repeat(0, $m_length + ($m_length >> 1));
            $lhs_value[] = 1;
            $rhs         = new Math_BigInteger();
            $rhs->value  = $m;

            list($u, $m1) = $lhs->divide($rhs);
            $u            = $u->value;
            $m1           = $m1->value;

            $cache[MATH_BIGINTEGER_DATA][] = array(
                'u'  => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
                'm1' => $m1, // m.length
            );
        } else {
            extract($cache[MATH_BIGINTEGER_DATA][$key]);
        }

        $cutoff = $m_length + ($m_length >> 1);
        $lsd    = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
        $msd    = array_slice($n, $cutoff);    // m.length >> 1
        $lsd    = $this->_trim($lsd);
        $temp   = $this->_multiply($msd, false, $m1, false);
        $n      = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1

        if ($m_length & 1) {
            return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
        }

        // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
        $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
        // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
        // if odd:  ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
        $temp = $this->_multiply($temp, false, $u, false);
        // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
        // if odd:  (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
        $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
        // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
        // if odd:  (m.length - (m.length >> 1)) + m.length     = 2 * m.length - (m.length >> 1)
        $temp = $this->_multiply($temp, false, $m, false);

        // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
        // number from a m.length + (m.length >> 1) + 1 digit number.  ie. there'd be an extra digit and the while loop
        // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).

        $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);

        while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
            $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
        }

        return $result[MATH_BIGINTEGER_VALUE];
    }

    /**
     * (Regular) Barrett Modular Reduction.
     *
     * For numbers with more than four digits Math_BigInteger::_barrett() is faster.  The difference between that and this
     * is that this function does not fold the denominator into a smaller form.
     *
     * @see _slidingWindow()
     *
     * @param array $x
     * @param array $n
     *
     * @return array
     */
    public function _regularBarrett($x, $n)
    {
        static $cache = array(
            MATH_BIGINTEGER_VARIABLE => array(),
            MATH_BIGINTEGER_DATA     => array(),
        );

        $n_length = count($n);

        if (count($x) > 2 * $n_length) {
            $lhs          = new Math_BigInteger();
            $rhs          = new Math_BigInteger();
            $lhs->value   = $x;
            $rhs->value   = $n;
            list(, $temp) = $lhs->divide($rhs);

            return $temp->value;
        }

        if (false === ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE]))) {
            $key                               = count($cache[MATH_BIGINTEGER_VARIABLE]);
            $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
            $lhs                               = new Math_BigInteger();
            $lhs_value                         = &$lhs->value;
            $lhs_value                         = $this->_array_repeat(0, 2 * $n_length);
            $lhs_value[]                       = 1;
            $rhs                               = new Math_BigInteger();
            $rhs->value                        = $n;
            list($temp)                        = $lhs->divide($rhs); // m.length
            $cache[MATH_BIGINTEGER_DATA][]     = $temp->value;
        }

        // 2 * m.length - (m.length - 1) = m.length + 1
        $temp = array_slice($x, $n_length - 1);
        // (m.length + 1) + m.length = 2 * m.length + 1
        $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
        // (2 * m.length + 1) - (m.length - 1) = m.length + 2
        $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);

        // m.length + 1
        $result = array_slice($x, 0, $n_length + 1);
        // m.length + 1
        $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
        // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)

        if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
            $corrector_value                          = $this->_array_repeat(0, $n_length + 1);
            $corrector_value[count($corrector_value)] = 1;
            $result                                   = $this->_add($result, false, $corrector_value, false);
            $result                                   = $result[MATH_BIGINTEGER_VALUE];
        }

        // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
        $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
        while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
            $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
        }

        return $result[MATH_BIGINTEGER_VALUE];
    }

    /**
     * Performs long multiplication up to $stop digits.
     *
     * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
     *
     * @see _regularBarrett()
     *
     * @param array $x_value
     * @param bool  $x_negative
     * @param array $y_value
     * @param bool  $y_negative
     * @param int   $stop
     *
     * @return array
     */
    public function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
    {
        $x_length = count($x_value);
        $y_length = count($y_value);

        if (!$x_length || !$y_length) { // a 0 is being multiplied
            return array(
                MATH_BIGINTEGER_VALUE => array(),
                MATH_BIGINTEGER_SIGN  => false,
            );
        }

        if ($x_length < $y_length) {
            $temp    = $x_value;
            $x_value = $y_value;
            $y_value = $temp;

            $x_length = count($x_value);
            $y_length = count($y_value);
        }

        $product_value = $this->_array_repeat(0, $x_length + $y_length);

        // the following for loop could be removed if the for loop following it
        // (the one with nested for loops) initially set $i to 0, but
        // doing so would also make the result in one set of unnecessary adds,
        // since on the outermost loops first pass, $product->value[$k] is going
        // to always be 0

        $carry = 0;

        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
            $temp              = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
            $carry             = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
        }

        if ($j < $stop) {
            $product_value[$j] = $carry;
        }

        // the above for loop is what the previous comment was talking about.  the
        // following for loop is the "one with nested for loops"

        for ($i = 1; $i < $y_length; ++$i) {
            $carry = 0;

            for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
                $temp              = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
                $carry             = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
                $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
            }

            if ($k < $stop) {
                $product_value[$k] = $carry;
            }
        }

        return array(
            MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
            MATH_BIGINTEGER_SIGN  => $x_negative != $y_negative,
        );
    }

    /**
     * Modular square.
     *
     * @see _slidingWindow()
     *
     * @param array $x
     * @param array $n
     * @param int   $mode
     *
     * @return array
     */
    public function _squareReduce($x, $n, $mode)
    {
        if (MATH_BIGINTEGER_MONTGOMERY == $mode) {
            return $this->_montgomeryMultiply($x, $x, $n);
        }

        return $this->_reduce($this->_square($x), $n, $mode);
    }

    /**
     * Montgomery Multiply.
     *
     * Interleaves the montgomery reduction and long multiplication algorithms together as described in
     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
     *
     * @see _prepMontgomery()
     * @see _montgomery()
     *
     * @param array $x
     * @param array $y
     * @param array $m
     *
     * @return array
     */
    public function _montgomeryMultiply($x, $y, $m)
    {
        $temp = $this->_multiply($x, false, $y, false);

        return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);

        // the following code, although not callable, can be run independently of the above code
        // although the above code performed better in my benchmarks the following could might
        // perform better under different circumstances. in lieu of deleting it it's just been
        // made uncallable

        static $cache = array(
            MATH_BIGINTEGER_VARIABLE => array(),
            MATH_BIGINTEGER_DATA     => array(),
        );

        if (false === ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE]))) {
            $key                               = count($cache[MATH_BIGINTEGER_VARIABLE]);
            $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
            $cache[MATH_BIGINTEGER_DATA][]     = $this->_modInverse67108864($m);
        }

        $n = max(count($x), count($y), count($m));
        $x = array_pad($x, $n, 0);
        $y = array_pad($y, $n, 0);
        $m = array_pad($m, $n, 0);
        $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
        for ($i = 0; $i < $n; ++$i) {
            $temp                     = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
            $temp                     = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
            $temp                     = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
            $temp                     = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
            $temp                     = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
            $a                        = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
            $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
        }
        if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
            $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
        }

        return $a[MATH_BIGINTEGER_VALUE];
    }

    /**
     * Modular multiply.
     *
     * @see _slidingWindow()
     *
     * @param array $x
     * @param array $y
     * @param array $n
     * @param int   $mode
     *
     * @return array
     */
    public function _multiplyReduce($x, $y, $n, $mode)
    {
        if (MATH_BIGINTEGER_MONTGOMERY == $mode) {
            return $this->_montgomeryMultiply($x, $y, $n);
        }
        $temp = $this->_multiply($x, false, $y, false);

        return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
    }

    /**
     * Modulos for Powers of Two.
     *
     * Calculates $x%$n, where $n = 2**$e, for some $e.  Since this is basically the same as doing $x & ($n-1),
     * we'll just use this function as a wrapper for doing that.
     *
     * @see _slidingWindow()
     *
     * @param Math_BigInteger
     *
     * @return Math_BigInteger
     */
    public function _mod2($n)
    {
        $temp        = new Math_BigInteger();
        $temp->value = array(1);

        return $this->bitwise_and($n->subtract($temp));
    }

    /**
     * Logical And.
     *
     * @param Math_BigInteger $x
     *
     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
     *
     * @return Math_BigInteger
     */
    public function bitwise_and($x)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp        = new Math_BigInteger();
                $temp->value = gmp_and($this->value, $x->value);

                return $this->_normalize($temp);
            case MATH_BIGINTEGER_MODE_BCMATH:
                $left  = $this->toBytes();
                $right = $x->toBytes();

                $length = max(strlen($left), strlen($right));

                $left  = str_pad($left, $length, chr(0), STR_PAD_LEFT);
                $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

                return $this->_normalize(new Math_BigInteger($left & $right, 256));
        }

        $result = $this->copy();

        $length = min(count($x->value), count($this->value));

        $result->value = array_slice($result->value, 0, $length);

        for ($i = 0; $i < $length; ++$i) {
            $result->value[$i] &= $x->value[$i];
        }

        return $this->_normalize($result);
    }

    /**
     * Calculates the greatest common divisor.
     *
     * Say you have 693 and 609.  The GCD is 21.
     *
     * Here's an example:
     * <code>
     * <?php
     *    include 'Math/BigInteger.php';
     *
     *    $a = new Math_BigInteger(693);
     *    $b = new Math_BigInteger(609);
     *
     *    $gcd = a->extendedGCD($b);
     *
     *    echo $gcd->toString() . "\r\n"; // outputs 21
     * ?>
     * </code>
     *
     * @param Math_BigInteger $n
     *
     * @return Math_BigInteger
     */
    public function gcd($n)
    {
        extract($this->extendedGCD($n));

        return $gcd;
    }

    /**
     * Logical Exclusive-Or.
     *
     * @param Math_BigInteger $x
     *
     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
     *
     * @return Math_BigInteger
     */
    public function bitwise_xor($x)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp        = new Math_BigInteger();
                $temp->value = gmp_xor($this->value, $x->value);

                return $this->_normalize($temp);
            case MATH_BIGINTEGER_MODE_BCMATH:
                $left  = $this->toBytes();
                $right = $x->toBytes();

                $length = max(strlen($left), strlen($right));

                $left  = str_pad($left, $length, chr(0), STR_PAD_LEFT);
                $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

                return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
        }

        $length        = max(count($this->value), count($x->value));
        $result        = $this->copy();
        $result->value = array_pad($result->value, $length, 0);
        $x->value      = array_pad($x->value, $length, 0);

        for ($i = 0; $i < $length; ++$i) {
            $result->value[$i] ^= $x->value[$i];
        }

        return $this->_normalize($result);
    }

    /**
     * Logical Not.
     *
     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
     *
     * @return Math_BigInteger
     */
    public function bitwise_not()
    {
        // calculuate "not" without regard to $this->precision
        // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)
        $temp    = $this->toBytes();
        $pre_msb = decbin(ord($temp[0]));
        $temp    = ~$temp;
        $msb     = decbin(ord($temp[0]));
        if (8 == strlen($msb)) {
            $msb = substr($msb, strpos($msb, '0'));
        }
        $temp[0] = chr(bindec($msb));

        // see if we need to add extra leading 1's
        $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
        $new_bits     = $this->precision - $current_bits;
        if ($new_bits <= 0) {
            return $this->_normalize(new Math_BigInteger($temp, 256));
        }

        // generate as many leading 1's as we need to.
        $leading_ones = chr((1 << ($new_bits & 0x7)) - 1).str_repeat(chr(0xFF), $new_bits >> 3);
        $this->_base256_lshift($leading_ones, $current_bits);

        $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);

        return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
    }

    /**
     * Logical Right Rotate.
     *
     * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
     *
     * @param int $shift
     *
     * @return Math_BigInteger
     */
    public function bitwise_rightRotate($shift)
    {
        return $this->bitwise_leftRotate(-$shift);
    }

    /**
     * Logical Left Rotate.
     *
     * Instead of the top x bits being dropped they're appended to the shifted bit string.
     *
     * @param int $shift
     *
     * @return Math_BigInteger
     */
    public function bitwise_leftRotate($shift)
    {
        $bits = $this->toBytes();

        if ($this->precision > 0) {
            $precision = $this->precision;
            if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) {
                $mask = $this->bitmask->subtract(new Math_BigInteger(1));
                $mask = $mask->toBytes();
            } else {
                $mask = $this->bitmask->toBytes();
            }
        } else {
            $temp = ord($bits[0]);
            for ($i = 0; $temp >> $i; ++$i);
            $precision = 8 * strlen($bits) - 8 + $i;
            $mask      = chr((1 << ($precision & 0x7)) - 1).str_repeat(chr(0xFF), $precision >> 3);
        }

        if ($shift < 0) {
            $shift += $precision;
        }
        $shift %= $precision;

        if (!$shift) {
            return $this->copy();
        }

        $left   = $this->bitwise_leftShift($shift);
        $left   = $left->bitwise_and(new Math_BigInteger($mask, 256));
        $right  = $this->bitwise_rightShift($precision - $shift);
        $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);

        return $this->_normalize($result);
    }

    /**
     * Logical Left Shift.
     *
     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
     *
     * @param int $shift
     *
     * @return Math_BigInteger
     *
     * @internal the only version that yields any speed increases is the internal version
     */
    public function bitwise_leftShift($shift)
    {
        $temp = new Math_BigInteger();

        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                static $two;

                if (!isset($two)) {
                    $two = gmp_init('2');
                }

                $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));

                break;
            case MATH_BIGINTEGER_MODE_BCMATH:
                $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);

                break;
            default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
                // and I don't want to do that...
                $temp->value = $this->value;
                $temp->_lshift($shift);
        }

        return $this->_normalize($temp);
    }

    /**
     * Logical Right Shift.
     *
     * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
     *
     * @param int $shift
     *
     * @return Math_BigInteger
     *
     * @internal the only version that yields any speed increases is the internal version
     */
    public function bitwise_rightShift($shift)
    {
        $temp = new Math_BigInteger();

        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                static $two;

                if (!isset($two)) {
                    $two = gmp_init('2');
                }

                $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));

                break;
            case MATH_BIGINTEGER_MODE_BCMATH:
                $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);

                break;
            default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
                // and I don't want to do that...
                $temp->value = $this->value;
                $temp->_rshift($shift);
        }

        return $this->_normalize($temp);
    }

    /**
     * Logical Or.
     *
     * @param Math_BigInteger $x
     *
     * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
     *
     * @return Math_BigInteger
     */
    public function bitwise_or($x)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                $temp        = new Math_BigInteger();
                $temp->value = gmp_or($this->value, $x->value);

                return $this->_normalize($temp);
            case MATH_BIGINTEGER_MODE_BCMATH:
                $left  = $this->toBytes();
                $right = $x->toBytes();

                $length = max(strlen($left), strlen($right));

                $left  = str_pad($left, $length, chr(0), STR_PAD_LEFT);
                $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

                return $this->_normalize(new Math_BigInteger($left | $right, 256));
        }

        $length        = max(count($this->value), count($x->value));
        $result        = $this->copy();
        $result->value = array_pad($result->value, $length, 0);
        $x->value      = array_pad($x->value, $length, 0);

        for ($i = 0; $i < $length; ++$i) {
            $result->value[$i] |= $x->value[$i];
        }

        return $this->_normalize($result);
    }

    /**
     * Generate a random prime number.
     *
     * If there's not a prime within the given range, false will be returned.  If more than $timeout seconds have elapsed,
     * give up and return false.
     *
     * @param Math_BigInteger          $arg1
     * @param optional Math_BigInteger $arg2
     * @param optional Integer         $timeout
     *
     * @return mixed
     *
     * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
     */
    public function randomPrime($arg1, $arg2 = false, $timeout = false)
    {
        if (false === $arg1) {
            return false;
        }

        if (false === $arg2) {
            $max = $arg1;
            $min = $this;
        } else {
            $min = $arg1;
            $max = $arg2;
        }

        $compare = $max->compare($min);

        if (!$compare) {
            return $min->isPrime() ? $min : false;
        } elseif ($compare < 0) {
            // if $min is bigger then $max, swap $min and $max
            $temp = $max;
            $max  = $min;
            $min  = $temp;
        }

        static $one, $two;
        if (!isset($one)) {
            $one = new Math_BigInteger(1);
            $two = new Math_BigInteger(2);
        }

        $start = time();

        $x = $this->random($min, $max);

        // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
        if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime')) {
            $p        = new Math_BigInteger();
            $p->value = gmp_nextprime($x->value);

            if ($p->compare($max) <= 0) {
                return $p;
            }

            if (!$min->equals($x)) {
                $x = $x->subtract($one);
            }

            return $x->randomPrime($min, $x);
        }

        if ($x->equals($two)) {
            return $x;
        }

        $x->_make_odd();
        if ($x->compare($max) > 0) {
            // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
            if ($min->equals($max)) {
                return false;
            }
            $x = $min->copy();
            $x->_make_odd();
        }

        $initial_x = $x->copy();

        while (true) {
            if (false !== $timeout && time() - $start > $timeout) {
                return false;
            }

            if ($x->isPrime()) {
                return $x;
            }

            $x = $x->add($two);

            if ($x->compare($max) > 0) {
                $x = $min->copy();
                if ($x->equals($two)) {
                    return $x;
                }
                $x->_make_odd();
            }

            if ($x->equals($initial_x)) {
                return false;
            }
        }
    }

    /**
     * Checks a numer to see if it's prime.
     *
     * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the
     * $t parameter is distributability.  Math_BigInteger::randomPrime() can be distributed across multiple pageloads
     * on a website instead of just one.
     *
     * @param optional Math_BigInteger $t
     *
     * @return bool
     *
     * @internal Uses the
     *     {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}.  See
     *     {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
     */
    public function isPrime($t = false)
    {
        $length = strlen($this->toBytes());

        if (!$t) {
            // see HAC 4.49 "Note (controlling the error probability)"
            // @codingStandardsIgnoreStart
            if ($length >= 163) {
                $t = 2;
            } // floor(1300 / 8)
            elseif ($length >= 106) {
                $t = 3;
            } // floor( 850 / 8)
            elseif ($length >= 81) {
                $t = 4;
            } // floor( 650 / 8)
            elseif ($length >= 68) {
                $t = 5;
            } // floor( 550 / 8)
            elseif ($length >= 56) {
                $t = 6;
            } // floor( 450 / 8)
            elseif ($length >= 50) {
                $t = 7;
            } // floor( 400 / 8)
            elseif ($length >= 43) {
                $t = 8;
            } // floor( 350 / 8)
            elseif ($length >= 37) {
                $t = 9;
            } // floor( 300 / 8)
            elseif ($length >= 31) {
                $t = 12;
            } // floor( 250 / 8)
            elseif ($length >= 25) {
                $t = 15;
            } // floor( 200 / 8)
            elseif ($length >= 18) {
                $t = 18;
            } // floor( 150 / 8)
            else {
                $t = 27;
            }
            // @codingStandardsIgnoreEnd
        }

        // ie. gmp_testbit($this, 0)
        // ie. isEven() or !isOdd()
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                return 0 != gmp_prob_prime($this->value, $t);
            case MATH_BIGINTEGER_MODE_BCMATH:
                if ('2' === $this->value) {
                    return true;
                }
                if ($this->value[strlen($this->value) - 1] % 2 == 0) {
                    return false;
                }
                break;
            default:
                if ($this->value == array(2)) {
                    return true;
                }
                if (~$this->value[0] & 1) {
                    return false;
                }
        }

        static $primes, $zero, $one, $two;

        if (!isset($primes)) {
            $primes = array(
                3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
                61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
                139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
                229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
                317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
                421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
                521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
                619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
                733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
                839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
                953, 967, 971, 977, 983, 991, 997,
            );

            if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
                for ($i = 0; $i < count($primes); ++$i) {
                    $primes[$i] = new Math_BigInteger($primes[$i]);
                }
            }

            $zero = new Math_BigInteger();
            $one  = new Math_BigInteger(1);
            $two  = new Math_BigInteger(2);
        }

        if ($this->equals($one)) {
            return false;
        }

        // see HAC 4.4.1 "Random search for probable primes"
        if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
            foreach ($primes as $prime) {
                list(, $r) = $this->divide($prime);
                if ($r->equals($zero)) {
                    return $this->equals($prime);
                }
            }
        } else {
            $value = $this->value;
            foreach ($primes as $prime) {
                list(, $r) = $this->_divide_digit($value, $prime);
                if (!$r) {
                    return 1 == count($value) && $value[0] == $prime;
                }
            }
        }

        $n   = $this->copy();
        $n_1 = $n->subtract($one);
        $n_2 = $n->subtract($two);

        $r       = $n_1->copy();
        $r_value = $r->value;
        // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
        if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) {
            $s = 0;
            // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
            while ($r->value[strlen($r->value) - 1] % 2 == 0) {
                $r->value = bcdiv($r->value, '2', 0);
                ++$s;
            }
        } else {
            for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
                $temp = ~$r_value[$i] & 0xFFFFFF;
                for ($j = 1; ($temp >> $j) & 1; ++$j);
                if (25 != $j) {
                    break;
                }
            }
            $s = 26 * $i + $j - 1;
            $r->_rshift($s);
        }

        for ($i = 0; $i < $t; ++$i) {
            $a = $this->random($two, $n_2);
            $y = $a->modPow($r, $n);

            if (!$y->equals($one) && !$y->equals($n_1)) {
                for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
                    $y = $y->modPow($two, $n);
                    if ($y->equals($one)) {
                        return false;
                    }
                }

                if (!$y->equals($n_1)) {
                    return false;
                }
            }
        }

        return true;
    }

    // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
    // at 32-bits, while java's longs are 64-bits.

    /**
     * Tests the equality of two numbers.
     *
     * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
     *
     * @param Math_BigInteger $x
     *
     * @return bool
     *
     * @see compare()
     */
    public function equals($x)
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                return 0 == gmp_cmp($this->value, $x->value);
            default:
                return $this->value === $x->value && $this->is_negative == $x->is_negative;
        }
    }

    /**
     * Generate a random number.
     *
     * Returns a random number between $min and $max where $min and $max
     * can be defined using one of the two methods:
     *
     * $min->random($max)
     * $max->random($min)
     *
     * @param Math_BigInteger          $arg1
     * @param optional Math_BigInteger $arg2
     *
     * @return Math_BigInteger
     *
     * @internal the API for creating random numbers used to be $a->random($min, $max), where $a was a Math_BigInteger object.
     *           That method is still supported for BC purposes
     */
    public function random($arg1, $arg2 = false)
    {
        if (false === $arg1) {
            return false;
        }

        if (false === $arg2) {
            $max = $arg1;
            $min = $this;
        } else {
            $min = $arg1;
            $max = $arg2;
        }

        $compare = $max->compare($min);

        if (!$compare) {
            return $this->_normalize($min);
        } elseif ($compare < 0) {
            // if $min is bigger then $max, swap $min and $max
            $temp = $max;
            $max  = $min;
            $min  = $temp;
        }

        static $one;
        if (!isset($one)) {
            $one = new Math_BigInteger(1);
        }

        $max  = $max->subtract($min->subtract($one));
        $size = strlen(ltrim($max->toBytes(), chr(0)));

        /*
            doing $random % $max doesn't work because some numbers will be more likely to occur than others.
            eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
            would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
            not all numbers would be equally likely. some would be more likely than others.

            creating a whole new random number until you find one that is within the range doesn't work
            because, for sufficiently small ranges, the likelihood that you'd get a number within that range
            would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
            would be pretty high that $random would be greater than $max.

            phpseclib works around this using the technique described here:

            http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
        */
        $random_max = new Math_BigInteger(chr(1).str_repeat("\0", $size), 256);
        $random     = $this->_random_number_helper($size);

        list($max_multiple) = $random_max->divide($max);
        $max_multiple       = $max_multiple->multiply($max);

        while ($random->compare($max_multiple) >= 0) {
            $random             = $random->subtract($max_multiple);
            $random_max         = $random_max->subtract($max_multiple);
            $random             = $random->bitwise_leftShift(8);
            $random             = $random->add($this->_random_number_helper(1));
            $random_max         = $random_max->bitwise_leftShift(8);
            list($max_multiple) = $random_max->divide($max);
            $max_multiple       = $max_multiple->multiply($max);
        }
        list(, $random) = $random->divide($max);

        return $this->_normalize($random->add($min));
    }

    /**
     * Generates a random BigInteger.
     *
     * Byte length is equal to $length. Uses crypt_random if it's loaded and mt_rand if it's not.
     *
     * @param int $length
     *
     * @return Math_BigInteger
     */
    public function _random_number_helper($size)
    {
        if (function_exists('crypt_random_string')) {
            $random = crypt_random_string($size);
        } else {
            $random = '';

            if ($size & 1) {
                $random .= chr(mt_rand(0, 255));
            }

            $blocks = $size >> 1;
            for ($i = 0; $i < $blocks; ++$i) {
                // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
                $random .= pack('n', mt_rand(0, 0xFFFF));
            }
        }

        return new Math_BigInteger($random, 256);
    }

    /**
     * Make the current number odd.
     *
     * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
     *
     * @see randomPrime()
     */
    public function _make_odd()
    {
        switch (MATH_BIGINTEGER_MODE) {
            case MATH_BIGINTEGER_MODE_GMP:
                gmp_setbit($this->value, 0);
                break;
            case MATH_BIGINTEGER_MODE_BCMATH:
                if ($this->value[strlen($this->value) - 1] % 2 == 0) {
                    $this->value = bcadd($this->value, '1');
                }
                break;
            default:
                $this->value[0] |= 1;
        }
    }
}
PK��#]5��8DD)system/bfnetwork/bfnetwork/Math/.htaccessnu�[���<Files ~ "^.*$">
Order deny,allow
Deny from all
Satisfy all
</Files>PK��#]J��OJOJ(system/bfnetwork/bfnetwork/bfEncrypt.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

header('X-MYJOOMLA: HIT');

/*
 * Some high level request checks
 * Only accept POSTs, if a GET then just expose the fact we are listening
 */
count($_POST) or die('Ready');

/**
 * Provide some code so that pathetic extensions code can be worked around.
 */
require './bfWorkarounds.php';

/*
 * Compose the Endpoint for Validation
 *
 * Note: The use of md5 here serves to clean to a known 32 string, we dont care if the data is real or fake at this
 * point as that is validated by the myJoomla.com endpoint.
 *
 * The only weakness here is if our service is compromised or your DNS is compromised, however small a chance that is
 * the request is still encrypted, and will have to pass decryption validation later on, so is still secure.
 *
 * An UNIQUE_REQUEST_ID can only be used once!
 */
switch ($_POST['APPLICATION_ENV']) { // Switch from insecure $_POST to a known clean value locally
    case'development':
    case 'local':
        $APPLICATION_ENV = 'development';
        $urlPattern      = 'https://nginx/validate/?%s=%s';
        break;
    case 'staging':
        $APPLICATION_ENV = 'staging';
        $urlPattern      = 'https://manage.myjoomla.com/validate/?%s=%s';
        break;
    default:
        // If brute force attempt to inject fake APPLICATION_ENV we reset to production
        $APPLICATION_ENV = 'production';
        $urlPattern      = 'https://manage.myjoomla.com/validate/?%s=%s';
        break;
}

$validationUrl = sprintf($urlPattern, md5($_POST['UNIQUE_REQUEST_ID']), md5(base64_encode(json_encode($_POST))));

/**
 * Allow override of validation method CURL/file_get_contents
 * Yes we are using a $_POST var here, but again we are only using it as a configuration switch and no evaluation is made
 * It an attacker switched on the _POST['VM'] nothing bad happens and they gain nothing.
 */
switch ($_POST['VM']) { // Switch from insecure $_POST to a known clean value locally
    case 'C'.'U'.'R'.'L':
        $overrideVMethod = 'C'.'U'.'R'.'L';
        break;
    default:
    case 'FILE':
        $overrideVMethod = 'FILE';
        break;
}

/*
 * Call validation service to validate the request
 *
 * Call back to myjoomla.com to authenticate that the request is genuine and from our service
 * If not a validated request fail to process anything else past this point.
 * Requests are valid if they have a valid UNIQUE_REQUEST_ID and the message has not been tampered with
 * The UNIQUE_REQUEST_ID also contains other security like, but limited to, time and site specific hashes
 *
 *  Ok so on some crappy servers - that firewall the outgoing requests, we cannot call home to validate the request
 *  so we need a way to "switch off" the validation process - this introduces a lesser level of security though :-(
 */

if ($overrideVMethod !== 'C'.'U'.'R'.'L' && true == ini_get('allow_url_fopen') && in_array('https', stream_get_wrappers())) {
    // Just so we can debug
    $vMethod = 'file_get_contents';

    $options = array(
        'http' => array(
            'method' => 'GET',
            'header' => "User-Agent: myJoomla.com validation with file_get_contents\r\n",
        ),
    );

    // create a new context for the request
    $context = stream_context_create($options);

    // safe as we explicitly set the url and the params as md5 strings above
    $validationResultHash = file_get_contents($validationUrl, false, $context);
} else {
    /**
     * If we cannot use file_get_contents because the https stream wrapper was removed from PHP
     * or if allow_url_fopen is disabled then we will need to runt he requests with curl :-(.
     */

    // Just so we can debug
    $vMethod = 'c'.'u'.'r'.'l';

    // init
    $ch = curl_init();

    // configure CURL request
    curl_setopt($ch, CURLOPT_URL, $validationUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'myJoomla.com validation with c'.'u'.'r'.'l');
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

    // run curl request
    $validationResultHash = curl_exec($ch);

    // did it work?
    if (false == $validationResultHash) {
        /*
         * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
         *
         * Ok try without validation of the SSL (gulp) but this is needed on some servers without a pem file
         * and we need to be compatible as possible - even on crappy webhosts when they need us most ;-(
         *
         * disabling the verification of the certificates, you leave the door open to potential MITM attacks HOWEVER
         * we are only sending md5's and expecting a 0 or hash back, no sensitive values are being sent, and all our
         * requests expire after 2 mins anyway, so even if a MITM attack was occurring there is absolutely no way to
         * exploit a site with the request or response of our service.
         */
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $vMethod              = 'C'.'U'.'R'.'L'.' with C'.'U'.'R'.'L'.'OPT_SSL_VERIFYPEER False';
        $validationResultHash = curl_exec($ch);

        if (false == $validationResultHash) {
            echo 'C'.'U'.'R'.'L ERROR: ';
            echo curl_error($ch);
            die;
        }
    }

    curl_close($ch);
}

/*
 * Check if request was authenticated
 *
 * Note: Again only using md5 to compare strings, no additional security is provided by the use of md5
 * Note: There is no valuable data hashed to make these md5 strings just randomisers
 */
if ('f59fbbcf2dc5e3888a079d34f821a75a' !== md5(trim($validationResultHash))) {
    echo 'Request not validated by myJoomla.com - This is fatal and means that YOUR server cannot send a request OUT to our service over https on port 443 using c'.'u'.'r'.'l or file_get_contents() - this normally means your server is blocking OUTGOING requests with a firewall or misconfiguration.';
    echo '<br/><br/>Debug: We tried the validation with PHP methods: '.$vMethod;
    echo '<br/><br/>Debug: env was '.$APPLICATION_ENV;
    echo '<br/><br/>Debug: response was '.print_r($validationResultHash, true);
    die();
}

/* IF WE GET HERE THEN THE REQUEST IS VALIDATED AS GENUINE, BUT IS STILL ENCRYPTED */

// Require our config file
require 'bfConfig.php';

// Require some logging
require 'bfLog.php';
bfLog::init();

// Require special error handling
require 'bfError.php';

// Require Timer - will init the logger too
require 'bfTimer.php';
bfTimer::getInstance();

// Require decryption classes
require 'Crypt/RSA.php';
require 'Crypt/RC4.php';

// Set up the decryption
$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents('Keys/private.key'));
bfLog::log('RSA Key loaded');

// Just in case - crappy servers :-(
global $dataObj;
global $rc4_key;

// Only handle two types of POST
switch (@$_POST['METHOD']) {
    /*
     * If our method is encrpyted (99.9% of our traffic) then decrypted it
     */
    case 'Encrypted':
        define('BF_REQUEST_ENCRYPTED', true);
        $dataObj = bfEncrypt::decrypt($rsa, true);
        bfLog::log('Request Decrypted');
        break;

    /*
     * If our method is an encrypted header, with some files unencrypted (1
     * call of our traffic) then decrypt the header, if ok then allow
     * proceed.
     */
    case 'EncryptedHeaderWithNotEncryptedData':

        // This is an NOTENCRYPTED connection - beware!
        define('BF_REQUEST_ENCRYPTED', false);
        $dataObj = bfEncrypt::decrypt($rsa);
        bfLog::log('Request EncryptedHeaderWithNotEncryptedData Decrypted');
        break;

    default:
        die(json_encode(array(
            'METHOD'       => 'NOTENCRYPTED',
            'RESULT'       => bfReply::ERROR,
            'NOTENCRYPTED' => array(
                'msg' => 'Failed Method',
            ),
        )));
        break;
}

/*
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */

// If we get here then we are through the decryption process
define('BF_REQUEST_METHOD', $_POST['METHOD']);

// Set unique host id for this site
if (property_exists($dataObj, 'SET_HOST_ID')) {
    file_put_contents('HOST_ID', $dataObj->SET_HOST_ID);
}

// Some basic tests, not really security but some basics
if (!is_object($dataObj)) {
    die(json_encode(array(
        'METHOD'       => 'NOTENCRYPTED',
        'RESULT'       => bfReply::ERROR,
        'NOTENCRYPTED' => array(
            'msg' => 'The connector you have installed currently on your site doesnt match the last one we generated for this site, and thus the encryption certificates are invalid and we cannot encrypt/decrypt data with them - you need to delete this site from myJoomla.com and start the connection process again from scratch, making sure you install the exact connector generated in the process, as each is unique.',
        ),
    )));
}

/* SOME CONSTs to make things easy on the eye */

final class bfReply
{
    const SUCCESS               = 'SUCCESS';
    const FAILURE               = 'FAILURE';
    const ERROR                 = 'ERROR';
    const NEEDSCONNECTORUPGRADE = 'NEEDSCONNECTORUPGRADE';
}

class bfEncrypt
{
    /**
     * Decrypt the incoming encrypted data
     * Will be encrypted with the public part of the key pair.
     *
     * @param Crypt_Rsa $rsa
     * @param bool      $enc
     *
     * @return mixed stdClass
     */
    public static function decrypt($rsa, $enc = false)
    {
        $start = time();
        bfLog::log('Starting Decryption....');
        // Create an empty class
        $dataObj = new stdClass();

        // If its a normal encrypted request - 99.9% of our requests
        if (true === $enc) {
            $header = json_decode($rsa->decrypt(base64_decode($_POST['ENCRYPTED'])));
        } else {
            // if an encrypted request, with an encrypted header, and non encrypted body 0.1% of our requests
            $header = json_decode($rsa->decrypt(base64_decode($_POST['ENCRYPTED_HEADER'])));
        }

        if (!$header) {
            // If we get here then then the KEYS are wrong, or the request are
            // wrong
            die(json_encode(array(
                'METHOD'       => 'NOTENCRYPTED',
                'RESULT'       => bfReply::ERROR,
                'NOTENCRYPTED' => array(
                    'msg' => 'The connector you have installed currently on your site doesnt match the last one we generated for this site, and thus the encryption certificates are invalid and we cannot encrypt/decrypt data with them - you need to delete this site from myJoomla.com and start the connection process again from scratch, making sure you install the exact connector generated in the process, as each is unique.',
                ),
            )));
        }

        /*
         * If we have got here then we have already passed through decrypting
         * the encrypted header and so we are sure we are now secure and no one
         * else cannot run the code below.
         */

        // When we get here we are DECRYPTED :-)
        bfLog::log('Finished Decryption.... took '.(time() - $start).' seconds');

        // Set the encryption key to send data back with
        define('RC4_KEY', $header->RC4_KEY);

        // attempt to ensure our tmp folder is writable
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            @chmod(dirname(__FILE__).'/tmp', 0755);
        }

        // Argh!
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            @chmod(dirname(__FILE__).'/tmp', 0777);
        }

        // Give Up!
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            bfEncrypt::reply(bfReply::ERROR, dirname(__FILE__).'/tmp folder not writeable');
        }

        // attempt to ensure our folder is writable
        if (!is_writeable(dirname(__FILE__))) {
            @chmod(dirname(__FILE__), 0755);
        }

        // Argh!
        if (!is_writeable(dirname(__FILE__))) {
            @chmod(dirname(__FILE__), 0777);
        }

        // Give Up!
        if (!is_writeable(dirname(__FILE__))) {
            bfEncrypt::reply(bfReply::ERROR, dirname(__FILE__).'/ folder not writeable');
        }

        // check Version - do I need an upgrade before I proceed?
        $myVersion = file_get_contents('./VERSION');
        if (!defined('_BF_IN_UPGRADE') && $myVersion != $header->REQ_CLIENT_VERSION) {
            // Force a client connector upgrade
            bfEncrypt::reply(bfReply::NEEDSCONNECTORUPGRADE, bfReply::NEEDSCONNECTORUPGRADE);
        }

        // If a fully encrypted request then return all the data
        if (true === $enc) {
            return $header;
        }

        // If a partially encrypted request, then we have an encrypted header,
        // and some non-encrypted body
        // check the checksum from the encrypted part of the request to prevent
        // spoofing
        if ('ENCRYPTED_HEADER' == $header->checksum) {
            // get the timestamp of the request
            $dataObj->timestamp = $header->timestamp;

            // get the non encrypted vars from the request
            if (array_key_exists('NOTENCRYPTED', $_POST)) {
                $dataObj->NOTENCRYPTED = $_POST['NOTENCRYPTED'];
                foreach ($dataObj->NOTENCRYPTED as $k => $v) {
                    $dataObj->$k = $v;
                }
            }

            return $dataObj;
        } else {
            // If we get here then then the KEYS are wrong, or the request are
            // wrong
            die(json_encode(array(
                'METHOD'       => 'NOTENCRYPTED',
                'RESULT'       => bfReply::ERROR,
                'NOTENCRYPTED' => array(
                    'msg' => 'The connector you have installed currently on your site doesnt match the last one we generated for this site, and thus the encryption certificates are invalid and we cannot encrypt/decrypt data with them - you need to delete this site from myJoomla.com and start the connection process again from scratch, making sure you install the exact connector generated in the process, as each is unique.',
                ),
            )));
        }
    }

    /**
     * Output the json with encrypted params.
     *
     * @param CONST|string $result from the bfReply:: namespace
     * @param string       $msg    Normally JSON
     */
    public static function reply($result = 'NOT_SET', $msg = 'NOT_SET')
    {
        if (bfReply::ERROR === $result) {
            bfLog::log('ERROR = '.json_encode($msg));
        }

        // remove any stray output
        echo ' '; // must have something to clean else warning occurs
        $contents = ob_get_contents();

        if (trim($contents)) {
            bfLog::log('Buffer Contents Found:  '.$contents);
        }

        // tmp debug the buffer
        if (true === _BF_API_DEBUG && $contents) {
            bfLog::log('WE HAVE AN OUTPUT BUFFER - Saving to file for debugging');
            file_put_contents(dirname(__FILE__).'/tmp/tmp.ob', $contents);
        }

        ob_clean();
        // ahhh nice and clean again

        $returnJson = new stdClass();

        // give a helpful hint if auto-login with out of date connector
        if (bfReply::NEEDSCONNECTORUPGRADE === $result) {
            $returnJson->HEY_HUMAN = 'If you can read this then you probably need to upgrade your connector - do this by manually running a snapshot and then try again. This is perfectly normal if we have pushed a new connector version and your site has not had chance to auto-update which happens within 24 hours or on first interaction with your snapshot.'; // This is NOT encrypted
        }

        $returnJson->METHOD = 'Encrypted'; // This is NOT encrypted
        $returnJson->RESULT = $result; // This is NOT encrypted

        // This is encrypted
        $returnJson->ENCRYPTED = bfEncrypt::getEncrypted($msg);

        // This is NOT encrypted
        $returnJson->CLIENT_VER = file_get_contents('./VERSION');

        /**
         * DO NOT ENABLE DEBUG THIS - It will mean that replies are sent as
         * encrypted AND non-encrypted
         * and so this is insecure (albeit very useful during development!).
         */
        $isLocalDevelopmentServer = (defined('APPLICATION_ENV') && (APPLICATION_ENV == 'development' || APPLICATION_ENV == 'local') ? true : false);
        if ($isLocalDevelopmentServer || true === _BF_API_DEBUG && true === _BF_API_REPLY_DEBUG_NEVER_ENABLE_THIS_EVER_WILL_LEAK_CONFIDENTIAL_INFO_IN_RESPONSES) {
            $returnJson->DEBUG = json_encode($msg);
        }

        bfLog::log('Returning encrypted status to server');
        die(json_encode($returnJson));
    }

    /**
     * Encrypt a string using the RC4 Key provided in the encrypted request
     * from the service backend.
     *
     * @param string $msg
     *
     * @return string Base64encoded message
     */
    public static function getEncrypted($msg)
    {
        $start = time();
        bfLog::log('Starting Encryption....');
        // check our msg is a string
        if (is_object($msg) || is_array($msg)) {
            $msg = json_encode($msg);
        }

        // init a RC4 encryption routine - MUCH faster than public/private key
        $rc4 = new Crypt_RC4();

        if (!defined('RC4_KEY')) {
            bfLog::log('NO RC4_KEY FOUND!!');
            die('No Encryption Key');
        }

        // Use the one time encryption key the requester provided
        $rc4->setKey(RC4_KEY);

        // encrypt the data
        $encrypted = $rc4->encrypt($msg);

        // return the data, encoded just in case
        $str = base64_encode($encrypted);
        bfLog::log('Finished Encryption.... took '.(time() - $start).' seconds');

        return $str;
    }
}
PK��#]�RI�$system/bfnetwork/bfnetwork/bfLog.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

class bfLog
{
    const FILE = '/tmp/log.php';

    /**
     * To log do bfLog::log('something');.
     *
     * @param      $msg
     * @param bool $truncate
     */
    public static function log($msg, $truncate = false, $forceThisLineThisTime = false)
    {
        $preferences = new bfPreferences();
        $prefs       = $preferences->getPreferences();

        if (false === $forceThisLineThisTime && false == $prefs->_BF_LOG) {
            return; // Dont log this call...
        }

        if (!is_string($msg)) {
            ob_start();
            var_dump($msg);
            $msg = ob_get_contents();
            ob_end_clean();
        }

        if (file_exists(dirname(__FILE__).bfLog::FILE)) {
            $logSize = number_format(filesize(dirname(__FILE__).bfLog::FILE) / 1024 / 1024, 2);
            if ($logSize > 10) {
                $truncate = true;
            }
        }
        $template = '%s  | %s';
        $msg      = sprintf($template,
            self::getTimestamp(),
            $msg);

        if (true === $truncate) {
            bfLog::truncate();
        }

        file_put_contents(dirname(__FILE__).bfLog::FILE, $msg.PHP_EOL, FILE_APPEND);
    }

    /**
     * I know this looks stupid now, but it allows custimisation of the timestamp in future.
     *
     * @return bool|string
     */
    public static function getTimestamp()
    {
        return date('H:i:s');
    }

    /**
     * Truncate the log file, prepare a new one.
     */
    public static function truncate()
    {
        $preferences = new bfPreferences();
        $prefs       = $preferences->getPreferences();

        bflog::checkPermissions();

        @unlink('tmp/log.tmp');
        @unlink('tmp/log.php');

        // temp change to allow debugging of logs - 82.112.150.169 is a static office IP for Phil.
//        if ($prefs->_BF_LOG) {
        /*            file_put_contents(dirname(__FILE__).bfLog::FILE, '<?php if ($_SERVER["REMOTE_ADDR"] != "82.112.150.169") die("NOTAUTH"); ?>'.PHP_EOL);*/
//        } else {
        file_put_contents(dirname(__FILE__).bfLog::FILE, '<?php die(); ?>'.PHP_EOL);
//        }
        bfLog::log('Log file truncated');

        // populate the config into the log
        bfLog::log('PHP Max Memory = '.ini_get('memory_limit'));
        bfLog::log('PHP ini_setted Max Time = '.ini_get('max_execution_time'));
        bfLog::log('PHP bfTimer Max Time = '.bfTimer::getInstance()
                ->getMaxTime());
    }

    /**
     * Require all we need to work.
     */
    public static function checkPermissions()
    {
        // attempt to ensure our tmp folder is writable
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            @chmod(dirname(__FILE__).'/tmp', 0755);
        }

        // Argh!
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            @chmod(dirname(__FILE__).'/tmp', 0777);
        }

        // Give Up!
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            die('Our '.dirname(__FILE__).'/tmp folder on your site is not writable!');
        }

        // attempt to ensure our folder is writable
        if (!is_writeable(dirname(__FILE__))) {
            @chmod(dirname(__FILE__), 0755);
        }

        // Argh!
        if (!is_writeable(dirname(__FILE__))) {
            @chmod(dirname(__FILE__), 0777);
        }

        // Give Up!
        if (!is_writeable(dirname(__FILE__))) {
            die(dirname(__FILE__).'/ folder not writeable');
        }
    }

    public static function convert($size)
    {
        $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');

        return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2).' '.$unit[$i];
    }

    /**
     * Check we have permissions to write a log file.
     */
    public static function init()
    {
        bfLog::checkPermissions();
    }

    public static function getLog()
    {
        return file_get_contents(dirname(__FILE__).bfLog::FILE);
    }

    /**
     * bfLog::getTail();.
     *
     * @param string $filename
     * @param int    $n
     *
     * @return array
     */
    public static function getTail($filename = null, $n = 1000)
    {
        if (null === $filename) {
            $filename = dirname(__FILE__).bfLog::FILE;
        }

        $buffer_size = 512;

        $fp = fopen($filename, 'r');
        if (!$fp) {
            return array();
        }

        fseek($fp, 0, SEEK_END);
        $pos = ftell($fp);

        $input      = '';
        $line_count = 0;

        while ($line_count < $n + 1) {
            // read the previous block of input
            $read_size = $pos >= $buffer_size ? $buffer_size : $pos;
            fseek($fp, $pos - $read_size, SEEK_SET);

            // prepend the current block, and count the new lines
            $input      = fread($fp, $read_size).$input;
            $line_count = substr_count(ltrim($input), "\n");

            // if $pos is == 0 we are at start of file
            $pos -= $read_size;
            if (!$pos) {
                break;
            }
        }

        // close the file pointer
        fclose($fp);

        // return the last 50 lines found
        return array_reverse(array_slice(explode("\n", rtrim($input)), -$n));
    }
}
PK��#]$=�_��&system/bfnetwork/bfnetwork/bfAudit.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

// Decrypt or die
require 'bfEncrypt.php';

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.....
 * ... ...
 */

// Get the steps
require 'bfStep.php';

if (!file_exists('bfAuditor.php')) {
    bfEncrypt::reply(bfReply::ERROR, 'Your pathetic web host (let me guess, HostGator/DreamHost?) has deleted bfAuditor.php file believing it to be a hackers tool, they really have no right to indiscriminately delete YOUR sites files. This is not my problem, shout at your webhost!');
}

// Get the gutsy auditor tool
require 'bfAuditor.php';

// Tick over... inject the decrypted object
$scanner = new bfAudit($dataObj);

// Tick Tock...
bfLog::log('Tick');
$scanner->tick();
PK��#]�P��#�#'system/bfnetwork/bfnetwork/bfConfig.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 08 Mar 1978 05:00:00 GMT'); // Phil Taylor's Birthday and Time :-)
header('Content-type: application/json');

// buffer it!
ob_start();

$isWin = ('WIN' == substr(PHP_OS, 0, 3));
$sep   = $isWin ? ';' : ':';
@ini_set('include_path', dirname(__FILE__).$sep.ini_get('include_path'));

// Allow persistent overide of the config\

require 'bfPreferences.php';
$preferences = new bfPreferences();
$preferences = $preferences->getPreferences();

if (!defined('_BF_LOG')) {
    define('_BF_LOG', $preferences->_BF_LOG);
}

// Attempt to screw up mysql if we can
@ini_set('mysql.connect_timeout', 300);
@ini_set('default_socket_timeout', 300);

// Set timezone
date_default_timezone_set('UTC'); // Should be "UTC"!

// Attempt to ensure we can access the internet on crap configured hosts
@ini_set('allow_url_fopen', 1);

// Get time limits
define('_BF_ORIGINAL_TIME_LIMIT', @ini_get('max_execution_time'));

// Set memory limits - Yes I know 1024M is a large, but hey ;-)
define('_BF_ORIGINAL_MEMORY_LIMIT', @ini_set('memory_limit', '1024M'));

// Set no display errors to the screen, prevent leaks of information
define('_BF_ORIGINAL_DISPLAY_ERRORS', @ini_set('display_errors', 0));

// Debug mode - never enable this on a live site! default: FALSE
define('_BF_API_DEBUG', false); //should always be  FALSE

// NEVER EVER DEFINE THIS AS TRUE ON A LIVE SITE - WILL leak all replies as non-encrypted!
define('_BF_API_REPLY_DEBUG_NEVER_ENABLE_THIS_EVER_WILL_LEAK_CONFIDENTIAL_INFO_IN_RESPONSES', false); //should always be FALSE

// used in bfAuditor    default: FALSE
define('_BF_CONFIG_RESET_STATE_ON_UPGRADE', false);

// used in bfAuditor    default: 0, 10, 20
define('_BF_CONFIG_FILES_TIMER_ONE', 0);

// used in bfAuditor    default: half of _BF_CONFIG_FILES_TIMER_ONE
define('_BF_CONFIG_FILES_TIMER_TWO', 0);

// used in bfAuditor    default: 0, 10, 20
define('_BF_CONFIG_FOLDERS_TIMER_ONE', 0);

// used in bfAuditor    default: half of _BF_CONFIG_FOLDERS_TIMER_ONE
define('_BF_CONFIG_FOLDERS_TIMER_TWO', 0);

// used in bfAuditor    default: 0, 10, 20
define('_BF_CONFIG_DEEPSCAN_TIMER_ONE', 1);

// not yet used   default: 5
define('_BF_CONFIG_ERROR_RESUME_RETRY_LIMIT', 5);

/**
 * Ok so I know we are using a raw request here... but we want to configure the defaults, log and timer BEFORE
 * we decrypt the encrypted request.
 *
 * we DONT so anything based on the unencrypted data apart from set hardcoded values - there is nothing that can
 * be hacked here,
 */
$allowedValues = array(
    'CRAPPYWEBHOST',
    'FIVE_SECOND_TIMEOUT',
    'SNAIL',
    'DEFAULT',
    'FAST',
);

if (!array_key_exists('SPEED', $_REQUEST)
    || !in_array($_REQUEST['SPEED'], $allowedValues)
    || !@$_REQUEST['SPEED']
) {
    $_REQUEST['SPEED'] = 'DEFAULT';
}

define('_BF_SPEED', $_REQUEST['SPEED']);

switch ($_REQUEST['SPEED']) {
    case 'FAST':
        @ini_set('max_execution_time', 90);

        // used in bfConfig     default: Something stupid large like 90
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_INI', 90);

        // used in bfTimer      default: 10
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME', 60);

        // used in bfTimer      default: null
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_HARD_LIMIT', 60);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FILES_TIMER_ONE
        define('_BF_CONFIG_FILES_COUNT_ONE', 60);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FOLDERS_TIMER_ONE
        define('_BF_CONFIG_FOLDERS_COUNT_ONE', 60);

        // number of folders to scan at a time  default: same as _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_COUNT_ONE', 60);

        // used in bfAuditor    default: half of _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_TIMER_TWO', 0);
        break;
    case 'SNAIL':
        @ini_set('max_execution_time', 60);

        // used in bfConfig     default: Something stupid large like 90
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_INI', 60);

        // used in bfTimer      default: 10
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME', 10);

        // used in bfTimer      default: null
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_HARD_LIMIT', 10);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FILES_TIMER_ONE
        define('_BF_CONFIG_FILES_COUNT_ONE', 10);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FOLDERS_TIMER_ONE
        define('_BF_CONFIG_FOLDERS_COUNT_ONE', 10);

        // number of folders to scan at a time  default: same as _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_COUNT_ONE', 10);

        // used in bfAuditor    default: half of _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_TIMER_TWO', 0);

        break;

    case '20SECGATEWAYTIMEOUT':
    case 'FIVE_SECOND_TIMEOUT':
        @ini_set('max_execution_time', 60);

        // used in bfConfig     default: Something stupid large like 90
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_INI', 60);

        // used in bfTimer      default: 10
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME', 5);

        // used in bfTimer      default: null
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_HARD_LIMIT', 5);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FILES_TIMER_ONE
        define('_BF_CONFIG_FILES_COUNT_ONE', 5);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FOLDERS_TIMER_ONE
        define('_BF_CONFIG_FOLDERS_COUNT_ONE', 5);

        // number of folders to scan at a time  default: same as _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_COUNT_ONE', 5);

        // used in bfAuditor    default: half of _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_TIMER_TWO', 0);
        break;

    case 'CRAPPYWEBHOST':

        @ini_set('max_execution_time', 60);

        // used in bfConfig     default: Something stupid large like 90
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_INI', 60);

        // used in bfTimer      default: 10
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME', 20);

        // used in bfTimer      default: null
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_HARD_LIMIT', 20);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FILES_TIMER_ONE
        define('_BF_CONFIG_FILES_COUNT_ONE', 5);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FOLDERS_TIMER_ONE
        define('_BF_CONFIG_FOLDERS_COUNT_ONE', 5);

        // number of folders to scan at a time  default: same as _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_COUNT_ONE', 5);

        // used in bfAuditor    default: half of _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_TIMER_TWO', 5);
        break;

    case 'DEFAULT':
    default:
        @ini_set('max_execution_time', 60);

        // used in bfConfig     default: Something stupid large like 90
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_INI', 60);

        // used in bfTimer      default: 10
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME', 20);

        // used in bfTimer      default: null
        define('_BF_CONFIG_PHP_MAX_EXEC_TIME_HARD_LIMIT', 20);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FILES_TIMER_ONE
        define('_BF_CONFIG_FILES_COUNT_ONE', 20);

        // number of folders to scan at a time  default: same as _BF_CONFIG_FOLDERS_TIMER_ONE
        define('_BF_CONFIG_FOLDERS_COUNT_ONE', 20);

        // number of folders to scan at a time  default: same as _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_COUNT_ONE', 20);

        // used in bfAuditor    default: half of _BF_CONFIG_DEEPSCAN_TIMER_ONE
        define('_BF_CONFIG_DEEPSCAN_TIMER_TWO', 0);
        break;
}

// Set a very high upper limit - bfTimer will attempt to clear WAYYYYY before this is hit
@set_time_limit(_BF_CONFIG_PHP_MAX_EXEC_TIME_INI);
PK��#]����&�&+system/bfnetwork/bfnetwork/bfFilesystem.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

class Bf_Filesystem
{
    /**
     * @copyright Copyright (c)2010-2011 Nicholas K. Dionysopoulos
     * @license   GNU General Public License version 3, or later
     *
     * @param string $file
     * @param string $buffer
     *
     * @return bool
     */
    public static function _write($file, $buffer)
    {
        // Initialize variables
        jimport('joomla.client.helper');
        jimport('joomla.filesystem.folder');
        jimport('joomla.filesystem.file');
        jimport('joomla.filesystem.path');

        $FTPOptions = JClientHelper::getCredentials('ftp');

        // If the destination directory doesn't exist we need to create it
        if (!file_exists(dirname($file))) {
            JFolder::create(dirname($file));
        }

        if (1 == $FTPOptions['enabled']) {
            // Connect the FTP client
            jimport('joomla.client.ftp');
            if (version_compare(JVERSION, '3.0', 'ge')) {
                $ftp = JClientFTP::getInstance($FTPOptions['host'], $FTPOptions['port'], null, $FTPOptions['user'], $FTPOptions['pass']);
            } else {
                $ftp = JFTP::getInstance($FTPOptions['host'], $FTPOptions['port'], null, $FTPOptions['user'], $FTPOptions['pass']);
            }

            // Translate path for the FTP account and use FTP write buffer to
            // file
            $file = JPath::clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/');
            $ret  = $ftp->write($file, $buffer);
        } else {
            if (!is_writable($file)) {
                chmod($file, 0755);
            }
            if (!is_writable($file)) {
                chmod($file, 0777);
            }
            $ret = @file_put_contents($file, $buffer);
            chmod($file, 0644);
        }
        if (!$ret) {
            jimport('joomla.filesystem.file');
            JFile::write($file, $buffer);
        }

        return $ret;
    }

    /**
     * @param        $path
     * @param string $filter
     * @param bool   $recurse
     * @param bool   $fullpath
     *
     * @return array
     */
    public static function readDirectory($path, $filter = '.', $recurse = false,
                                  $fullpath = false)
    {
        $arr = array();
        if (!@is_dir($path)) {
            return $arr;
        }
        $handle = opendir($path);

        while ($file = readdir($handle)) {
            $dir   = Bf_Filesystem::pathName($path.'/'.$file, false);
            $isDir = is_dir($dir);
            if (('.' != $file) && ('..' != $file)) {
                if (preg_match("/$filter/", $file)) {
                    if ($fullpath) {
                        $arr[] = trim(
                            Bf_Filesystem::pathName($path.'/'.$file, false));
                    } else {
                        $arr[] = trim($file);
                    }
                }
                if ($recurse && $isDir) {
                    $arr2 = Bf_Filesystem::readDirectory($dir, $filter,
                                                         $recurse, $fullpath);
                    $arr = array_merge($arr, $arr2);
                }
            }
        }
        closedir($handle);
        asort($arr);

        return $arr;
    }

    /**
     * @param      $p_path
     * @param bool $p_addtrailingslash
     *
     * @return mixed|string
     */
    public static function pathName($p_path, $p_addtrailingslash = true)
    {
        $retval = '';

        $isWin = ('WIN' == substr(PHP_OS, 0, 3));

        if ($isWin) {
            $retval = str_replace('/', '\\', $p_path);
            if ($p_addtrailingslash) {
                if ('\\' != substr($retval, -1)) {
                    $retval .= '\\';
                }
            }

            // Check if UNC path
            $unc = '\\\\' == substr($retval, 0, 2) ? 1 : 0;

            // Remove double \\
            $retval = str_replace('\\\\', '\\', $retval);

            // If UNC path, we have to add one \ in front or everything breaks!
            if (1 == $unc) {
                $retval = '\\'.$retval;
            }
        } else {
            $retval = str_replace('\\', '/', $p_path);
            if ($p_addtrailingslash) {
                if ('/' != substr($retval, -1)) {
                    $retval .= '/';
                }
            }

            // Check if UNC path
            $unc = '//' == substr($retval, 0, 2) ? 1 : 0;

            // Remove double //
            $retval = str_replace('//', '/', $retval);

            // If UNC path, we have to add one / in front or everything breaks!
            if (1 == $unc) {
                $retval = '/'.$retval;
            }
        }

        return $retval;
    }

    /**
     * returns the directories in the path
     * if append path is set then this path will appended to the results.
     *
     * @param string      $path
     * @param bool|string $appendPath
     *
     * @return array
     */
    public static function getDirectories($path, $appendPath = false)
    {
        if (is_dir($path)) {
            $contents = scandir($path); //open directory and get contents
            if (is_array($contents)) { //it found files
                $returnDirs = false;
                foreach ($contents as $dir) {
                    //validate that this is a directory
                    if (is_dir($path.'/'.$dir) &&
                        '.' != $dir && '..' != $dir && '.svn' != $dir
                    ) {
                        $returnDirs[] = $appendPath.$dir;
                    }
                }

                if ($returnDirs) {
                    return $returnDirs;
                }
            }
        }
    }

    /**
     * adds a complete directory path
     * eg: /my/own/path
     * will create
     * >my
     * >>own
     * >>>path.
     *
     * @param string $base
     * @param string $path
     *
     * @return bool
     */
    public static function makeRecursive($base, $path)
    {
        $pathArray = explode('/', $path);
        if (is_array($pathArray)) {
            $strPath = null;
            foreach ($pathArray as $path) {
                if (!empty($path)) {
                    $strPath .= '/'.$path;
                    if (!is_dir($base.$strPath)) {
                        if (!self::make($base.$strPath)) {
                            return false;
                        }
                    }
                }
            }

            return true;
        }
    }

    /**
     * this is getting a little extreme i know
     * but it will help out later when we want to keep updated indexes
     * for right now, not much.
     *
     * @param string $path
     *
     * @return bool
     */
    public static function make($path)
    {
        return mkdir($path, 0777);
    }

    /**
     * deletes a directory recursively
     * Bf_Filesystem::deleteRecursive(JPATH_ROOT .'/tmp', TRUE);.
     *
     * @param string $target
     * @param bool   $ignoreWarnings
     * @param array  $msg
     *
     * @return bool
     */
    public static function deleteRecursive($target, $ignoreWarnings = false, $msg = array())
    {
        $exceptions = array('.', '..');
        if (!$sourceDir = @opendir($target)) {
            if (true !== $ignoreWarnings) {
                $msg['result']   = 'failure';
                $msg['errors'][] = $target;

                return $msg;
            }
        }

        if (!$sourceDir) {
            return;
        }

        while (false !== ($sibling = readdir($sourceDir))) {
            if (!in_array($sibling, $exceptions)) {
                $object = str_replace('//', '/', $target.'/'.$sibling);
                if (is_dir($object)) {
                    $msg = Bf_Filesystem::deleteRecursive($object,
                                                          $ignoreWarnings, $msg);
                }

                if (is_file($object)) {
                    bfLog::log('Deleting '.$object);

                    $result = unlink($object);
                    if ($result) {
                        $msg['deleted_files'][] = $object;
                    }
                    if (!$result) {
                        $msg['errors'][] = $object;
                    }
                }
            }
        }

        closedir($sourceDir);

        if (is_dir($target)) {
            bfLog::log('Deleting '.$target);

            if ($result = rmdir($target)) {
                $msg['deleted_folders'][] = $target;
                $msg['result']            = 'success';
            } else {
                bfLog::log(sprintf('Deleting %S FAILED', $target));
                $msg['result'] = 'failure';
            }
        } else {
        }

        return $msg;
    }
}
PK��#]��O1[1[$system/bfnetwork/bfnetwork/bfZip.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

if (!class_exists('Bf_Zip')) {
    class Bf_Zip extends PclZip
    {
    }
}

// --------------------------------------------------------------------------------
// PhpConcept Library - Zip Module 2.8.2
// --------------------------------------------------------------------------------
// License GNU/LGPL - Vincent Blavet - August 2009
// http://www.phpconcept.net
// --------------------------------------------------------------------------------
//
// Presentation :
//   PclZip is a PHP library that manage ZIP archives.
//   So far tests show that archives generated by PclZip are readable by
//   WinZip application and other tools.
//
// Description :
//   See readme.txt and http://www.phpconcept.net
//
// Warning :
//   This library and the associated files are non commercial, non professional
//   work.
//   It should not have unexpected results. However if any damage is caused by
//   this software the author can not be responsible.
//   The use of this software is at the risk of the user.
//
// --------------------------------------------------------------------------------
// $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $
// --------------------------------------------------------------------------------

// ----- Constants
if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
    define('PCLZIP_READ_BLOCK_SIZE', 2048);
}

// ----- File list separator
// In version 1.x of PclZip, the separator for file list is a space
// (which is not a very smart choice, specifically for windows paths !).
// A better separator should be a comma (,). This constant gives you the
// abilty to change that.
// However notice that changing this value, may have impact on existing
// scripts, using space separated filenames.
// Recommanded values for compatibility with older versions :
//define( 'PCLZIP_SEPARATOR', ' ' );
// Recommanded values for smart separation of filenames.
if (!defined('PCLZIP_SEPARATOR')) {
    define('PCLZIP_SEPARATOR', ',');
}

// ----- Error configuration
// 0 : PclZip Class integrated error handling
// 1 : PclError external library error handling. By enabling this
//     you must ensure that you have included PclError library.
// [2,...] : reserved for futur use
if (!defined('PCLZIP_ERROR_EXTERNAL')) {
    define('PCLZIP_ERROR_EXTERNAL', 0);
}

// ----- Optional static temporary directory
//       By default temporary files are generated in the script current
//       path.
//       If defined :
//       - MUST BE terminated by a '/'.
//       - MUST be a valid, already created directory
//       Samples :
// define( 'PCLZIP_TEMPORARY_DIR', '/temp/' );
// define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' );
if (!defined('PCLZIP_TEMPORARY_DIR')) {
    define('PCLZIP_TEMPORARY_DIR', '');
}

// ----- Optional threshold ratio for use of temporary files
//       Pclzip sense the size of the file to add/extract and decide to
//       use or not temporary file. The algorythm is looking for
//       memory_limit of PHP and apply a ratio.
//       threshold = memory_limit * ratio.
//       Recommended values are under 0.5. Default 0.47.
//       Samples :
// define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 );
if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
    define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47);
}

// --------------------------------------------------------------------------------
// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
// --------------------------------------------------------------------------------

// ----- Global variables
$g_pclzip_version = '2.8.2';

// ----- Error codes
//   -1 : Unable to open file in binary write mode
//   -2 : Unable to open file in binary read mode
//   -3 : Invalid parameters
//   -4 : File does not exist
//   -5 : Filename is too long (max. 255)
//   -6 : Not a valid zip file
//   -7 : Invalid extracted file size
//   -8 : Unable to create directory
//   -9 : Invalid archive extension
//  -10 : Invalid archive format
//  -11 : Unable to delete file (unlink)
//  -12 : Unable to rename file (rename)
//  -13 : Invalid header checksum
//  -14 : Invalid archive size
define('PCLZIP_ERR_USER_ABORTED', 2);
define('PCLZIP_ERR_NO_ERROR', 0);
define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1);
define('PCLZIP_ERR_READ_OPEN_FAIL', -2);
define('PCLZIP_ERR_INVALID_PARAMETER', -3);
define('PCLZIP_ERR_MISSING_FILE', -4);
define('PCLZIP_ERR_FILENAME_TOO_LONG', -5);
define('PCLZIP_ERR_INVALID_ZIP', -6);
define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7);
define('PCLZIP_ERR_DIR_CREATE_FAIL', -8);
define('PCLZIP_ERR_BAD_EXTENSION', -9);
define('PCLZIP_ERR_BAD_FORMAT', -10);
define('PCLZIP_ERR_DELETE_FILE_FAIL', -11);
define('PCLZIP_ERR_RENAME_FILE_FAIL', -12);
define('PCLZIP_ERR_BAD_CHECKSUM', -13);
define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14);
define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15);
define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16);
define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17);
define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18);
define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19);
define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20);
define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21);

// ----- Options values
define('PCLZIP_OPT_PATH', 77001);
define('PCLZIP_OPT_ADD_PATH', 77002);
define('PCLZIP_OPT_REMOVE_PATH', 77003);
define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004);
define('PCLZIP_OPT_SET_CHMOD', 77005);
define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006);
define('PCLZIP_OPT_NO_COMPRESSION', 77007);
define('PCLZIP_OPT_BY_NAME', 77008);
define('PCLZIP_OPT_BY_INDEX', 77009);
define('PCLZIP_OPT_BY_EREG', 77010);
define('PCLZIP_OPT_BY_PREG', 77011);
define('PCLZIP_OPT_COMMENT', 77012);
define('PCLZIP_OPT_ADD_COMMENT', 77013);
define('PCLZIP_OPT_PREPEND_COMMENT', 77014);
define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015);
define('PCLZIP_OPT_REPLACE_NEWER', 77016);
define('PCLZIP_OPT_STOP_ON_ERROR', 77017);
// Having big trouble with crypt. Need to multiply 2 long int
// which is not correctly supported by PHP ...
//define( 'PCLZIP_OPT_CRYPT', 77018 );
define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019);
define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020);
define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias
define('PCLZIP_OPT_TEMP_FILE_ON', 77021);
define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias
define('PCLZIP_OPT_TEMP_FILE_OFF', 77022);
define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias

// ----- File description attributes
define('PCLZIP_ATT_FILE_NAME', 79001);
define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002);
define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003);
define('PCLZIP_ATT_FILE_MTIME', 79004);
define('PCLZIP_ATT_FILE_CONTENT', 79005);
define('PCLZIP_ATT_FILE_COMMENT', 79006);

// ----- Call backs values
define('PCLZIP_CB_PRE_EXTRACT', 78001);
define('PCLZIP_CB_POST_EXTRACT', 78002);
define('PCLZIP_CB_PRE_ADD', 78003);
define('PCLZIP_CB_POST_ADD', 78004);
/* For futur use
  define( 'PCLZIP_CB_PRE_LIST', 78005 );
  define( 'PCLZIP_CB_POST_LIST', 78006 );
  define( 'PCLZIP_CB_PRE_DELETE', 78007 );
  define( 'PCLZIP_CB_POST_DELETE', 78008 );
  */

// --------------------------------------------------------------------------------
// Class : PclZip
// Description :
//   PclZip is the class that represent a Zip archive.
//   The public methods allow the manipulation of the archive.
// Attributes :
//   Attributes must not be accessed directly.
// Methods :
//   PclZip() : Object creator
//   create() : Creates the Zip archive
//   listContent() : List the content of the Zip archive
//   extract() : Extract the content of the archive
//   properties() : List the properties of the archive
// --------------------------------------------------------------------------------
class PclZip
{
    // ----- Filename of the zip file
    public $zipname = '';

    // ----- File descriptor of the zip file
    public $zip_fd = 0;

    // ----- Internal error handling
    public $error_code   = 1;
    public $error_string = '';

    // ----- Current status of the magic_quotes_runtime
    // This value store the php configuration for magic_quotes
    // The class can then disable the magic_quotes and reset it after
    public $magic_quotes_status;

    // --------------------------------------------------------------------------------
    // Function : PclZip()
    // Description :
    //   Creates a PclZip object and set the name of the associated Zip archive
    //   filename.
    //   Note that no real action is taken, if the archive does not exist it is not
    //   created. Use create() for that.
    // --------------------------------------------------------------------------------
    // Function name changed for PHP 7 :-)
    public function __construct($p_zipname)
    {
        // Handle ubuntu that doesnt have gzopen but does have gzopen64
        if (!function_exists('gzopen') && function_exists('gzopen64')) {
            function gzopen($filename, $mode, $use_include_path = 0)
            {
                return gzopen64($filename, $mode, $use_include_path);
            }
        }

        if (!function_exists('gzopen')) {
            die('Abort '.basename(__FILE__).' : Missing zlib extensions');
        }

        // ----- Set the attributes
        $this->zipname             = $p_zipname;
        $this->zip_fd              = 0;
        $this->magic_quotes_status = -1;

        // ----- Return
        return;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function :
    //   create($p_filelist, $p_add_dir="", $p_remove_dir="")
    //   create($p_filelist, $p_option, $p_option_value, ...)
    // Description :
    //   This method supports two different synopsis. The first one is historical.
    //   This method creates a Zip Archive. The Zip file is created in the
    //   filesystem. The files and directories indicated in $p_filelist
    //   are added in the archive. See the parameters description for the
    //   supported format of $p_filelist.
    //   When a directory is in the list, the directory and its content is added
    //   in the archive.
    //   In this synopsis, the function takes an optional variable list of
    //   options. See bellow the supported options.
    // Parameters :
    //   $p_filelist : An array containing file or directory names, or
    //                 a string containing one filename or one directory name, or
    //                 a string containing a list of filenames and/or directory
    //                 names separated by spaces.
    //   $p_add_dir : A path to add before the real path of the archived file,
    //                in order to have it memorized in the archive.
    //   $p_remove_dir : A path to remove from the real path of the file to archive,
    //                   in order to have a shorter path memorized in the archive.
    //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir
    //                   is removed first, before $p_add_dir is added.
    // Options :
    //   PCLZIP_OPT_ADD_PATH :
    //   PCLZIP_OPT_REMOVE_PATH :
    //   PCLZIP_OPT_REMOVE_ALL_PATH :
    //   PCLZIP_OPT_COMMENT :
    //   PCLZIP_CB_PRE_ADD :
    //   PCLZIP_CB_POST_ADD :
    // Return Values :
    //   0 on failure,
    //   The list of the added files, with a status of the add action.
    //   (see PclZip::listContent() for list entry format)
    // --------------------------------------------------------------------------------
    public function create($p_filelist)
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Set default values
        $v_options                            = array();
        $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;

        // ----- Look for variable options arguments
        $v_size = func_num_args();

        // ----- Look for arguments
        if ($v_size > 1) {
            // ----- Get the arguments
            $v_arg_list = func_get_args();

            // ----- Remove from the options list the first argument
            array_shift($v_arg_list);
            --$v_size;

            // ----- Look for first arg
            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
                // ----- Parse the options
                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
                    array(PCLZIP_OPT_REMOVE_PATH         => 'optional',
                          PCLZIP_OPT_REMOVE_ALL_PATH     => 'optional',
                          PCLZIP_OPT_ADD_PATH            => 'optional',
                          PCLZIP_CB_PRE_ADD              => 'optional',
                          PCLZIP_CB_POST_ADD             => 'optional',
                          PCLZIP_OPT_NO_COMPRESSION      => 'optional',
                          PCLZIP_OPT_COMMENT             => 'optional',
                          PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
                          PCLZIP_OPT_TEMP_FILE_ON        => 'optional',
                          PCLZIP_OPT_TEMP_FILE_OFF       => 'optional',
                        //, PCLZIP_OPT_CRYPT => 'optional'
                    ));
                if (1 != $v_result) {
                    return 0;
                }
            } // ----- Look for 2 args
            // Here we need to support the first historic synopsis of the
            // method.
            else {
                // ----- Get the first argument
                $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];

                // ----- Look for the optional second argument
                if (2 == $v_size) {
                    $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
                } elseif ($v_size > 2) {
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
                        'Invalid number / type of arguments');

                    return 0;
                }
            }
        }

        // ----- Look for default option values
        $this->privOptionDefaultThreshold($v_options);

        // ----- Init
        $v_string_list    = array();
        $v_att_list       = array();
        $v_filedescr_list = array();
        $p_result_list    = array();

        // ----- Look if the $p_filelist is really an array
        if (is_array($p_filelist)) {
            // ----- Look if the first element is also an array
            //       This will mean that this is a file description entry
            if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
                $v_att_list = $p_filelist;
            } // ----- The list is a list of string names
            else {
                $v_string_list = $p_filelist;
            }
        } // ----- Look if the $p_filelist is a string
        elseif (is_string($p_filelist)) {
            // ----- Create a list from the string
            $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
        } // ----- Invalid variable type for $p_filelist
        else {
            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_filelist');

            return 0;
        }

        // ----- Reformat the string list
        if (0 != sizeof($v_string_list)) {
            foreach ($v_string_list as $v_string) {
                if ('' != $v_string) {
                    $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
                } else {
                }
            }
        }

        // ----- For each file in the list check the attributes
        $v_supported_attributes
            = array(PCLZIP_ATT_FILE_NAME           => 'mandatory',
                    PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
                    PCLZIP_ATT_FILE_NEW_FULL_NAME  => 'optional',
                    PCLZIP_ATT_FILE_MTIME          => 'optional',
                    PCLZIP_ATT_FILE_CONTENT        => 'optional',
                    PCLZIP_ATT_FILE_COMMENT        => 'optional',
        );
        foreach ($v_att_list as $v_entry) {
            $v_result = $this->privFileDescrParseAtt($v_entry,
                $v_filedescr_list,
                $v_options,
                $v_supported_attributes);
            if (1 != $v_result) {
                return 0;
            }
        }

        // ----- Expand the filelist (expand directories)
        $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
        if (1 != $v_result) {
            return 0;
        }

        // ----- Call the create fct
        $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
        if (1 != $v_result) {
            return 0;
        }

        // ----- Return
        return $p_result_list;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function :
    //   add($p_filelist, $p_add_dir="", $p_remove_dir="")
    //   add($p_filelist, $p_option, $p_option_value, ...)
    // Description :
    //   This method supports two synopsis. The first one is historical.
    //   This methods add the list of files in an existing archive.
    //   If a file with the same name already exists, it is added at the end of the
    //   archive, the first one is still present.
    //   If the archive does not exist, it is created.
    // Parameters :
    //   $p_filelist : An array containing file or directory names, or
    //                 a string containing one filename or one directory name, or
    //                 a string containing a list of filenames and/or directory
    //                 names separated by spaces.
    //   $p_add_dir : A path to add before the real path of the archived file,
    //                in order to have it memorized in the archive.
    //   $p_remove_dir : A path to remove from the real path of the file to archive,
    //                   in order to have a shorter path memorized in the archive.
    //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir
    //                   is removed first, before $p_add_dir is added.
    // Options :
    //   PCLZIP_OPT_ADD_PATH :
    //   PCLZIP_OPT_REMOVE_PATH :
    //   PCLZIP_OPT_REMOVE_ALL_PATH :
    //   PCLZIP_OPT_COMMENT :
    //   PCLZIP_OPT_ADD_COMMENT :
    //   PCLZIP_OPT_PREPEND_COMMENT :
    //   PCLZIP_CB_PRE_ADD :
    //   PCLZIP_CB_POST_ADD :
    // Return Values :
    //   0 on failure,
    //   The list of the added files, with a status of the add action.
    //   (see PclZip::listContent() for list entry format)
    // --------------------------------------------------------------------------------

    public function privErrorReset()
    {
        if (PCLZIP_ERROR_EXTERNAL == 1) {
            PclErrorReset();
        } else {
            $this->error_code   = 0;
            $this->error_string = '';
        }
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : listContent()
    // Description :
    //   This public method, gives the list of the files and directories, with their
    //   properties.
    //   The properties of each entries in the list are (used also in other functions) :
    //     filename : Name of the file. For a create or add action it is the filename
    //                given by the user. For an extract function it is the filename
    //                of the extracted file.
    //     stored_filename : Name of the file / directory stored in the archive.
    //     size : Size of the stored file.
    //     compressed_size : Size of the file's data compressed in the archive
    //                       (without the headers overhead)
    //     mtime : Last known modification date of the file (UNIX timestamp)
    //     comment : Comment associated with the file
    //     folder : true | false
    //     index : index of the file in the archive
    //     status : status of the action (depending of the action) :
    //              Values are :
    //                ok : OK !
    //                filtered : the file / dir is not extracted (filtered by user)
    //                already_a_directory : the file can not be extracted because a
    //                                      directory with the same name already exists
    //                write_protected : the file can not be extracted because a file
    //                                  with the same name already exists and is
    //                                  write protected
    //                newer_exist : the file was not extracted because a newer file exists
    //                path_creation_fail : the file is not extracted because the folder
    //                                     does not exist and can not be created
    //                write_error : the file was not extracted because there was a
    //                              error while writing the file
    //                read_error : the file was not extracted because there was a error
    //                             while reading the file
    //                invalid_header : the file was not extracted because of an archive
    //                                 format error (bad file header)
    //   Note that each time a method can continue operating when there
    //   is an action error on a file, the error is only logged in the file status.
    // Return Values :
    //   0 on an unrecoverable failure,
    //   The list of the files in the archive.
    // --------------------------------------------------------------------------------

    public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false)
    {
        $v_result = 1;

        // ----- Read the options
        $i = 0;
        while ($i < $p_size) {
            // ----- Check if the option is supported
            if (!isset($v_requested_options[$p_options_list[$i]])) {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");

                // ----- Return
                return PclZip::errorCode();
            }

            // ----- Look for next option
            switch ($p_options_list[$i]) {
                // ----- Look for options that request a path value
                case PCLZIP_OPT_PATH:
                case PCLZIP_OPT_REMOVE_PATH:
                case PCLZIP_OPT_ADD_PATH:
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);
                    ++$i;
                    break;

                case PCLZIP_OPT_TEMP_FILE_THRESHOLD:
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        return PclZip::errorCode();
                    }

                    // ----- Check for incompatible options
                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");

                        return PclZip::errorCode();
                    }

                    // ----- Check the value
                    $v_value = $p_options_list[$i + 1];
                    if ((!is_integer($v_value)) || ($v_value < 0)) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        return PclZip::errorCode();
                    }

                    // ----- Get the value (and convert it in bytes)
                    $v_result_list[$p_options_list[$i]] = $v_value * 1048576;
                    ++$i;
                    break;

                case PCLZIP_OPT_TEMP_FILE_ON:
                    // ----- Check for incompatible options
                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");

                        return PclZip::errorCode();
                    }

                    $v_result_list[$p_options_list[$i]] = true;
                    break;

                case PCLZIP_OPT_TEMP_FILE_OFF:
                    // ----- Check for incompatible options
                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");

                        return PclZip::errorCode();
                    }
                    // ----- Check for incompatible options
                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");

                        return PclZip::errorCode();
                    }

                    $v_result_list[$p_options_list[$i]] = true;
                    break;

                case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION:
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    if (is_string($p_options_list[$i + 1])
                        && ('' != $p_options_list[$i + 1])
                    ) {
                        $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);
                        ++$i;
                    } else {
                    }
                    break;

                // ----- Look for options that request an array of string for value
                case PCLZIP_OPT_BY_NAME:
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    if (is_string($p_options_list[$i + 1])) {
                        $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1];
                    } elseif (is_array($p_options_list[$i + 1])) {
                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
                    } else {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }
                    ++$i;
                    break;

                // ----- Look for options that request an EREG or PREG expression
                case PCLZIP_OPT_BY_EREG:
                    // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
                    // to PCLZIP_OPT_BY_PREG
                    $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
                    // no break
                case PCLZIP_OPT_BY_PREG:
                    //case PCLZIP_OPT_CRYPT :
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    if (is_string($p_options_list[$i + 1])) {
                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
                    } else {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }
                    ++$i;
                    break;

                // ----- Look for options that takes a string
                case PCLZIP_OPT_COMMENT:
                case PCLZIP_OPT_ADD_COMMENT:
                case PCLZIP_OPT_PREPEND_COMMENT:
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
                            "Missing parameter value for option '"
                            .PclZipUtilOptionText($p_options_list[$i])
                            ."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    if (is_string($p_options_list[$i + 1])) {
                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
                    } else {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
                            "Wrong parameter value for option '"
                            .PclZipUtilOptionText($p_options_list[$i])
                            ."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }
                    ++$i;
                    break;

                // ----- Look for options that request an array of index
                case PCLZIP_OPT_BY_INDEX:
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    $v_work_list = array();
                    if (is_string($p_options_list[$i + 1])) {
                        // ----- Remove spaces
                        $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', '');

                        // ----- Parse items
                        $v_work_list = explode(',', $p_options_list[$i + 1]);
                    } elseif (is_integer($p_options_list[$i + 1])) {
                        $v_work_list[0] = $p_options_list[$i + 1].'-'.$p_options_list[$i + 1];
                    } elseif (is_array($p_options_list[$i + 1])) {
                        $v_work_list = $p_options_list[$i + 1];
                    } else {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Reduce the index list
                    // each index item in the list must be a couple with a start and
                    // an end value : [0,3], [5-5], [8-10], ...
                    // ----- Check the format of each item
                    $v_sort_flag  = false;
                    $v_sort_value = 0;
                    for ($j = 0; $j < sizeof($v_work_list); ++$j) {
                        // ----- Explode the item
                        $v_item_list      = explode('-', $v_work_list[$j]);
                        $v_size_item_list = sizeof($v_item_list);

                        // ----- TBC : Here we might check that each item is a
                        // real integer ...

                        // ----- Look for single value
                        if (1 == $v_size_item_list) {
                            // ----- Set the option value
                            $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
                            $v_result_list[$p_options_list[$i]][$j]['end']   = $v_item_list[0];
                        } elseif (2 == $v_size_item_list) {
                            // ----- Set the option value
                            $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
                            $v_result_list[$p_options_list[$i]][$j]['end']   = $v_item_list[1];
                        } else {
                            // ----- Error log
                            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                            // ----- Return
                            return PclZip::errorCode();
                        }

                        // ----- Look for list sort
                        if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
                            $v_sort_flag = true;

                            // ----- TBC : An automatic sort should be writen ...
                            // ----- Error log
                            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                            // ----- Return
                            return PclZip::errorCode();
                        }
                        $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
                    }

                    // ----- Sort the items
                    if ($v_sort_flag) {
                        // TBC : To Be Completed
                    }

                    // ----- Next option
                    ++$i;
                    break;

                // ----- Look for options that request no value
                case PCLZIP_OPT_REMOVE_ALL_PATH:
                case PCLZIP_OPT_EXTRACT_AS_STRING:
                case PCLZIP_OPT_NO_COMPRESSION:
                case PCLZIP_OPT_EXTRACT_IN_OUTPUT:
                case PCLZIP_OPT_REPLACE_NEWER:
                case PCLZIP_OPT_STOP_ON_ERROR:
                    $v_result_list[$p_options_list[$i]] = true;
                    break;

                // ----- Look for options that request an octal value
                case PCLZIP_OPT_SET_CHMOD:
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
                    ++$i;
                    break;

                // ----- Look for options that request a call-back
                case PCLZIP_CB_PRE_EXTRACT:
                case PCLZIP_CB_POST_EXTRACT:
                case PCLZIP_CB_PRE_ADD:
                case PCLZIP_CB_POST_ADD:
                    /* for futur use
        case PCLZIP_CB_PRE_DELETE :
        case PCLZIP_CB_POST_DELETE :
        case PCLZIP_CB_PRE_LIST :
        case PCLZIP_CB_POST_LIST :
        */
                    // ----- Check the number of parameters
                    if (($i + 1) >= $p_size) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Get the value
                    $v_function_name = $p_options_list[$i + 1];

                    // ----- Check that the value is a valid existing function
                    if (!function_exists($v_function_name)) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");

                        // ----- Return
                        return PclZip::errorCode();
                    }

                    // ----- Set the attribute
                    $v_result_list[$p_options_list[$i]] = $v_function_name;
                    ++$i;
                    break;

                default:
                    // ----- Error log
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
                        "Unknown parameter '"
                        .$p_options_list[$i]."'");

                    // ----- Return
                    return PclZip::errorCode();
            }

            // ----- Next options
            ++$i;
        }

        // ----- Look for mandatory options
        if (false !== $v_requested_options) {
            for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
                // ----- Look for mandatory option
                if ('mandatory' == $v_requested_options[$key]) {
                    // ----- Look if present
                    if (!isset($v_result_list[$key])) {
                        // ----- Error log
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Missing mandatory parameter '.PclZipUtilOptionText($key).'('.$key.')');

                        // ----- Return
                        return PclZip::errorCode();
                    }
                }
            }
        }

        // ----- Look for default values
        if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function :
    //   extract($p_path="./", $p_remove_path="")
    //   extract([$p_option, $p_option_value, ...])
    // Description :
    //   This method supports two synopsis. The first one is historical.
    //   This method extract all the files / directories from the archive to the
    //   folder indicated in $p_path.
    //   If you want to ignore the 'root' part of path of the memorized files
    //   you can indicate this in the optional $p_remove_path parameter.
    //   By default, if a newer file with the same name already exists, the
    //   file is not extracted.
    //
    //   If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
    //   are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
    //   at the end of the path value of PCLZIP_OPT_PATH.
    // Parameters :
    //   $p_path : Path where the files and directories are to be extracted
    //   $p_remove_path : First part ('root' part) of the memorized path
    //                    (if any similar) to remove while extracting.
    // Options :
    //   PCLZIP_OPT_PATH :
    //   PCLZIP_OPT_ADD_PATH :
    //   PCLZIP_OPT_REMOVE_PATH :
    //   PCLZIP_OPT_REMOVE_ALL_PATH :
    //   PCLZIP_CB_PRE_EXTRACT :
    //   PCLZIP_CB_POST_EXTRACT :
    // Return Values :
    //   0 or a negative value on failure,
    //   The list of the extracted files, with a status of the action.
    //   (see PclZip::listContent() for list entry format)
    // --------------------------------------------------------------------------------

    public function privErrorLog($p_error_code = 0, $p_error_string = '')
    {
        if (PCLZIP_ERROR_EXTERNAL == 1) {
            PclError($p_error_code, $p_error_string);
        } else {
            $this->error_code   = $p_error_code;
            $this->error_string = $p_error_string;
        }
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function :
    //   extractByIndex($p_index, $p_path="./", $p_remove_path="")
    //   extractByIndex($p_index, [$p_option, $p_option_value, ...])
    // Description :
    //   This method supports two synopsis. The first one is historical.
    //   This method is doing a partial extract of the archive.
    //   The extracted files or folders are identified by their index in the
    //   archive (from 0 to n).
    //   Note that if the index identify a folder, only the folder entry is
    //   extracted, not all the files included in the archive.
    // Parameters :
    //   $p_index : A single index (integer) or a string of indexes of files to
    //              extract. The form of the string is "0,4-6,8-12" with only numbers
    //              and '-' for range or ',' to separate ranges. No spaces or ';'
    //              are allowed.
    //   $p_path : Path where the files and directories are to be extracted
    //   $p_remove_path : First part ('root' part) of the memorized path
    //                    (if any similar) to remove while extracting.
    // Options :
    //   PCLZIP_OPT_PATH :
    //   PCLZIP_OPT_ADD_PATH :
    //   PCLZIP_OPT_REMOVE_PATH :
    //   PCLZIP_OPT_REMOVE_ALL_PATH :
    //   PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
    //     not as files.
    //     The resulting content is in a new field 'content' in the file
    //     structure.
    //     This option must be used alone (any other options are ignored).
    //   PCLZIP_CB_PRE_EXTRACT :
    //   PCLZIP_CB_POST_EXTRACT :
    // Return Values :
    //   0 on failure,
    //   The list of the extracted files, with a status of the action.
    //   (see PclZip::listContent() for list entry format)
    // --------------------------------------------------------------------------------
    //function extractByIndex($p_index, options...)

    public function errorCode()
    {
        if (PCLZIP_ERROR_EXTERNAL == 1) {
            return PclErrorCode();
        } else {
            return $this->error_code;
        }
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function :
    //   delete([$p_option, $p_option_value, ...])
    // Description :
    //   This method removes files from the archive.
    //   If no parameters are given, then all the archive is emptied.
    // Parameters :
    //   None or optional arguments.
    // Options :
    //   PCLZIP_OPT_BY_INDEX :
    //   PCLZIP_OPT_BY_NAME :
    //   PCLZIP_OPT_BY_EREG :
    //   PCLZIP_OPT_BY_PREG :
    // Return Values :
    //   0 on failure,
    //   The list of the files which are still present in the archive.
    //   (see PclZip::listContent() for list entry format)
    // --------------------------------------------------------------------------------

    public function privOptionDefaultThreshold(&$p_options)
    {
        $v_result = 1;

        if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
            || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])
        ) {
            return $v_result;
        }

        // ----- Get 'memory_limit' configuration value
        $v_memory_limit = ini_get('memory_limit');
        $v_memory_limit = trim($v_memory_limit);
        $last           = strtolower(substr($v_memory_limit, -1));

        if ('g' == $last) {
            //$v_memory_limit = $v_memory_limit*1024*1024*1024;
            $v_memory_limit = $v_memory_limit * 1073741824;
        }
        if ('m' == $last) {
            //$v_memory_limit = $v_memory_limit*1024*1024;
            $v_memory_limit = $v_memory_limit * 1048576;
        }
        if ('k' == $last) {
            $v_memory_limit = $v_memory_limit * 1024;
        }

        $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO);

        // ----- Sanity check : No threshold if value lower than 1M
        if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
            unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : deleteByIndex()
    // Description :
    //   ***** Deprecated *****
    //   delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
    // --------------------------------------------------------------------------------

    public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false)
    {
        $v_result = 1;

        // ----- For each file in the list check the attributes
        foreach ($p_file_list as $v_key => $v_value) {
            // ----- Check if the option is supported
            if (!isset($v_requested_options[$v_key])) {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");

                // ----- Return
                return PclZip::errorCode();
            }

            // ----- Look for attribute
            switch ($v_key) {
                case PCLZIP_ATT_FILE_NAME:
                    if (!is_string($v_value)) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, 'Invalid type '.gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }

                    $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);

                    if ('' == $p_filedescr['filename']) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }

                    break;

                case PCLZIP_ATT_FILE_NEW_SHORT_NAME:
                    if (!is_string($v_value)) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, 'Invalid type '.gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }

                    $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);

                    if ('' == $p_filedescr['new_short_name']) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }
                    break;

                case PCLZIP_ATT_FILE_NEW_FULL_NAME:
                    if (!is_string($v_value)) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, 'Invalid type '.gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }

                    $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);

                    if ('' == $p_filedescr['new_full_name']) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }
                    break;

                // ----- Look for options that takes a string
                case PCLZIP_ATT_FILE_COMMENT:
                    if (!is_string($v_value)) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, 'Invalid type '.gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }

                    $p_filedescr['comment'] = $v_value;
                    break;

                case PCLZIP_ATT_FILE_MTIME:
                    if (!is_integer($v_value)) {
                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, 'Invalid type '.gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");

                        return PclZip::errorCode();
                    }

                    $p_filedescr['mtime'] = $v_value;
                    break;

                case PCLZIP_ATT_FILE_CONTENT:
                    $p_filedescr['content'] = $v_value;
                    break;

                default:
                    // ----- Error log
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
                        "Unknown parameter '".$v_key."'");

                    // ----- Return
                    return PclZip::errorCode();
            }

            // ----- Look for mandatory options
            if (false !== $v_requested_options) {
                for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
                    // ----- Look for mandatory option
                    if ('mandatory' == $v_requested_options[$key]) {
                        // ----- Look if present
                        if (!isset($p_file_list[$key])) {
                            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Missing mandatory parameter '.PclZipUtilOptionText($key).'('.$key.')');

                            return PclZip::errorCode();
                        }
                    }
                }
            }

            // end foreach
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : properties()
    // Description :
    //   This method gives the properties of the archive.
    //   The properties are :
    //     nb : Number of files in the archive
    //     comment : Comment associated with the archive file
    //     status : not_exist, ok
    // Parameters :
    //   None
    // Return Values :
    //   0 on failure,
    //   An array with the archive properties.
    // --------------------------------------------------------------------------------

    public function privFileDescrExpand(&$p_filedescr_list, &$p_options)
    {
        $v_result = 1;

        // ----- Create a result list
        $v_result_list = array();

        // ----- Look each entry
        for ($i = 0; $i < sizeof($p_filedescr_list); ++$i) {
            // ----- Get filedescr
            $v_descr = $p_filedescr_list[$i];

            // ----- Reduce the filename
            $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
            $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);

            // ----- Look for real file or folder
            if (file_exists($v_descr['filename'])) {
                if (@is_file($v_descr['filename'])) {
                    $v_descr['type'] = 'file';
                } elseif (@is_dir($v_descr['filename'])) {
                    $v_descr['type'] = 'folder';
                } elseif (@is_link($v_descr['filename'])) {
                    // skip
                    continue;
                } else {
                    // skip
                    continue;
                }
            } // ----- Look for string added as file
            elseif (isset($v_descr['content'])) {
                $v_descr['type'] = 'virtual_file';
            } // ----- Missing file
            else {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");

                // ----- Return
                return PclZip::errorCode();
            }

            // ----- Calculate the stored filename
            $this->privCalculateStoredFilename($v_descr, $p_options);

            // ----- Add the descriptor in result list
            $v_result_list[sizeof($v_result_list)] = $v_descr;

            // ----- Look for folder
            if ('folder' == $v_descr['type']) {
                // ----- List of items in folder
                $v_dirlist_descr = array();
                $v_dirlist_nb    = 0;
                if ($v_folder_handler = @opendir($v_descr['filename'])) {
                    while (false !== ($v_item_handler = @readdir($v_folder_handler))) {
                        // ----- Skip '.' and '..'
                        if (('.' == $v_item_handler) || ('..' == $v_item_handler)) {
                            continue;
                        }

                        // ----- Compose the full filename
                        $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;

                        // ----- Look for different stored filename
                        // Because the name of the folder was changed, the name of the
                        // files/sub-folders also change
                        if (($v_descr['stored_filename'] != $v_descr['filename'])
                            && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
                        ) {
                            if ('' != $v_descr['stored_filename']) {
                                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
                            } else {
                                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
                            }
                        }

                        ++$v_dirlist_nb;
                    }

                    @closedir($v_folder_handler);
                } else {
                    // TBC : unable to open folder in read mode
                }

                // ----- Expand each element of the list
                if (0 != $v_dirlist_nb) {
                    // ----- Expand
                    if (1 != ($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options))) {
                        return $v_result;
                    }

                    // ----- Concat the resulting list
                    $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
                } else {
                }

                // ----- Free local array
                unset($v_dirlist_descr);
            }
        }

        // ----- Get the result list
        $p_filedescr_list = $v_result_list;

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : duplicate()
    // Description :
    //   This method creates an archive by copying the content of an other one. If
    //   the archive already exist, it is replaced by the new one without any warning.
    // Parameters :
    //   $p_archive : The filename of a valid archive, or
    //                a valid PclZip object.
    // Return Values :
    //   1 on success.
    //   0 or a negative value on error (error code).
    // --------------------------------------------------------------------------------

    public function privCalculateStoredFilename(&$p_filedescr, &$p_options)
    {
        $v_result = 1;

        // ----- Working variables
        $p_filename = $p_filedescr['filename'];
        if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
            $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
        } else {
            $p_add_dir = '';
        }
        if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
            $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
        } else {
            $p_remove_dir = '';
        }
        if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
            $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
        } else {
            $p_remove_all_dir = 0;
        }

        // ----- Look for full name change
        if (isset($p_filedescr['new_full_name'])) {
            // ----- Remove drive letter if any
            $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
        } // ----- Look for path and/or short name change
        else {
            // ----- Look for short name change
            // Its when we cahnge just the filename but not the path
            if (isset($p_filedescr['new_short_name'])) {
                $v_path_info = pathinfo($p_filename);
                $v_dir       = '';
                if ('' != $v_path_info['dirname']) {
                    $v_dir = $v_path_info['dirname'].'/';
                }
                $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
            } else {
                // ----- Calculate the stored filename
                $v_stored_filename = $p_filename;
            }

            // ----- Look for all path to remove
            if ($p_remove_all_dir) {
                $v_stored_filename = basename($p_filename);
            } // ----- Look for partial path remove
            elseif ('' != $p_remove_dir) {
                if ('/' != substr($p_remove_dir, -1)) {
                    $p_remove_dir .= '/';
                }

                if (('./' == substr($p_filename, 0, 2))
                    || ('./' == substr($p_remove_dir, 0, 2))
                ) {
                    if (('./' == substr($p_filename, 0, 2))
                        && ('./' != substr($p_remove_dir, 0, 2))
                    ) {
                        $p_remove_dir = './'.$p_remove_dir;
                    }
                    if (('./' != substr($p_filename, 0, 2))
                        && ('./' == substr($p_remove_dir, 0, 2))
                    ) {
                        $p_remove_dir = substr($p_remove_dir, 2);
                    }
                }

                $v_compare = PclZipUtilPathInclusion($p_remove_dir,
                    $v_stored_filename);
                if ($v_compare > 0) {
                    if (2 == $v_compare) {
                        $v_stored_filename = '';
                    } else {
                        $v_stored_filename = substr($v_stored_filename,
                            strlen($p_remove_dir));
                    }
                }
            }

            // ----- Remove drive letter if any
            $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);

            // ----- Look for path to add
            if ('' != $p_add_dir) {
                if ('/' == substr($p_add_dir, -1)) {
                    $v_stored_filename = $p_add_dir.$v_stored_filename;
                } else {
                    $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
                }
            }
        }

        // ----- Filename (reduce the path of stored name)
        $v_stored_filename              = PclZipUtilPathReduction($v_stored_filename);
        $p_filedescr['stored_filename'] = $v_stored_filename;

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : merge()
    // Description :
    //   This method merge the $p_archive_to_add archive at the end of the current
    //   one ($this).
    //   If the archive ($this) does not exist, the merge becomes a duplicate.
    //   If the $p_archive_to_add archive does not exist, the merge is a success.
    // Parameters :
    //   $p_archive_to_add : It can be directly the filename of a valid zip archive,
    //                       or a PclZip object archive.
    // Return Values :
    //   1 on success,
    //   0 or negative values on error (see below).
    // --------------------------------------------------------------------------------

    public function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
    {
        $v_result      = 1;
        $v_list_detail = array();

        // ----- Magic quotes trick
        $this->privDisableMagicQuotes();

        // ----- Open the file in write mode
        if (1 != ($v_result = $this->privOpenFd('wb'))) {
            // ----- Return
            return $v_result;
        }

        // ----- Add the list of files
        $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);

        // ----- Close
        $this->privCloseFd();

        // ----- Magic quotes trick
        $this->privSwapBackMagicQuotes();

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : errorCode()
    // Description :
    // Parameters :
    // --------------------------------------------------------------------------------

    public function privDisableMagicQuotes()
    {
        $v_result = 1;

        // ----- Look if function exists
        if ((!function_exists('get_magic_quotes_runtime'))
            || (!function_exists('set_magic_quotes_runtime'))
        ) {
            return $v_result;
        }

        // ----- Look if already done
        if (-1 != $this->magic_quotes_status) {
            return $v_result;
        }

        // ----- Get and memorize the magic_quote value
        $this->magic_quotes_status = @get_magic_quotes_runtime();

        // ----- Disable magic_quotes
        if (1 == $this->magic_quotes_status) {
            @set_magic_quotes_runtime(0);
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : errorName()
    // Description :
    // Parameters :
    // --------------------------------------------------------------------------------

    public function privOpenFd($p_mode)
    {
        $v_result = 1;

        // ----- Look if already open
        if (0 != $this->zip_fd) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Open the zip file
        if (0 == ($this->zip_fd = @fopen($this->zipname, $p_mode))) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : errorInfo()
    // Description :
    // Parameters :
    // --------------------------------------------------------------------------------

    public function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
    {
        $v_result = 1;

        // ----- Add the files
        $v_header_list = array();
        if (1 != ($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options))) {
            // ----- Return
            return $v_result;
        }

        // ----- Store the offset of the central dir
        $v_offset = @ftell($this->zip_fd);

        // ----- Create the Central Dir files header
        for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); ++$i) {
            // ----- Create the file header
            if ('ok' == $v_header_list[$i]['status']) {
                if (1 != ($v_result = $this->privWriteCentralFileHeader($v_header_list[$i]))) {
                    // ----- Return
                    return $v_result;
                }
                ++$v_count;
            }

            // ----- Transform the header to a 'usable' info
            $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
        }

        // ----- Zip file comment
        $v_comment = '';
        if (isset($p_options[PCLZIP_OPT_COMMENT])) {
            $v_comment = $p_options[PCLZIP_OPT_COMMENT];
        }

        // ----- Calculate the size of the central header
        $v_size = @ftell($this->zip_fd) - $v_offset;

        // ----- Create the central dir footer
        if (1 != ($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment))) {
            // ----- Reset the file list
            unset($v_header_list);

            // ----- Return
            return $v_result;
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
    // *****                                                        *****
    // *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privCheckFormat()
    // Description :
    //   This method check that the archive exists and is a valid zip archive.
    //   Several level of check exists. (futur)
    // Parameters :
    //   $p_level : Level of check. Default 0.
    //              0 : Check the first bytes (magic codes) (default value))
    //              1 : 0 + Check the central directory (futur)
    //              2 : 1 + Check each file header (futur)
    // Return Values :
    //   true on success,
    //   false on error, the error code is set.
    // --------------------------------------------------------------------------------

    public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
    {
        $v_result = 1;
        $v_header = array();

        // ----- Recuperate the current number of elt in list
        $v_nb = sizeof($p_result_list);

        // ----- Loop on the files
        for ($j = 0; ($j < sizeof($p_filedescr_list)) && (1 == $v_result); ++$j) {
            // ----- Format the filename
            $p_filedescr_list[$j]['filename']
                = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);

            // ----- Skip empty file names
            // TBC : Can this be possible ? not checked in DescrParseAtt ?
            if ('' == $p_filedescr_list[$j]['filename']) {
                continue;
            }

            // ----- Check the filename
            if (('virtual_file' != $p_filedescr_list[$j]['type'])
                && (!file_exists($p_filedescr_list[$j]['filename']))
            ) {
                PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");

                return PclZip::errorCode();
            }

            // ----- Look if it is a file or a dir with no all path remove option
            // or a dir with all its path removed
//      if (   (is_file($p_filedescr_list[$j]['filename']))
//          || (   is_dir($p_filedescr_list[$j]['filename'])
            if (('file' == $p_filedescr_list[$j]['type'])
                || ('virtual_file' == $p_filedescr_list[$j]['type'])
                || (('folder' == $p_filedescr_list[$j]['type'])
                    && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])
                        || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
            ) {
                // ----- Add the file
                $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header,
                    $p_options);
                if (1 != $v_result) {
                    return $v_result;
                }

                // ----- Store the file infos
                $p_result_list[$v_nb++] = $v_header;
            }
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privParseOptions()
    // Description :
    //   This internal methods reads the variable list of arguments ($p_options_list,
    //   $p_size) and generate an array with the options and values ($v_result_list).
    //   $v_requested_options contains the options that can be present and those that
    //   must be present.
    //   $v_requested_options is an array, with the option value as key, and 'optional',
    //   or 'mandatory' as value.
    // Parameters :
    //   See above.
    // Return Values :
    //   1 on success.
    //   0 on failure.
    // --------------------------------------------------------------------------------

    public function privAddFile($p_filedescr, &$p_header, &$p_options)
    {
        $v_result = 1;

        // ----- Working variable
        $p_filename = $p_filedescr['filename'];

        // TBC : Already done in the fileAtt check ... ?
        if ('' == $p_filename) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Invalid file list parameter (invalid or empty list)');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Look for a stored different filename
        /* TBC : Removed
    if (isset($p_filedescr['stored_filename'])) {
      $v_stored_filename = $p_filedescr['stored_filename'];
    }
    else {
      $v_stored_filename = $p_filedescr['stored_filename'];
    }
    */

        // ----- Set the file properties
        clearstatcache();
        $p_header['version']           = 20;
        $p_header['version_extracted'] = 10;
        $p_header['flag']              = 0;
        $p_header['compression']       = 0;
        $p_header['crc']               = 0;
        $p_header['compressed_size']   = 0;
        $p_header['filename_len']      = strlen($p_filename);
        $p_header['extra_len']         = 0;
        $p_header['disk']              = 0;
        $p_header['internal']          = 0;
        $p_header['offset']            = 0;
        $p_header['filename']          = $p_filename;
        // TBC : Removed    $p_header['stored_filename'] = $v_stored_filename;
        $p_header['stored_filename'] = $p_filedescr['stored_filename'];
        $p_header['extra']           = '';
        $p_header['status']          = 'ok';
        $p_header['index']           = -1;

        // ----- Look for regular file
        if ('file' == $p_filedescr['type']) {
            $p_header['external'] = 0x00000000;
            $p_header['size']     = filesize($p_filename);
        } // ----- Look for regular folder
        elseif ('folder' == $p_filedescr['type']) {
            $p_header['external'] = 0x00000010;
            $p_header['mtime']    = filemtime($p_filename);
            $p_header['size']     = filesize($p_filename);
        } // ----- Look for virtual file
        elseif ('virtual_file' == $p_filedescr['type']) {
            $p_header['external'] = 0x00000000;
            $p_header['size']     = strlen($p_filedescr['content']);
        }

        // ----- Look for filetime
        if (isset($p_filedescr['mtime'])) {
            $p_header['mtime'] = $p_filedescr['mtime'];
        } elseif ('virtual_file' == $p_filedescr['type']) {
            $p_header['mtime'] = time();
        } else {
            $p_header['mtime'] = filemtime($p_filename);
        }

        // ------ Look for file comment
        if (isset($p_filedescr['comment'])) {
            $p_header['comment_len'] = strlen($p_filedescr['comment']);
            $p_header['comment']     = $p_filedescr['comment'];
        } else {
            $p_header['comment_len'] = 0;
            $p_header['comment']     = '';
        }

        // ----- Look for pre-add callback
        if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_header, $v_local_header);

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
            if (0 == $v_result) {
                // ----- Change the file status
                $p_header['status'] = 'skipped';
                $v_result           = 1;
            }

            // ----- Update the informations
            // Only some fields can be modified
            if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
                $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
            }
        }

        // ----- Look for empty stored filename
        if ('' == $p_header['stored_filename']) {
            $p_header['status'] = 'filtered';
        }

        // ----- Check the path length
        if (strlen($p_header['stored_filename']) > 0xFF) {
            $p_header['status'] = 'filename_too_long';
        }

        // ----- Look if no error, or file not skipped
        if ('ok' == $p_header['status']) {
            // ----- Look for a file
            if ('file' == $p_filedescr['type']) {
                // ----- Look for using temporary file to zip
                if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
                    && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
                        || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
                            && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))
                ) {
                    $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
                    if ($v_result < PCLZIP_ERR_NO_ERROR) {
                        return $v_result;
                    }
                } // ----- Use "in memory" zip algo
                else {
                    // ----- Open the source file
                    if (0 == ($v_file = @fopen($p_filename, 'rb'))) {
                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");

                        return PclZip::errorCode();
                    }

                    // ----- Read the file content
                    $v_content = @fread($v_file, $p_header['size']);

                    // ----- Close the file
                    @fclose($v_file);

                    // ----- Calculate the CRC
                    $p_header['crc'] = @crc32($v_content);

                    // ----- Look for no compression
                    if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
                        // ----- Set header parameters
                        $p_header['compressed_size'] = $p_header['size'];
                        $p_header['compression']     = 0;
                    } // ----- Look for normal compression
                    else {
                        // ----- Compress the content
                        $v_content = @gzdeflate($v_content);

                        // ----- Set header parameters
                        $p_header['compressed_size'] = strlen($v_content);
                        $p_header['compression']     = 8;
                    }

                    // ----- Call the header generation
                    if (1 != ($v_result = $this->privWriteFileHeader($p_header))) {
                        @fclose($v_file);

                        return $v_result;
                    }

                    // ----- Write the compressed (or not) content
                    @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
                }
            } // ----- Look for a virtual file (a file from string)
            elseif ('virtual_file' == $p_filedescr['type']) {
                $v_content = $p_filedescr['content'];

                // ----- Calculate the CRC
                $p_header['crc'] = @crc32($v_content);

                // ----- Look for no compression
                if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
                    // ----- Set header parameters
                    $p_header['compressed_size'] = $p_header['size'];
                    $p_header['compression']     = 0;
                } // ----- Look for normal compression
                else {
                    // ----- Compress the content
                    $v_content = @gzdeflate($v_content);

                    // ----- Set header parameters
                    $p_header['compressed_size'] = strlen($v_content);
                    $p_header['compression']     = 8;
                }

                // ----- Call the header generation
                if (1 != ($v_result = $this->privWriteFileHeader($p_header))) {
                    //@fclose($v_file);
                    return $v_result;
                }

                // ----- Write the compressed (or not) content
                @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
            } // ----- Look for a directory
            elseif ('folder' == $p_filedescr['type']) {
                // ----- Look for directory last '/'
                if ('/' != @substr($p_header['stored_filename'], -1)) {
                    $p_header['stored_filename'] .= '/';
                }

                // ----- Set the file properties
                $p_header['size'] = 0;
                //$p_header['external'] = 0x41FF0010;   // Value for a folder : to be checked
                $p_header['external'] = 0x00000010; // Value for a folder : to be checked

                // ----- Call the header generation
                if (1 != ($v_result = $this->privWriteFileHeader($p_header))) {
                    return $v_result;
                }
            }
        }

        // ----- Look for post-add callback
        if (isset($p_options[PCLZIP_CB_POST_ADD])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_header, $v_local_header);

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
            if (0 == $v_result) {
                // ----- Ignored
                $v_result = 1;
            }

            // ----- Update the informations
            // Nothing can be modified
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privOptionDefaultThreshold()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privConvertHeader2FileInfo($p_header, &$p_info)
    {
        $v_result = 1;

        // ----- Get the interesting attributes
        $v_temp_path               = PclZipUtilPathReduction($p_header['filename']);
        $p_info['filename']        = $v_temp_path;
        $v_temp_path               = PclZipUtilPathReduction($p_header['stored_filename']);
        $p_info['stored_filename'] = $v_temp_path;
        $p_info['size']            = $p_header['size'];
        $p_info['compressed_size'] = $p_header['compressed_size'];
        $p_info['mtime']           = $p_header['mtime'];
        $p_info['comment']         = $p_header['comment'];
        $p_info['folder']          = (($p_header['external'] & 0x00000010) == 0x00000010);
        $p_info['index']           = $p_header['index'];
        $p_info['status']          = $p_header['status'];
        $p_info['crc']             = $p_header['crc'];

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privFileDescrParseAtt()
    // Description :
    // Parameters :
    // Return Values :
    //   1 on success.
    //   0 on failure.
    // --------------------------------------------------------------------------------

    public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
    {
        $v_result = PCLZIP_ERR_NO_ERROR;

        // ----- Working variable
        $p_filename = $p_filedescr['filename'];

        // ----- Open the source file
        if (0 == ($v_file = @fopen($p_filename, 'rb'))) {
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");

            return PclZip::errorCode();
        }

        // ----- Creates a compressed temporary file
        $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
        if (0 == ($v_file_compressed = @gzopen($v_gzip_temp_name, 'wb'))) {
            fclose($v_file);
            PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');

            return PclZip::errorCode();
        }

        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
        $v_size = filesize($p_filename);
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($v_file, $v_read_size);
            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
            @gzputs($v_file_compressed, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Close the file
        @fclose($v_file);
        @gzclose($v_file_compressed);

        // ----- Check the minimum file size
        if (filesize($v_gzip_temp_name) < 18) {
            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');

            return PclZip::errorCode();
        }

        // ----- Extract the compressed attributes
        if (0 == ($v_file_compressed = @fopen($v_gzip_temp_name, 'rb'))) {
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');

            return PclZip::errorCode();
        }

        // ----- Read the gzip file header
        $v_binary_data = @fread($v_file_compressed, 10);
        $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);

        // ----- Check some parameters
        $v_data_header['os'] = bin2hex($v_data_header['os']);

        // ----- Read the gzip file footer
        @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8);
        $v_binary_data = @fread($v_file_compressed, 8);
        $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);

        // ----- Set the attributes
        $p_header['compression'] = ord($v_data_header['cm']);
        //$p_header['mtime'] = $v_data_header['mtime'];
        $p_header['crc']             = $v_data_footer['crc'];
        $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18;

        // ----- Close the file
        @fclose($v_file_compressed);

        // ----- Call the header generation
        if (1 != ($v_result = $this->privWriteFileHeader($p_header))) {
            return $v_result;
        }

        // ----- Add the compressed data
        if (0 == ($v_file_compressed = @fopen($v_gzip_temp_name, 'rb'))) {
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');

            return PclZip::errorCode();
        }

        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
        fseek($v_file_compressed, 10);
        $v_size = $p_header['compressed_size'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($v_file_compressed, $v_read_size);
            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
            @fwrite($this->zip_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Close the file
        @fclose($v_file_compressed);

        // ----- Unlink the temporary file
        @unlink($v_gzip_temp_name);

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privFileDescrExpand()
    // Description :
    //   This method look for each item of the list to see if its a file, a folder
    //   or a string to be added as file. For any other type of files (link, other)
    //   just ignore the item.
    //   Then prepare the information that will be stored for that file.
    //   When its a folder, expand the folder with all the files that are in that
    //   folder (recursively).
    // Parameters :
    // Return Values :
    //   1 on success.
    //   0 on failure.
    // --------------------------------------------------------------------------------

    public function privWriteFileHeader(&$p_header)
    {
        $v_result = 1;

        // ----- Store the offset position of the file
        $p_header['offset'] = ftell($this->zip_fd);

        // ----- Transform UNIX mtime to DOS format mdate/mtime
        $v_date  = getdate($p_header['mtime']);
        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];

        // ----- Packed data
        $v_binary_data = pack('VvvvvvVVVvv', 0x04034b50,
            $p_header['version_extracted'], $p_header['flag'],
            $p_header['compression'], $v_mtime, $v_mdate,
            $p_header['crc'], $p_header['compressed_size'],
            $p_header['size'],
            strlen($p_header['stored_filename']),
            $p_header['extra_len']);

        // ----- Write the first 148 bytes of the header in the archive
        fputs($this->zip_fd, $v_binary_data, 30);

        // ----- Write the variable fields
        if (0 != strlen($p_header['stored_filename'])) {
            fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
        }
        if (0 != $p_header['extra_len']) {
            fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privCreate()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privWriteCentralFileHeader(&$p_header)
    {
        $v_result = 1;

        // TBC
        //for(reset($p_header); $key = key($p_header); next($p_header)) {
        //}

        // ----- Transform UNIX mtime to DOS format mdate/mtime
        $v_date  = getdate($p_header['mtime']);
        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];

        // ----- Packed data
        $v_binary_data = pack('VvvvvvvVVVvvvvvVV', 0x02014b50,
            $p_header['version'], $p_header['version_extracted'],
            $p_header['flag'], $p_header['compression'],
            $v_mtime, $v_mdate, $p_header['crc'],
            $p_header['compressed_size'], $p_header['size'],
            strlen($p_header['stored_filename']),
            $p_header['extra_len'], $p_header['comment_len'],
            $p_header['disk'], $p_header['internal'],
            $p_header['external'], $p_header['offset']);

        // ----- Write the 42 bytes of the header in the zip file
        fputs($this->zip_fd, $v_binary_data, 46);

        // ----- Write the variable fields
        if (0 != strlen($p_header['stored_filename'])) {
            fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
        }
        if (0 != $p_header['extra_len']) {
            fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
        }
        if (0 != $p_header['comment_len']) {
            fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privAdd()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
    {
        $v_result = 1;

        // ----- Packed data
        $v_binary_data = pack('VvvvvVVv', 0x06054b50, 0, 0, $p_nb_entries,
            $p_nb_entries, $p_size,
            $p_offset, strlen($p_comment));

        // ----- Write the 22 bytes of the header in the zip file
        fputs($this->zip_fd, $v_binary_data, 22);

        // ----- Write the variable fields
        if (0 != strlen($p_comment)) {
            fputs($this->zip_fd, $p_comment, strlen($p_comment));
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privOpenFd()
    // Description :
    // Parameters :
    // --------------------------------------------------------------------------------

    public function privCloseFd()
    {
        $v_result = 1;

        if (0 != $this->zip_fd) {
            @fclose($this->zip_fd);
        }
        $this->zip_fd = 0;

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privCloseFd()
    // Description :
    // Parameters :
    // --------------------------------------------------------------------------------

    public function privSwapBackMagicQuotes()
    {
        $v_result = 1;

        // ----- Look if function exists
        if ((!function_exists('get_magic_quotes_runtime'))
            || (!function_exists('set_magic_quotes_runtime'))
        ) {
            return $v_result;
        }

        // ----- Look if something to do
        if (-1 != $this->magic_quotes_status) {
            return $v_result;
        }

        // ----- Swap back magic_quotes
        if (1 == $this->magic_quotes_status) {
            @set_magic_quotes_runtime($this->magic_quotes_status);
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privAddList()
    // Description :
    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
    //   different from the real path of the file. This is usefull if you want to have PclTar
    //   running in any directory, and memorize relative path from an other directory.
    // Parameters :
    //   $p_list : An array containing the file or directory names to add in the tar
    //   $p_result_list : list of added files with their properties (specially the status field)
    //   $p_add_dir : Path to add in the filename path archived
    //   $p_remove_dir : Path to remove in the filename path archived
    // Return Values :
    // --------------------------------------------------------------------------------
    //  function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)

    public function add($p_filelist)
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Set default values
        $v_options                            = array();
        $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;

        // ----- Look for variable options arguments
        $v_size = func_num_args();

        // ----- Look for arguments
        if ($v_size > 1) {
            // ----- Get the arguments
            $v_arg_list = func_get_args();

            // ----- Remove form the options list the first argument
            array_shift($v_arg_list);
            --$v_size;

            // ----- Look for first arg
            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
                // ----- Parse the options
                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
                    array(PCLZIP_OPT_REMOVE_PATH         => 'optional',
                          PCLZIP_OPT_REMOVE_ALL_PATH     => 'optional',
                          PCLZIP_OPT_ADD_PATH            => 'optional',
                          PCLZIP_CB_PRE_ADD              => 'optional',
                          PCLZIP_CB_POST_ADD             => 'optional',
                          PCLZIP_OPT_NO_COMPRESSION      => 'optional',
                          PCLZIP_OPT_COMMENT             => 'optional',
                          PCLZIP_OPT_ADD_COMMENT         => 'optional',
                          PCLZIP_OPT_PREPEND_COMMENT     => 'optional',
                          PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
                          PCLZIP_OPT_TEMP_FILE_ON        => 'optional',
                          PCLZIP_OPT_TEMP_FILE_OFF       => 'optional',
                        //, PCLZIP_OPT_CRYPT => 'optional'
                    ));
                if (1 != $v_result) {
                    return 0;
                }
            } // ----- Look for 2 args
            // Here we need to support the first historic synopsis of the
            // method.
            else {
                // ----- Get the first argument
                $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];

                // ----- Look for the optional second argument
                if (2 == $v_size) {
                    $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
                } elseif ($v_size > 2) {
                    // ----- Error log
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Invalid number / type of arguments');

                    // ----- Return
                    return 0;
                }
            }
        }

        // ----- Look for default option values
        $this->privOptionDefaultThreshold($v_options);

        // ----- Init
        $v_string_list    = array();
        $v_att_list       = array();
        $v_filedescr_list = array();
        $p_result_list    = array();

        // ----- Look if the $p_filelist is really an array
        if (is_array($p_filelist)) {
            // ----- Look if the first element is also an array
            //       This will mean that this is a file description entry
            if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
                $v_att_list = $p_filelist;
            } // ----- The list is a list of string names
            else {
                $v_string_list = $p_filelist;
            }
        } // ----- Look if the $p_filelist is a string
        elseif (is_string($p_filelist)) {
            // ----- Create a list from the string
            $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
        } // ----- Invalid variable type for $p_filelist
        else {
            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");

            return 0;
        }

        // ----- Reformat the string list
        if (0 != sizeof($v_string_list)) {
            foreach ($v_string_list as $v_string) {
                $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
            }
        }

        // ----- For each file in the list check the attributes
        $v_supported_attributes
            = array(PCLZIP_ATT_FILE_NAME           => 'mandatory',
                    PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
                    PCLZIP_ATT_FILE_NEW_FULL_NAME  => 'optional',
                    PCLZIP_ATT_FILE_MTIME          => 'optional',
                    PCLZIP_ATT_FILE_CONTENT        => 'optional',
                    PCLZIP_ATT_FILE_COMMENT        => 'optional',
        );
        foreach ($v_att_list as $v_entry) {
            $v_result = $this->privFileDescrParseAtt($v_entry,
                $v_filedescr_list,
                $v_options,
                $v_supported_attributes);
            if (1 != $v_result) {
                return 0;
            }
        }

        // ----- Expand the filelist (expand directories)
        $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
        if (1 != $v_result) {
            return 0;
        }

        // ----- Call the create fct
        $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
        if (1 != $v_result) {
            return 0;
        }

        // ----- Return
        return $p_result_list;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privAddFileList()
    // Description :
    // Parameters :
    //   $p_filedescr_list : An array containing the file description
    //                      or directory names to add in the zip
    //   $p_result_list : list of added files with their properties (specially the status field)
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
    {
        $v_result      = 1;
        $v_list_detail = array();

        // ----- Look if the archive exists or is empty
        if ((!is_file($this->zipname)) || (0 == filesize($this->zipname))) {
            // ----- Do a create
            $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);

            // ----- Return
            return $v_result;
        }
        // ----- Magic quotes trick
        $this->privDisableMagicQuotes();

        // ----- Open the zip file
        if (1 != ($v_result = $this->privOpenFd('rb'))) {
            // ----- Magic quotes trick
            $this->privSwapBackMagicQuotes();

            // ----- Return
            return $v_result;
        }

        // ----- Read the central directory informations
        $v_central_dir = array();
        if (1 != ($v_result = $this->privReadEndCentralDir($v_central_dir))) {
            $this->privCloseFd();
            $this->privSwapBackMagicQuotes();

            return $v_result;
        }

        // ----- Go to beginning of File
        @rewind($this->zip_fd);

        // ----- Creates a temporay file
        $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';

        // ----- Open the temporary file in write mode
        if (0 == ($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb'))) {
            $this->privCloseFd();
            $this->privSwapBackMagicQuotes();

            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Copy the files from the archive to the temporary file
        // TBC : Here I should better append the file and go back to erase the central dir
        $v_size = $v_central_dir['offset'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = fread($this->zip_fd, $v_read_size);
            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Swap the file descriptor
        // Here is a trick : I swap the temporary fd with the zip fd, in order to use
        // the following methods on the temporary fil and not the real archive
        $v_swap        = $this->zip_fd;
        $this->zip_fd  = $v_zip_temp_fd;
        $v_zip_temp_fd = $v_swap;

        // ----- Add the files
        $v_header_list = array();
        if (1 != ($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options))) {
            fclose($v_zip_temp_fd);
            $this->privCloseFd();
            @unlink($v_zip_temp_name);
            $this->privSwapBackMagicQuotes();

            // ----- Return
            return $v_result;
        }

        // ----- Store the offset of the central dir
        $v_offset = @ftell($this->zip_fd);

        // ----- Copy the block of file headers from the old archive
        $v_size = $v_central_dir['size'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($v_zip_temp_fd, $v_read_size);
            @fwrite($this->zip_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Create the Central Dir files header
        for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); ++$i) {
            // ----- Create the file header
            if ('ok' == $v_header_list[$i]['status']) {
                if (1 != ($v_result = $this->privWriteCentralFileHeader($v_header_list[$i]))) {
                    fclose($v_zip_temp_fd);
                    $this->privCloseFd();
                    @unlink($v_zip_temp_name);
                    $this->privSwapBackMagicQuotes();

                    // ----- Return
                    return $v_result;
                }
                ++$v_count;
            }

            // ----- Transform the header to a 'usable' info
            $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
        }

        // ----- Zip file comment
        $v_comment = $v_central_dir['comment'];
        if (isset($p_options[PCLZIP_OPT_COMMENT])) {
            $v_comment = $p_options[PCLZIP_OPT_COMMENT];
        }
        if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
            $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
        }
        if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
            $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
        }

        // ----- Calculate the size of the central header
        $v_size = @ftell($this->zip_fd) - $v_offset;

        // ----- Create the central dir footer
        if (1 != ($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment))) {
            // ----- Reset the file list
            unset($v_header_list);
            $this->privSwapBackMagicQuotes();

            // ----- Return
            return $v_result;
        }

        // ----- Swap back the file descriptor
        $v_swap        = $this->zip_fd;
        $this->zip_fd  = $v_zip_temp_fd;
        $v_zip_temp_fd = $v_swap;

        // ----- Close
        $this->privCloseFd();

        // ----- Close the temporary file
        @fclose($v_zip_temp_fd);

        // ----- Magic quotes trick
        $this->privSwapBackMagicQuotes();

        // ----- Delete the zip file
        // TBC : I should test the result ...
        @unlink($this->zipname);

        // ----- Rename the temporary file
        // TBC : I should test the result ...
        //@rename($v_zip_temp_name, $this->zipname);
        PclZipUtilRename($v_zip_temp_name, $this->zipname);

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privAddFile()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privReadEndCentralDir(&$p_central_dir)
    {
        $v_result = 1;

        // ----- Go to the end of the zip file
        $v_size = filesize($this->zipname);
        @fseek($this->zip_fd, $v_size);
        if (@ftell($this->zip_fd) != $v_size) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- First try : look if this is an archive with no commentaries (most of the time)
        // in this case the end of central dir is at 22 bytes of the file end
        $v_found = 0;
        if ($v_size > 26) {
            @fseek($this->zip_fd, $v_size - 22);
            if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');

                // ----- Return
                return PclZip::errorCode();
            }

            // ----- Read for bytes
            $v_binary_data = @fread($this->zip_fd, 4);
            $v_data        = @unpack('Vid', $v_binary_data);

            // ----- Check signature
            if (0x06054b50 == $v_data['id']) {
                $v_found = 1;
            }

            $v_pos = ftell($this->zip_fd);
        }

        // ----- Go back to the maximum possible size of the Central Dir End Record
        if (!$v_found) {
            $v_maximum_size = 65557; // 0xFFFF + 22;
            if ($v_maximum_size > $v_size) {
                $v_maximum_size = $v_size;
            }
            @fseek($this->zip_fd, $v_size - $v_maximum_size);
            if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');

                // ----- Return
                return PclZip::errorCode();
            }

            // ----- Read byte per byte in order to find the signature
            $v_pos   = ftell($this->zip_fd);
            $v_bytes = 0x00000000;
            while ($v_pos < $v_size) {
                // ----- Read a byte
                $v_byte = @fread($this->zip_fd, 1);

                // -----  Add the byte
                //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
                // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
                // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
                $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | ord($v_byte);

                // ----- Compare the bytes
                if (0x504b0506 == $v_bytes) {
                    ++$v_pos;
                    break;
                }

                ++$v_pos;
            }

            // ----- Look if not found end of central dir
            if ($v_pos == $v_size) {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to find End of Central Dir Record signature');

                // ----- Return
                return PclZip::errorCode();
            }
        }

        // ----- Read the first 18 bytes of the header
        $v_binary_data = fread($this->zip_fd, 18);

        // ----- Look for invalid block size
        if (18 != strlen($v_binary_data)) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid End of Central Dir Record size : '.strlen($v_binary_data));

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Extract the values
        $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);

        // ----- Check the global size
        if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
            // ----- Removed in release 2.2 see readme file
            // The check of the file size is a little too strict.
            // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
            // While decrypted, zip has training 0 bytes
            if (0) {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
                    'The central dir is not at the end of the archive.'
                    .' Some trailing bytes exists after the archive.');

                // ----- Return
                return PclZip::errorCode();
            }
        }

        // ----- Get comment
        if (0 != $v_data['comment_size']) {
            $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
        } else {
            $p_central_dir['comment'] = '';
        }

        $p_central_dir['entries']      = $v_data['entries'];
        $p_central_dir['disk_entries'] = $v_data['disk_entries'];
        $p_central_dir['offset']       = $v_data['offset'];
        $p_central_dir['size']         = $v_data['size'];
        $p_central_dir['disk']         = $v_data['disk'];
        $p_central_dir['disk_start']   = $v_data['disk_start'];

        // TBC
        //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
        //}

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privAddFileUsingTempFile()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function listContent()
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Check archive
        if (!$this->privCheckFormat()) {
            return 0;
        }

        // ----- Call the extracting fct
        $p_list = array();
        if (1 != ($v_result = $this->privList($p_list))) {
            unset($p_list);

            return 0;
        }

        // ----- Return
        return $p_list;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privCalculateStoredFilename()
    // Description :
    //   Based on file descriptor properties and global options, this method
    //   calculate the filename that will be stored in the archive.
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privCheckFormat($p_level = 0)
    {
        $v_result = true;

        // ----- Reset the file system cache
        clearstatcache();

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Look if the file exits
        if (!is_file($this->zipname)) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");

            return false;
        }

        // ----- Check that the file is readeable
        if (!is_readable($this->zipname)) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");

            return false;
        }

        // ----- Check the magic code
        // TBC

        // ----- Check the central header
        // TBC

        // ----- Check each file header
        // TBC

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privWriteFileHeader()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privList(&$p_list)
    {
        $v_result = 1;

        // ----- Magic quotes trick
        $this->privDisableMagicQuotes();

        // ----- Open the zip file
        if (0 == ($this->zip_fd = @fopen($this->zipname, 'rb'))) {
            // ----- Magic quotes trick
            $this->privSwapBackMagicQuotes();

            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Read the central directory informations
        $v_central_dir = array();
        if (1 != ($v_result = $this->privReadEndCentralDir($v_central_dir))) {
            $this->privSwapBackMagicQuotes();

            return $v_result;
        }

        // ----- Go to beginning of Central Dir
        @rewind($this->zip_fd);
        if (@fseek($this->zip_fd, $v_central_dir['offset'])) {
            $this->privSwapBackMagicQuotes();

            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Read each entry
        for ($i = 0; $i < $v_central_dir['entries']; ++$i) {
            // ----- Read the file header
            if (1 != ($v_result = $this->privReadCentralFileHeader($v_header))) {
                $this->privSwapBackMagicQuotes();

                return $v_result;
            }
            $v_header['index'] = $i;

            // ----- Get the only interesting attributes
            $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
            unset($v_header);
        }

        // ----- Close the zip file
        $this->privCloseFd();

        // ----- Magic quotes trick
        $this->privSwapBackMagicQuotes();

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privWriteCentralFileHeader()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privReadCentralFileHeader(&$p_header)
    {
        $v_result = 1;

        // ----- Read the 4 bytes signature
        $v_binary_data = @fread($this->zip_fd, 4);
        $v_data        = unpack('Vid', $v_binary_data);

        // ----- Check signature
        if (0x02014b50 != $v_data['id']) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Read the first 42 bytes of the header
        $v_binary_data = fread($this->zip_fd, 42);

        // ----- Look for invalid block size
        if (42 != strlen($v_binary_data)) {
            $p_header['filename'] = '';
            $p_header['status']   = 'invalid_header';

            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid block size : '.strlen($v_binary_data));

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Extract the values
        $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);

        // ----- Get filename
        if (0 != $p_header['filename_len']) {
            $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
        } else {
            $p_header['filename'] = '';
        }

        // ----- Get extra
        if (0 != $p_header['extra_len']) {
            $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
        } else {
            $p_header['extra'] = '';
        }

        // ----- Get comment
        if (0 != $p_header['comment_len']) {
            $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
        } else {
            $p_header['comment'] = '';
        }

        // ----- Extract properties

        // ----- Recuperate date in UNIX format
        //if ($p_header['mdate'] && $p_header['mtime'])
        // TBC : bug : this was ignoring time with 0/0/0
        if (1) {
            // ----- Extract time
            $v_hour    = ($p_header['mtime'] & 0xF800) >> 11;
            $v_minute  = ($p_header['mtime'] & 0x07E0) >> 5;
            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;

            // ----- Extract date
            $v_year  = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
            $v_day   = $p_header['mdate'] & 0x001F;

            // ----- Get UNIX date format
            $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
        } else {
            $p_header['mtime'] = time();
        }

        // ----- Set the stored filename
        $p_header['stored_filename'] = $p_header['filename'];

        // ----- Set default status to ok
        $p_header['status'] = 'ok';

        // ----- Look if it is a directory
        if ('/' == substr($p_header['filename'], -1)) {
            //$p_header['external'] = 0x41FF0010;
            $p_header['external'] = 0x00000010;
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privWriteCentralHeader()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function extract()
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Check archive
        if (!$this->privCheckFormat()) {
            return 0;
        }

        // ----- Set default values
        $v_options = array();
//    $v_path = "./";
        $v_path            = '';
        $v_remove_path     = '';
        $v_remove_all_path = false;

        // ----- Look for variable options arguments
        $v_size = func_num_args();

        // ----- Default values for option
        $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;

        // ----- Look for arguments
        if ($v_size > 0) {
            // ----- Get the arguments
            $v_arg_list = func_get_args();

            // ----- Look for first arg
            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
                // ----- Parse the options
                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
                    array(PCLZIP_OPT_PATH                    => 'optional',
                          PCLZIP_OPT_REMOVE_PATH             => 'optional',
                          PCLZIP_OPT_REMOVE_ALL_PATH         => 'optional',
                          PCLZIP_OPT_ADD_PATH                => 'optional',
                          PCLZIP_CB_PRE_EXTRACT              => 'optional',
                          PCLZIP_CB_POST_EXTRACT             => 'optional',
                          PCLZIP_OPT_SET_CHMOD               => 'optional',
                          PCLZIP_OPT_BY_NAME                 => 'optional',
                          PCLZIP_OPT_BY_EREG                 => 'optional',
                          PCLZIP_OPT_BY_PREG                 => 'optional',
                          PCLZIP_OPT_BY_INDEX                => 'optional',
                          PCLZIP_OPT_EXTRACT_AS_STRING       => 'optional',
                          PCLZIP_OPT_EXTRACT_IN_OUTPUT       => 'optional',
                          PCLZIP_OPT_REPLACE_NEWER           => 'optional',
                          PCLZIP_OPT_STOP_ON_ERROR           => 'optional',
                          PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
                          PCLZIP_OPT_TEMP_FILE_THRESHOLD     => 'optional',
                          PCLZIP_OPT_TEMP_FILE_ON            => 'optional',
                          PCLZIP_OPT_TEMP_FILE_OFF           => 'optional',
                    ));
                if (1 != $v_result) {
                    return 0;
                }

                // ----- Set the arguments
                if (isset($v_options[PCLZIP_OPT_PATH])) {
                    $v_path = $v_options[PCLZIP_OPT_PATH];
                }
                if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
                    $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
                }
                if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
                    $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
                }
                if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
                    // ----- Check for '/' in last path char
                    if ((strlen($v_path) > 0) && ('/' != substr($v_path, -1))) {
                        $v_path .= '/';
                    }
                    $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
                }
            } // ----- Look for 2 args
            // Here we need to support the first historic synopsis of the
            // method.
            else {
                // ----- Get the first argument
                $v_path = $v_arg_list[0];

                // ----- Look for the optional second argument
                if (2 == $v_size) {
                    $v_remove_path = $v_arg_list[1];
                } elseif ($v_size > 2) {
                    // ----- Error log
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Invalid number / type of arguments');

                    // ----- Return
                    return 0;
                }
            }
        }

        // ----- Look for default option values
        $this->privOptionDefaultThreshold($v_options);

        // ----- Trace

        // ----- Call the extracting fct
        $p_list   = array();
        $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
            $v_remove_all_path, $v_options);
        if ($v_result < 1) {
            unset($p_list);

            return 0;
        }

        // ----- Return
        return $p_list;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privList()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
    {
        $v_result = 1;

        // ----- Magic quotes trick
        $this->privDisableMagicQuotes();

        // ----- Check the path
        if (('' == $p_path)
            || (('/' != substr($p_path, 0, 1))
                && ('../' != substr($p_path, 0, 3))
                && (':/' != substr($p_path, 1, 2)))
        ) {
            $p_path = './'.$p_path;
        }

        // ----- Reduce the path last (and duplicated) '/'
        if (('./' != $p_path) && ('/' != $p_path)) {
            // ----- Look for the path end '/'
            while ('/' == substr($p_path, -1)) {
                $p_path = substr($p_path, 0, strlen($p_path) - 1);
            }
        }

        // ----- Look for path to remove format (should end by /)
        if (('' != $p_remove_path) && ('/' != substr($p_remove_path, -1))) {
            $p_remove_path .= '/';
        }
        $p_remove_path_size = strlen($p_remove_path);

        // ----- Open the zip file
        if (1 != ($v_result = $this->privOpenFd('rb'))) {
            $this->privSwapBackMagicQuotes();

            return $v_result;
        }

        // ----- Read the central directory informations
        $v_central_dir = array();
        if (1 != ($v_result = $this->privReadEndCentralDir($v_central_dir))) {
            // ----- Close the zip file
            $this->privCloseFd();
            $this->privSwapBackMagicQuotes();

            return $v_result;
        }

        // ----- Start at beginning of Central Dir
        $v_pos_entry = $v_central_dir['offset'];

        // ----- Read each entry
        $j_start = 0;
        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; ++$i) {
            // ----- Read next Central dir entry
            @rewind($this->zip_fd);
            if (@fseek($this->zip_fd, $v_pos_entry)) {
                // ----- Close the zip file
                $this->privCloseFd();
                $this->privSwapBackMagicQuotes();

                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');

                // ----- Return
                return PclZip::errorCode();
            }

            // ----- Read the file header
            $v_header = array();
            if (1 != ($v_result = $this->privReadCentralFileHeader($v_header))) {
                // ----- Close the zip file
                $this->privCloseFd();
                $this->privSwapBackMagicQuotes();

                return $v_result;
            }

            // ----- Store the index
            $v_header['index'] = $i;

            // ----- Store the file position
            $v_pos_entry = ftell($this->zip_fd);

            // ----- Look for the specific extract rules
            $v_extract = false;

            // ----- Look for extract by name rule
            if ((isset($p_options[PCLZIP_OPT_BY_NAME]))
                && (0 != $p_options[PCLZIP_OPT_BY_NAME])
            ) {
                // ----- Look if the filename is in the list
                for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); ++$j) {
                    // ----- Look for a directory
                    if ('/' == substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1)) {
                        // ----- Look if the directory is in the filename path
                        if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
                            && ($p_options[PCLZIP_OPT_BY_NAME][$j] == substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])))
                        ) {
                            $v_extract = true;
                        }
                    } // ----- Look for a filename
                    elseif ($p_options[PCLZIP_OPT_BY_NAME][$j] == $v_header['stored_filename']) {
                        $v_extract = true;
                    }
                }
            } // ----- Look for extract by ereg rule
            // ereg() is deprecated with PHP 5.3
            /*
      else if (   (isset($p_options[PCLZIP_OPT_BY_EREG]))
               && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {

          if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
              $v_extract = true;
          }
      }
      */

            // ----- Look for extract by preg rule
            elseif ((isset($p_options[PCLZIP_OPT_BY_PREG]))
                && ('' != $p_options[PCLZIP_OPT_BY_PREG])
            ) {
                if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
                    $v_extract = true;
                }
            } // ----- Look for extract by index rule
            elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX]))
                && (0 != $p_options[PCLZIP_OPT_BY_INDEX])
            ) {
                // ----- Look if the index is in the list
                for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); ++$j) {
                    if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
                        $v_extract = true;
                    }
                    if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
                        $j_start = $j + 1;
                    }

                    if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {
                        break;
                    }
                }
            } // ----- Look for no rule, which means extract all the archive
            else {
                $v_extract = true;
            }

            // ----- Check compression method
            if (($v_extract)
                && ((8 != $v_header['compression'])
                    && (0 != $v_header['compression']))
            ) {
                $v_header['status'] = 'unsupported_compression';

                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
                    && (true === $p_options[PCLZIP_OPT_STOP_ON_ERROR])
                ) {
                    $this->privSwapBackMagicQuotes();

                    PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
                        "Filename '".$v_header['stored_filename']."' is "
                        .'compressed by an unsupported compression '
                        .'method ('.$v_header['compression'].') ');

                    return PclZip::errorCode();
                }
            }

            // ----- Check encrypted files
            if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
                $v_header['status'] = 'unsupported_encryption';

                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
                    && (true === $p_options[PCLZIP_OPT_STOP_ON_ERROR])
                ) {
                    $this->privSwapBackMagicQuotes();

                    PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
                        'Unsupported encryption for '
                        ." filename '".$v_header['stored_filename']
                        ."'");

                    return PclZip::errorCode();
                }
            }

            // ----- Look for real extraction
            if (($v_extract) && ('ok' != $v_header['status'])) {
                $v_result = $this->privConvertHeader2FileInfo($v_header,
                    $p_file_list[$v_nb_extracted++]);
                if (1 != $v_result) {
                    $this->privCloseFd();
                    $this->privSwapBackMagicQuotes();

                    return $v_result;
                }

                $v_extract = false;
            }

            // ----- Look for real extraction
            if ($v_extract) {
                // ----- Go to the file position
                @rewind($this->zip_fd);
                if (@fseek($this->zip_fd, $v_header['offset'])) {
                    // ----- Close the zip file
                    $this->privCloseFd();

                    $this->privSwapBackMagicQuotes();

                    // ----- Error log
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');

                    // ----- Return
                    return PclZip::errorCode();
                }

                // ----- Look for extraction as string
                if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
                    $v_string = '';

                    // ----- Extracting the file
                    $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
                    if ($v_result1 < 1) {
                        $this->privCloseFd();
                        $this->privSwapBackMagicQuotes();

                        return $v_result1;
                    }

                    // ----- Get the only interesting attributes
                    if (1 != ($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted]))) {
                        // ----- Close the zip file
                        $this->privCloseFd();
                        $this->privSwapBackMagicQuotes();

                        return $v_result;
                    }

                    // ----- Set the file content
                    $p_file_list[$v_nb_extracted]['content'] = $v_string;

                    // ----- Next extracted file
                    ++$v_nb_extracted;

                    // ----- Look for user callback abort
                    if (2 == $v_result1) {
                        break;
                    }
                } // ----- Look for extraction in standard output
                elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
                    && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])
                ) {
                    // ----- Extracting the file in standard output
                    $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
                    if ($v_result1 < 1) {
                        $this->privCloseFd();
                        $this->privSwapBackMagicQuotes();

                        return $v_result1;
                    }

                    // ----- Get the only interesting attributes
                    if (1 != ($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]))) {
                        $this->privCloseFd();
                        $this->privSwapBackMagicQuotes();

                        return $v_result;
                    }

                    // ----- Look for user callback abort
                    if (2 == $v_result1) {
                        break;
                    }
                } // ----- Look for normal extraction
                else {
                    // ----- Extracting the file
                    $v_result1 = $this->privExtractFile($v_header,
                        $p_path, $p_remove_path,
                        $p_remove_all_path,
                        $p_options);
                    if ($v_result1 < 1) {
                        $this->privCloseFd();
                        $this->privSwapBackMagicQuotes();

                        return $v_result1;
                    }

                    // ----- Get the only interesting attributes
                    if (1 != ($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]))) {
                        // ----- Close the zip file
                        $this->privCloseFd();
                        $this->privSwapBackMagicQuotes();

                        return $v_result;
                    }

                    // ----- Look for user callback abort
                    if (2 == $v_result1) {
                        break;
                    }
                }
            }
        }

        // ----- Close the zip file
        $this->privCloseFd();
        $this->privSwapBackMagicQuotes();

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privConvertHeader2FileInfo()
    // Description :
    //   This function takes the file informations from the central directory
    //   entries and extract the interesting parameters that will be given back.
    //   The resulting file infos are set in the array $p_info
    //     $p_info['filename'] : Filename with full path. Given by user (add),
    //                           extracted in the filesystem (extract).
    //     $p_info['stored_filename'] : Stored filename in the archive.
    //     $p_info['size'] = Size of the file.
    //     $p_info['compressed_size'] = Compressed size of the file.
    //     $p_info['mtime'] = Last modification date of the file.
    //     $p_info['comment'] = Comment associated with the file.
    //     $p_info['folder'] = true/false : indicates if the entry is a folder or not.
    //     $p_info['status'] = status of the action on the file.
    //     $p_info['crc'] = CRC of the file content.
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
    {
        $v_result = 1;

        // ----- Read the file header
        $v_header = array();
        if (1 != ($v_result = $this->privReadFileHeader($v_header))) {
            // ----- Return
            return $v_result;
        }

        // ----- Check that the file header is coherent with $p_entry info
        if (1 != $this->privCheckFileHeaders($v_header, $p_entry)) {
            // TBC
        }

        // ----- Look for pre-extract callback
        if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
            if (0 == $v_result) {
                // ----- Change the file status
                $p_entry['status'] = 'skipped';
                $v_result          = 1;
            }

            // ----- Look for abort result
            if (2 == $v_result) {
                // ----- This status is internal and will be changed in 'skipped'
                $p_entry['status'] = 'aborted';
                $v_result          = PCLZIP_ERR_USER_ABORTED;
            }

            // ----- Update the informations
            // Only some fields can be modified
            $p_entry['filename'] = $v_local_header['filename'];
        }

        // ----- Look if extraction should be done
        if ('ok' == $p_entry['status']) {
            // ----- Do the extraction (if not a folder)
            if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
                // ----- Look for not compressed file
                //      if ($p_entry['compressed_size'] == $p_entry['size'])
                if (0 == $p_entry['compression']) {
                    // ----- Reading the file
                    $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
                } else {
                    // ----- Reading the file
                    $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);

                    // ----- Decompress the file
                    if (false === ($p_string = @gzinflate($v_data))) {
                        // TBC
                    }
                }

                // ----- Trace
            } else {
                // TBC : error : can not extract a folder in a string
            }
        }

        // ----- Change abort status
        if ('aborted' == $p_entry['status']) {
            $p_entry['status'] = 'skipped';
        } // ----- Look for post-extract callback
        elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);

            // ----- Swap the content to header
            $v_local_header['content'] = $p_string;
            $p_string                  = '';

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);

            // ----- Swap back the content to header
            $p_string = $v_local_header['content'];
            unset($v_local_header['content']);

            // ----- Look for abort result
            if (2 == $v_result) {
                $v_result = PCLZIP_ERR_USER_ABORTED;
            }
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privExtractByRule()
    // Description :
    //   Extract a file or directory depending of rules (by index, by name, ...)
    // Parameters :
    //   $p_file_list : An array where will be placed the properties of each
    //                  extracted file
    //   $p_path : Path to add while writing the extracted files
    //   $p_remove_path : Path to remove (from the file memorized path) while writing the
    //                    extracted files. If the path does not match the file path,
    //                    the file is extracted with its memorized path.
    //                    $p_remove_path does not apply to 'list' mode.
    //                    $p_path and $p_remove_path are commulative.
    // Return Values :
    //   1 on success,0 or less on error (see error code list)
    // --------------------------------------------------------------------------------

    public function privReadFileHeader(&$p_header)
    {
        $v_result = 1;

        // ----- Read the 4 bytes signature
        $v_binary_data = @fread($this->zip_fd, 4);
        $v_data        = unpack('Vid', $v_binary_data);

        // ----- Check signature
        if (0x04034b50 != $v_data['id']) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Read the first 42 bytes of the header
        $v_binary_data = fread($this->zip_fd, 26);

        // ----- Look for invalid block size
        if (26 != strlen($v_binary_data)) {
            $p_header['filename'] = '';
            $p_header['status']   = 'invalid_header';

            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid block size : '.strlen($v_binary_data));

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Extract the values
        $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);

        // ----- Get filename
        $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);

        // ----- Get extra_fields
        if (0 != $v_data['extra_len']) {
            $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
        } else {
            $p_header['extra'] = '';
        }

        // ----- Extract properties
        $p_header['version_extracted'] = $v_data['version'];
        $p_header['compression']       = $v_data['compression'];
        $p_header['size']              = $v_data['size'];
        $p_header['compressed_size']   = $v_data['compressed_size'];
        $p_header['crc']               = $v_data['crc'];
        $p_header['flag']              = $v_data['flag'];
        $p_header['filename_len']      = $v_data['filename_len'];

        // ----- Recuperate date in UNIX format
        $p_header['mdate'] = $v_data['mdate'];
        $p_header['mtime'] = $v_data['mtime'];
        if ($p_header['mdate'] && $p_header['mtime']) {
            // ----- Extract time
            $v_hour    = ($p_header['mtime'] & 0xF800) >> 11;
            $v_minute  = ($p_header['mtime'] & 0x07E0) >> 5;
            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;

            // ----- Extract date
            $v_year  = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
            $v_day   = $p_header['mdate'] & 0x001F;

            // ----- Get UNIX date format
            $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
        } else {
            $p_header['mtime'] = time();
        }

        // TBC
        //for(reset($v_data); $key = key($v_data); next($v_data)) {
        //}

        // ----- Set the stored filename
        $p_header['stored_filename'] = $p_header['filename'];

        // ----- Set the status field
        $p_header['status'] = 'ok';

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privExtractFile()
    // Description :
    // Parameters :
    // Return Values :
    //
    // 1 : ... ?
    // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
    // --------------------------------------------------------------------------------

    public function privCheckFileHeaders(&$p_local_header, &$p_central_header)
    {
        $v_result = 1;

        // ----- Check the static values
        // TBC
        if ($p_local_header['filename'] != $p_central_header['filename']) {
        }
        if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
        }
        if ($p_local_header['flag'] != $p_central_header['flag']) {
        }
        if ($p_local_header['compression'] != $p_central_header['compression']) {
        }
        if ($p_local_header['mtime'] != $p_central_header['mtime']) {
        }
        if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
        }

        // ----- Look for flag bit 3
        if (($p_local_header['flag'] & 8) == 8) {
            $p_local_header['size']            = $p_central_header['size'];
            $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
            $p_local_header['crc']             = $p_central_header['crc'];
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privExtractFileUsingTempFile()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privExtractFileInOutput(&$p_entry, &$p_options)
    {
        $v_result = 1;

        // ----- Read the file header
        if (1 != ($v_result = $this->privReadFileHeader($v_header))) {
            return $v_result;
        }

        // ----- Check that the file header is coherent with $p_entry info
        if (1 != $this->privCheckFileHeaders($v_header, $p_entry)) {
            // TBC
        }

        // ----- Look for pre-extract callback
        if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
            if (0 == $v_result) {
                // ----- Change the file status
                $p_entry['status'] = 'skipped';
                $v_result          = 1;
            }

            // ----- Look for abort result
            if (2 == $v_result) {
                // ----- This status is internal and will be changed in 'skipped'
                $p_entry['status'] = 'aborted';
                $v_result          = PCLZIP_ERR_USER_ABORTED;
            }

            // ----- Update the informations
            // Only some fields can be modified
            $p_entry['filename'] = $v_local_header['filename'];
        }

        // ----- Trace

        // ----- Look if extraction should be done
        if ('ok' == $p_entry['status']) {
            // ----- Do the extraction (if not a folder)
            if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
                // ----- Look for not compressed file
                if ($p_entry['compressed_size'] == $p_entry['size']) {
                    // ----- Read the file in a buffer (one shot)
                    $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);

                    // ----- Send the file to the output
                    echo $v_buffer;
                    unset($v_buffer);
                } else {
                    // ----- Read the compressed file in a buffer (one shot)
                    $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);

                    // ----- Decompress the file
                    $v_file_content = gzinflate($v_buffer);
                    unset($v_buffer);

                    // ----- Send the file to the output
                    echo $v_file_content;
                    unset($v_file_content);
                }
            }
        }

        // ----- Change abort status
        if ('aborted' == $p_entry['status']) {
            $p_entry['status'] = 'skipped';
        } // ----- Look for post-extract callback
        elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);

            // ----- Look for abort result
            if (2 == $v_result) {
                $v_result = PCLZIP_ERR_USER_ABORTED;
            }
        }

        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privExtractFileInOutput()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
    {
        $v_result = 1;

        // ----- Read the file header
        if (1 != ($v_result = $this->privReadFileHeader($v_header))) {
            // ----- Return
            return $v_result;
        }

        // ----- Check that the file header is coherent with $p_entry info
        if (1 != $this->privCheckFileHeaders($v_header, $p_entry)) {
            // TBC
        }

        // ----- Look for all path to remove
        if (true == $p_remove_all_path) {
            // ----- Look for folder entry that not need to be extracted
            if (($p_entry['external'] & 0x00000010) == 0x00000010) {
                $p_entry['status'] = 'filtered';

                return $v_result;
            }

            // ----- Get the basename of the path
            $p_entry['filename'] = basename($p_entry['filename']);
        } // ----- Look for path to remove
        elseif ('' != $p_remove_path) {
            if (2 == PclZipUtilPathInclusion($p_remove_path, $p_entry['filename'])) {
                // ----- Change the file status
                $p_entry['status'] = 'filtered';

                // ----- Return
                return $v_result;
            }

            $p_remove_path_size = strlen($p_remove_path);
            if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {
                // ----- Remove the path
                $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
            }
        }

        // ----- Add the path
        if ('' != $p_path) {
            $p_entry['filename'] = $p_path.'/'.$p_entry['filename'];
        }

        // ----- Check a base_dir_restriction
        if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
            $v_inclusion
                = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
                $p_entry['filename']);
            if (0 == $v_inclusion) {
                PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
                    "Filename '".$p_entry['filename']."' is "
                    .'outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION');

                return PclZip::errorCode();
            }
        }

        // ----- Look for pre-extract callback
        if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
            if (0 == $v_result) {
                // ----- Change the file status
                $p_entry['status'] = 'skipped';
                $v_result          = 1;
            }

            // ----- Look for abort result
            if (2 == $v_result) {
                // ----- This status is internal and will be changed in 'skipped'
                $p_entry['status'] = 'aborted';
                $v_result          = PCLZIP_ERR_USER_ABORTED;
            }

            // ----- Update the informations
            // Only some fields can be modified
            $p_entry['filename'] = $v_local_header['filename'];
        }

        // ----- Look if extraction should be done
        if ('ok' == $p_entry['status']) {
            // ----- Look for specific actions while the file exist
            if (file_exists($p_entry['filename'])) {
                // ----- Look if file is a directory
                if (is_dir($p_entry['filename'])) {
                    // ----- Change the file status
                    $p_entry['status'] = 'already_a_directory';

                    // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
                    // For historical reason first PclZip implementation does not stop
                    // when this kind of error occurs.
                    if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
                        && (true === $p_options[PCLZIP_OPT_STOP_ON_ERROR])
                    ) {
                        PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
                            "Filename '".$p_entry['filename']."' is "
                            .'already used by an existing directory');

                        return PclZip::errorCode();
                    }
                } // ----- Look if file is write protected
                elseif (!is_writeable($p_entry['filename'])) {
                    // ----- Change the file status
                    $p_entry['status'] = 'write_protected';

                    // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
                    // For historical reason first PclZip implementation does not stop
                    // when this kind of error occurs.
                    if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
                        && (true === $p_options[PCLZIP_OPT_STOP_ON_ERROR])
                    ) {
                        PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
                            "Filename '".$p_entry['filename']."' exists "
                            .'and is write protected');

                        return PclZip::errorCode();
                    }
                } // ----- Look if the extracted file is older
                elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) {
                    // ----- Change the file status
                    if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
                        && (true === $p_options[PCLZIP_OPT_REPLACE_NEWER])
                    ) {
                    } else {
                        $p_entry['status'] = 'newer_exist';

                        // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
                        // For historical reason first PclZip implementation does not stop
                        // when this kind of error occurs.
                        if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
                            && (true === $p_options[PCLZIP_OPT_STOP_ON_ERROR])
                        ) {
                            PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
                                "Newer version of '".$p_entry['filename']."' exists "
                                .'and option PCLZIP_OPT_REPLACE_NEWER is not selected');

                            return PclZip::errorCode();
                        }
                    }
                } else {
                }
            } // ----- Check the directory availability and create it if necessary
            else {
                if ((($p_entry['external'] & 0x00000010) == 0x00000010) || ('/' == substr($p_entry['filename'], -1))) {
                    $v_dir_to_check = $p_entry['filename'];
                } elseif (!strstr($p_entry['filename'], '/')) {
                    $v_dir_to_check = '';
                } else {
                    $v_dir_to_check = dirname($p_entry['filename']);
                }

                if (1 != ($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010)))) {
                    // ----- Change the file status
                    $p_entry['status'] = 'path_creation_fail';

                    // ----- Return
                    //return $v_result;
                    $v_result = 1;
                }
            }
        }

        // ----- Look if extraction should be done
        if ('ok' == $p_entry['status']) {
            // ----- Do the extraction (if not a folder)
            if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
                // ----- Look for not compressed file
                if (0 == $p_entry['compression']) {
                    // ----- Opening destination file
                    if (0 == ($v_dest_file = @fopen($p_entry['filename'], 'wb'))) {
                        // ----- Change the file status
                        $p_entry['status'] = 'write_error';

                        // ----- Return
                        return $v_result;
                    }

                    // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
                    $v_size = $p_entry['compressed_size'];
                    while (0 != $v_size) {
                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
                        $v_buffer    = @fread($this->zip_fd, $v_read_size);
                        /* Try to speed up the code
            $v_binary_data = pack('a'.$v_read_size, $v_buffer);
            @fwrite($v_dest_file, $v_binary_data, $v_read_size);
            */
                        @fwrite($v_dest_file, $v_buffer, $v_read_size);
                        $v_size -= $v_read_size;
                    }

                    // ----- Closing the destination file
                    fclose($v_dest_file);

                    // ----- Change the file mtime
                    touch($p_entry['filename'], $p_entry['mtime']);
                } else {
                    // ----- TBC
                    // Need to be finished
                    if (($p_entry['flag'] & 1) == 1) {
                        PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');

                        return PclZip::errorCode();
                    }

                    // ----- Look for using temporary file to unzip
                    if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
                        && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
                            || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
                                && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))
                    ) {
                        $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
                        if ($v_result < PCLZIP_ERR_NO_ERROR) {
                            return $v_result;
                        }
                    } // ----- Look for extract in memory
                    else {
                        // ----- Read the compressed file in a buffer (one shot)
                        $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);

                        // ----- Decompress the file
                        $v_file_content = @gzinflate($v_buffer);
                        unset($v_buffer);
                        if (false === $v_file_content) {
                            // ----- Change the file status
                            // TBC
                            $p_entry['status'] = 'error';

                            return $v_result;
                        }

                        // ----- Opening destination file
                        if (0 == ($v_dest_file = @fopen($p_entry['filename'], 'wb'))) {
                            // ----- Change the file status
                            $p_entry['status'] = 'write_error';

                            return $v_result;
                        }

                        // ----- Write the uncompressed data
                        @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
                        unset($v_file_content);

                        // ----- Closing the destination file
                        @fclose($v_dest_file);
                    }

                    // ----- Change the file mtime
                    @touch($p_entry['filename'], $p_entry['mtime']);
                }

                // ----- Look for chmod option
                if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
                    // ----- Change the mode of the file
                    @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
                }
            }
        }

        // ----- Change abort status
        if ('aborted' == $p_entry['status']) {
            $p_entry['status'] = 'skipped';
        } // ----- Look for post-extract callback
        elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
            // ----- Generate a local information
            $v_local_header = array();
            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);

            // ----- Call the callback
            // Here I do not use call_user_func() because I need to send a reference to the
            // header.
//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
            $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);

            // ----- Look for abort result
            if (2 == $v_result) {
                $v_result = PCLZIP_ERR_USER_ABORTED;
            }
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privExtractFileAsString()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privDirCheck($p_dir, $p_is_dir = false)
    {
        $v_result = 1;

        // ----- Remove the final '/'
        if (($p_is_dir) && ('/' == substr($p_dir, -1))) {
            $p_dir = substr($p_dir, 0, strlen($p_dir) - 1);
        }

        // ----- Check the directory availability
        if ((is_dir($p_dir)) || ('' == $p_dir)) {
            return 1;
        }

        // ----- Extract parent directory
        $p_parent_dir = dirname($p_dir);

        // ----- Just a check
        if ($p_parent_dir != $p_dir) {
            // ----- Look for parent directory
            if ('' != $p_parent_dir) {
                if (1 != ($v_result = $this->privDirCheck($p_parent_dir))) {
                    return $v_result;
                }
            }
        }

        // ----- Create the directory
        if (!@mkdir($p_dir, 0777)) {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privReadFileHeader()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privExtractFileUsingTempFile(&$p_entry, &$p_options)
    {
        $v_result = 1;

        // ----- Creates a temporary file
        $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
        if (0 == ($v_dest_file = @fopen($v_gzip_temp_name, 'wb'))) {
            // fclose($v_gzip_temp_name);
            PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');

            return PclZip::errorCode();
        }

        // ----- Write gz file format header
        $v_binary_data = pack('va1a1Va1a1', 0x8b1f, chr($p_entry['compression']), chr(0x00), time(), chr(0x00), chr(3));
        @fwrite($v_dest_file, $v_binary_data, 10);

        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
        $v_size = $p_entry['compressed_size'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($this->zip_fd, $v_read_size);
            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
            @fwrite($v_dest_file, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Write gz file format footer
        $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
        @fwrite($v_dest_file, $v_binary_data, 8);

        // ----- Close the temporary file
        @fclose($v_dest_file);

        // ----- Opening destination file
        if (0 == ($v_dest_file = @fopen($p_entry['filename'], 'wb'))) {
            $p_entry['status'] = 'write_error';

            return $v_result;
        }

        // ----- Open the temporary gz file
        if (0 == ($v_src_file = @gzopen($v_gzip_temp_name, 'rb'))) {
            @fclose($v_dest_file);
            $p_entry['status'] = 'read_error';
            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');

            return PclZip::errorCode();
        }

        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
        $v_size = $p_entry['size'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @gzread($v_src_file, $v_read_size);
            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
            @fwrite($v_dest_file, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }
        @fclose($v_dest_file);
        @gzclose($v_src_file);

        // ----- Delete the temporary file
        @unlink($v_gzip_temp_name);

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privReadCentralFileHeader()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function extractByIndex($p_index)
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Check archive
        if (!$this->privCheckFormat()) {
            return 0;
        }

        // ----- Set default values
        $v_options = array();
//    $v_path = "./";
        $v_path            = '';
        $v_remove_path     = '';
        $v_remove_all_path = false;

        // ----- Look for variable options arguments
        $v_size = func_num_args();

        // ----- Default values for option
        $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;

        // ----- Look for arguments
        if ($v_size > 1) {
            // ----- Get the arguments
            $v_arg_list = func_get_args();

            // ----- Remove form the options list the first argument
            array_shift($v_arg_list);
            --$v_size;

            // ----- Look for first arg
            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
                // ----- Parse the options
                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
                    array(PCLZIP_OPT_PATH                    => 'optional',
                          PCLZIP_OPT_REMOVE_PATH             => 'optional',
                          PCLZIP_OPT_REMOVE_ALL_PATH         => 'optional',
                          PCLZIP_OPT_EXTRACT_AS_STRING       => 'optional',
                          PCLZIP_OPT_ADD_PATH                => 'optional',
                          PCLZIP_CB_PRE_EXTRACT              => 'optional',
                          PCLZIP_CB_POST_EXTRACT             => 'optional',
                          PCLZIP_OPT_SET_CHMOD               => 'optional',
                          PCLZIP_OPT_REPLACE_NEWER           => 'optional',
                          PCLZIP_OPT_STOP_ON_ERROR           => 'optional',
                          PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
                          PCLZIP_OPT_TEMP_FILE_THRESHOLD     => 'optional',
                          PCLZIP_OPT_TEMP_FILE_ON            => 'optional',
                          PCLZIP_OPT_TEMP_FILE_OFF           => 'optional',
                    ));
                if (1 != $v_result) {
                    return 0;
                }

                // ----- Set the arguments
                if (isset($v_options[PCLZIP_OPT_PATH])) {
                    $v_path = $v_options[PCLZIP_OPT_PATH];
                }
                if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
                    $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
                }
                if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
                    $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
                }
                if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
                    // ----- Check for '/' in last path char
                    if ((strlen($v_path) > 0) && ('/' != substr($v_path, -1))) {
                        $v_path .= '/';
                    }
                    $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
                }
                if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
                    $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
                } else {
                }
            } // ----- Look for 2 args
            // Here we need to support the first historic synopsis of the
            // method.
            else {
                // ----- Get the first argument
                $v_path = $v_arg_list[0];

                // ----- Look for the optional second argument
                if (2 == $v_size) {
                    $v_remove_path = $v_arg_list[1];
                } elseif ($v_size > 2) {
                    // ----- Error log
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Invalid number / type of arguments');

                    // ----- Return
                    return 0;
                }
            }
        }

        // ----- Trace

        // ----- Trick
        // Here I want to reuse extractByRule(), so I need to parse the $p_index
        // with privParseOptions()
        $v_arg_trick     = array(PCLZIP_OPT_BY_INDEX, $p_index);
        $v_options_trick = array();
        $v_result        = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
            array(PCLZIP_OPT_BY_INDEX => 'optional'));
        if (1 != $v_result) {
            return 0;
        }
        $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];

        // ----- Look for default option values
        $this->privOptionDefaultThreshold($v_options);

        // ----- Call the extracting fct
        if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
            return 0;
        }

        // ----- Return
        return $p_list;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privCheckFileHeaders()
    // Description :
    // Parameters :
    // Return Values :
    //   1 on success,
    //   0 on error;
    // --------------------------------------------------------------------------------

    public function deleteByIndex($p_index)
    {
        $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);

        // ----- Return
        return $p_list;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privReadEndCentralDir()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function delete()
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Check archive
        if (!$this->privCheckFormat()) {
            return 0;
        }

        // ----- Set default values
        $v_options = array();

        // ----- Look for variable options arguments
        $v_size = func_num_args();

        // ----- Look for arguments
        if ($v_size > 0) {
            // ----- Get the arguments
            $v_arg_list = func_get_args();

            // ----- Parse the options
            $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
                array(PCLZIP_OPT_BY_NAME  => 'optional',
                      PCLZIP_OPT_BY_EREG  => 'optional',
                      PCLZIP_OPT_BY_PREG  => 'optional',
                      PCLZIP_OPT_BY_INDEX => 'optional', ));
            if (1 != $v_result) {
                return 0;
            }
        }

        // ----- Magic quotes trick
        $this->privDisableMagicQuotes();

        // ----- Call the delete fct
        $v_list = array();
        if (1 != ($v_result = $this->privDeleteByRule($v_list, $v_options))) {
            $this->privSwapBackMagicQuotes();
            unset($v_list);

            return 0;
        }

        // ----- Magic quotes trick
        $this->privSwapBackMagicQuotes();

        // ----- Return
        return $v_list;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privDeleteByRule()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privDeleteByRule(&$p_result_list, &$p_options)
    {
        $v_result      = 1;
        $v_list_detail = array();

        // ----- Open the zip file
        if (1 != ($v_result = $this->privOpenFd('rb'))) {
            // ----- Return
            return $v_result;
        }

        // ----- Read the central directory informations
        $v_central_dir = array();
        if (1 != ($v_result = $this->privReadEndCentralDir($v_central_dir))) {
            $this->privCloseFd();

            return $v_result;
        }

        // ----- Go to beginning of File
        @rewind($this->zip_fd);

        // ----- Scan all the files
        // ----- Start at beginning of Central Dir
        $v_pos_entry = $v_central_dir['offset'];
        @rewind($this->zip_fd);
        if (@fseek($this->zip_fd, $v_pos_entry)) {
            // ----- Close the zip file
            $this->privCloseFd();

            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Read each entry
        $v_header_list = array();
        $j_start       = 0;
        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; ++$i) {
            // ----- Read the file header
            $v_header_list[$v_nb_extracted] = array();
            if (1 != ($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted]))) {
                // ----- Close the zip file
                $this->privCloseFd();

                return $v_result;
            }

            // ----- Store the index
            $v_header_list[$v_nb_extracted]['index'] = $i;

            // ----- Look for the specific extract rules
            $v_found = false;

            // ----- Look for extract by name rule
            if ((isset($p_options[PCLZIP_OPT_BY_NAME]))
                && (0 != $p_options[PCLZIP_OPT_BY_NAME])
            ) {
                // ----- Look if the filename is in the list
                for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); ++$j) {
                    // ----- Look for a directory
                    if ('/' == substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1)) {
                        // ----- Look if the directory is in the filename path
                        if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
                            && ($p_options[PCLZIP_OPT_BY_NAME][$j] == substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])))
                        ) {
                            $v_found = true;
                        } elseif ((0x00000010 == ($v_header_list[$v_nb_extracted]['external'] & 0x00000010)) /* Indicates a folder */
                            && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])
                        ) {
                            $v_found = true;
                        }
                    } // ----- Look for a filename
                    elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
                        $v_found = true;
                    }
                }
            } // ----- Look for extract by ereg rule
            // ereg() is deprecated with PHP 5.3
            /*
      else if (   (isset($p_options[PCLZIP_OPT_BY_EREG]))
               && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {

          if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
              $v_found = true;
          }
      }
      */

            // ----- Look for extract by preg rule
            elseif ((isset($p_options[PCLZIP_OPT_BY_PREG]))
                && ('' != $p_options[PCLZIP_OPT_BY_PREG])
            ) {
                if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
                    $v_found = true;
                }
            } // ----- Look for extract by index rule
            elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX]))
                && (0 != $p_options[PCLZIP_OPT_BY_INDEX])
            ) {
                // ----- Look if the index is in the list
                for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); ++$j) {
                    if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
                        $v_found = true;
                    }
                    if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
                        $j_start = $j + 1;
                    }

                    if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {
                        break;
                    }
                }
            } else {
                $v_found = true;
            }

            // ----- Look for deletion
            if ($v_found) {
                unset($v_header_list[$v_nb_extracted]);
            } else {
                ++$v_nb_extracted;
            }
        }

        // ----- Look if something need to be deleted
        if ($v_nb_extracted > 0) {
            // ----- Creates a temporay file
            $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';

            // ----- Creates a temporary zip archive
            $v_temp_zip = new PclZip($v_zip_temp_name);

            // ----- Open the temporary zip file in write mode
            if (1 != ($v_result = $v_temp_zip->privOpenFd('wb'))) {
                $this->privCloseFd();

                // ----- Return
                return $v_result;
            }

            // ----- Look which file need to be kept
            for ($i = 0; $i < sizeof($v_header_list); ++$i) {
                // ----- Calculate the position of the header
                @rewind($this->zip_fd);
                if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
                    // ----- Close the zip file
                    $this->privCloseFd();
                    $v_temp_zip->privCloseFd();
                    @unlink($v_zip_temp_name);

                    // ----- Error log
                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');

                    // ----- Return
                    return PclZip::errorCode();
                }

                // ----- Read the file header
                $v_local_header = array();
                if (1 != ($v_result = $this->privReadFileHeader($v_local_header))) {
                    // ----- Close the zip file
                    $this->privCloseFd();
                    $v_temp_zip->privCloseFd();
                    @unlink($v_zip_temp_name);

                    // ----- Return
                    return $v_result;
                }

                // ----- Check that local file header is same as central file header
                if (1 != $this->privCheckFileHeaders($v_local_header,
                        $v_header_list[$i])
                ) {
                    // TBC
                }
                unset($v_local_header);

                // ----- Write the file header
                if (1 != ($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i]))) {
                    // ----- Close the zip file
                    $this->privCloseFd();
                    $v_temp_zip->privCloseFd();
                    @unlink($v_zip_temp_name);

                    // ----- Return
                    return $v_result;
                }

                // ----- Read/write the data block
                if (1 != ($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size']))) {
                    // ----- Close the zip file
                    $this->privCloseFd();
                    $v_temp_zip->privCloseFd();
                    @unlink($v_zip_temp_name);

                    // ----- Return
                    return $v_result;
                }
            }

            // ----- Store the offset of the central dir
            $v_offset = @ftell($v_temp_zip->zip_fd);

            // ----- Re-Create the Central Dir files header
            for ($i = 0; $i < sizeof($v_header_list); ++$i) {
                // ----- Create the file header
                if (1 != ($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i]))) {
                    $v_temp_zip->privCloseFd();
                    $this->privCloseFd();
                    @unlink($v_zip_temp_name);

                    // ----- Return
                    return $v_result;
                }

                // ----- Transform the header to a 'usable' info
                $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
            }

            // ----- Zip file comment
            $v_comment = '';
            if (isset($p_options[PCLZIP_OPT_COMMENT])) {
                $v_comment = $p_options[PCLZIP_OPT_COMMENT];
            }

            // ----- Calculate the size of the central header
            $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset;

            // ----- Create the central dir footer
            if (1 != ($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment))) {
                // ----- Reset the file list
                unset($v_header_list);
                $v_temp_zip->privCloseFd();
                $this->privCloseFd();
                @unlink($v_zip_temp_name);

                // ----- Return
                return $v_result;
            }

            // ----- Close
            $v_temp_zip->privCloseFd();
            $this->privCloseFd();

            // ----- Delete the zip file
            // TBC : I should test the result ...
            @unlink($this->zipname);

            // ----- Rename the temporary file
            // TBC : I should test the result ...
            //@rename($v_zip_temp_name, $this->zipname);
            PclZipUtilRename($v_zip_temp_name, $this->zipname);

            // ----- Destroy the temporary archive
            unset($v_temp_zip);
        } // ----- Remove every files : reset the file
        elseif (0 != $v_central_dir['entries']) {
            $this->privCloseFd();

            if (1 != ($v_result = $this->privOpenFd('wb'))) {
                return $v_result;
            }

            if (1 != ($v_result = $this->privWriteCentralHeader(0, 0, 0, ''))) {
                return $v_result;
            }

            $this->privCloseFd();
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privDirCheck()
    // Description :
    //   Check if a directory exists, if not it creates it and all the parents directory
    //   which may be useful.
    // Parameters :
    //   $p_dir : Directory path to check.
    // Return Values :
    //    1 : OK
    //   -1 : Unable to create directory
    // --------------------------------------------------------------------------------

    public function properties()
    {
        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Magic quotes trick
        $this->privDisableMagicQuotes();

        // ----- Check archive
        if (!$this->privCheckFormat()) {
            $this->privSwapBackMagicQuotes();

            return 0;
        }

        // ----- Default properties
        $v_prop            = array();
        $v_prop['comment'] = '';
        $v_prop['nb']      = 0;
        $v_prop['status']  = 'not_exist';

        // ----- Look if file exists
        if (@is_file($this->zipname)) {
            // ----- Open the zip file
            if (0 == ($this->zip_fd = @fopen($this->zipname, 'rb'))) {
                $this->privSwapBackMagicQuotes();

                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');

                // ----- Return
                return 0;
            }

            // ----- Read the central directory informations
            $v_central_dir = array();
            if (1 != ($v_result = $this->privReadEndCentralDir($v_central_dir))) {
                $this->privSwapBackMagicQuotes();

                return 0;
            }

            // ----- Close the zip file
            $this->privCloseFd();

            // ----- Set the user attributes
            $v_prop['comment'] = $v_central_dir['comment'];
            $v_prop['nb']      = $v_central_dir['entries'];
            $v_prop['status']  = 'ok';
        }

        // ----- Magic quotes trick
        $this->privSwapBackMagicQuotes();

        // ----- Return
        return $v_prop;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privMerge()
    // Description :
    //   If $p_archive_to_add does not exist, the function exit with a success result.
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function duplicate($p_archive)
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Look if the $p_archive is a PclZip object
        if ((is_object($p_archive)) && ('pclzip' == get_class($p_archive))) {
            // ----- Duplicate the archive
            $v_result = $this->privDuplicate($p_archive->zipname);
        } // ----- Look if the $p_archive is a string (so a filename)
        elseif (is_string($p_archive)) {
            // ----- Check that $p_archive is a valid zip file
            // TBC : Should also check the archive format
            if (!is_file($p_archive)) {
                // ----- Error log
                PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
                $v_result = PCLZIP_ERR_MISSING_FILE;
            } else {
                // ----- Duplicate the archive
                $v_result = $this->privDuplicate($p_archive);
            }
        } // ----- Invalid variable
        else {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_archive_to_add');
            $v_result = PCLZIP_ERR_INVALID_PARAMETER;
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privDuplicate()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function privDuplicate($p_archive_filename)
    {
        $v_result = 1;

        // ----- Look if the $p_archive_filename exists
        if (!is_file($p_archive_filename)) {
            // ----- Nothing to duplicate, so duplicate is a success.
            $v_result = 1;

            // ----- Return
            return $v_result;
        }

        // ----- Open the zip file
        if (1 != ($v_result = $this->privOpenFd('wb'))) {
            // ----- Return
            return $v_result;
        }

        // ----- Open the temporary file in write mode
        if (0 == ($v_zip_temp_fd = @fopen($p_archive_filename, 'rb'))) {
            $this->privCloseFd();

            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Copy the files from the archive to the temporary file
        // TBC : Here I should better append the file and go back to erase the central dir
        $v_size = filesize($p_archive_filename);
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = fread($v_zip_temp_fd, $v_read_size);
            @fwrite($this->zip_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Close
        $this->privCloseFd();

        // ----- Close the temporary file
        @fclose($v_zip_temp_fd);

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privErrorLog()
    // Description :
    // Parameters :
    // --------------------------------------------------------------------------------

    public function merge($p_archive_to_add)
    {
        $v_result = 1;

        // ----- Reset the error handler
        $this->privErrorReset();

        // ----- Check archive
        if (!$this->privCheckFormat()) {
            return 0;
        }

        // ----- Look if the $p_archive_to_add is a PclZip object
        if ((is_object($p_archive_to_add)) && ('pclzip' == get_class($p_archive_to_add))) {
            // ----- Merge the archive
            $v_result = $this->privMerge($p_archive_to_add);
        } // ----- Look if the $p_archive_to_add is a string (so a filename)
        elseif (is_string($p_archive_to_add)) {
            // ----- Create a temporary archive
            $v_object_archive = new PclZip($p_archive_to_add);

            // ----- Merge the archive
            $v_result = $this->privMerge($v_object_archive);
        } // ----- Invalid variable
        else {
            // ----- Error log
            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_archive_to_add');
            $v_result = PCLZIP_ERR_INVALID_PARAMETER;
        }

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privErrorReset()
    // Description :
    // Parameters :
    // --------------------------------------------------------------------------------

    public function privMerge(&$p_archive_to_add)
    {
        $v_result = 1;

        // ----- Look if the archive_to_add exists
        if (!is_file($p_archive_to_add->zipname)) {
            // ----- Nothing to merge, so merge is a success
            $v_result = 1;

            // ----- Return
            return $v_result;
        }

        // ----- Look if the archive exists
        if (!is_file($this->zipname)) {
            // ----- Do a duplicate
            $v_result = $this->privDuplicate($p_archive_to_add->zipname);

            // ----- Return
            return $v_result;
        }

        // ----- Open the zip file
        if (1 != ($v_result = $this->privOpenFd('rb'))) {
            // ----- Return
            return $v_result;
        }

        // ----- Read the central directory informations
        $v_central_dir = array();
        if (1 != ($v_result = $this->privReadEndCentralDir($v_central_dir))) {
            $this->privCloseFd();

            return $v_result;
        }

        // ----- Go to beginning of File
        @rewind($this->zip_fd);

        // ----- Open the archive_to_add file
        if (1 != ($v_result = $p_archive_to_add->privOpenFd('rb'))) {
            $this->privCloseFd();

            // ----- Return
            return $v_result;
        }

        // ----- Read the central directory informations
        $v_central_dir_to_add = array();
        if (1 != ($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add))) {
            $this->privCloseFd();
            $p_archive_to_add->privCloseFd();

            return $v_result;
        }

        // ----- Go to beginning of File
        @rewind($p_archive_to_add->zip_fd);

        // ----- Creates a temporay file
        $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';

        // ----- Open the temporary file in write mode
        if (0 == ($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb'))) {
            $this->privCloseFd();
            $p_archive_to_add->privCloseFd();

            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');

            // ----- Return
            return PclZip::errorCode();
        }

        // ----- Copy the files from the archive to the temporary file
        // TBC : Here I should better append the file and go back to erase the central dir
        $v_size = $v_central_dir['offset'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = fread($this->zip_fd, $v_read_size);
            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Copy the files from the archive_to_add into the temporary file
        $v_size = $v_central_dir_to_add['offset'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = fread($p_archive_to_add->zip_fd, $v_read_size);
            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Store the offset of the central dir
        $v_offset = @ftell($v_zip_temp_fd);

        // ----- Copy the block of file headers from the old archive
        $v_size = $v_central_dir['size'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($this->zip_fd, $v_read_size);
            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Copy the block of file headers from the archive_to_add
        $v_size = $v_central_dir_to_add['size'];
        while (0 != $v_size) {
            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($p_archive_to_add->zip_fd, $v_read_size);
            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
            $v_size -= $v_read_size;
        }

        // ----- Merge the file comments
        $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];

        // ----- Calculate the size of the (new) central header
        $v_size = @ftell($v_zip_temp_fd) - $v_offset;

        // ----- Swap the file descriptor
        // Here is a trick : I swap the temporary fd with the zip fd, in order to use
        // the following methods on the temporary fil and not the real archive fd
        $v_swap        = $this->zip_fd;
        $this->zip_fd  = $v_zip_temp_fd;
        $v_zip_temp_fd = $v_swap;

        // ----- Create the central dir footer
        if (1 != ($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment))) {
            $this->privCloseFd();
            $p_archive_to_add->privCloseFd();
            @fclose($v_zip_temp_fd);
            $this->zip_fd = null;

            // ----- Reset the file list
            unset($v_header_list);

            // ----- Return
            return $v_result;
        }

        // ----- Swap back the file descriptor
        $v_swap        = $this->zip_fd;
        $this->zip_fd  = $v_zip_temp_fd;
        $v_zip_temp_fd = $v_swap;

        // ----- Close
        $this->privCloseFd();
        $p_archive_to_add->privCloseFd();

        // ----- Close the temporary file
        @fclose($v_zip_temp_fd);

        // ----- Delete the zip file
        // TBC : I should test the result ...
        @unlink($this->zipname);

        // ----- Rename the temporary file
        // TBC : I should test the result ...
        //@rename($v_zip_temp_name, $this->zipname);
        PclZipUtilRename($v_zip_temp_name, $this->zipname);

        // ----- Return
        return $v_result;
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privDisableMagicQuotes()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function errorInfo($p_full = false)
    {
        if (PCLZIP_ERROR_EXTERNAL == 1) {
            return PclErrorString();
        } else {
            if ($p_full) {
                return $this->errorName(true).' : '.$this->error_string;
            } else {
                return $this->error_string.' [code '.$this->error_code.']';
            }
        }
    }

    // --------------------------------------------------------------------------------

    // --------------------------------------------------------------------------------
    // Function : privSwapBackMagicQuotes()
    // Description :
    // Parameters :
    // Return Values :
    // --------------------------------------------------------------------------------

    public function errorName($p_with_code = false)
    {
        $v_name = array(PCLZIP_ERR_NO_ERROR                => 'PCLZIP_ERR_NO_ERROR',
                        PCLZIP_ERR_WRITE_OPEN_FAIL         => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
                        PCLZIP_ERR_READ_OPEN_FAIL          => 'PCLZIP_ERR_READ_OPEN_FAIL',
                        PCLZIP_ERR_INVALID_PARAMETER       => 'PCLZIP_ERR_INVALID_PARAMETER',
                        PCLZIP_ERR_MISSING_FILE            => 'PCLZIP_ERR_MISSING_FILE',
                        PCLZIP_ERR_FILENAME_TOO_LONG       => 'PCLZIP_ERR_FILENAME_TOO_LONG',
                        PCLZIP_ERR_INVALID_ZIP             => 'PCLZIP_ERR_INVALID_ZIP',
                        PCLZIP_ERR_BAD_EXTRACTED_FILE      => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
                        PCLZIP_ERR_DIR_CREATE_FAIL         => 'PCLZIP_ERR_DIR_CREATE_FAIL',
                        PCLZIP_ERR_BAD_EXTENSION           => 'PCLZIP_ERR_BAD_EXTENSION',
                        PCLZIP_ERR_BAD_FORMAT              => 'PCLZIP_ERR_BAD_FORMAT',
                        PCLZIP_ERR_DELETE_FILE_FAIL        => 'PCLZIP_ERR_DELETE_FILE_FAIL',
                        PCLZIP_ERR_RENAME_FILE_FAIL        => 'PCLZIP_ERR_RENAME_FILE_FAIL',
                        PCLZIP_ERR_BAD_CHECKSUM            => 'PCLZIP_ERR_BAD_CHECKSUM',
                        PCLZIP_ERR_INVALID_ARCHIVE_ZIP     => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
                        PCLZIP_ERR_MISSING_OPTION_VALUE    => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
                        PCLZIP_ERR_INVALID_OPTION_VALUE    => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
                        PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
                        PCLZIP_ERR_UNSUPPORTED_ENCRYPTION  => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION',
                        PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE',
                        PCLZIP_ERR_DIRECTORY_RESTRICTION   => 'PCLZIP_ERR_DIRECTORY_RESTRICTION',
        );

        if (isset($v_name[$this->error_code])) {
            $v_value = $v_name[$this->error_code];
        } else {
            $v_value = 'NoName';
        }

        if ($p_with_code) {
            return $v_value.' ('.$this->error_code.')';
        } else {
            return $v_value;
        }
    }

    // --------------------------------------------------------------------------------
}

// End of class
// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// Function : PclZipUtilPathReduction()
// Description :
// Parameters :
// Return Values :
// --------------------------------------------------------------------------------
function PclZipUtilPathReduction($p_dir)
{
    $v_result = '';

    // ----- Look for not empty path
    if ('' != $p_dir) {
        // ----- Explode path by directory names
        $v_list = explode('/', $p_dir);

        // ----- Study directories from last to first
        $v_skip = 0;
        for ($i = sizeof($v_list) - 1; $i >= 0; --$i) {
            // ----- Look for current path
            if ('.' == $v_list[$i]) {
                // ----- Ignore this directory
                // Should be the first $i=0, but no check is done
            } elseif ('..' == $v_list[$i]) {
                ++$v_skip;
            } elseif ('' == $v_list[$i]) {
                // ----- First '/' i.e. root slash
                if (0 == $i) {
                    $v_result = '/'.$v_result;
                    if ($v_skip > 0) {
                        // ----- It is an invalid path, so the path is not modified
                        // TBC
                        $v_result = $p_dir;
                        $v_skip   = 0;
                    }
                } // ----- Last '/' i.e. indicates a directory
                elseif ($i == (sizeof($v_list) - 1)) {
                    $v_result = $v_list[$i];
                } // ----- Double '/' inside the path
                else {
                    // ----- Ignore only the double '//' in path,
                    // but not the first and last '/'
                }
            } else {
                // ----- Look for item to skip
                if ($v_skip > 0) {
                    --$v_skip;
                } else {
                    $v_result = $v_list[$i].($i != (sizeof($v_list) - 1) ? '/'.$v_result : '');
                }
            }
        }

        // ----- Look for skip
        if ($v_skip > 0) {
            while ($v_skip > 0) {
                $v_result = '../'.$v_result;
                --$v_skip;
            }
        }
    }

    // ----- Return
    return $v_result;
}

// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// Function : PclZipUtilPathInclusion()
// Description :
//   This function indicates if the path $p_path is under the $p_dir tree. Or,
//   said in an other way, if the file or sub-dir $p_path is inside the dir
//   $p_dir.
//   The function indicates also if the path is exactly the same as the dir.
//   This function supports path with duplicated '/' like '//', but does not
//   support '.' or '..' statements.
// Parameters :
// Return Values :
//   0 if $p_path is not inside directory $p_dir
//   1 if $p_path is inside directory $p_dir
//   2 if $p_path is exactly the same as $p_dir
// --------------------------------------------------------------------------------
function PclZipUtilPathInclusion($p_dir, $p_path)
{
    $v_result = 1;

    // ----- Look for path beginning by ./
    if (('.' == $p_dir)
        || ((strlen($p_dir) >= 2) && ('./' == substr($p_dir, 0, 2)))
    ) {
        $p_dir = PclZipUtilTranslateWinPath(getcwd(), false).'/'.substr($p_dir, 1);
    }
    if (('.' == $p_path)
        || ((strlen($p_path) >= 2) && ('./' == substr($p_path, 0, 2)))
    ) {
        $p_path = PclZipUtilTranslateWinPath(getcwd(), false).'/'.substr($p_path, 1);
    }

    // ----- Explode dir and path by directory separator
    $v_list_dir       = explode('/', $p_dir);
    $v_list_dir_size  = sizeof($v_list_dir);
    $v_list_path      = explode('/', $p_path);
    $v_list_path_size = sizeof($v_list_path);

    // ----- Study directories paths
    $i = 0;
    $j = 0;
    while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
        // ----- Look for empty dir (path reduction)
        if ('' == $v_list_dir[$i]) {
            ++$i;
            continue;
        }
        if ('' == $v_list_path[$j]) {
            ++$j;
            continue;
        }

        // ----- Compare the items
        if (($v_list_dir[$i] != $v_list_path[$j]) && ('' != $v_list_dir[$i]) && ('' != $v_list_path[$j])) {
            $v_result = 0;
        }

        // ----- Next items
        ++$i;
        ++$j;
    }

    // ----- Look if everything seems to be the same
    if ($v_result) {
        // ----- Skip all the empty items
        while (($j < $v_list_path_size) && ('' == $v_list_path[$j])) {
            ++$j;
        }
        while (($i < $v_list_dir_size) && ('' == $v_list_dir[$i])) {
            ++$i;
        }

        if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
            // ----- There are exactly the same
            $v_result = 2;
        } elseif ($i < $v_list_dir_size) {
            // ----- The path is shorter than the dir
            $v_result = 0;
        }
    }

    // ----- Return
    return $v_result;
}

// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// Function : PclZipUtilCopyBlock()
// Description :
// Parameters :
//   $p_mode : read/write compression mode
//             0 : src & dest normal
//             1 : src gzip, dest normal
//             2 : src normal, dest gzip
//             3 : src & dest gzip
// Return Values :
// --------------------------------------------------------------------------------
function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0)
{
    $v_result = 1;

    if (0 == $p_mode) {
        while (0 != $p_size) {
            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($p_src, $v_read_size);
            @fwrite($p_dest, $v_buffer, $v_read_size);
            $p_size -= $v_read_size;
        }
    } elseif (1 == $p_mode) {
        while (0 != $p_size) {
            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @gzread($p_src, $v_read_size);
            @fwrite($p_dest, $v_buffer, $v_read_size);
            $p_size -= $v_read_size;
        }
    } elseif (2 == $p_mode) {
        while (0 != $p_size) {
            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @fread($p_src, $v_read_size);
            @gzwrite($p_dest, $v_buffer, $v_read_size);
            $p_size -= $v_read_size;
        }
    } elseif (3 == $p_mode) {
        while (0 != $p_size) {
            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
            $v_buffer    = @gzread($p_src, $v_read_size);
            @gzwrite($p_dest, $v_buffer, $v_read_size);
            $p_size -= $v_read_size;
        }
    }

    // ----- Return
    return $v_result;
}

// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// Function : PclZipUtilRename()
// Description :
//   This function tries to do a simple rename() function. If it fails, it
//   tries to copy the $p_src file in a new $p_dest file and then unlink the
//   first one.
// Parameters :
//   $p_src : Old filename
//   $p_dest : New filename
// Return Values :
//   1 on success, 0 on failure.
// --------------------------------------------------------------------------------
function PclZipUtilRename($p_src, $p_dest)
{
    $v_result = 1;

    // ----- Try to rename the files
    if (!@rename($p_src, $p_dest)) {
        // ----- Try to copy & unlink the src
        if (!@copy($p_src, $p_dest)) {
            $v_result = 0;
        } elseif (!@unlink($p_src)) {
            $v_result = 0;
        }
    }

    // ----- Return
    return $v_result;
}

// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// Function : PclZipUtilOptionText()
// Description :
//   Translate option value in text. Mainly for debug purpose.
// Parameters :
//   $p_option : the option value.
// Return Values :
//   The option text value.
// --------------------------------------------------------------------------------
function PclZipUtilOptionText($p_option)
{
    $v_list = get_defined_constants();
    for (reset($v_list); $v_key = key($v_list); next($v_list)) {
        $v_prefix = substr($v_key, 0, 10);
        if ((('PCLZIP_OPT' == $v_prefix)
                || ('PCLZIP_CB_' == $v_prefix)
                || ('PCLZIP_ATT' == $v_prefix))
            && ($v_list[$v_key] == $p_option)
        ) {
            return $v_key;
        }
    }

    $v_result = 'Unknown';

    return $v_result;
}

// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// Function : PclZipUtilTranslateWinPath()
// Description :
//   Translate windows path by replacing '\' by '/' and optionally removing
//   drive letter.
// Parameters :
//   $p_path : path to translate.
//   $p_remove_disk_letter : true | false
// Return Values :
//   The path translated.
// --------------------------------------------------------------------------------
function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true)
{
    if (stristr(php_uname(), 'windows')) {
        // ----- Look for potential disk letter
        if (($p_remove_disk_letter) && (false != ($v_position = strpos($p_path, ':')))) {
            $p_path = substr($p_path, $v_position + 1);
        }
        // ----- Change potential windows directory separator
        if ((strpos($p_path, '\\') > 0) || ('\\' == substr($p_path, 0, 1))) {
            $p_path = strtr($p_path, '\\', '/');
        }
    }

    return $p_path;
}
// --------------------------------------------------------------------------------
PK��#](�F�gSgS+system/bfnetwork/bfnetwork/bfExtensions.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * If we have not already included bfEncrypt then this must be a direct call, and
 * so we need to decrypt the incoming request.
 */
if (!class_exists('bfEncrypt')) {
    require 'bfEncrypt.php';
}

/*
 * Ok so this is stupid, but we are dealing with XML Parsing on crappy servers on sites with 100+ extensions installed - gulp!
 * 5 Mins! GULP - Most well configured servers will probably not honour this, but in our live tests on crappy servers this seems to work
 */
@set_time_limit(60 * 5);

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */
final class bfExtensions
{
    /**
     * @var JDatabase|JDatabaseDriver|object
     */
    private $db;

    /**
     * Incoming decrypted vars from the request.
     *
     * @var stdClass
     */
    private $_dataObj;

    /**
     * We pass the command to run as a simple integer in our encrypted
     * request this is mainly to speed up the decryption process, plus its a
     * single digit(or 2) rather than a huge string to remember :-).
     */
    private $_methods = array(
        1 => 'getExtensions',
        2 => 'installExtensionFromUrl',
    );

    /**
     * PHP 5 Constructor,
     * I inject the request to the object.
     *
     * @param stdClass $dataObj
     */
    public function __construct($dataObj = null)
    {
        // init Joomla
        require 'bfInitJoomla.php';

        // Set the request vars
        $this->_dataObj = $dataObj;
    }

    /**
     * I'm the controller - I run methods based on the request integer.
     */
    public function run()
    {
        if (property_exists($this->_dataObj, 'c')) {
            $c = (int) $this->_dataObj->c;
            if (array_key_exists($c, $this->_methods)) {
                // call the right method
                $this->{$this->_methods[$c]} ();
            } else {
                // Die if an unknown function
                bfEncrypt::reply('error', 'No Such method #err1 - '.$c);
            }
        } else {
            // Die if an unknown function
            bfEncrypt::reply('error', 'No Such method #err2');
        }
    }

    /**
     * Install an extension from a provided URL.
     *
     * Parts of this code are from Joomla CMS, Modified under license.
     *
     * @license GNU General Public License version 2 or later; see https://github.com/joomla/joomla-cms/blob/staging/LICENSE.txt
     * @copyright Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
     */
    public function installExtensionFromUrl()
    {
        // Get an installer instance.
        $installer = JInstaller::getInstance();

        // Get the URL of the package to install.
        $url = $this->_dataObj->url;

        // Download the package at the URL given.
        $p_file = JInstallerHelper::downloadPackage($url);

        // Was the package downloaded?
        if ($p_file) {
            // Unpack the downloaded package file.
            $package = JInstallerHelper::unpack(JFactory::getConfig()->get('tmp_path').'/'.$p_file, true);

            // Install the package.
            if (!$installer->install($package['dir'])) {
                // There was an error installing the package.
                $msg     = 'There was an error installing the package';
                $result  = false;
                $msgType = 'error';
            } else {
                // Package installed successfully.
                $msg     = 'Package installed successfully';
                $result  = true;
                $msgType = 'message';
            }

            // Cleanup the install files.
            if (!is_file($package['packagefile'])) {
                $config                 = JFactory::getConfig();
                $package['packagefile'] = $config->get('tmp_path').'/'.$package['packagefile'];
            }

            // Cleanup the package file
            JInstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']);
        } else {
            $result  = false;
            $msgType = 'error';
            $msg     = 'Could not download package from URL: '.$url;
        }

        $res = array(
            'result'            => $result,
            'msgType'           => $msgType,
            'message'           => $msg,
            'extension_message' => $installer->get('extension_message'),
            'redirect_url'      => $installer->get('redirect_url'),
        );

        bfEncrypt::reply($res['result'],
            $res
        );
    }

    /**
     * Get a JSON formatted list of installed extensions
     * Needs to be public so we can call it from the audit.
     *
     * @return string
     */
    public function getExtensions()
    {
        // connect/get the Joomla db object
        $this->db = JFactory::getDbo();

        // crazy way of handling Joomla 1.5.x legacy :-(
        $one5 = false;

        // Get Joomla 2.0+ Extensions
        $this->db->setQuery('SELECT e.extension_id, e.name, e.type, e.element, e.enabled, e.folder,
                                (
                                 SELECT title
                                 FROM #__menu AS m
                                 WHERE m.component_id = e.extension_id
                                 AND parent_id = 1
                                 ORDER BY ID ASC LIMIT 1
                                 )
                                 AS title
                                FROM #__extensions AS e
                                WHERE protected = 0');
        $installedExtensions = $this->db->loadObjectList();

        // ok if we have none maybe we are Joomla < 1.5.26
        if (!$installedExtensions) {
            // Yooo hoo I'm on a crap old, out of date, probably hackable Joomla version!
            $one5 = true;

            // Get the extensions - used to be called components
            $this->db->setQuery('SELECT "component" as "type", name, `option` as "element", enabled FROM #__components WHERE iscore != 1 and parent = 0');
            $components = $this->db->loadObjectList();

            // Get the plugins
            $this->db->setQuery('SELECT "plugin" as "type", name, element, folder, published as enabled FROM #__plugins WHERE iscore != 1');
            $plugins = $this->db->loadObjectList();

            // get the modules
            $this->db->setQuery('SELECT  "module" as "type", module, module as name, client_id, published as enabled FROM #__modules WHERE iscore != 1');
            $modules = $this->db->loadObjectList();

            /**
             * Get the templates - I n Joomla 1.5.x the templates are not in the
             * db unless published so we need to read the folders from the /templates folders
             * Note in Joomla 1.5.x there was no such think as admin templates.
             */
            $folders   = array_merge(scandir(JPATH_BASE.'/templates'), scandir(JPATH_ADMINISTRATOR.'/templates'));
            $templates = array();
            foreach ($folders as $templateFolder) {
                $f = JPATH_BASE.'/templates/'.trim($templateFolder);
                $a = JPATH_ADMINISTRATOR.'/templates/'.trim($templateFolder);

                // We dont want index.html etc...
                if (!is_dir($f) && !is_dir($a) || ('.' == $templateFolder || '..' == $templateFolder)) {
                    continue;
                }

                if (is_dir($a)) {
                    $client_id = 1;
                } else {
                    $client_id = 0;
                }

                // make it look like we want like Joomla 2.5+ would
                $template = array(
                    'type'      => 'template',
                    'template'  => $templateFolder,
                    'client_id' => $client_id,
                    'enabled'   => 1,
                );

                // Convert to an obj
                $templates[] = json_decode(json_encode($template));
            }

            // Merge all the "extensions" we have found all over the place
            $installedExtensions = array_merge($components, $plugins, $modules, $templates);
        }

        $lang = JFactory::getLanguage();

        // Load all the language strings up front incase any strings are shared
        foreach ($installedExtensions as $k => $ext) {
            $lang->load(strtolower($ext->element).'.sys', JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($ext->element).'.sys', JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($ext->name).'.sys', JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($ext->name).'.sys', JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($ext->title).'.sys', JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($ext->title).'.sys', JPATH_SITE, 'en-GB', true);

            $lang->load(strtolower($ext->element), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($ext->element), JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($ext->name), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($ext->name), JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($ext->title), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($ext->title), JPATH_SITE, 'en-GB', true);

            $element = str_replace('_TITLE', '', strtoupper($ext->element));
            $name    = str_replace('_TITLE', '', strtoupper($ext->name));
            $title   = str_replace('_TITLE', '', strtoupper($ext->title));

            $lang->load(strtolower($element).'.sys', JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($element).'.sys', JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($name).'.sys', JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($name).'.sys', JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($title).'.sys', JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($title).'.sys', JPATH_SITE, 'en-GB', true);

            $lang->load(strtolower($element), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($element), JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($name), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($name), JPATH_SITE, 'en-GB', true);
            $lang->load(strtolower($title), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load(strtolower($title), JPATH_SITE, 'en-GB', true);

            // templates
            $lang->load('tpl_'.strtolower($name), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load('tpl_'.strtolower($name), JPATH_SITE, 'en-GB', true);

            // Joomla 1.5.x modules
            $lang->load('mod_'.strtolower($name), JPATH_ADMINISTRATOR, 'en-GB', true);
            $lang->load('mod_'.strtolower($name), JPATH_SITE, 'en-GB', true);

            // tut tut Akeeba - bad naming!
            $lang->load(strtolower('PLG_SYSTEM_SRP'), JPATH_ADMINISTRATOR, 'en-GB', true); // should be plg_srp
            $lang->load(strtolower('PLG_SYSTEM_ONECLICKACTION'), JPATH_SITE, 'en-GB', true); // should be plg_oneclickaction
            $lang->load(strtolower('PLG_SYSTEM_ONECLICKACTION'), JPATH_ADMINISTRATOR, 'en-GB', true); // should be plg_oneclickaction

            // Joomla 1.5 plugins
            if ('plugin' == $ext->type) {
                $plg = 'plg_'.$ext->folder.'_'.$ext->element;
                $lang->load(strtolower($plg), JPATH_SITE, 'en-GB', true);
                $lang->load(strtolower($plg), JPATH_ADMINISTRATOR, 'en-GB', true);
            }

            if ('template' == $ext->type) {
                $plg = 'tpl_'.$ext->name;
                $lang->load(strtolower($plg), JPATH_SITE, 'en-GB', true);
                $lang->load(strtolower($plg), JPATH_ADMINISTRATOR, 'en-GB', true);
            }
        }

        // ok now we have the extensions - get the xml for further offline crunching
        foreach ($installedExtensions as $k => $ext) {
            // remove not supported types :-(
            if ('file' == $ext->type || 'package' == $ext->type) {
                unset($installedExtensions[$k]);
                continue;
            }
            $ext->xmlFile = $this->findManifest($ext);

            try {
                if (false !== $ext->xmlFile) {
                    $parts = explode('/', $ext->xmlFile);
                    array_pop($parts);
                    $ext->path = implode('/', $parts);
                    bfLog::log('Loading XML file = '.str_replace(JPATH_BASE, '', $ext->xmlFile));
                    $xml   = trim(file_get_contents($ext->xmlFile));
                    $myXML = new SimpleXMLElement($xml);
                    if (property_exists($myXML, 'description')) {
                        $ext->desc = $myXML->description;
                    }
                    $ext->xmlFileContents = base64_encode(gzcompress($xml));
                    $ext->xmlFileCreated  = filemtime($ext->xmlFile);
                } else {
                    $ext->MANIFESTERROR = true;
                }
            } catch (Exception $e) {
                bfLog::log('EXCEPTION = '.$ext->xmlFile.' '.$e->getMessage());
                die('Could not process XML file at: '.str_replace(JPATH_BASE, '', $ext->xmlFile));
            }

            $ext->name  = JText::_($ext->name);
            $ext->title = JText::_($ext->title);
            $ext->desc  = base64_encode(gzcompress(JText::_($ext->desc)));

            // remove base paths - we dont want to leak data :)
            $ext->xmlFile = $this->removeBase($ext->xmlFile);
            $ext->path    = $this->removeBase($ext->path);

            // Sort so its pretty - not that anyone sees, but debugging is easier
            $ext = (array) $ext;
            ksort($ext);

            // push to the result
            $installedExtensions[$k] = $ext;
        }

        return json_encode($installedExtensions);
    }

    /**
     * Find the XML file to parse.
     *
     * @param $ext stdClass
     *
     * @return bool
     */
    private function findManifest($ext)
    {
        $prefixes = array('com_',
            'ext_',
            'plg_content_',
            'plg_system_',
            'plg_user_',
            'plg_authentication_',
            'plg_authentication_',
            'plg_captcha_',
            'plg_content_',
            'plg_editors_',
            'plg_editors-xtd_',
            'plg_extension_',
            'plg_finder_',
            'plg_quickicon_',
            'plg_search_',
            'plg_system_',
            'plg_twofactorauth_',
            'plg_user_',
            'plg_',
        );

        if (property_exists($ext, 'element')) {
            $shortName = str_replace($prefixes, '', strtolower($ext->element));
        } else {
            $shortName = str_replace($prefixes, '', strtolower($ext->option));
        }

        $try = array();

        // Let the UGLY code begin
        switch ($ext->type) {
            case 'component':
                $try[]  = JPATH_ADMINISTRATOR.'/components/'.$ext->element.'/'.$shortName.'.xml';
                $last[] = JPATH_ADMINISTRATOR.'/components/'.$ext->element.'/';
                break;
            case 'module':
                $try[]  = JPATH_ADMINISTRATOR.'/modules/'.$ext->element.'/'.$shortName.'.xml';
                $try[]  = JPATH_BASE.'/modules/'.$ext->element.'/'.$shortName.'.xml';
                $try[]  = JPATH_ADMINISTRATOR.'/modules/'.$ext->module.'/'.$ext->module.'.xml';
                $try[]  = JPATH_BASE.'/modules/'.$ext->module.'/'.$ext->module.'.xml';
                $last[] = JPATH_ADMINISTRATOR.'/modules/'.$ext->module.'/';
                $last[] = JPATH_BASE.'/modules/'.$ext->module.'/';
                break;
            case 'template':

                $try[] = JPATH_ADMINISTRATOR.'/templates/'.$ext->element.'/templateDetails.xml';
                $try[] = JPATH_BASE.'/templates/'.$ext->element.'/templateDetails.xml';
                if (property_exists($ext, 'template')) {
                    $try[] = JPATH_ADMINISTRATOR.'/templates/'.$ext->template.'/templateDetails.xml';
                    $try[] = JPATH_BASE.'/templates/'.$ext->template.'/templateDetails.xml';
                }
                if (property_exists($ext, 'name')) {
                    $try[] = JPATH_ADMINISTRATOR.'/templates/'.$ext->name.'/templateDetails.xml';
                    $try[] = JPATH_BASE.'/templates/'.$ext->name.'/templateDetails.xml';
                }
                break;
            case 'language':
                $try[] = JPATH_ADMINISTRATOR.'/language/'.$ext->element.'/'.$ext->element.'.xml';
                $try[] = JPATH_BASE.'/language/'.$ext->element.'/'.$ext->element.'.xml';
                break;
            case 'plugin':
                $try[] = JPATH_ADMINISTRATOR.'/plugins/'.$ext->element.'/'.$shortName.'.xml';
                $try[] = JPATH_BASE.'/plugins/'.$ext->folder.'/'.$ext->element.'/'.$shortName.'.xml';
                $try[] = JPATH_BASE.'/plugins/'.$ext->element.'/'.$shortName.'.xml';
                $try[] = JPATH_BASE.'/plugins/'.$ext->folder.'/'.$shortName.'.xml';
                $try[] = JPATH_BASE.'/plugins/'.$ext->option.'/'.$shortName.'.xml';

                $last[] = JPATH_ADMINISTRATOR.'/plugins/'.$ext->element.'/';
                $last[] = JPATH_BASE.'/plugins/'.$ext->folder.'/'.$ext->element.'/';
                $last[] = JPATH_BASE.'/plugins/'.$ext->element.'/';
                $last[] = JPATH_BASE.'/plugins/'.$ext->folder.'/';
                $last[] = JPATH_BASE.'/plugins/'.$ext->option.'/';
                break;
        }

        if (count($try)) {
            foreach ($try as $tryThisFile) {
                if (file_exists($tryThisFile)) {
                    return $tryThisFile;
                }
            }
        }

        // argh! still no xml file! - ok lets get tough!
        foreach ($last as $tryThisFolder) {
            $foldersAndFiles = scandir($tryThisFolder);
            foreach ($foldersAndFiles as $f) {
                if (preg_match('/\.xml/', $f)) {
                    $fileContents = file_get_contents($tryThisFolder.'/'.$f);
                    if (preg_match('/(\<install|\<extension )/', $fileContents)) {
                        return realpath($tryThisFolder.'/'.$f);
                    }
                }
            }
            // look for ANY xml files in this folder

            // If you find an xml file - look inside it to see if its a manifest/install
        }

        return false;
    }

    /**
     * Remove the JPATH_BASE from a file with path to prevent leaking absolute paths.
     *
     * @param $path string The full path to a file
     *
     * @return string The absolute path to the file
     */
    private function removeBase($path)
    {
        return str_replace(JPATH_BASE, '', $path);
    }

    /**
     * Updates an extension.
     *
     * @param $extensionId
     *
     * @return bool
     */
    public function doUpdate($extensionId)
    {
        // Manipulate the base Uri in the Joomla Stack to provide compatibility with some 3pd extensions like ACL Manager!
        try {
            $uri = \Joomla\CMS\Uri\Uri::getInstance();

            $reflection   = new \ReflectionClass($uri);
            $baseProperty = $reflection->getProperty('base');
            $baseProperty->setAccessible(true);
            $base           = $baseProperty->getValue();
            $base['prefix'] = $uri->toString(array('scheme', 'host'));
            $base['path']   = '/';
            $baseProperty->setValue($base);
        } catch (ReflectionException $e) {
        }

        require JPATH_BASE.'/administrator/components/com_installer/models/update.php';

        $model = new InstallerModelUpdate();

        if ($res = $model->update(array($extensionId))) {
            $cache = JFactory::getCache('mod_menu');
            $cache->clean();
        }

        return $model->getState('result');
    }
}
PK��#]/c5�&system/bfnetwork/bfnetwork/tmp/log.phpnu�[���<?php die(); ?>
PK��#]�A�D��(system/bfnetwork/bfnetwork/tmp/index.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */
PK��#]}��u  2system/bfnetwork/bfnetwork/tmp/tmp.pattern.lastmd5nu�[���440a6bbbb49e0b624b9d2756a580e16bPK��#]g����(system/bfnetwork/bfnetwork/tmp/STATE.phpnu�[���<?php die();?>O:8:"stdClass":45:{s:20:"alreadyAddedRootDirs";b:1;s:9:"foundDirs";i:2564;s:10:"foundFiles";i:9021;s:12:"suspectfiles";s:1:"0";s:19:"noMoreFoldersToScan";b:1;s:17:"noMoreFilesToScan";b:1;s:16:"deepscancomplete";b:1;s:8:"tickOver";i:32;s:9:"startTime";i:1561669208;s:7:"endTime";i:1561669356;s:7:"version";s:5:"3.9.1";s:8:"platform";s:6:"Joomla";s:12:"scancomplete";N;s:31:"foundRecentlyModifiedFilesTotal";s:1:"0";s:15:"hashfailedcount";s:1:"0";s:4:"step";i:13;s:16:"connectorversion";s:5:"F291D";s:9:"files_777";s:1:"0";s:6:"hacked";s:1:"0";s:9:"zerobytes";s:1:"2";s:11:"folders_777";s:1:"0";s:14:"hidden_folders";s:1:"0";s:12:"hidden_files";s:1:"6";s:18:"renamedtohidefiles";s:1:"0";s:14:"nestedinstalls";s:1:"1";s:15:"error_logs_seen";s:1:"0";s:15:"encrypted_files";s:1:"0";s:11:"large_files";s:1:"0";s:19:"has_robots_modified";i:1;s:22:"user_hasdefaultuserids";s:1:"0";s:13:"archive_files";s:1:"0";s:14:"htaccess_files";s:1:"5";s:10:"phpiniseen";s:1:"0";s:8:"uploader";s:1:"0";s:6:"mailer";s:1:"1";s:18:"max_allowed_packet";N;s:15:"phpinwrongplace";i:0;s:12:"notcorefiles";s:4:"2920";s:16:"missingcorefiles";s:1:"2";s:27:"modifiedfilessincelastaudit";s:1:"0";s:19:"tmp_install_folders";s:1:"0";s:12:"sqlfilesseen";s:2:"30";s:17:"admintoolbreaches";s:1:"1";s:22:"dotunderscorefilesseen";s:1:"0";s:14:"extensionsjson";s:228156:"{"0":{"desc":"eJwLycgsVkjOzy3Iz0vNK1HITcxLTE8tVkhKzMtLLSpWSMxLgbIVknMygSqK9QDhHhK6","element":"com_banners","enabled":"1","extension_id":"4","folder":"","name":"Banners","path":"\/administrator\/components\/com_banners","title":"Banners","type":"component","xmlFile":"\/administrator\/components\/com_banners\/banners.xml","xmlFileContents":"eJylVU1v2zgQPTu\/YqJD0T1YclrsItjK6iauEaRInCBpgb0FtDSx2VKkSlJJ\/O93SH0nchB0T6LmvRm+4QyH8eenXMADasOVnAdH4SwAlKnKuNzMg9LeT4+Dz8lBjE8WpeOA3RU4D1KVF0qitEHn\/DE8CiBHu1UZuRYbzTIMkoNJLFmOCXncrZmUxI4jbyGElcTWyVelcsEO4VqrH5jaOKrtxEg1MkvhvzCLyUmhuYAPs9lfcTQAHFEVO803W5u8X\/zhOH\/ClD5Hx3BVoIRbVeoU4ZJZSwpCOBECPN2ARoP6AbOQgrZBKKLgKeWMydnqO5whCWcCrss1meGigprc4QMoDYKU6E9gEOHifLFc3S5D+0TJNHHafJc54yJhWc7lPz986qHSmybrCm3J37VIHh8fw5dEhxCt1pB8DGfhLI6aX0IyNKnmhTulZHF1eXd6slotb27v\/r28uPuyvF3cnF9\/O79axVGfeECOXBrLhEggPpxO4aaUBijJ2grTKQWfxOaX254W91wgZJrTzvMg35E9gHTLtEHrW+g4SMgW1e6hZ4TOHtIijpy7DxhVEeOG6dalHNfS2n9XTRvgDXo6Ee5wHG7gXonM7WC49U1e2X1f110eFtuiilZ3e4+SKmm1EgL1ayytSjvO8JsnWxSFv071fw\/KVYaij1QRjO8r13jcWM2qgpNXjrIEntOVTwUz5u86hWB4ax2rOuxy3awnrizuO1kpi2C3zIIryzvIS2NhjUC9xQrMwCp4x\/LiEx2dJh6CrxRZifPABM98FOpNYDJzxsIVjVY7z65LgNrRqqJXur2b4PLnPFC+hec90YFHHzg+zoOBaSRZb2eC2uS0skSnfcTvOOnFbr5eSdQdyH5RKU2IjdIcjT+JdqjuU9zx94meEmVE+OKZ40vtXei3y699vXYvMBWcnoCh5L5pTG8fH2ruIyOCK\/h\/qKWGT38OxPYtI1r78EDqtx7wUmnlNhRKw6S7M89GiL+PQTe9\/DVnaYrGhPQ6D+\/+W+bMcNDc882rYV6bRe086UiDcfPaKNo\/izrIsjWdxCjkKjQcbe0Eo6eZyU3JNnsOsUHBMqopyunZaZA0xsj\/h72ChTQN6ZWu8d8LYXYjYbo\/P3ej54M3jtoJkPwHelYRyw==","xmlFileCreated":1543258276},"1":{"desc":"eJwNydEJgDAQA9BVMkGncYGjWBtoE\/EOXF\/f7zsmE937tk4VcvpNBBazqAsef6qiF6jhZ0fRah8wyhRw","element":"com_contact","enabled":"1","extension_id":"8","folder":"","name":"Contacts","path":"\/administrator\/components\/com_contact","title":"Contacts","type":"component","xmlFile":"\/administrator\/components\/com_contact\/contact.xml","xmlFileContents":"eJylVF1v0zAUfd5+xcUPCB6adCDQBGlglGoa2tppHxJvk5fctQbHDrazrf+ea+ej6ZYNBE9x7jk+vtc5J8mn+0LCLRortJqwvWjMAFWmc6GWE1a5m9E++5TuJnjvUHkOuHWJE5bpotQKlWObzW+jPQYFupXOaWu5NDxHlu7uJIoXmNKOq0wrxzOXxKFCCK+IbdJvWheSv4BTo3+gx5s6MTKD3JH8V+4wPSiNkPBmPH6fxFuAJ+pybcRy5dJX09ee8w5G9Njbh0WJCs51ZTKEE+4c9RvBgZQQ6BYMWjS3mEck2omQohQZzYzp4fwSDlGh4RJOq2sqw3ENtbPDG9AGJHViPoJFhOOj6Wx+PovcPQ3T6nTzzgouZMrzQqjPP8LokTbLduoa7ciXRqZ3d3fRY6JHiNb0kL6NxtE4idtXQnK0mRGlv6V0uji5mi7mFwfTi6vvJ8dXX2fn07Oj04ujxTyJ+8Rd2iiUdVzKFJIXoxGcVcoCDdlUYTQi8Z3E\/vLH0+JGSITcCDp5woo11RlkK24sumChfZZSLW62R4ER+XpEiyT224NgXCsmLdOvKzXcS1f\/1246gb\/oZ9OEvxyPW7jRMvcnWOGCyet64\/Tg8qhclbVa4\/YHFKOlRPMci7LEc+54RBl9imN05YZVQoPpCmVJjiCwfu9Bhc5RDiK3Au\/6QC1tQyi4WlZ8OXgDLQaO088D1ejwC0vbYhzeo95vIBJKUDoaPBzTqYebDgkR1hleO5OOKFBVIAqSzyS39kMjxfr+TmLPql1RXbfrHe8f\/9yZa0ctrrgD75+XUFTWwTUChYCXmIPT8JIX5Uea0BAPIViKqsS55VLkQYVCBFzlvlh6d9FqHdiNV9B4Wu3Opm8p1M8J0yFnk95FsKGJwiFckmmndSVunnZr2PZ5vpn6ydPo\/7TURqAN43W\/9K1WwrH++1M\/HX+owRHBDPoN2ni62bHd48HF7HBxdjTrdUnx2nycB6EKH55t8hxMzbMMrX2che1Y3YjlnyjD4fzLdHYZ2ZC2ItThKJGmc8PgQCqfiWUHOX5N1zQIPYxsL7NDoe3f8P\/G9h8k7No+ltmKP709jH8Sd5ZNfwOwcuHX","xmlFileCreated":1543258276},"2":{"desc":"eJwLycgsVkjOzy3Iz0vNK1HITcxLTE8tVggKDlZIzEtRcCzJz1XISy0vVkhLTU0p1gMAnHcQ1g==","element":"com_newsfeeds","enabled":"1","extension_id":"17","folder":"","name":"News Feeds","path":"\/administrator\/components\/com_newsfeeds","title":"News Feeds","type":"component","xmlFile":"\/administrator\/components\/com_newsfeeds\/newsfeeds.xml","xmlFileContents":"eJylVE1z2zYQPcu\/YoNDpj2IlJNpx5NQTFJZ8bhjy56omeSmgcmVhBQEWAC0rX+fBfghiaHTTHIisPvwdhd8D8mbx0LCPRortJqy02jCAFWmc6E2U1a59fiMvUlPEnx0qDwG3K7EKct0UWqFyrH94ZfRKYMC3VbndLTcGJ4jS09GieIFpnRipfDBrhFzm8QhRjleEd6kf2tdSP4Mbo3+gplL4iZOiMwgd1TgnDtM35VGSHgxmfyZxEcJD9TlzojN1qW\/zX73mD9gTJ\/TM7gpUcFSVyZDuObOUccRvJMSAtyCQYvmHvOISDsSYpQio6kxvVh8hAtUaLiE2+qOwnBVp9rp4QVoA5I6Ma\/BIsLV5Wy+WM4j90jDtDzdvPOCC5nyvBDq7ZcweqTNpp26znbgj0amDw8P0bdAnyFY00P6MppEkyRut5TJ0WZGlP6W0tnN9Wox\/7R8P5+fL1efr69W5\/Pl7MPl7T+XN4skPoTSSaGs41KmkDwbj+FDpSzQlE0UxmPCjBL7n69Pi7WQCLkRVHrKih3FGWRbbiy6oKIzllIsbo5HARH5eESLJPbHA2FcMyYt0q8rNdxLF\/\/ZbjqCH+hn38TJSV3AwlrL3FewwgWd1\/FG7MoZLSWaqNyWNWGj+AMUeYXn3PGIPPgUprPM94iMrtxwqdBiukVZkigoWe8PUoXOUQ5m7gWVPkjU1Db4gqtNxTeDd9DmwHF6QVCNL\/5iaRuMwz46egsioQRZpEGEQh1\/MIF3ibDO8Eabo6RAVYEoiD+T3NpXHRfrPzMeWYujumvXIy8j\/x0ttKM+t9yBl9FzKCrr4A6BrMBLzMFpeM6L8jWNaQiHEJRFUcLccynywEJWAq5yHyy9yGi1C+hGMmg8rBZp07sU6t8p08Ft06OW6T2le5+yZjM4ZKjKJYl50cbi9wPjr3qX8FTxjJ6tjTYCbZi2e+t7nYWydXf7E8MtjgnAoNfibH+o1+ee7uCPxQe\/rOe4IAm2N3vQO88ytPZbLx3bci02\/wd50rk\/ZsvOQHuqI391eZRI87nh5IBlv+PZLuX4ncThVN\/PB4YecvThHf+6p3+KxO4GiHqvQ9x\/HpK402\/6FQRH9xs=","xmlFileCreated":1543258276},"3":{"desc":"eJxzzs8tyM9LzStRSMsvUihOTSxKzlBIK81LLsnMzyvWAwC+EwvY","element":"com_search","enabled":"1","extension_id":"19","folder":"","name":"Search","path":"\/administrator\/components\/com_search","title":"Search","type":"component","xmlFile":"\/administrator\/components\/com_search\/search.xml","xmlFileContents":"eJylVMtu2zAQPCdfsdWpPZiyE7QIWpmp6xipA78QN0BvBiutZaYUKZCUH39f6mk7dooUPQncmR3u7iwV3G4TAWvUhivZ9Tqk7QHKUEVcxl0vs8vWjXdLLwPcWpQ5B+wuxa4XqiRVEqX19snXpONBgnalIpeaxppF6NHLi0CyBKnLWBhkOlwFfhFwAMscWdMHpRLB3sFMq2cMbeBXcccINTLr1O+YRdpLNRdw1W5\/CvwjICeqdKd5vLL0ff9DzvkILffp3MA0RQlzlekQYcysdeUS6AkBBd2ARoN6jRFxoo2IUxQ8dC0jvZ88wT1K1EzALPvlwjAqobp1uAKlQbhK9BcwiDAa9geT+YDYrWum1mn6HSSMC8qihMuvz0XrROm47rpEG\/KTFnSz2ZBTYo44WlUDvSZt0g78+uiQCE2oeZpPifan48V80Hvsf1\/8HI8Wd4N5\/3E4+zGcTgL\/kOfSllyggaUSEequZ7gtTCzjlZPSaiUEapKu0sBvgCOWVpn9O6PchnOM4m6aqAiFcVh5PEDWHDeHQJlvCteYjDMWn+2gxsAyt9woW\/ffPFoH\/eJM9mtKuOTOvQoubmnEC39yA7mxmlWTuwgSlBkILn93PVXMs7uX84An7tZQMGM+VyE6rx5EntgMZ196cUVR+\/H4lzwm7t0ej+2NDr3BgGbOe50jGxp8hSJ9DTt171X7Dvw7Z+DhFP7Twn9XMDtzqvJiE\/yXqxD4zf+S\/gEihc+3","xmlFileCreated":1543258276},"4":{"desc":"eJwLzk0sKlEITk0sSs7QAwAhigSs","element":"com_finder","enabled":"1","extension_id":"27","folder":"","name":"Smart Search","path":"\/administrator\/components\/com_finder","title":"Smart Search","type":"component","xmlFile":"\/administrator\/components\/com_finder\/finder.xml","xmlFileContents":"eJylVV1P2zAUfR6\/wvPT9oDTMk1Cm2vGSoc6QUEwpL1VJrlNzRw7s52W\/vs5TvPRUugQD22ae879tM8tPXnMJFqAsUKrAe6THkagYp0IlQ5w4WaHx\/iEHVB4dKBKDnKrHAY41lmuFSiHW+dPpI9RBm6uE++ap4YngNnBO6p4Bsx7TGdCJWBoFAwe4IUnG\/ZT60zy9+ja6AeIHY3Wds+Idb4yIp079mH4ER31ep\/RoX\/0j9FVDgrd6sLEgC65c74Kgk6lRIFukQELZgEJoVEbpIxogDtf7xl3wE6LtLCuDNj3tC7imVLEvmdg55M7dA4KDJfourj3ZnRRQXXv6Ahpg6T3M1+RBUAX4+Focjsi7tF3U8dpGh5lXEjGk0yobw+hd6JNWrddoQ35zki2XC7JU2KJeNq6BvaJ9EiPRvWrRxKwsRF52RMbXl1Of4wnZ6Ob6e\/Li+nZ6HZ4M77+Nb6a0KjL824ZqAJJof4MsA7GQXt2uBOIRiWz9JgJCRbNtPSMAbbChXOv7OvDV85oKcGQfJ7TqAE2WFWKlxhGF243I+Tu5LGeUNk68Bxk\/gyU6QTkTmQhYNkFqsy2mlQiOPLjc0KFqxOEUY+qGUig4W7Mh52ZYruZJ\/iVv4SyjksZuPZveFZDQfGcGwsuSPUYo8SIRci48jTM\/Fe09iXBRPynqn9\/jFxbl3oVbQdq7ZvRaFSVRqO2XFqot9TeeL+9+jbU\/vq7RVPJVVrwdOf9rjHkuN+WoA7Pv2NWG6PwTtoLQYQSfhus4ZCpCR70Xi4EYZ3hayVuCysQcNt7uP08jsFa4tf4piQ21TcT6T7KswL9D4XuE+BLCnxBgg1UHdRTu+P3fkA7oW3ZdnS761C7s33jsb4+gl3Zp1E2b8d6LYvMx4slt\/ZLvWVetamj7UtGo+avnf0DKeOz8w==","xmlFileCreated":1543258276},"5":{"desc":"eJxzzs8rSc0rUfDILC7JL6pUcM7PLcjPA4roAQCGPQnv","element":"com_contenthistory","enabled":"1","extension_id":"30","folder":"","name":"Content History","path":"\/administrator\/components\/com_contenthistory","title":"","type":"component","xmlFile":"\/administrator\/components\/com_contenthistory\/contenthistory.xml","xmlFileContents":"eJyllMlu2zAQhs\/NU0x1ag+mHAcFAlRm2jqG68IbYgdoTwYrjSUGFCmQ9Pb2GcmW1+RQ9Djzf7NTih42uYIVWieNbge3rBkA6tgkUqftYOkXjfvggd9EuPGoSwb8tsB2EJu8MBq1D47Bd6wVQI4+MwmFFqkVCQb85kOkRY6cIuax0ZTGZ9J5Y7dRWAkEiCUFWf7LmFyJjzCx5gVjH4V7PxGxReGpyqPwyIdiC63m7V0UnrlLzBRbK9PM80+dz8Q0v0CjRO9hXKCGqVnaGGEovKemGXxXCircgUWHdoUJo6SHJJRRyZgGR94bPUMPNVqhYLL8S24Y7KR6AdACY0FRJ\/YrOEQY9Dvd0bTL\/IZGqfMcpu3mQiouklzqby\/V4MzYtJ55px7gZ6v4er1m12CpELbvgdMNWDMKa5OUBF1sZVFuiXfGw3lnPJp1R7Of\/els\/PRn\/ns4mD92p52n\/mTWH4+i8JSn8IVU6GBhVIK2HTjpq5Pu\/Pu7nt6UFVkRhQfxjJQ6wQ3LfK7OiJ3hqmHLbVAiK\/blL+tXQNXARQfWKIX2uvo\/NEpoVeUknyNi5zvVM1TFe1qOiRRvKyZB9XbQSuL6TDmuhB6g0OlSpO8soVbBC\/peUTd6PwJeO8PKZtdfHqMt05PcY\/+VyW3ddbajVZ01vLxrFB7+J\/wVj7+G\/Q==","xmlFileCreated":1543258276},"6":{"desc":"eJxzzs8tyM9LzStRKMlXyE3MS0xPVUguLS7Jz1VIy0zNSSnWAwDhvQzA","element":"com_fields","enabled":"1","extension_id":"33","folder":"","name":"Fields","path":"\/administrator\/components\/com_fields","title":"","type":"component","xmlFile":"\/administrator\/components\/com_fields\/fields.xml","xmlFileContents":"eJydVE2P2jAQPXd\/hZtTe8Bht2q7UoO3LVDEii+VrtQbMskQvHLsyHb4+PedmCTAFtRVj5735um9mUmih10myQaMFVp1glvaDgioWCdCpZ2gcKvWffDAbiLYOVAlh7h9Dp0g1lmuFSgXHJs\/0M9lewZurRNszlPDEwjYzZtI8QwY9ixWAmRio9AXEOAFkg171DqT\/C2ZGf0MsYvCqo6M2AB3qN\/jDtiYm3hN7tq3n6LwDCiJOt8bka4de9d9j5z2R9IqqfdkmoMic12YGMiYO4eGKfkmJfF0SwxYMBtIKIo2IqgoRYyhgQ0mT2QACgyXZFYssUxGB6gOT+6INkSiE\/OFWAAyGnb7k3mfuh2GqXWavP2MC8l4kgn19dlHp9qkdeoD2pCfjGTb7Zb+TSwRpFUemJ9\/FNZPRBKwsRF5OSXWnY4XP4b9UW+++D0eLXr9effncPZrOJ1E4SkP21ZCgiUrLRMwncAK55d4qFebVM5oKcHQfJ1HYQOcsQ67vsTwyicqeBBV7QSWfK8LdwodZKwfTTk7YZ3hlemXrj3B2z5xxOMYrKV48ueOXhntFdn+Fa7B1yDza5gUS8ONgMtophOQlyHHl\/JK10bA9nzMzTDx0LlKC55eGV+NEsfxnwCqNfgesLoY+jc9ftsU94InX8H\/pWD3F1SOL38A4csLiMLmH8X+AGy0n9A=","xmlFileCreated":1543258276},"7":{"desc":"eJzzzC0oyi9LTVHILc0pyczJzEsvTcxRSM7PK0nNK1HITcxLTE\/NBTGT83ML8vOALAD2thPJ","element":"com_associations","enabled":"1","extension_id":"34","folder":"","name":"Multilingual Associations","path":"\/administrator\/components\/com_associations","title":"Multilingual Associations","type":"component","xmlFile":"\/administrator\/components\/com_associations\/associations.xml","xmlFileContents":"eJyllE1v2zAMhs\/tr9B82g6R0w5Di01Rl6VBkCJfmFdgt0CTGUeFLBmSnI9\/X9px0qRNe9nN4vuQJsXXZnebXJMVOK+s6URXtB0RMNKmymSdqAyL1m10xy8ZbAKYiiFhW0AnkjYvrAETopfkr\/QmIjmEpU0xtcicSCHilxfMiBw4ZsyF91YqERD3LK7DKIsSUxx\/sDbX4hOZOfsEMrC4iSMhHdRJ9yIAfxCmFI5ct69uWHyiVKQttk5ly8A\/974g0\/5GWhV6S6YFGJLY0kkgYxECdk1JV2tS45448OBWkFIseiiCFbWSODnwweSRDMCAE5rMyn8YJqOdtL8Bck2sIxo7cT+IByCjYa8\/Sfo0bHCafZ3DwP1cKM1Fmivz86menVqX7cfeqQf40Wm+Xq\/pW7BSEGt64LgE2mbx\/ohKCl46VVS3xHvT8bybJNPesPtnOJ0k87\/j0fy+n\/R+D2dVgMXHdPX2qj3lgxNN5ILlYEqicrSH1LjQ78dLjd68gcUVXyculAZPFlan4DpRXbmyR6PUbhBSgvcUPcniQ\/AUkdYsVPYhctwRLZbFR7WCs1qDO4vVnR5B6NkmdqwvQRfvaVpsbRnOa7lNQZ+XVgrWJ8quNV8\/amGyUmTvXOVeJUHghsC0Br8ivg\/G9Zm+\/hQprhgN2kD\/Ucdvz9R6OVX9o21fWYrFh58LfwZHV4mT","xmlFileCreated":1543258276},"8":{"desc":"eJw9jsENwzAMA1fhAEV26A5dQLWVyIBiAZacINtXKdD++Dge+ZLm2K1OZbjY6SBo84CtCGEUUu6VRjI9xHG2ENAo0g6uGaIVZV\/wXIMHLpsQOrIm1LcEboUHxfRbSP3XQNjf8kgqT3xXz6aKN4Nm2E6JkuqFjTsPCq7LB\/yjQCg=","element":"mod_articles_archive","enabled":"1","extension_id":"200","folder":"","name":"Articles - Archived","path":"\/modules\/mod_articles_archive","title":"","type":"module","xmlFile":"\/modules\/mod_articles_archive\/mod_articles_archive.xml","xmlFileContents":"eJydVlFz2jgQfk5+heqn60Ns0k477dSo5zguhTGQiaGTe\/Io9gLqybJHkkn495UtmUAhcL0nS9r9Vt+3u1rwvz4XDK1BSFryvnPt9hwEPCtzypd9p1aLq0\/OV3zpw7MC3vggtamg7xRlXjNwXpDv3WsHZYwCV31HUqVtBahVmeso1VKQHBx8eeFzUgDW4JQIRTMGUi+yFV2D77Um7UJqDRN4VJYFI2\/QnSh\/QqZ8z55rj0wAUfrWW6IAj2q2Qe96vY++t3fe+JXVRtDlSuGwW6G\/wreN9wd0pT\/Xn9C0Ao6SshYZoDFRSutxUcAYat0lEiBBrCF3dfhtOB2b0UwnBPBgMkcD4CAIQ3f1oz5GsTF1uUHvUCkQ05zEFyQBUDwMo0kSuepZq+ribIVHBaEMk7yg\/O+fbQ7cUiw7+ca6dZ4Lhp+entxDx8ai3SwH\/N7tuT3f67bakoPMBK2afOHx9DYN7mfDMI4SvQi\/D39E6cM4Tm+jJLwf3s2G04nv7SJ0gAXV5dMLs2qqh0xXtN1xUGDnaNndalX5XhfARCtZDgKromLaYja7t+AVsArEAdJsZFscwpc1WVp63Q4ponsa+NXgxsHtxz1KiXKq62JB\/yuC3MiDKC+blmIjAv0Lm74z+h7Fd2n0MNNNofOcpLoa8zhKx8EkGET3B4VxkGeamy\/o0mYGWC5Rk4e+UxFBCtk8tq0FlLU9EkkzY7K2dnlhrFlZc+WYE\/PKeV08grBHjDwC6ztHe+XbMIpv03A6n8zSOLiJYovZaZn\/gGy6bQtckJrpUXLdsye6uPoF9R3KFSw7Up6R6XU68eUx2SRfE55B\/qpyRjZlvS\/dtPKewSZgZCgHcSP1n+n8hOIdV1tUi3hR6hnKR0gZBhkjUqZy8bzHTul5TPS022cWTsf2nsTm1ezCOEiSNPn28DrT89Cd4ojySeqJf05ARrIV7NFmVKpzlMNAN8Zk8CdUO8jR\/jnVPhemIS78so2N1oTV0GDwaBBPb4I4nSdRapa+V3aj7wik5+BDXj+CeB6lk6nltx\/BNu3p7KWKFnD2SR7PSJTOhuPoT\/NoUcdS+bl37i2ekqLbeV\/JiuY58N8vkUr\/hGcny2Nd8Cv5\/G0gvOzaIdyNTd\/b\/qXBvwB3Pq2m","xmlFileCreated":1543258276},"9":{"desc":"eJwNye0JgDAMRdFV3gTu4A4uUNtIArGVfCBub\/5d7jlYHPcaqQTn9ToaVDywLgRTUbVRpxn64cmzkGmgzYGeZvWxW0hX8u0HU\/Mcig==","element":"mod_articles_latest","enabled":"1","extension_id":"201","folder":"","name":"Articles - Latest","path":"\/modules\/mod_articles_latest","title":"","type":"module","xmlFile":"\/modules\/mod_articles_latest\/mod_articles_latest.xml","xmlFileContents":"eJydV993ojgUfu78FVmedh+qdmbnnNldZZYiVXsQegR32qecCFGZDYQTQlv\/+7lAsKKitU+S3B+533dvcq\/9768xQ89UZBFPBtpNp6chmgQ8jJLVQMvl8vqb9l3\/1KevkiaFDpKblA60mIc5o9qb5ZfOjYYCFtFEDrQskiCLqVzzELykK0FCqumfrvoJiakOxpgIGQWMZpgRSTPZ75YS0CA5WAn9nvOYkd\/Qg+A\/aQBytQ8agaBEwqFDsNTvc7ZBn3u9P\/vdxn6hx9ONiFZrqZv1F\/rd\/KPQ\/oqu4efmG3JTmiCP5yKgaEqkBDgdZDCGSvUMCZpR8UzDDrjfugPfLAqAD6qPnDka0YQKwtBDvoBtZFeimhr0GXGBCpTiH5RRiuyJaTme1ZGvgKr2swVuxSRiOgnjKPn3Z8lBh4tVDb+SbpXngukvLy+dQ8VCAmoqBv1Lp9fp9bv1EiQhzQIRpQVf+tQdYtvwLc\/HjvXDw49TGw8tz5xNHvyJ6\/S7u8pgu4wgcfBRfRWJQ1U9lHWxn1rtWL476Trtd2vzyhdnIRW6jFMGkmqxe4a+piyl4sCyWmRlVkiyyslKBVevkCRQyzS5Ht1qevnTORZRlESQD2XzEQfZJjtw8rYoAywgoP\/pZqDdjy37AVuPPtQCcOxhSMLctvDUcIyRNdvNh4a6VTkny2ilKKEszFBBwEBLiSBxVtyurYRKJVuQLAoqkZKVn1eVNIDrEmrVTnWtYYeuuNioTUYWlEGsJgQzcmdPanunHAbafvHcTSx7iGuLso6U2fYNgXN4jAEPrKUSxjmTUVqUkBQ5VZuQWLg2Ay1KJLAtiIoL6GhDxPOtxwpRkscLKpp4WkJ2544P+7eWfQHO0mgHZEiXBKAMtK+HGOiqjqQdQbbmL3gJD1kuaDM3LMrke3DcWYY\/n1nDS6Fs7Y6hOQXmqqqvqz4v\/aNnwnKIV9PvvbH7o9\/l9cNxRKkHWuPJ0DqtdaMdvFH\/Gfbcwq5jP+HilG30TUfF2wAEt7LNBbwy0Oo+RLQ7G1qziTO6lOit3TGiUxxmwUleg1KjhZCZBc3Fx8ZwuE\/Fvpv4HW5AOIGYz3hK3+HpYX5rT7zx2aDeA85352arpyvlSZAk5PEZTzPDubBgchgHcPSxizn3ynf9olopbY7VSe9kjfTagBvOk+ucuW2LDY5pq4OisvDtE56e8ZJwecKN4\/rv9lTOdTTEi02bN3MGt790dlk2q1mpkczG1sl0GnN\/7F6cUGW1k9Kjna9oA4UTVW9\/73BQN5A3fNDvK4j77Z+EzyQJoI+0TQCMbHjebJjVJNcQ1GOAQmAXXfLJnZ9oljuqaq5RFm+421tgFUHASJbhbPnaiE7CEEGAi2ZkpjtV59Q0VyvTNjwPe3eP7ZGeN91JleAvGfzVOTuFkGBNzzwRh+eahjk+2U3aTY49EDcfaNnQZ+9Htntr2MXDg6vPsw38MK76jqv4LruUJXtYRnGTwmOD3HFGLOxPptalPCqrY1T+1eudIvNMIUA5N5GsozCkyf4hmYRp\/HTnVyp6C597D8LbqvwfUv996He3c7j+C4H3pQQ=","xmlFileCreated":1543258276},"10":{"desc":"eJxNjdENwjAMBVd5E7ADM8ACJjU4khtHjlPo9rh8VPxZuvO9u9SB1ZapjCH2HiBoHQF7IoQT5d2tTyVHn49kwguuHrUoj3QoQJ7PUVVRpju3uOBmK\/\/BLDestENoY\/CnV88Kb9xSsvmSY2z\/ueeqczlSX\/k+O28=","element":"mod_articles_popular","enabled":"1","extension_id":"202","folder":"","name":"Articles - Most Read","path":"\/modules\/mod_articles_popular","title":"","type":"module","xmlFile":"\/modules\/mod_articles_popular\/mod_articles_popular.xml","xmlFileContents":"eJzNV1tz4jYUfs7+CtVP7UxjSDK7s22Ntw4YQsZgBsM2edIotgBvZcsjy0nor++RL4CDgZC+9Anp3HzOdy46GN9eI4aeqUhDHne0K72tIRr7PAjjZUfL5OLyq\/bN\/GTQV0ljJYPkOqEdLeJBxqi21bzRrzTks5DGsqOloQReROWKB2AlWQoSUM38dGHEJKImKGMiZOgzmuKEJxkjwmjlLBAhGagJ857ziJGf0ETwH9SXRqukg4QvKJHw1R6R1LzP2Bpdt9tfjFaNruR4shbhciXNbnVCP3d\/UdKf0SX8XH1FbkJj5PFM+BSNiJQQj44sxlAuniJBUyqeaaCD+Y05sM1CHwCh5mA8RwMaU0EYmmRPQEZOwaqwQdeIC8TAJ\/EHSilFzrBrjz1bl68QVWVnE7gdkZCZJIjC+M8fOQY6F8sq\/IK7EZ4LZr68vOj7gooDYqUP5o3e1ttGq7oCJ6CpL8JE4WWO3B6euJO5Y03xw8jBPdvrToeT2dAdG61dQdBbhJA1OBQnlTRUFENeFHt51RqzrSerxGhVBgprnAVUmDJKGHCKy+5XzBVlCd3XLC5pnhMSLzOyLN2rbkgSKGUaXw5uNTP\/0RtdCuMQ0lEqfchCuk73rGwvuYsqCPQ3XXe0+zvbmWD7YQa1ADh7GJIwd2w8ssbWwJ7C1ZvhqW31NNQqijlehMsSEsqCFCkAOlpCBIlS1VwbDpUl74mkoV+wSl5+vCi4PjRLoBWUoquBQpdcrEsiI0+Ugadda2YP3OljSd4piI62Wzr9oe30cCWdV1Gpshkf8A0eYYgF7rJkRhmTYaIKSIqMlkRIKjRMRwtjCUALUvoEUByKhmcbi0U0cRY9UVGPpcFddz6eYce6tZ13xpcr7AQX0AWBEDra533f6bLy4LDn6Yq\/4IXgb9yHmRnyU973bWs2n9q9cwLY6OzE4DOSplAwMr5cCp4laHO6XNM05m9DvToW6kVRcRcGz31Az4RlVOmY996d+5fR4tU0aZBqg9TdsGfXpVSXA2wHMcwrPU2IT8VVDcWCVpJWYrfGDmckgD7ARWjwDtbssTCVp5LSgw7oD52ZPR2OB+dkpq7YVGJ8sTiKseLXxrmbT3Hs9vv4u+XM7ePgC5hVtNGAcm1qjQf2u8xQeO7C52ZLU9uxZsPvds96bLJ1KtNlboD6wbyo09k5yU8N+SB6vnTQyhnVy8pOvYJ+z3H9dQPLsQxuLTaB14UXYQat+44kEPVIhYBUsyUgDSGud5pK1GqTrnCWNBrzZtZ0NpnfOkPvTpXuB\/KaSnhPcY5bUYX1hwne+4CcHOa5Hypj52R4q7STYQlOpGppW3AREVl7m1SSZRjVH6w0\/AcI19dvBmMG6yPOpP+O+jg1lQCB\/4qPPe6di06l8v\/GpmqtHKAPbAHboXQeOjW9pgFx0z76Uh6KuTYpWsVy16q2uwKFt8seCZ5J7KtuP4ARI2ue1XeMYnOvMaqlr4jPctRu9OjOj6xIO6LlDltqbPE4nLjCg3z9wOniteadhLWRwDCse9Z1R+V3vDIJxa3rWJ6Hvf7DYU9Pq+6kUPAX2IhuTu6dxF\/VK27\/Kdr\/btfq3h1dDg6rNFXZR9exgePeWg6eezYujid3s32\/8lmPx27p33lTP0cPq4FxsmmbEbHxbDg60rJHtZqg\/K19tGNPFAKUcz2SVRgENH77EXjs4L\/j0fSUIuYRPHcnwvaW\/+ms\/i0arc1fL\/NftwEpeQ==","xmlFileCreated":1543258276},"11":{"desc":"eJwLyUhVcErMy0stUvDNTynNSVVIySwuyEmsLFYoAUolJpdklsFUFCukFeXngsWd83ML8vNS80r0AAnWF8M=","element":"mod_banners","enabled":"1","extension_id":"203","folder":"","name":"Banners","path":"\/modules\/mod_banners","title":"","type":"module","xmlFile":"\/modules\/mod_banners\/mod_banners.xml","xmlFileContents":"eJytV1t3ozYQfk5+hcpT+2DjJN0921PMlmDiOMXgY+zu5okjg2yzFYgjRBL\/+w4IHKhvS7dP6DIzmu+bi4T2+S2m6IXwLGLJULnpDxREkoCFUbIZKrlY9z4pn\/VrjbwJkhQySOxSMlRiFuaUKO+ad\/0bBQU0IokYKlkkYC8mYstCsJJuOA6Jol9faQmOiQ7K\/gonCehqarkCOzgHaa4\/MRZT\/BOacfaNBEJTq3WQCDjBAg4bYUH0p5zu0O1g8FFTW+uFHEt3PNpshW7WI\/Sz+Ush\/QH14HPzCbkpSZDHch4QNMVCgCt9ZFCKSvEMcZIR\/kLCPpjfmwPbNAqAB6KPnSUaE0CAKZrlK1hGttyqKUG3iHFEwSf+O8oIQfbEtBzP6os3QFXb2QO3YhxRHYdxlPzxreSgz\/imhi9398JLTvXX19f+oWCxA2KVD\/pdf9AfaGo9hZ2QZAGP0oIvfeqO\/HvDcay553+d2v7I8sz5ZLaYuI6mNgVBbx1RksFAjoqgIZkDZS7U4VSase2n21RTa3Gpy2hIuC7ilMKOnDRt6ltCU8IPNOUkKyOAk02ON5Uz9QwJDPlKkt74XtHLT7\/pSZREwHkl20Ux2x0qv09KhwqX0d9kN1SeHi175ltfFxBn4NDzgeClbflTwzHG1rzmWkGqTNNkHW0q+ISGGSrADpUUcxxnRbXsd4goJldyf4WzKFDKBRyGpUCKxXaoqGX2RJngWDAOeRunLIF6zIphjUgFdIRmqjQszejX5UceVg6rowTmGyKk0JUsfAr2qwWKV4QOlWYWPUwse+QvjPnYWvi2cW\/ZlWwjm85oFAm4V1jjnEIvuakWIAGglIZKlAiyIbxa1eVHY6Vp9IJpDk4OFP3pfu5+8ax5ZXlmzC1noamsTugjWjcHWo715bzK7eFB7mw5aytpkuyTLAcsT9okJ3m82kM8SbPpLp1OLEuFYyR\/OEtyQHGWDRXAHIXQz3rgHuF1DqqncUVhC5XMQHlHXMImZ6Y9sbpBbOk1kB4FdsZ1uFDazsMK2TC+azv+ZBoLa+zOn78zAJV007P9zVokwr5Mq80YohOlRZMVPCeHWHzMOd61w1TrmNLjiGSX0EIL9DOCebBtQYZLO2KXa33crdDHTfCVyyuR9Dac5Snaj3o7kiXs33k6+A\/NoCjrZ8s7X8hFx3DcbnXLOFxf8E7q3B\/nhjNypxPP6sLcu9KxAh5c6odNg38Z9tLyvcXE\/PPZnY+s+cQZn6eH4yRk8Wkre+e6Mbgl8C7kvoAaaJFYLGB41V0i8tEywPsuLFYaRzpDhtdkK2JaLXP2Col5V+cpozD7dXCpktaMiR8B9OC6i26AKo0fBvQeLXhttN8e1bsEhy84CUio6CfAU7xjeRu3fCK2NurOKd037KK9P7vLM12+IVo9qCqNd9CnIyI9KPuMn63fviMqpjutzqk5ljPTNjzP9x6+nvb0smojTq2AnLuKgi250GIOzzUN8xGquourtcr\/9Qgr+u7Ydu8N219C15LDi1340C\/ZZxy38q\/j26pgzxdR3Kbw2APrOCOWv5hMzzTqs1rHqPxtcPYSO1aK9az896h\/GzR1\/3LQ\/wG3SHwY","xmlFileCreated":1543258276},"12":{"desc":"eJwFwYEJgDAMBMBVfgKncYHgf20gNoVUpNt7d3YvPMk3BIvIr7C6QK8Ztn3cyAZD7UG\/bIloEo8fPzUURg==","element":"mod_feed","enabled":"1","extension_id":"206","folder":"","name":"Feed Display","path":"\/administrator\/modules\/mod_feed","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_feed\/mod_feed.xml","xmlFileContents":"eJzdWN9z4jYQfs79Faqf2gdsuMx1rlPjqwMOB2Mgg6HNPXkUewFfZcsnyyH0r+\/6J3ABgtPOtJMnJO230n6fdmUJ\/dNTyMgjiCTgUVfpqG2FQORxP4hWXSWVy9ZH5ZPxTocnCVGGIXIbQ1cJuZ8yUHae12pHIR4LIJJdhfphEAWJFFRyoZAQ5Jr7OF28EtQHxXh3pUc0BANncZcAvq7lXRymKUKFMeI8ZPQHcif4V\/CkrpXjiPAEUIlL9qkEY5SyLXnfbn\/QtYPxDMfjrQhWa2n0qhb5sfdTjiYt\/Ol8JNMYIuLwVHhAxlRKJKMSkzGSwxMiIAHxCL6K09fT4dws8FANMAaTBRlABIIycpc+4DCxC1MlDHlPuCAMYxK\/kgSA2MOeNXEsVT4hq2qemrgV0oAZuXy\/fc01ULlYVfQLaw1eCGZsNhv1OTCzIKyMwbhW22pb16ouWnxIPBHEmV7GeNp3by2r796PbbdvOb3Z8G4+nE50bR+FTsuAQYKNopXtGCnSIE+HfCOVekvVeB3rWgU88DLWwGIQxxCc+SAMGcYMLUUHF9aqlXVGo1VKV2UYVY9IiskKUWtwoxj5j1qHgXmIOpfAi72SbfLMc9fJQ8lIkD9h21VGny37zrXu57ixqJvjoqIL23LH5sQcWDPX7I+Hk1xihWhFakbLYFVqAsxPSKZAV4mpoGGSlUdtAVnaHmgSeIWptOXNq8IqkiQVTCmGigrd9Rl9ANZV6n2+HVp23505zmJmu7Z5Y9klcG+\/T8Gz\/CjRuCmY1fsLJcFfuPCHdtkV8C0NBGDhS5FCOfhIWeBjOez5oSanaQl5SAsPkICfJzZvwGp+QMljNElQaxm1VoKnMalbrS0kEa9nXNKU4TnX\/k6KIJKwAlGOFpt1pfN8bYLMUyTQUYzRF8vRNV4V1hFQG0GT6SEmKwPU55xYMpAMmsrlOPPhHNO1QSYUDv9AuM7\/TLgsIxvq1jfnl2uWg\/+FRPsPlEFWTZXZfUMuF2jP5w3lVRDi56KhfMMxfjUuFq5AvyXJJOA3cF+yKA0f6oBOaDa3xs7lmuXoPc1qMa7PiXH2O5WF\/YpayUJ5Tb187\/fGEuAV53GuSJMzuXZ4KxeADRe+6\/E0kk3L54\/prN+bLibzi8XbeeypV9z\/fm4kklbcdrXqunv08kv9Rxp52fPiBHVGtzw9pF08TQ4MJflRQcG0M7pfposzrPeg5aW+9NixPn0qFBHkKeUmy6eD6CQ+qCm+WA8j603H5TpOqXPR69mm47jO7f3pSF923dsowTdJfdidJuBRb31Yhgwf9S+F3DN7n4eTQZNQK5djR\/Jrj6eBPb0xbXfhWG7RfLHgnsf1u2kvLHcyLeNrVo65eq4MQnixHI8rYrnz4fjMeXbW65iUv7Qbl2LVy9+\/1btV1+q\/g4y\/AZ9fH6M=","xmlFileCreated":1543258276},"13":{"desc":"eJwLycgsVsjNTynNSVUozsgvL1YoyUhV8MrPz81JVFRIzi+oLMpMzyhRyMxLyy\/KTSzJzM\/TAwAALBOE","element":"mod_footer","enabled":"1","extension_id":"207","folder":"","name":"Footer","path":"\/modules\/mod_footer","title":"","type":"module","xmlFile":"\/modules\/mod_footer\/mod_footer.xml","xmlFileContents":"eJyVVcFymzAQPadfoerUHgJOO+20U0xLHOI6g02m2J30pFFgbdMKxEgiif++CwLHNE0yOSHtvl29fVot3te7QpAbUDqX5ZieOCNKoExllpebMa3N+vgT\/eq\/8uDOQNlgiNlVMKaFzGoB9D7yvXNCSSpyKM2Y6tygrwCzlRlmqTaKZ0D9V0deyQvwMZitpTSgPLc1oIPXCFb+hZSF4K\/JpZK\/ITWe29kRkSrgBs864wb8i1rsyLvR6KPnDuwNTlY7lW+2xp\/0K\/Jm8rZBfyDH+Dn5ROIKSpLIWqVA5twgE+2QQAjSwjVRoEHdQOZg+n06zC3yFGUAf7pYkSmUoLggl\/U1mklkXb0i5B2RigjkpL4QDUCi2SRcJKFj7rCqPs++8LDgufB5VuTlt9+tBo5Um758692DV0r4t7e3zkNg40FYx8F\/74yckef2W\/RkoFOVV41e\/jw+Y+dxvAx\/sKt5xM7CZPJjdrmcxQvPPcRh2DoXoHFhV82dEdsBbSd0l0kPLtaptpXn9mAbKUUGyjdFJdBjN5ja7XN7gpebmm+6g\/odMRw7Ecrj6Sn1249zcExe5qhmB31BnN7pB7H3m5bOFkRF\/sBuTC++h9ElC6+WeIGoTsJQuVUUsnmwCKaonhWREte2X7nON51WIDJNGgXGtOKKF7p5BHsPmM7HsxteppBZb+dul0cWIPhO1oZa0+ELHDgEvwaBdM9nYXTGgmjJouBXvGo+p2HUgQ5udgDtauoimmawAVjUI6Qsg1RwrZle3w3YGRwYHB\/mkNkknnfnJMyebHeTKEgSlpxfPc70+dB7ykdK3mocSc8VkPJ0CwPaItfmOcqTYPJ9tpi+hGofckAxgzWvBc7Kk86AzwAbc0zz0sAGH5O12oY48mSbm9xwUUMT419Mo\/g0iNgqCZldeq7s3+t\/QkbUf8jrZxCtQraIO37DDM3LRMGeVo+ZvBhKWNbF9Z7+kyKGbDmbhy\/VsYv6n5SfR6OnxHymEbCdh5Vs8yyD8t9DtMG\/Tfrk9XQQ\/xE979c4AdpB0e3aGdTPD8\/d\/3P9v0NMRkg=","xmlFileCreated":1543258276},"14":{"desc":"eJw1y8ENg0AMRNFWpoL0EHFOTmlg2R0HSyZG9iJC9wGJXN+feU3EPbpWI57cUqzkhIe39YBNzdA0Fys7CkS\/bPis88iAy\/+XkPD56LmwqmjFUDrfHjs8TmY\/1xcq8\/YDyCUqOw==","element":"mod_articles_news","enabled":"1","extension_id":"210","folder":"","name":"Articles - Newsflash","path":"\/modules\/mod_articles_news","title":"","type":"module","xmlFile":"\/modules\/mod_articles_news\/mod_articles_news.xml","xmlFileContents":"eJzdWW1zm0YQ\/pz8CsqndMbWix130lQixRKWcJHwAEriT8wZzhIJcJrjsK3++u7xJmEhIWg77eST7mV3b\/fZh7u90+DTS+ALT5hGHgmHYr\/TEwUcOsT1wuVQjNnj+Qfxk\/R2gF8YDrmMwDZrPBQD4sY+Freal52+KDi+h0M2FCOPwVyA2Yq4YGW9pMjFovT2zSBEAZZA2UaUeY6PIzvEz9Ggm4zDPIpBh0q3hAQ++km4o+Qbdtigm42DhEMxYrDkGDEs3cb+Rrjo9X4ZdEvjXI6sN9Rbrpg0ylvCu9HPXPpKOIef\/gdBX+NQMElMHSzMEGMQTEeQfV9IxCOB4gjTJ+x2wHxhDmz7ngNoYGkyXwgTHGKKfOEufoBhQUuncmCEC4FQwQef6G9ChLGgqSNlbiod9gJR5XaKwJUAeb6E3MALf\/+WYNAhdJmHn84WwgvqS8\/Pz519QT4DYpkP0mWn1+kNunkXZlwcOdRbc7ykmT62ZcNSR5pi2nPli2l\/nWn2WDFHhnpnqfp80N0VB+1HDxIHjbTFUyekfEh4UU6tuJ\/tznq1HnRz1dQO8V1MJRasfZhJO7v2pRX215juaaadKMkJCpcxWmaO5T2BIeAxDs8n16KU\/HT2\/fFCD3KRaTRXjzb7JradxDnuvvAdb4bi7VTR7mzlqwUsAGxNG+BfaIo9k+fyRDHKmbjRZHMqdlM6h4\/eMgMF+24kcAiG4hpRFET82ypmMMvmHlDkOelUNpc036SzDnwurpiOpB81jOAloZts0EcP2AePR7KlTHTjPhveIcNQ3CfPjapoYzvXSXiUKRZ7CKxEAhsigj7LJoPYZ96aU4jRGGeDkFz4cIaiFzLAnKLcM8dHUQRky3RGqd8ejtJ5AOxAzJDOUsTbfh6sJU+q4uTju7EAC0A9xBHD7j8QgYWWtb57AbCp5D3sqh4p+38oH+oM2GXamnytaE3ymOntRJ55\/sDC8yUl8VooWucbHIWksP6IILih2NtHAi8xzUZTcr4ZkMQP4Qn5MQTWF6Xbe8UcdEm+51QI9UBorpdl+H4AsB3BcGmDA5TYj7Hvl8D0vYg1wjKbao1prr+DbQFaSEJ8FKEkCLFi79aTLdtW55ahJwsVAAmVhhIcDtu5WWha2UyllcTfFulgOLCZx\/zWvLZUq00KUrUfhdW+F35PYYxaUlpT53+0hHKrWkXkozBloDurP8Nzh\/gkH49W5JkvuaXHx\/5RZAGziaZfy5q9MBU7bTaH+aR8nUTpFUa8gG6cjBTHqSKP1XnlMVSjslu1vc7E6n1bdFcciGn\/OFirCy50USN0yYUua4Tec6H3NUJXXOiqWW4YFPDAPvwEZUfUescx1AkUaspnZW61OFDL6n9jB+r\/n3YgzikNRczEvB5lxZfcGF1TuZMN2dKN5shuVX8kVNNyhUHt3BrSqf4lKQcsuHW0gLWkXrXHH8fsxAwchpY7UI\/tVB0rzdClsEkHhLYuPQzYc2e60eLILDT\/gwLk30LTIXFYpmgYBw+FQ3UltaXM2txOErUqTl4dg+fwHSv54h4xYjHF5bvx6bXUjSJbC0MZNw+n0GxcSR0si9qmu4I6+15\/lrWFYutz7T7ZJQr\/mzGHUBfTNtVSCppujBWD1z6N4S40q+BGnTV\/0ItWdrw+CnJJsAKkV2vdLa411ZzyJMtWDeiokzxqAhPr7Y5gU7FOtBoQ14M0nGIWBFQYOs1ukcl6u3mjzuTKg0qtqO6nqlVzzFIUuu9+PsEBQ56P9VkzproexQ4Xr6Fq7m6ymD1WDWWUXKYPMvSQQvPTNi\/u81R83KXnWUGosy0JzrZ5O8vwPkb33jYbqbeyOVLm49pU9l\/r8diqFIskbNsRZmlOXj9wIvcJhQ4n8qGbMdqQuHwspS\/VpYk8bSlFZI1XSff64kixtCOavd9mGtuMHT5kUg+SA9+OHl\/KD5JQ6CHIUdmzkT7L1sl5nPZGmmyatnnz9bCn9ao7JKPkGWqQy7oAHOSscM03sL\/uSB5Nj+7Th1Wafwe1JGzwULDvV3rwzfXMv4aVEkcPLt5BGcKqcqkaEQUu\/bMjZedRrSoof+0drSZriMCfwkuRrDzXxeHrRfhzQ\/F\/w4FHzVREOm1D2PaS\/1vyP0gG3eJ\/BukvSDEvxw==","xmlFileCreated":1543258276},"15":{"desc":"eJwNxtENwCAIBcBV3gSdpgsQwUoCYiB+uH29r3uHFjx4m4C1ltEpEJImh0OdPkHP2xM70UaUTPQwlnx+qCoWOg==","element":"mod_random_image","enabled":"1","extension_id":"211","folder":"","name":"Random Image","path":"\/modules\/mod_random_image","title":"","type":"module","xmlFile":"\/modules\/mod_random_image\/mod_random_image.xml","xmlFileContents":"eJydVltzmzoQfk5\/hcpT+xBw2mmnM8W01CY2OfgysX1O+sQosLaVCsEIEcf\/\/iwIHHuInTpPSLv7rb69Sdg\/nhJOHkHmLBVd48rsGARElMZMrLpGoZaX34wfzjsbnhSI0oaobQZdI0njgoPxjPxsXhkk4gyE6ho5U6hLQK3TGL1kK0ljMJx3F7agCTgIDiUVcZqELKErsK1KjGpaIEQ6N2macPqeTGX6AJGyrVqOFpEEqvDEPlXg3BR8Sz51Ol9t60Be2qXZVrLVWjm9ZkU+9D6W1l\/IJX6uvpFJBoLM0kJGQEZUKYzFJC7npDLPiYQc5CPEJrrfuUPfnEWYDHAG4wUZgABJOZkW9ygmgVY1eSGfSCoJR07yO8kBSOD3vPHMM9UTRtX42QXuJZRxh8YJEz8fqhyYqVw14WvtznghubPZbMy2YalBs5qD89nsmB3baraoiSGPJMvKfDmjST+8dcf9ySj0R+7AC+9GQdj3Zr1bfzr3J2Pb2rdG8JJxyHGhV2XliO6GqisOCmu0Sm1m68y2GqD2kvIYpKOSjKNGb\/a9O2vgGcgWUm\/yqiBUrAr0rmk1O6Io9jCIy8Evw6k+ZosOEwzrUAPORufbvOXheVNRK8mTP7DtGjdDL5iG3t0cGwDzOgsx84vAC0fuGNN+e1AEg1i6icWSrepsAI9zUsbeNTIqaZKXA7XTgKp19zRnkVbVump5obXl9BpaoAdZ4WTXAk7vgXeNVkNc+17QD+e\/p14YuL+8oDbfa4vToLKZdpglLTjeEA\/ZSoswziNUdSu8jez1JOhjSs+lW8OeCR9nx5n48zZugT\/+52xmFehveG1YrNYHxESR3O\/yeJraf35\/Pjybm0a9VOWrTqcW4ajiHdg1mFCwatgcj2IN5V371jCGnj8Yzs+Oo4btBXKKdXn96MF7cQxp\/EhFBPHRSeR0mxaHIepr9EBRB3qjGbpBGdXvyeJEcHum9QVTI\/6mezSDiNM8D\/PlU6vBKb6yh8x6mER9zqxOo971Anc2C2fXd8eZvg7dK4VMNzn+ZbwWQESj9eEFx1muXqPcc3tDfzw4h2oDeantTzb9hW6ICzutfJNHygsoMU77kH\/dYOGF40l9mG2lzSv83IBOuxmbXfUaNW+Ibe3+4Zz\/AaMO5Sc=","xmlFileCreated":1543258276},"16":{"desc":"eJyNUUtOwzAQvcqsWJVwABBSi4ToohKqeoGJPW2sOp50xknI7bGdpGKBEEs\/v6\/m1DiFlm3vCazTzuOkwLEhga1EZzwpxAYjoBAIeYxkIXLCCDgQ1OTCBQZHI9kKTg3pQnMctIhII9beaZOE9VSEB4oIV5pGFqsVvNQCT69b78vnigOfy9v0IhTiWqd4KqGYbIgXdEFTu1\/EGZuXdP1aYN1UwTsL0Be2nacNTNxDixM0OKSAcM\/iAA+3nuPzTohsXvqJIhx1RhM1VQhzyJ37kdEjOs38nUdzhTc2V4zMi66C\/blkumB8b+ln9cWkKzlLjAtQp5B7+00WhKI6LifZR2oVDvMhR5emp8WxUP5csC4ds2E+Y6b8d0fZPzhDjwOJYvUNlYXUqg==","element":"mod_related_items","enabled":"1","extension_id":"212","folder":"","name":"Articles - Related","path":"\/modules\/mod_related_items","title":"","type":"module","xmlFile":"\/modules\/mod_related_items\/mod_related_items.xml","xmlFileContents":"eJydVtty2kgQfba\/YqKn5AEJ4qQqWxHKyqBgKAEuC3adJ9VYamCS0YxqNDLw99u6YShu5X1ipm86ffq0hP1jk3DyCipjUnSNjtk2CIhIxkwsu0auF61vxg\/n1oaNBlHEEL1NoWskMs45GG+Zd2bHIBFnIHTXyJhGXwJ6JWOski4VjcFwbm9sQRNwMDlUwKmGOMTIJLOt0o5+mmOOckZSJpx+II9K\/oZI21Ztx4hIAdX4yD6mO6Ocb8nndvuLbR3YiziZbhVbrrTTa07kY+9TEf2VtPCn841MUxAkkLmKgIyp1tiMSVzOSRmeEQUZqFeITSy\/K4e1OYuQDXAGkzkZgABFOXnMX9BM\/MrVEEM+E6lI0ar6TjIA4g973iTwTL3Brpo6u8a9hDLu0Dhh4u\/fJQemVMum\/cq7C54r7qzXa\/M4sPBgWI3BuTPbZtu2mit6YsgixdKCL2c87YdPnu\/OvH74PPbDvhf0noaPs+F0Ylv7gZi3YBwyPFSnYmikUkKpiMOhGsdzNtNValtNalVH8hiUo5OUo6e67Nd3VsBTUEeZ1SUrp0HFMqfLGlhzI5qigkG0BveGU\/6Yx3iYYDiFOuP96dn2uMTbpQRXwCd\/YNs1Rg+e\/xh6zzOcP3IbhEj83PfCsTtxB95T6D7Nhj3fC5phGMSqdCwWbFlzAjzOSMFA10ipogXJ6Gg8oGvfC81YVLlqX3m8qbzZSq6LLTEqY7XQuKFM1hZOX4B3jX1h\/Bx6fj8MHqb\/9vEe+u6959fRexK5mFPoqk6JOM0yhKlFa6lknpLdqbWFTMhd5QXNOb5P2rUBR46L1DWY0LAEVVurPm9sWWIgr5Tn2FDHcEa\/vMC2ZKPeE0FtDJpMD2MKZSFjzu0Z+hK6YUmeHLAn8uRlh+csfWP3+T3MFeF7pO3Y+HqJDasShNUo4qQ+aPxKRQTxWYlwupW5Pmix2vMDR93oqILr+jPs7td0Pjvf5F5orf46461P6zzxJYJSO2G22Byg0\/iBovgFOETWm47r5wQNp+Wt57tBEAY\/L4zjeureaJRco5zvrjUg1yKi0epw8TjL9DXUPbf3MJwM3oO2STkloM7\/XKeBP713\/XAeeGF1vLpcx7j+cf25F06mNb73rV7JXqhZAle37zQjXjgbji+8vi5mnaLyr\/bFd9OpbWxu5beiebvb1u4flvMfEKzT1w==","xmlFileCreated":1543258276},"17":{"desc":"eJwLycgsVsjNTynNSVUoz8zJUUjJLC7ISaxUSFQoTk0sSs5QSMqv0AMAEqkN2w==","element":"mod_search","enabled":"1","extension_id":"213","folder":"","name":"Search","path":"\/modules\/mod_search","title":"","type":"module","xmlFile":"\/modules\/mod_search\/mod_search.xml","xmlFileContents":"eJy9WN9zozYQfs79FSpP7UOwfWlnri3m6ticQwYbT8Bt7omRQba5CsQIEcf\/fRcENpx\/EDJzfYqk3U\/69tvVWkT7\/BpR9EJ4GrJ4qAzUvoJI7LMgjDdDJRPr20\/KZ\/2DRl4FiXMfJPYJGSoRCzJKlCPyTh0oyKchicVQSUMBtoiILQtgl2TDcUAU\/cONFuOI6AD2UoK5v9V6xQIYcAbOXH9kLKL4J7Tg7BvxhdYr18HD5wQLOGuCBdEfM7pHH\/v9X7VeYz33Y8meh5ut0MfVCP08\/iX3\/g3dwp\/BJ2QnJEYOy7hP0AwLAVGoaEQpKtxTxElK+AsJVNj+sB3sTUMfZCD6dL5EUxITjilaZCtYRpY0VYqgj4hxRIET\/xOlhCDLHBtzx1DFK0RV7XMI3IhwSHUcRGH817dCA5XxTRW+tB6cl5zqu91OPXXMLeBWctDv1L7a13rVFCwBSX0eJrle+syeeI4xeho\/eM8zy5sYzvjJXLimPdd6dT+ArUNKUhjIUZ4zJCugqIQymUotsWqyTbRe5SyRjAaE6yJKKFjkpL6jviU0IfwEKSdpIT+ONxnelFSqGRIYapXEt9N7RS\/+qDUiYRyC3qVrB1y6T0+wx0lBJyeM\/iX7ofL4YFgLz3h2IcWgn+OBtkvL8Gaj+WhqPJUyK6gnCzReh5sydkKDFOWRDpUEcxyl+TU5WIgobSuchr40lbZieCOtFK8IVeSKvJ\/1lWI8VGrp\/mIa1sSzRveG5bnAWg5L91rqr4PygpEYCOsCs10YiG2DWZxFK8JbqN3bz\/+YE\/ehA7ED5EjrBgoH7t9QCWNBNtWhl8kK6HINrrWFS0w7yvdm4VaZECxusIEmGrI24Zaua8+7yCYBNdECssYZhS7ev6bijU9xmgJPEd9uOMsSdBjd7kkaV0Rlyd5orCCAXjDNIJSBoj9+NRytx6oWc8apD05zu+mTNwNQqkU2L2Fp8zqEaVsipRAL2+ksXo45px8l6+rQdMt2+Q6S3h+Dq+IUvzaKfnLa3yNraXhP5vTBvS5ccfAlvGV8aYELllxEu\/biOnjFIMLoIv7eBsVm3XIaRtBw33kfzBn0386Xoo76YTejU0386AvzntYnBerYAGugmrLntbjcHVmSP5+KR0fXirAX+TOsWHg76xqoxvqNiT6UzeBq2fzPiT9K6IlQwFu+Y\/ZrknQsge+RZ+rgSK69FuCR5MH3RhQGjRAiEmf5cksYjuGarjEzJx0COGK6N4eLCayd4hiWMXa9mTFfevKgC6k9jkGEs+9GHLzg2CfBlafjnmXNqy9f9g1Dqd6jjH9k5en+ai+vZL3mWr6FS8RbHj+SQXG9vHT9elKaGD75mszG9qw8xymTJGdja+Q4nvPl+TLTdmgty5zt4MbftQXgY3\/bvFGnL5DTc8ej8YM5n3ahWkHOFeJ7283Usu9Hlrd0DE8OW5vPKS\/5az+3S37dWlOhHnSlqCnhuS+H84rAO8WcGV11LFHnpPy9f\/VWtxQClHMzkm0YBCT+\/pBGEzuvdemiv7UfVLPi27X67tR6h\/\/m6P8B2DUWnw==","xmlFileCreated":1543258276},"18":{"desc":"eJxFjcsNAjEMRFuZCuiBAjhBAw7xkkjZWPKHiO7xsgeu82bmPRrj7uTdvD8NN6kxGNZkGfrcRPdkMkFFwvGRUBjrmzWpOY1xYpcXe8t0dW+w\/+HBUrG4WHdG5NhAs\/7SGXvJjWy4arYHH85TUsmpkPHlC3FqPL4=","element":"mod_stats","enabled":"1","extension_id":"214","folder":"","name":"Statistics","path":"\/modules\/mod_stats","title":"","type":"module","xmlFile":"\/modules\/mod_stats\/mod_stats.xml","xmlFileContents":"eJzdV01z4jgQPSe\/QuvT7gEbJrtVMzXGs46jMKaMSWEzlTm5FFuAZmXZJctJ+Pfb\/uJjgBDmOCck9Wvp9etWW5hfXlOOnqksWCaG2kDva4iKOEuYWA61Ui16H7Uv1rVJXxUVFQapdU6HWpolJafa1vNGH2go5owKNdQKpsCWUrXKEtglX0qSUM26vjIFSakFzlGhiCpMo57DOikBK61xlqWc\/IEeZPaDxso02nVAxJISBUfdEUWtccnX6EO\/\/7dp7K1XuCxfS7ZcKcvpRuhP568K\/Q\/qwc\/gI5rmVKAgK2VM0YQoBUHoyOYc1fACSVpQ+UwTHbbfbAd7cxaDCtQa+XM0ooJKwtFD+QTLyGtMnSDoA8ok4sBJfkYFpchzHewHWFevEFW3zyZwnBLGLZKkTPz7o9ZAz+SyC7+xbsBzya2Xlxf9EFhZANZysG70vt43jW4KloQWsWR5pZc1md5FQWiHQfQ48aI7HDgz9yF0p75p7MLAa8E4LWDQjKqUoSb\/dR00qdS2WdXzVW4aHbTxy3hCpaXSnIOlmezuZ60oz6k88GwmRa09EcuSLFsi3QwpAnVKRW90q1n1j77lwQQDrVvk+92K9aHrdlKTqeii\/+h6qI2\/Yu8hwo8hZBe0CyKQde7haGL79gjPaoXdIHSdQENGU59iwZZt9JQnBapiHWo5kSQtqkuysVDV2p5IweLG1Nrq4VVjrWtVMrHItGa5uaJw51i3wskT5UNtm\/J7F3swxrNveOb699PIs2+x16J30v+mT1UzrUvMSVEAUSV6S5mVOdqMemtaiGyz84KUHDpEv12A9MIVGWpMKLqksl1tIr0ys5oDeia8hIAGmjX+jgPTyLrKPALqA8if7mOqKgLNrOtTAkK7+iX53BBfKF7n8btIF2clHC8vVc6Zzv0Qbse7hescfhfdmKi+WwXdE06U6dOG0AnlXN+ZYTvAFyv4s+OOku+TyGhak9H1pqOdiiTPRMQ0OdmsOFlnpdoLu\/mW7Bna4McNddsLIc7v03l4OtwdaNuBW49tnMbJbDQM6oKKisXrHjsFTx8Cudpn5kwn7Tmdvs3M8ewgiIL7x9NMz7vupEZmL1DjN+cCiEm82q8lzgp1jrJjO19df3QJ1c7lWPUMfvGCjbzpre1F8wBHzfDsdTvk9c325jjypy2\/C5tYpV6kWHr+Oh5XBEehO8GX6th6HZPyU\/\/cVXwrFCjn\/UhWLEmo+PmQ6rUDz4q30tNCrBN6HvSDbla\/mLqXjmls\/j1Y\/wMrdpUi","xmlFileCreated":1543258276},"19":{"desc":"eJwFwcEJACEMBMBWtgKrsQEhiwYiSjY+rvub6cuFfewFYa4b4xNqETGKKiSnq5g0PDHVftDJEqQ=","element":"mod_users_latest","enabled":"1","extension_id":"216","folder":"","name":"Latest Users","path":"\/modules\/mod_users_latest","title":"","type":"module","xmlFile":"\/modules\/mod_users_latest\/mod_users_latest.xml","xmlFileContents":"eJydVl1z2joQfU5\/ha6f2gcMNNOZdq5xS8ChZMzHxHAnffIo9gJuZckjySH8+64tm+ACoblPSNo98tmzZ22cr88pI08gVSJ4z+raHYsAj0Sc8HXPyvWq9dn66r5z4FkDL3KI3mXQs1IR5wysF+S13bVIxBLgumepRGMsBb0RMd6SrSWNwXLfXTmcpuAiOMwVIkNGNSjttMtjDNMcIdK9EyJl9B8yl+InRBivzjEjkkA1PnGISHcIEaSPIMnHTueL027EilyR7WSy3mh3UK\/I+8GHIvsTaeFP9zOZZcBJIHIZAZlQrZGVTfqMkTJdEQlI9AliG6\/fX4d3syRCQcAdTZdkBBwkZWSeP+Ix8U2o1oZ8JEKSolL5L1EAxB8PvGng2foZK6vv2RfvpTRhLo3ThH\/7WepgC7muJTDRffJSMne73drHiUUE0yoO7rXdsTtOu95iJAYVySQr9HIns2G4DLz7IPT7Cy9YhA8TPxx6weB+PF+MZ1OnfZiN4FXCQOHCrIruEeOI0hmN5lpH7bazTea0a6C5RbAYpKvTjGHEbA5vdzfAMpBHSLNRZUMoX+d0XdGqd0RT9DHw1ujGcssf+4hOwhPsQwV4M1rt1NENL5uSWkGe\/IJdz7r77vnz0HtYoAFQ1yBE5Ze+F0760\/7Iu6\/lL3thkbYxMV8l60oNYLEiRe09K6OSpqoYqn0EdBV7pCqJTKiKlcsrE1UbseV5MTeWOTYj3Thi9BFYzzoyxu3Y84fhdDm5KdneeH4FODDIJVhhrD1qRXOGb4xP1QG2E+ekZyVcw7pmgzqcKcWkh2sp8kw1qsE3TiL+qpjbsb9AVqP72XIevLmmJvqgtIhRpbAVmrdKemS\/au1AcfGnAp3XFLgyvbxyRMmGPFGWY5Fdy7374QVOW9STeSKpg0nTWTOnmBuU0pinXbvnpJdo\/ER5BPFZOzG6E7luiG\/eBY1A1YM7o1rfX6CMP2bLxXnBD1KrKakQLyKfN4ZhUPYgVKvnBjuNHzOKn4oms8FsUj0nqFprdgO\/HwRhcPtwnull6IEvpNiiLa4vFRDRaAMN2ixR+hLlQX\/wfTwdvYVqDTk1ld3\/6cmRP7vp+8W4hGZ50aHHvP7r+0svnM4qfmf8+5p6oU5SuPiKO62IFy7GE++tOlaoU1J+6bw64BeMgHZuVrJJ4hj4nw9RGv\/\/RK+2p0px\/\/Z9UO\/Kr1r9LXLa+\/+D7m+mcQWp","xmlFileCreated":1543258276},"20":{"desc":"eJw1zcEKwjAURNFfmZ12Yf\/BlSsRRHGdNmMaSN+TTIL07xXB\/eHe20I8Ft8JFyvZiLPHXoiY9SphE9oXWF8nVvgTR3PbVu\/CXazCnmMacepU04BgEVemrMbK+CduFIqnxHjINnyLoSFUYu610lrZEOaZUrb02705KTeOHwSVN\/4=","element":"mod_whosonline","enabled":"1","extension_id":"218","folder":"","name":"Who's Online","path":"\/modules\/mod_whosonline","title":"","type":"module","xmlFile":"\/modules\/mod_whosonline\/mod_whosonline.xml","xmlFileContents":"eJytVl1zqzYQfU5+hcpT+xBwknbmdoq5dRzij8EmE+ze3CdGgY3NrZAYScTxv++CwLHjjzQz98nS7p7V7jkrYffra87IC0iVCd61Lu2ORYAnIs34omuV+vnii\/XVO3fhVQOvYoheF9C1cpGWDKw35LV9aZGEZcB111KZRl8OeilSzFIsJE3B8s7PXE5z8BAcr5ZCCc4yDq5TG9FJSwRIbyxEzugv5F6KH5Bo12nsGJFIoBrPu6UavHHJ1uSq0\/nddXbsVZwo1jJbLLXXb1fk1\/5vVfQf5AJ\/Lr+QsABOIlHKBMiEao2d2KTHGKnDFZGgQL5AamP6TTrMzbIEqQBvMJ2TAXCQlJH78gnNJDCulhVyRYQkDGuSfxEFQIJR359Gvq1fsas2z6ZxP6cZ82iaZ\/zvHzUHtpCLtn3j3QTPJfNWq5W9H1h5MKypwbu2O3bHddotelJQicyKii9vEt7G34ZhFE6D0dSPHydBfOtH\/YfR\/WwUTl1nOxahzxkDhQuzqnQjZhLqidgS1Xonsl0sC9dpQSaDYClIT+cFQ4\/ZbGf2lsAKkHtIs1G1FJQvSrpoSmp3RFOcXeAXgxvLq3\/sd8VkPEP+m\/BPYtVa7eHfNnVZVeHkX1h3rfHQD+5j\/3GGsiOfUYx8zwM\/nvSmvYH\/UFEfG+ot4pjB5c\/ZouEBWKpI1XXXKqikuaqu0MYDuvE9UZUlxtX46uWZ8aqlWGELYBmjub4sU7oxMPoErGu9G4RoGH5Dkx8HvRs\/aEK3huE4oBqfTfwzLRm+B53GgMLhXehaGdewANlYTeVnrqgzkxfKSqgw74fzbuQHt\/E\/vWDux9P55MZ\/cB3RjuaBDJenM\/QmfnQ6wdXJBDfhbLiLryYT2ffOj0hh2o8XUpSF2tED38dMnBTEnHw3CmY4NoOHcH4f\/W9tDmG3ZEoYVQrHSPOLujSyWV2sQXHxM9RELcbfP+IbJR9PwyOcvq1x8g\/eA5q+UJ5AevQqMLoWpd4h3rxeO46G\/7FhrRfMkOfv4Xx2nO6t0OZ+N4g3kp2jQ2EqqDWI1fPrTnUaP7sUP227lfXDSXNO1Ehrdv2gF0VxdPd4vNKPoVtzIcUKx+L6owYSmiw\/el32z+33+sPRdPCZUlvIT3xh9g9pHoewOexzF7ymItZZvssHL\/OnTS0nGfHj2Why4tE9iTrEy5+dk8w4B+5Vu6u\/a+33yHU2\/wC9\/wCkHAKi","xmlFileCreated":1543258276},"21":{"desc":"eJwFwYEJwCAMBMBVfoJO0wWCifigfmksWb9392Biyb8ZyKFK2Ab7aytQ3K7CEfKJxs5wTDU71L5+Z6IVRA==","element":"mod_wrapper","enabled":"1","extension_id":"219","folder":"","name":"Wrapper","path":"\/modules\/mod_wrapper","title":"","type":"module","xmlFile":"\/modules\/mod_wrapper\/mod_wrapper.xml","xmlFileContents":"eJzdV02T4jYQPc\/+CsVVqUoOA8xOtmpTMd54wANMGUzxkZ09uYTdgDfC8sryMOTXp23JjFm+4hz3hKR+Lb1+3S1h89PrhpEXEGnE47Zx12gZBOKAh1G8ahuZXN5+ND5Z70x4lRDnGCJ3CbSNDQ8zBsab533jziABiyCWbSONJNo2INc8xF2SlaAhGNa7GzOmG7DQ2d8KmiQgzGaxghaaIVpYT5xvGP2JjAX\/CoE0m3odEYEAKvGwLpVgeYHkCxDkfav1m9k8MOVQnuxEtFpLq1OOyC+dX3P0B3KLP3cfiZdATKY8EwGQIZUSI2kQmzFSwFMiIAXxAmEDt99vh3uzKEApwOqN5qQHMQjKyDhb4DJxlalUhbwnXBCGnMQfJAUg7qDjjKZOQ75iYOU++9idDY2YRcNNFP\/5tZChwcWqVEBZ9+C5YNZ2u20cA3MLwjQH677RarTMZjlFSwhpIKIk18sael3\/88Qej52J\/zx0\/a4z7UwG49nAG5nNKhD9lhGDFAdqlOeNqDIoyqHMqFFNbyNZJ2azhCtfzkIQltwkDC1qUt3TWgM75akmaZEBGq8yutJkyhmRFEsW4tveg2EVP40qkyiOUHONreOY7tIj57dJQSinTP6GXdt46jvu2HeeZ5hn1HDqo8Bz1\/GH9sjuocZaa4M0VZnGy2ilwwcWpiQPtm0kVNBNmjfM3gJS2xY0jQJl0rZieKOsmWCGmqs+ldi4eoHRBbC2Uc3448Bxu\/584vqu\/eC4GlhJ+zl4XiYanUb\/4Dn3LT0V8C2LBGDbS5GBWsRYz9ClYXhAF++JiF\/ja3e7dfjm8ArfgNE0RRllfLsSPEvIfnS7gzTm+02XNGN4l93pBaw+7OO2EcUSVljmalXl4cbkxfHkhbIMch\/r6YszNZu8bJ4ToBaCRt4hJi9ylOisXhgoZwzv5gPVWJReTTK2tefWyrP2qEi31wQvGn5RgAJgHe\/5l+3OHd+ez7zL2mAajsX5HoTpOqXzNQ23USjXtZvk86A769eRTzkcNcqHo\/pqtX6+1iZryB+f2pz7zqDXn9UhrT2us8aH9L+R9iu1UqfHsUTq0694\/Sgdv8SXABZchHsCNVR8nNhDp46AyuFH0U5SsYL6bTOzJz2nVt1pj7OvYlO95M3yKT\/5sNPwhcYBhGffdkZ3PDsMR\/3\/OjDosJ50R7h5IF+8+YV4KlD9b0V7vMVzvssVg6JM\/HT5eiQ2xX\/mh8w63lCfM9XyqVnHtadTf\/r4fJ7pdddKCgTfYuXeXwsgoMEarjynx+d27E5\/MOrVoVq6nHpQ\/2\/b9FzvwXb9+dTx1fBqEx3zUm\/yyNP86rVYoZ4vo82hhHG2WezpXxTR8WeDS3fURa9TUv5evkynxbxSCFjOh5GsozCE+PtDUomfm8HF9GiIdUbPo\/ugnBVfF+WHgdncf3hb\/wJeYWpT","xmlFileCreated":1543258276},"22":{"desc":"eJwNysENgDAMA8BVPAHTsEDUuhApJSguD7aHe99+ujCzP0F01x32CoZwLeSA1fIWFEblRF5E1t+LaLZ4ZDm1fWG4GQ8=","element":"mod_articles_category","enabled":"1","extension_id":"220","folder":"","name":"Articles - Category","path":"\/modules\/mod_articles_category","title":"","type":"module","xmlFile":"\/modules\/mod_articles_category\/mod_articles_category.xml","xmlFileContents":"eJztXFtvo0gWfu7+FdXeh5mRNk7SmZZmsw6ztCE2XgyRjXtirVaIQMVmgsFd4CTeX7+nuNlgTHFxpFW2X7oNVedQfOc7l7qQ3u+vKwc9Y+LbnnvTuexedBB2Tc+y3cVNZxM8nv3W+Z372MOvAXZpHxRs1\/ims\/KsjYM7O8mr7mUHmY6N3eCm49sBtK1wsPQs0LJeEMPCHe7jh55rrDAHwrpBAtt0sK+bRoAXHtn2zsM26GNsQI5wI89bOcYndEe8P7EZ9M7j+9DDJNgI4LECyHK3+IFsDLJFny8uL3rnmTba11tvib1YBlw\/+YV+7v8CvS++oDMq9BtS19hFU29DTIzGRhDAS3UR7zgo7O4jgn1MnrHVBfWpOtDt2CaggrmBMkMD7GJiOOhu8wC3kRw1JQChz8gjyIExkb8jH2MkS31RmYrd4BXeLNGTvry4MmyHM6yV7f7jzxCHrkcWCQRRa9p5Rhzu5eWle9iRtkC3eAzcVfeiCwgll9BiYd8k9prixY1VQecnmtSXxane5zVxoE7m+v1Y1gVx2p9Id5qkKr3zfRHQ8GiDEeFH9IuaEEXcCDlyaOZOsfW76+W6d56oiPR5joUJF6zWDrREF\/vP4ZbYWWNyIBld+KF9DHexMRbxAJMrFBjAbeyeDb52uPC\/bvGYbNcG28RSzVT4W\/9Aze4iHCR9DfSEtzed0VCU73TxXgNmANZTHUwyk0V9zCv8QJwcWqeDziOKu4\/2IgYHO5aPKBQ3nbVBjJVP\/S5twUHc9mD4thk1xW3hzw9RK7wM7kQ3In93bD+IbzjGA3ZuOsV0uZVEWaDjFnWZ\/yrKscweaSpIUr6lgo\/GxoGQ4npkZTjx3WjYH3peqBE9G84Gp12OEFkN+asr6mTMy\/o3Xp6JvXMv4XGBOmsLWFCMSvUJc4UfS\/0ihZSIgCv38QjI\/tJ70T03YY2+BkZkQIeoaXvVUZ8O1T9UJW69A8Y0M8Ghmj17mI7h+8CewD1bEG+zRumvsy32XS9vtsv4BrgkhL6bju2CY2AS36UI0OFQul0neJeZ+LLDjej4yi13Ab2GknDMHLvf4A6RdVLv+LgzTzRkyIPRiCoYYDBRZ3fwW9bEiaQM9uA\/ygHT27hBxujuZvWQAlThoX11pmjNLB2JFnnbRZnZzssZ\/Ui83CvVCx7Uvrcir80motCcwamGotej4yzlWdihCtWWNi1sCtiW7+i5zpYRSlRFnqfDbhBPUsL6a8PE5CJjg+hefGsJJg3IBrPsmaQxPVWtU21tghRcpg6ize8axqgDLW8Woo7GoVJTSkpfnk2lb2KVRHPBUCbelyhjkQJMaFsZg6WVWMZmo7SmqG+K6HLPBOlsgQa4lQ71CVwnIWAFqNtrWiDuKLgPPuRDYmyzxkxk+tHYbexXCkXm0nastBhLy7O2SbY\/lGQhuZ92bByqitXVDstVid+C0cLp+FysisVmBz9jJ2u\/2vmS1wTxThs2DjyRdJF5qhU7Zcy8vmTxOhfkL9sH+UijDjOajK7ddRIhNH5QBBe9n7BZlMV+pqKglR3YCPsBtk7g\/5qxYHp+DqHP7RGKJtMnTIL8TBuqk6JCsQYV80p+pMBjKZCuCGFLf9hmbBZZta7R2tgq4xgtvIAPR17XEa5O5giGYxv+yd2BlyV+ehKfyGn64RhMx4hMmiXId6eRBVsbjukl3zeYbGGA2MFmgCyYXNquGfycf5tfEMxEV+gvelJ\/opclJhjl+6FPN+inn5BHLEzQw\/awnU+H84TpVAhQPIpdaDZGn0Jv5mkHdlmb8+lf2\/s0fjWdjYWt4uo4gFLegNeoToW4uhPa1cUHWvad2HMAvsukGCbeC1xe1UTuS3vkLDCunlslarTiIcBly8CXVVFUnHqPj6Vhi7Yz1idub6uELGK4C8xaNYXrCa8MKsVAgh2YxD6zdE5EmdcgEgr8vEkwjK0Jd1taMnyv6LKxKfd0FNnS6MahJTe1yDLy0zXL5js95dD2JyLcKVyUOlQJJb8NOLJ0QqMEb1hR6ZruqvlLfbNmqJ1q0HQ3+ypL0yF1hSbr8hDxAj3EMuLyPh9Mw8GuZdSoG8MRUaM2XCFIxfeYEMDAfLqb+Ej3PIJMeqRkCOxVNmf69n\/gxudkMpTUMxsfZn6bwCzl0fUeCiV5xLVOh5moCM0RS4T\/t\/FKoloIWqsVjV3ga4pYRkNRwLkqX3k6hkMSuPehqLL1EtZi9Xde1IlQeeMl2XTLPqpR0I\/vFzy9TgGcU1Ic9gM7cDAjpKdvxMjmyZMqxN\/HdV2tZfsYh0Ne2oHPUDyUtGk1ZRFG3Gggq195WdckTWbK2KxsJVV8k6jO50axUXcTIpbgyRPxG6ThUybh4yne8l5chv5bSQHN9R4AQdnyVqwaklcEdVxNXUCXPqL9W0Tw941NMMxDnr2AVah+U7VqdW\/4iJrKJxDIm5U9+YioW\/BQk8qfLjYKUtMFtEM9RRFyN1UvhjSUYUxNoAtUEBVZxTP18WXq6p5JCJeq6ifG8N9camLyIPusNtYvenxt06dKik8HueVpMezAjRRVYRh0i6FOLbfoXOQn1SKwGyz1CgrHqqINq2qNl625UbRkVt453WBKkmLy6HKxgG6zcHRjp8EcOuHNSSbTidVbzqezaooYVDyhzvvCNbXmX\/cMW8a5\/7eUzmLHDjY9moYdrDRW50bqMrf0PF\/D8095JUW8uEXzRpwo2UTJyZ8yzyY8b5tn9\/UUofLkeyRg4PLpmhmVn0io55QJ+amCxmopuWpOtmx\/7SRbdZVTsiBN72R+XikjO7b7FEXwVkdXZEn5Zzgbargmvydf\/\/RD28Mpo7k4ZZ\/6VNQGR3APFmAKcB3RLFJ76W6o\/nF0SeVtz\/K0PyXLQuwk6b1lWq+bztPBJ+dsfmTuukZvm7hTs7VJ3HklRQyYn63OLDS8tq99FgtYpwizByaPx4imRyjDQ4AFxyjfRawI1\/ZaZC06uHDxr\/H5ylD6vcGaOb10nJLRJLEJaodHlt4FbkF6grAEtSMnHVmQgdj7IxqMlXh7Mb6xE0uKNlE18b5hzM+qeEcopwDrjr2y230MlAIkS2OpIdA5HYWl\/kW1\/cAsgSqmW6i9rJVH2CV5vMFD7aJDKSaM1UnJ\/mdx93fEowx4+v5OYU0IwzleXSAjoTebF2YYlbwko4p\/S7BTnKv57BGuljtpmVAh0F+qO+UOwn\/xivDvAu7kvPXoSkj8PbFhPRuuSWc4R1cxjK23yUIVfSmeaUgASzZQKT5zdVYG065r\/L10LLHD6HjEiUYQklD3H18PJjaHZx\/76jh+znT3zTJc9WV+OtWnt\/fHR8oW3TNrxWON3otrGuaS9bX24aP7fH9YuidzXKS+lx930Jjjs6moRz+Z3no4rnBGqytqPL66H8gBejo9AMT04mJEaOwbl8TLUqkiKP9Wnl3PD3YLd1fhXxdI\/hxA7zz9Do\/7L0dRTyA=","xmlFileCreated":1543258276},"23":{"desc":"eJw1ybENgDAMBMBVfgKmYQGLfMCSE0e2KbI9Fdfe+WhieHuNaJrLZCcEplnwjkuKt4cy0cMHfBJLgrP+2scHTVQY7A==","element":"mod_articles_categories","enabled":"1","extension_id":"221","folder":"","name":"Articles - Categories","path":"\/modules\/mod_articles_categories","title":"","type":"module","xmlFile":"\/modules\/mod_articles_categories\/mod_articles_categories.xml","xmlFileContents":"eJztWE1z4jgQPWd+hdan3UMw+ZpJasGzDjhAykAqhtnMyaXYHfCsbHkkOYR\/v+0PDAzgBLKn1J6Q1K9b0tPrtkTj60vIyDMIGfCoqZ3U6hqByON+EE2aWqKeji+1r8anBrwoiFIMUfMYmlrI\/YSBtvQ8q51oxGMBRKqpyUChLQQ15T5GiSeC+qAZn44aEQ3BQGeXChV4DKTrUQUTLgKQDT2zIoom6CmMW85DRn8jd4L\/AE819GIcEZ4AqnDiNnobN\/AoEirm5LR+Um\/oa7YUy+O5CCZTZbQWLfJ76w9E1y\/Icep0SYYxRMThifCA9KlSuK0aMRkjGVwSARLEM\/g1DF+Gw9gs8JAXMDqDMelABIIycpc84jCxc9OCInJKuCAM1yT+JBKA2L2WNXCsmnrBnS3ilJu3Qhowg\/phEP31I+OhxsVkQUFuLcFjwYzZbFbbBKYWhBVrMM5q9RoytOiixQfpiSBO+TL6w7Zr3o96Ldty3JY5sjrD+x42H\/q227ac1n3vbtQbDhr6qhPGeArwILGRt9JDJLk+Mp1sO2ptlwZq8TRu6IsweUzOfBCGCmOGlryzOpcxBRaD2PDMOzI7JRpNEjopFrnoEUVR4xAdd641I\/up7VpVEAV4RoXfoUHkfDPQspMtNN0K+QfmTe22a9l3rvUwQo0g546LhzO2LbdvDsyOdb\/tnDSi53KPnoJJQREwX5KUkKYWU0FDmWZhaQFV2B6pDDwttRxR38+MMVXTpqZnCgykElRxgdoPYx5hjsu0ubI5HTcNTOp53CxSNlExU9Y8KteBAfLJjspqQtki2rwwMfoIrKntEuVNz7Lb7p15bw1Grm1eW3bhtyLON3qn2i6cyzrX1LIN8kgtF4t6wuxtagEOTkAUo3Ga7nIKWOmKEQE\/k0CkA0okUAxKYFjD1oYimK31wQ\/WAaggKlZH8IB3sCqnfOaubH2NXyy\/Ad+HVqc7\/Hs15Q8leCPOCtUeo1Ki9FR0PBE8iUnZOp6DjHg52xNNGPJSrzyFXG1HDZ6tizxTluDGTzTj9rvlNHS+KFZbQHUEDYbrmEau5J10R0mI37hQvo\/mwbjfG1l951B6S\/+PQmumYm8aMB9rxH8g4Va3Z7cxx9+l3zLIR2HZ48kvBRgLmNqH3NZwfHjVzZ1XyHwXSykBpm1Xs5RSeVINOUXIaTXkDCFn1ZBzhJxXQy4QclEN+YyQz9WQLwj5Ug25RMhlNeQKIVevUJcSnF6r91FYSF8YPAN7l8j65oNtfbPsQ3VW+v8vtY8gtWUb76258n69xlL\/mUYe+Nquuyejc55s3D3xpbJmKNR5m8vItNNK9304rih4K9Dinl54LKW3++qWXiTcKdD0zX1gwox6I5yza5nt3qCzf76su29Ll\/MDv1\/dN6RC9w250H1DMnTfkA3diz0LWaaO7GvvyqeXteNR+FjAtwxdP6LWsF9ooKxDWa9lm47jOjcPu4\/nddeVoxF8JlNuXhEXn0Ue9abwirA2p26ZeO+pEtNul20COjlQQB17eG3a7tix3Lz56nVoc13fTHtsuYNhsb49L0spe64KwnUK8QHwWC6\/kkQL06tv7ctj4bWNyqt65cdL3yiVy172j8PiD4KGXr52jX8Ba3jBEQ==","xmlFileCreated":1543258276},"24":{"desc":"eJwLycgsVgCiRIXg3MSiEoXg1MSi5AyF3PyU0pxUPQCgzQqH","element":"mod_finder","enabled":"1","extension_id":"223","folder":"","name":"Smart Search","path":"\/modules\/mod_finder","title":"","type":"module","xmlFile":"\/modules\/mod_finder\/mod_finder.xml","xmlFileContents":"eJztWFtzozYUfs7+CpWn9iHGyc7O7EwxW2xjhxQbT8Btti+MbGSbrUAMEkncX98DwgTGDr6k2770xSPpXHTOd84nS2hfXiKKnkjKQxb3lJtOV0EkXrIgjNc9JROr68\/KF\/2DRl4EiXMdJLYJ6SkRCzJKlFfLj50bBS1pSGLRU3goQBYRsWEBeEnWKQ6Ion+40mIcER2M\/VUYByTV1GIBBDgD5VS\/Zyyi+Ac0S9k3shSaWq6DxjIlWMBeQyyIbmTrjAt027250dSGJNdkyTYN1xuh\/zj4CXS6n9B1rvoZOQmJkcuydEnQBAsB0XeQQSkq1DlKCSfpEwk64LRyAh5puIT0iT6eztGYxCTFFM2yBSwjW4p2SKBbxFJEIZL0Z8QJQbY1MKeu2REvkM3OT5WwGeGQ6jiIwviXb0XuHZaud2lLaaU8T6n+\/Pzc2VfMJaBWxqB\/7HQ7XU3dTUESEL5MwyRHSZ84Q39kTYfmg\/84sf2h6Q4erJlnOVNNreuB2SqkhMNAjvJaIVn5ogPKIiq1gnaSTaKpO2VpySgIdBElFCRyUveobwhNDljKCS\/gx\/E6w+sylN0MCQw9SuLrcV\/Rd4tqMZe\/nVpcYRwC\/KXS5W74lu+5ep0UwebpoD\/Jtqfc35n2zDcfPWgAQNf1Afm5bfoTY2qMAX13Yjx4vmsaD4M7BamydeNVuC7xITTgKEejpyQ4xRFXEA6CYj3BYtNT1KJxQi5SLFgKLRslLAYG8nxYhqxC9IRyVbrLSVj5JqL0vsA8XEpRKSuGV1LKCU6XGygG9LQiBfIQOCCgeEFoT6m12Mgy7aFren7fcK1Bme3Isj2Q2UbftEvLWuedbF9r3crLCmcUjiA5B0zfSmrDnn0gD+PZGgonGonBcRWyUzMy5p7jzsdj0\/UuSahu3pLPTbkg0e4pYSzIuoJ9STHnUEcRX69TliWoGl1vCY93ucgKX2msiAo9YZqR3LV+7945v2sq2xH\/gFYXtO6sodnU0mRfHYE5eMLxkgQNjGlYgX68aSA63xj+ZkwH5vCirmk4aIG52wrzYWRuFf3UnZ1iU9+2pr+2o\/09a1Is+Dz8izQKEmfR4hQeV8kUK75r\/WGeV5JDDlpKcvuprSZHGF7kcQm3qyCLAhb5XZhlzcF+licS98Rj4N\/vpQJBP2H8Am43Ce3PHPdChF\/tW9qIkpVoham47AEIY9vpG7b\/YI3vvHbICpeVgW2OjugLljSOioEzHVnj3aHgObN28wUTgkUtHvqO5zmT8wqIqThAEgH3\/TMKaNhn\/vU1LPeKdoTTiwxwiN9P6v4c4Jq+h9Wlh\/fT+pK\/ne9Jawnxe3ldwnM5sWsO\/mf2ucxmSf7UzG\/o51IFds2frPlF+\/TC1Y3+u\/+5r6Z7nA9T51IkfREKSs48KuvIePAavAzTwvKco5IIPxQkCpvX7ojEWb58zmFpepZnTqwzb94H7P\/hi3e3wRjXtM2B50\/M6dyX+71R5dcxYHTwPVw9WN56ElO8ZVnzzSi\/izQEJbj3spbyT\/KrM29pgJpq+a2gtMiRO1ZxGUHBNJ+vXva6FKcENyMbOJNyH7dsODkb2Ibr+u7o8e1Ij5u+hnyVsmcg\/8c33+h7FdnNiq8ru28imlp9hdT\/BsHo8oY=","xmlFileCreated":1543258276},"25":{"desc":"eJwFwYEJgDAMBMBVfgKncYHgf20gNoVUpNt7d3YvPMk3BIvIr7C6QK8Ztn3cyAZD7UG\/bIloEo8fPzUURg==","element":"mod_feed","enabled":"1","extension_id":"301","folder":"","name":"Feed Display","path":"\/administrator\/modules\/mod_feed","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_feed\/mod_feed.xml","xmlFileContents":"eJzdWN9z4jYQfs79Faqf2gdsuMx1rlPjqwMOB2Mgg6HNPXkUewFfZcsnyyH0r+\/6J3ABgtPOtJMnJO230n6fdmUJ\/dNTyMgjiCTgUVfpqG2FQORxP4hWXSWVy9ZH5ZPxTocnCVGGIXIbQ1cJuZ8yUHae12pHIR4LIJJdhfphEAWJFFRyoZAQ5Jr7OF28EtQHxXh3pUc0BANncZcAvq7lXRymKUKFMeI8ZPQHcif4V\/CkrpXjiPAEUIlL9qkEY5SyLXnfbn\/QtYPxDMfjrQhWa2n0qhb5sfdTjiYt\/Ol8JNMYIuLwVHhAxlRKJKMSkzGSwxMiIAHxCL6K09fT4dws8FANMAaTBRlABIIycpc+4DCxC1MlDHlPuCAMYxK\/kgSA2MOeNXEsVT4hq2qemrgV0oAZuXy\/fc01ULlYVfQLaw1eCGZsNhv1OTCzIKyMwbhW22pb16ouWnxIPBHEmV7GeNp3by2r796PbbdvOb3Z8G4+nE50bR+FTsuAQYKNopXtGCnSIE+HfCOVekvVeB3rWgU88DLWwGIQxxCc+SAMGcYMLUUHF9aqlXVGo1VKV2UYVY9IiskKUWtwoxj5j1qHgXmIOpfAi72SbfLMc9fJQ8lIkD9h21VGny37zrXu57ixqJvjoqIL23LH5sQcWDPX7I+Hk1xihWhFakbLYFVqAsxPSKZAV4mpoGGSlUdtAVnaHmgSeIWptOXNq8IqkiQVTCmGigrd9Rl9ANZV6n2+HVp23505zmJmu7Z5Y9klcG+\/T8Gz\/CjRuCmY1fsLJcFfuPCHdtkV8C0NBGDhS5FCOfhIWeBjOez5oSanaQl5SAsPkICfJzZvwGp+QMljNElQaxm1VoKnMalbrS0kEa9nXNKU4TnX\/k6KIJKwAlGOFpt1pfN8bYLMUyTQUYzRF8vRNV4V1hFQG0GT6SEmKwPU55xYMpAMmsrlOPPhHNO1QSYUDv9AuM7\/TLgsIxvq1jfnl2uWg\/+FRPsPlEFWTZXZfUMuF2jP5w3lVRDi56KhfMMxfjUuFq5AvyXJJOA3cF+yKA0f6oBOaDa3xs7lmuXoPc1qMa7PiXH2O5WF\/YpayUJ5Tb187\/fGEuAV53GuSJMzuXZ4KxeADRe+6\/E0kk3L54\/prN+bLibzi8XbeeypV9z\/fm4kklbcdrXqunv08kv9Rxp52fPiBHVGtzw9pF08TQ4MJflRQcG0M7pfposzrPeg5aW+9NixPn0qFBHkKeUmy6eD6CQ+qCm+WA8j603H5TpOqXPR69mm47jO7f3pSF923dsowTdJfdidJuBRb31Yhgwf9S+F3DN7n4eTQZNQK5djR\/Jrj6eBPb0xbXfhWG7RfLHgnsf1u2kvLHcyLeNrVo65eq4MQnixHI8rYrnz4fjMeXbW65iUv7Qbl2LVy9+\/1btV1+q\/g4y\/AZ9fH6M=","xmlFileCreated":1543258276},"26":{"desc":"eJwNycEJgEAMBMBWtgJ7sAcbOHIrCUQDSUTs3vsNzKFWuGI+TpTGWxhwq0acaOWq5aTwbv8gydGc2LNNnLX948MXLA==","element":"mod_latest","enabled":"1","extension_id":"302","folder":"","name":"Articles - Latest","path":"\/administrator\/modules\/mod_latest","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_latest\/mod_latest.xml","xmlFileContents":"eJyVVktzozgQPmd+hZbT7sHYmdmpmqrFzBKb8diFIWXwVnyiZGgTZgWihEjifz\/N03bi5wmpX+r++lMj7ftbwsgLiDzm6VC5VwcKgTTgYZxGQ6WQm9435bv+SYM3CWlpQ+Q2g6GS8LBgoOw8v6j3CglYDKkcKjRM4jTOpaCSC4UkIJ95iOGySNAQFP3TnZbSBHSM4jMqIZdavxKgghZoLPQZ5wmjf5BHwX9BgPpGjhaBACrx0DF66rOCbcnnweBvrX8gL+14thVx9Cz1Ubsif47+Kq2\/kh5+7r8RJ4OUuLwQAZA5lRLLUYnBGKnMcyIgB\/ECoYrhu3AYm8UB4gH6xF6SCaQgKCOPxRrFxKpVLTTkM+GClFWKf0gOQKzpyLRdU5VvWFUbpyvcTGjM9ArAf39VGKhcRG35tbYzXgqmv76+qh8NSw2aNTnoX9SBOtD67RY1IeSBiLMSL33ujH3L8EzX85\/mlj823dFi+uhNHVvr79uh2yZmkOOiXpU9IzUVKko0zVT2Gqtmz5nWb40PPPVnYBmIYxachSB0mWQMNfUGD++3p2uMplFBoyaVdkckRdJC2ps8KHr1UfcSQUYi3o3pDX75Nv\/gu9tU6ZSFkP9hO1RmP03r0TefPGwx4uf6iO3SMv25YRsTc+Eb4\/nUbsBWSL+mabqJowYZYGFOShyGSkYFTfLysnQakI1uTfM4qFWNrlre1dqAF6lUakl9XdMiWYNoRIyugQ2Vva7\/mJrW2B85S9tD0YNpNZZ7zT9pX7KlM9\/QguH9\/9oIsF9I+6ESpxKi9nws+kTeXGCjcfAcpM5wjlxI3FmMzcXUntyQe+dyLP3AD\/OgEdYY32m8ikReKCugtdA\/hP3PsJbmLrgxHptjrc\/b63MkUnJdJNRPUfEuWHkjEMOTgAY4D8MDNFECERfbQ0RnIzx64ixW1\/W9Md7HLg4PT+v+FyUbEx85jnv5HuhzNDmBvKLPnGo0+Ya96lK5DZYCZ7r\/DpgraGYsvZ\/Owr2BZa3HMZINzpY5OEmJNiaW79jmeXKtt34CFyM9rPz5hUApl9dEsh3vWLSuH7s1jrKjg42GLzQNIDw52xjd8uJwuNU\/oANFy+umDVY51lbO8sx02zNtRnbjsevd6cFVZxAwmud+vnk7yE7iVaD4MjnMbOTMm3PcBsl6N7IM1\/XdH0+nM73sukc3wV9zfJxdKgAfDTzB6xv4Mpb4rtsvAJ9sMb+UPTLAmRvedOR7U68C7+rs37vuZV8hijSWaS8SvMhIt+ptIU\/5qTt1y0C5x4myMt3z\/MfrOLOda1nd7qqHQvt71\/rdTNR\/A5SJXJ0=","xmlFileCreated":1543258276},"27":{"desc":"eJwLycgsVsjNTynNSVUozsgvL1ZIVMjJLC5RyE9TKMlIVfDJT09PTdHNzFMILU4tKtYDAKmuERw=","element":"mod_logged","enabled":"1","extension_id":"303","folder":"","name":"Logged-in Users","path":"\/administrator\/modules\/mod_logged","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_logged\/mod_logged.xml","xmlFileContents":"eJydVk1T2zAQPdNfoerUHmKHdjrTmTqmJnHTZJyYwckMnDzC3hi3suSRZCD\/vuuvkAAptBciad+unt4+yThnDwUnd6B0LsWInlpDSkAkMs1FNqKV2Qy+0jP3nQMPBkSNIWZbwogWMq040MfMz9YpJQnPQZgRZWmRi1wbxYxUlBRgbmWK5cpMsRSo++7EEawAF6vEXGYZpI7dLGCAVQhW7lzKgrP35ELJX5AYx+7WEZEoYAY3nTAD7pyJiqkt+TQcfnHsg1ANleVW5dmtccf9iHwYf2zQZIA\/p19JWIIgkaxUAmTBjMETWcTjnDRwTRRoUHeQWlh+Vw5r8zxBScCdLtdkCgIU4+SiusFlErShXh3yiUhFOHJS34gGIMFs7C8j3zIPeLC+zu7sfsFy7jYafv\/VyGBJlfUKtNEdeK24e39\/bz0H1hGEdRzcz9bQGjp2P8VICjpReVnr5S7CSRyE06k\/ia8WQTzxo\/Hl7GI1C5eOvY\/DtE3OQeOgHdVtI60bGld0\/aR7vbXK29Kxe3CbKXkKyjVFyTHSTrC03dd2OBNZxbJuo35GDENXghhMz6nb\/Fh726DlUM0O+g95equf5T5OGjq3wEvyG7YjOv\/pBxexf7XCBqI6UYzKrQM\/XnhLb+pfxt5kMVt2UlJityYUmzzrFAOealLrMKIlU6zQ9W3YRcB0sRum86QNdbFmeNJGE1kJQ9uV9j6KqrgB1S1xdgN8RPd6+mPmB5N4HK6Xqzjwzv2gQ+619ii+9sIOvmEVxwv+pVvAfqGpRzQXBrJ+fzz0Ed713wPaHB+Jo6SX3sJ\/E88a+CLN07\/RPGnVPXFkU5fcMV5BneM+4eDYsjf\/C\/ghdefTIDz3gngd+ZfPE2pXow5tm+2+zy92naV3TCT17TkiIGdbWR12vr17B4FOynmrjhfUPb8O139p\/R6083OX8ajq8a62DBLOtI715uGAncEPB8NH+ZDZOFx0+0RdC9vZOPCiKI5+XB1n+nrqnhGUvNf4aXrtAPheygK\/G0lscsMPHYofrFy+xt5br8KFt5qN49Vs1Yj3ZvZPU\/fYN4riU2DEIFOyKsluNNiCFvKp24f\/5\/b5tR+9bvFl+FZX97PmFe3fPsfe\/Qfh\/gH+2YHR","xmlFileCreated":1543258276},"28":{"desc":"eJwLycgsVsjNTynNSVVIySwuyEmsLFZIVMhNzStVyM9TKMlIVXArys8rSc1L0QMAbQwQCg==","element":"mod_menu","enabled":"1","extension_id":"305","folder":"","name":"Menu","path":"\/administrator\/modules\/mod_menu","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_menu\/mod_menu.xml","xmlFileContents":"eJzlV0tz2zYQPtu\/AuGpzYxIKZ50Mi3FVJFoWy71GNGa2CcOTEISE5DgAKBl9dd3AZDUw5Yt99BLT8JiH9jv28UScr8+ZRQ9Ei5Slnetjt22EMljlqT5smuVctH6Yn31zl3yJEmubJDcFKRrZSwpKbG2nhd2x0IxTUkuuxZOsjRPheRYMm6hjMgVSyBcseQ4IZZ3fubmOCMeRIkykpeuo0XYxiWYcu+GsYziD2jK2Q8SS9ep9sEi5gRLOHKAJfFGmMcr9Knd\/s119hTKkBUbni5X0uvXK\/RL\/1dl\/Rm14KfzBU0KkqOQlTwmaISlBDQ26lGKtLlAnAjCH0liQ\/gmHMSmaQx0EO9qPEdXJCccUzQtH2AbBUZVM4M+IcYRhZz4H0gQgoJh3x+Hvi2fAFYdp0HuZzilnubvzx+aBJvxZY3faBvjOafeer22nxsqDZhVOXgXdttuu04tgiYhIuZpofjyRpNBNPLH8+huFEQDP+zPhtPb4WTsOrtW4LRIKRGwMCtVMmT6QPeDrqTV1NQuVoXr1IbGi9GEcK9QrAL4StzRyKyg+\/u1+4rQgvCXYtbCi2caQeiS4XxZ4mUFoJaQxNDnJG9dfbM8\/WM3AKCFoUKV4cleYiOeeW4FnYoCg36STde6ufaDaeTf3UJLAONhBLWYB3406o17V\/4s6g1Gw7EujoUc09T5Il1WyAlNBFJIu1aBOc6EulmNhshK94BFGhtVpdPLM6NVSas7bZnN6nqrUpoNih8I7VpNk1wO\/cAsb++nfhT0vvlBZbrTLscdVINV9mZcpDAZOtWOSfLMZToIesS0hGw+Wt6xaBPdqdF05g\/8y+HYH7gOq\/tVBXI0Xu\/8CHjTis+gT3e3XyYATgz925PhV+Y74HGS6HQKLFcHExNmTVawHLgRaqn7SjjQYYQKA0hUQcSKrdVpdRF\/\/2gUzlHE8YrEP\/cAw0hO2atY+9d+\/6+ToRrrvTJjIaANZd5aclYWqFm1NkTkrIm5wCWV22aAqwtTs2uluSRLwo9A\/lBjPtI8Hcu7uffD\/b44NGqD0Xjyvt5RieRk\/U4uw+vJ97H\/\/QQeK8v\/jsk3iFQcXQ8H\/utMKrpV5u\/nUk3Ff0GmmqAnsqmH7f+BzgXjZRaVnO7xuZVfZvNyMpuP5rPg5JveOOxwWnOzPUykf8PhF+1DNt8eYVukMI0N2MNvG04ecR6T5OjnjeINKw8mvH6z7CkqQm4Mrl6gBvv9ZP7KfN8xrb7ZlceWi+ND2GSg2y8Si6e97CQ8tTE8Zfcz609G1Tlh\/QnUUj\/ohWEUXt4dz\/Rt153ycbaGG3FxrARbSb9q6teI6zT\/D7x\/AMoMl7o=","xmlFileCreated":1543258276},"29":{"desc":"eJxNjdENwjAMBVd5E7ADM8ACJjU4khtHjlPo9rh8VPxZuvO9u9SB1ZapjCH2HiBoHQF7IoQT5d2tTyVHn49kwguuHrUoj3QoQJ7PUVVRpju3uOBmK\/\/BLDestENoY\/CnV88Kb9xSsvmSY2z\/ueeqczlSX\/k+O28=","element":"mod_popular","enabled":"1","extension_id":"307","folder":"","name":"Popular Articles","path":"\/administrator\/modules\/mod_popular","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_popular\/mod_popular.xml","xmlFileContents":"eJyVVluTojgUfu75Fdk87T4I9sxO1VQtMksr42ghWKJb7VMqQqSZDYQKobv993u4ivaq3U8k58Z3Lt8B4\/trwtEzk3ks0hG+14YYsTQQYZxGI1yo\/eAb\/m5+MtirYmlpg9QhYyOciLDgDB89v2j3GAU8ZqkaYRomcRrnSlIlJEYJU08ihHBZJGnIsPnpzkhpwkyIQjKRFZxKQ68koKEFWEtzLkTC6W9oKcUvFihDb+RgEUhGFbx1QhUz5wU\/oM\/D4Z+GfiIv7UR2kHH0pMxxe0K\/j\/8orb+iATzuvyEvYynyRSEDhhZUKchHQxbnqDLPkWQ5k88s1CB8Fw5i8ziAgjBz6m7QlKVMUo6WxQ7EyKlVbW3QZyQk4oBJ\/oVyxpAzG9uub2vqFbJq43SJ2wmNuVlV8O9fVQ00IaM2\/VrbGW8kN19eXrS3hqUGzBoM5hdtqA0Nvb2CJmR5IOOsrJe58CZk6S03jrUijwuHTGx\/vJot1zPPNfS+IfjtY85yONSnsmmoHoZqKNp24n5vtewpM\/TWvPYVPGTSVEnGQVNf+jHNJ8Yz9tazvuRVB2gaFTRqwLQ3pCgMLksH0wdsVg+tjwTGEmre2H7EMT\/kb5yPlwpQCRn9yw4jPP9pO0tiP66hz1BDn0CBN45NFpZrTe0VsSaLmdtWHCO9HtZ0H0dNERgPc1SmPMIZlTTJS850GqYa3Y7mcVCrGl11vKu1gShShWtJzdq0SHZMNiJOd4yPcL\/3P2a2MyFjb+OuiWM92E5j2huByw7l0HT2e1pwWARfGwE0DcZ\/hONUsahFAGlfQg40Dk+Qg4RFQh5Osc\/H1tqeeqvtO3E21n2ocXj6um7RlfVLCHQF7uo8r2tp3dX9uDNEBQQ9U15ABticexWjiOVuOyiGLlpmlS56VYqLdSlgF5GzynDYs7c6am3WP72V\/5Geti7\/19Xh1USH2Hwb7h\/L2dhl5p5rn+Z87r47kIRdCTGZ2BPirUpKzUAxIQ9bsrgRMxXqalDXW78vcNeg4xnYWPfrnJw0fKZpwMKL\/OT0IIpTgtab9ETRjnrTFqdk5tbbXCFoz7TZO43HsZeXqVcjCDjNc5LvX0\/QKSAHhW\/sKbKxt2je4zdFrW9jx\/J94v94vIz0tmtv\/KR4yeE\/41YC8PkTCRA6ICpW8IvSTwD+PmJxCz1Mvrew1rMxWc\/WVfHejf7ctYe+qihMt0oHkRRFhrrT4MDyVFzi2EdWzD3smK3tX+cC0HPueu8b6+Ot+tq1nyhD77ak+R935wgK","xmlFileCreated":1543258276},"30":{"desc":"eJwdi9ENgCAMBVd5C+g0LkCkQCPShNfq+hL\/7pK7oylxW44uYLOX8LbIkwdh5bdutUredCAok0gj40lTbSXrmX6Go+u4uH+V7x19","element":"mod_status","enabled":"1","extension_id":"309","folder":"","name":"User Status","path":"\/administrator\/modules\/mod_status","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_status\/mod_status.xml","xmlFileContents":"eJzdlt9zmzgQx5+Tv0LlqfdgcJq5TmeK6bk2cZzBdibYbe6JUWCNaQViJGHH\/30XJPwjbSYT9+WuT0ja7y6rzy5I7qfHnJE1CJnxomdd2F2LQBHzJCvSnlWpZeeD9ck7d+FRQVFriNqW0LNynlQMrL3npX1hkZhlUKieRZM8KzKpBFVcWCQHteIJhitTQROwvPMzt6A5eBglkoqqSrpOs4AGWqFYeDec54y+IbeCf4NYuY5ZR0UsgCp86ZAq8K7ggbzrdt+7ztFyLePlVmTpSnlvB3\/Vmr9JBx8XH8ishIKEvBIxkAlVCvdgkz5jpJFLIkCCWENiY9BdEIzIshghgDeaLsgIChCUkdvqAZdJoE0tD\/KOcEEYZiI+EglAgvHAn4a+rR5xK22c3W79nGbMa6j9863ZuM1F2u5ZW3fihWDeZrOxfxbWFpSZHLxLu2t3XaedoiUBGYusrCl5k9kwCuf9+SKM7idBNPTDwd34dj6eTV3nUIduy4yBxIEe1YUiuv5NH5gKWgfVtMtV6TqtWHtyloDwVF4ytOgJhnba2C6jRVrR1LyonRFFsQ+h6Iw+W17zsA9eg02GNI30FX5y+7PvftKkswJWku+w7Vk3135wG\/n3cywg0gkjJLcI\/GjSn\/ZH\/l3UH07GU4PSIo5uvWKZpYYYsESSmkPPKqmguaz7f2cBZWwPVGaxNhlbMzzTVrnim2idwUZmCixt0V8iflEZNyuMPgDrWQelvRr7AU6uZ1+jL2P\/azie+1HQ\/+wHxuOg0i\/61S1i3GJGpcScVdFJBa9Ksht1tiALvou+pBXDH8KFWcBq4yfRs7JCQQrCrOpNn7m8yYOsKaug9vFu6gRch7ed+AtVF1XX46F\/rKr7Cgl65y\/hbL6503nq2p8AVDv+BtHuf5Eo42kKeHREFf5A5WlYg9lo5A8RziL078LXsn3i\/ae17DHg6De69wmokxr5lzH+NOQ5SFkfCqdhnvhhiKfEq\/t45\/d\/xLkf4\/Gm6T497WiypkUMybMHHqNbXqkj6PrOcWQw7G80uX4wR87\/zhbz53EfSM05bjz2oJ1nG0Jn0NQhksvHo+wUXpEpXkGPMxvMJuY9bXn1bBD0wzAKr+6fz\/Rl14PeEHyDrXG528CTEuxnzU2nvZ+4zu5e7\/0AWDuJwA==","xmlFileCreated":1543258276},"31":{"desc":"eJwLycgsVsjNTynNSVUozsgvL1YoyUhVCC5N0vVNzStV8Essy0xPLMnMz1PwBSvSAwDBmxHk","element":"mod_submenu","enabled":"1","extension_id":"310","folder":"","name":"Administrator Sub-Menu","path":"\/administrator\/modules\/mod_submenu","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_submenu\/mod_submenu.xml","xmlFileContents":"eJyVVE1v2zAMPbe\/QtNpO9ROW6woMEedm7hZCjsJ6gboToZiM4472TIkuUn+\/eivNEFRDDtJ1HukyEdKzt0uF+QNlM5kMaSX1oASKGKZZEU6pJVZX9zSO3buwM5AUXOI2ZcwpLlMKgH03fPauqQkFhkUZkh5kmdFpo3iRipKcjAbmWC4MlU8AcrOz5yC58AwSqSrVQ5F5djNCSK8QrZij1Lmgn8hCyVfITaO3Z0jI1bADd465gbYA6zI1WBw49gnxzVNlnuVpRvDRv2OfB19q9nfyQUul7dkXkJBQlmpGEjAjcFyLOIKQRq6Jgo0qDdILAx\/CIexRRajHsAmsyWZQAGKC7KoVnhM\/BbqpSFXRCoiMCf1g2gA4k9H3iz0LLPDovo4h7q9nGeCNQL+fG0ksKRK++pb9EBeKsG22631kVgjSOtyYNfWwBo4dm8ikoCOVVbWerFgPo7C5X3gzZbRS+BHYy8cPU0Xz9P5zLGPiei3zgRo3LS7umeknYVmJvpu0uPWWuWmdOye3vpKkYBiJi8FIq2Bwe0+uiN4kVY87a7qLWI4TiUUF5N7yprFOr4HZw4V7bj\/46j3+oPzu9EktAFRkj+wH9LHX56\/iLyXZ+wiKhRGKN\/S96LAnbkT7ylyx8F01utJid2OYrHO0k42EIkmtRRDWnLFc10\/iAMCpsN48saLGJIW7eBme9YSBN\/LytD26PhZngCCr0Bg1g9Tzx9Hrv8c+e7v+bJe7j2\/Ix01+YTaldZ51HPROmBRnyTVZhALrnWk17uT7Az+Ihwf6Wlmo3nQ3RNG7c2tNfLdMIzCh5fPM\/2363vKZ0puNf5ThwLq9O1e86Y1ndU0v++YYx++PvYXoNmiCA==","xmlFileCreated":1543258276},"32":{"desc":"eJwLycgsVsjNTynNSVUozsgvL1YoyUhVCMnPz0lKLFJwzs8tyM9LzStRCMksyUnVAwCS0BEK","element":"mod_title","enabled":"1","extension_id":"311","folder":"","name":"Title","path":"\/administrator\/modules\/mod_title","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_title\/mod_title.xml","xmlFileContents":"eJyNVE1v2zAMPbe\/QtNpO9ROWwwoMEedm7hZCucDdQJ0J0O1mcSdbBmSnI9\/P9qykwZFsZ0kio\/U4yMl736fC7IFpTNZ9Om106MEikSmWbHu08qsru7oPbv0YG+gqDHEHEro01ymlQB6irx1rilJRAaF6VOe5lmRaaO4kYqSHMxGppiuXCueAmWXF17Bc2CYJTaZEeC5jY3nvEKsYk9S5oJ\/IXMl3yAxntueIyJRwA3eOeQG2FRuyU2v991zz45rmCwPKltvDBt0O\/J18K1Bkytcru\/IrISCRLJSCZAJNwaLcYgvBGngmijQoLaQOpj+mA5ziyxBNYCNpksyggIUF2ReveIxCa2rE4bcEKmIQE7qB9EAJBwPgmkUOGaPRXV5jnUHOc8Ea+T7+dZI4Ei17qq33iN4qQTb7XbOR2DtQVjLgd06PafnuZ2JnhR0orKy1otNZsN4MV6EQfwyCeNhEA2ex\/PFeDb13PcwjFplAjRu7K7uGLFz0MyD7SQ9NdUpN6XndlAbJ0UKipm8FOixBiZ2u8ye4MW64uv2ms4ihuM0QnE1eqCsWZzTLThpqGSL\/P8wfdAfQk9GQ2YDoiR\/4NCnT7+CcB4HLwvsHSoTxSjaEhWb+FN\/FDzH\/nAynloVKXHt+BWrbN2KBSLVpBahT0uueK7rJ3D0gGl9PN3yIoHUelt3s72wAMEPsjLUHr1\/iGcOwV9BIOfHcRAOYz9cxKH\/e7asl4cgbEHvWnsGbQtrI+ppsAFY1CekLINEcK1jvdqfsTP4b3B8mOfMBrNJe08U25utNQj9KIqjx5fPmf479ET5Qsmdxp\/pWEBN3+00b1rTWk3ru4557vGzY38BYnGcog==","xmlFileCreated":1543258276},"33":{"desc":"eJwLycgsVsjNTynNSVUozsgvL1YoyQCyShJLSosV8tPAvNzSnJLMnMy89NLEHIWCxKLE3NSS1KJiPQCxGBbH","element":"mod_multilangstatus","enabled":"1","extension_id":"313","folder":"","name":"Multilingual Status","path":"\/administrator\/modules\/mod_multilangstatus","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_multilangstatus\/mod_multilangstatus.xml","xmlFileContents":"eJytVE1zmzAQPSe\/QtWpPQTsdDqTmWJSYhPXGbA9wZ5JT4wCa5tUIEYSsf3vuyDwR5NML72AVu\/t09PujpzbXc7JK0iViWJA+1aPEigSkWbFekArvbq6obfupQM7DUXNIXpfwoDmIq040GPmV6tPScIzKPSAsjTPikxpybSQlOSgNyJFuXItWQrUvbxwCpaDiypxXnGdcVaslWa6Uo7dIMhgFWZJ90GInLNPZC7FCyTasdt9ZCQSmMbTR0yDG0GpIX8GSa57\/b5jn4E1WZR7ma032h12K\/J5+AXZvW\/kqk66IbMSChKJSiZAQqY1Xs4iHuekoSsiQYF8hdRC+YMcavMsweqAO54uyRgKkIyTefWM2yQwUFcock2EJBw9ye9EAZBgMvSnkW\/pHV6t0znc3s9Zxt2mnD9emkJYQq67Ghj0QF5K7m63W+stsUaQ1npwv1o9q+fYXYhICiqRWVnXyw1nozhcBotJ4E3H0cJbLKP4KQzikR8NHyfzxWQ2dezThEsUWGUcFCqZVd1CYkakGZW\/m0zf67xVbkrH7tKNluApSFfnJUfEBCf7dW7F1nCCGQHVeOpg46uLiGY42VBcje\/oQcFuYvO13vOG44ztadn\/QU\/t32oeA+N\/A7wkv2E\/oA8\/\/WAe+08LHBUsfxRjj5aBH4fe1Bv7j7E3CifTY9MosRuBRBSrbF0v67YATxWpSzugJZMsxy7USAeBbkGWvrIigbSFW7xZXhgGZ3tRaWq2Tt+DM4CzZ+Do\/X7iB6PYCxZx4P2aLevfnR+0pJM5OqO2F2wz6tEzCfaHpoyDhDOlYrXanbnT+HwxfA\/OnQ1nYXtOFJuTTTQMvCiKo\/unj53+O\/Vo+UKKrcIH8uwC9ZyaqjfD1EbNEHRdc+zDo+v+AQRIzPk=","xmlFileCreated":1543258276},"34":{"desc":"eJwLycgsVsjNTynNSVVIySwuyEmsLFYoyUhV8MrPz81JVFQoSy0qzszP0wMAQQgPIA==","element":"mod_version","enabled":"1","extension_id":"314","folder":"","name":"Joomla! Version Information","path":"\/administrator\/modules\/mod_version","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_version\/mod_version.xml","xmlFileContents":"eJylVVFvozgQfm5\/hc9Ptw+BpNVKlY6wl01oNhEJUWhX3SfkwoSyZ2xkTNv8+x0w0GSb9E66F+SZ+WY8\/uazcb685pw8gyozKcZ0ZA0pARHLJBPpmFZ6N7ihX9xLB141iBpD9L6AMc1lUnGgb5nX1oiSmGcg9JiyJM9EVmrFtFSU5KCfZILlilSxBKh7eeEIloOLVaK2gmM3HoywCtHKXUqZc\/YH2Sj5E2Lt2K0fEbECpjFnxjS4SyYqpvbkaji6cuyjUA2VxV5l6ZN2p92K\/Dn9hOjhZzKok25IUIAgoaxUDGTFtMaGLDLhnDTwkigoQT1DYmH5vhzW5lmMnIA7X9+TOQhQjJNN9Yhu4ptQRw+5IlIRjj2pv0gJQPzF1FuHnqVf8WBdnf7sXs4y7jYk\/v2zocGSKu0YMNEefK+4+\/LyYr0H1hGEtT2419bQGjp2Z2IkgTJWWVHz5a6CWfTd24aLYB09rPxo5oXT7WJzh7ZjHwIxb5dxKHFhVvXciNFDo4tuovRwvFbxVDh2Bze5kiegXM5EWrEUMGocBzGdF\/zY3xV4Al6AelfVGGUznbauabSziGaoaxCD+Vfab203tvlah02jiHE8Lep\/1Cn35btab0bTbn0g8g\/sx3T5zfM3kfdwhwpB9sMIR3Pve9Fqsp7MvW00ma0W625WlNhG5mKXpS1FwJOS1ISMacEUy8v6wvUR0G3skZVZbEJtrFlemOhOqpxpalzmznO80a2Ds0fgY3oomttgu5rcRf7kq+e3qAPZnMTWGuuhO1ZxfDpKFG63i+ntwpFNCfLMeAUdwj1RL\/wWbO8cW3ZCPZHMpUhP5vrBen6cWmsJSXEvzzBUKNR8fEwRPm+ZPM\/RZoujnP5HkjrwAUsxZ2WJk9NikCpZFaRfDfZQCvk7maPWgZcCn54xzYSGFNSH9I6ou\/zhhR\/TOETQOjjD19saxXZSeix5ZiKG5Kz6ONvL6pha88IcBVqGl7cLz59FE78m9kdw\/wG\/B9D2VrUZbyTbZwduOmhmEJW716PuNP4gGf57jjubBqt2nzAyOxtr6k\/CMApvH853+u+pB7pQ8gVlcd0f4N0EOqt5d7rHwrH7v7r7C+6tcmE=","xmlFileCreated":1543258276},"35":{"desc":"eJxFjcsNAjEMRFuZCuiBAjhBAw7xkkjZWPKHiO7xsgeu82bmPRrj7uTdvD8NN6kxGNZkGfrcRPdkMkFFwvGRUBjrmzWpOY1xYpcXe8t0dW+w\/+HBUrG4WHdG5NhAs\/7SGXvJjWy4arYHH85TUsmpkPHlC3FqPL4=","element":"mod_stats_admin","enabled":"1","extension_id":"315","folder":"","name":"Statistics","path":"\/administrator\/modules\/mod_stats_admin","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_stats_admin\/mod_stats_admin.xml","xmlFileContents":"eJzdV91zokgQf07+ijme7h4E3dxV7dUhe4QQFws1JbiVfaIm0Cp7A0MNQxL\/+2u+VKLGuI\/75Ex\/za9\/3T2M+pfXhJFnEHnM06EyUPsKgTTkUZyuhkohl73PyhfjWodXCWlpQ+Qmg6GS8KhgoOw8b9SBQkIWQyqHCo2SOI1zKajkQiEJyDWPMFy2EjQCxbi+0lOagIFRglxSmQeVh65VUtTSAj2EMeY8YfQ38iD4DwilrjVytAgFUIkn31EJxrhgG\/Kp3\/9T1zry0o5nGxGv1tKw2hX53fqjtP6L9PBn8JnMMkiJxwsRAplQKTEnlZiMkco8JwJyEM8QqRh+Gw5jszhEUsAYTRdkBCkIyshD8YRi4taqlh\/yiXBBGGIS\/5AcgLiOZU89W5WvmFUbZ5u4ndCYGRUn\/\/6oOFC5WLXp19qt8UIw4+XlRT00LDVo1mAwbtS+2te1douaCPJQxFnJlzGZ3QWeb\/pe8Dhxgzvbs+bOg+\/Mprq2b4Zey5hBjot6VZaM1O1QtcV+QZW3FVazdaZrrVsdg7MIhCGTjKGm3uzJGU1XBV1BV9cGWAPLQBxErTd5VaPGvwbc7oik2N6Q9ka3ilH9qFukKrYu1qSx\/Lhbvjl03W0qMCVc8h9shsr4q+0+BPajj12AHHsB0r9w7WBiTs2RPa8q4Xi+Y3kK0eo+TpfxqskeWJSTMtehklFBk7wcqa0GZKN7onkc1qpGVy2vam3V0yJOl1ypxfVk44TGrYTRJ2BDZdca947t4tqef7PnzvR+Frjmre021ntt8q5P2VuNS8honiNQmfZWghcZ2a56G8hTvo28pAXDi6XfCLC8OEpDJU4lrEA00jrTK51XGMgzZQUmNFCM8Xfb0zXedvARoz4aTWddm7KLkDPj+hSBsYSfos\/x7QvJaz1+FepCXuDx4lLmrNli6uN0fJi41uFX4S1Oy+9bDh3i0iJ52gI6wZwztea26dkXM\/jWcY\/Jj1Gk1VeT1t5NR28qGj3TNITo5GXF6IYXspN2\/c3pKJrkxzV00\/Uxz++zhX863T3T5gZuPHZ5aierUSOoGirIl68ddBJfTBRr1UVmzSbNOS2\/9c5yTc8LvPvH00jPu+4gkyvBX7DJb85lENJw3W0mhs+2c5gt0\/rqTEeXYG1djrXP4CcnbOTObk03WHh2UC\/Pztshrm+mu7CD6azBd+EtVrIXyDg5P4\/HGbED35nYl\/LYeB2j8u\/+uVl8LxXs524m6ziKIH17SPncwXfFe+VpTIwTfB5cCO2uejK1Tx1d2\/7rMP4Hty+pwQ==","xmlFileCreated":1543258276},"36":{"desc":"eJwdjdERwCAIQ1fJBJ2mC6jQljsVT\/Cj2xf7F0Lycj5iaEqrMkhs1PQaPN2GZUzQDn8YJs6QjoQq5tAZqlRdhMjr8gPnrpTUkTnexDPK+YWL1238OkB9tcwTeu2NOzIBbobUgyQtDoJrwG1wkUtKABpj8BSl4wPJpz1s","element":"mod_tags_popular","enabled":"1","extension_id":"316","folder":"","name":"Tags - Popular","path":"\/modules\/mod_tags_popular","title":"","type":"module","xmlFile":"\/modules\/mod_tags_popular\/mod_tags_popular.xml","xmlFileContents":"eJzVWN9z4jYQfk7+CtVPdw8BkszNXFvjqwMOITU2g6FN+uJRbAG6ky2PLIfQv77rX8QOYIe0L31C0upb7X67Xq1Qv70EDD0TEVMe9pXLTk9BJPS4T8NVX0nk8uKr8k07V8mLJGG6B8ltRPpKwP2EEeUVed25VJDHKAllX4mpBFlA5Jr7oCVaCewTRTs\/U0McEA3ArsSr2I14lDAs1G62DGKcAERo95wHDP+EpoJ\/J55Uu8U67PAEwRJOHGJJtHscJlhs0VXv8lrt1kTpVh5tBV2tpTYoR+jT4DPs7n1BFynoK7IjEiKHJ8IjaIKlBHc6SGcMZdtjJEhMxDPxO6B+pw50M+oBH0QbWQs0IiERmKFp8gTLyMxFJTXoCnGBGNgkfkUxIcgcDwzLMTryBRwr9ex8NwJMmYb9gIa\/fc9o6HCxKhnIpbvNC8G0zWbT2d+YSmBbYYMG0en01G45BYlPYk\/QKOVLm9hDd66PHHdqTxemPnMfJqY7NJzBbDydj21L7VZ3A3hJGYlhkI\/S4KE8IbLEqMVW2Yt2J1pHarcE5lo484nQZBAxkOSTqnZtTVhE9pH5JM4CgsNVgleFWeUMwcF9hYQXoxtFy346e+bQkEIcCsDJ6Hgb72l4nWSmpcajH2TbV+7vDHPqGg9zSADg1XGB+YVpuBPd0kfGrBYEBXXzJA6XdFWwQZgfo9T3vhJhgYM4\/aZ2EiIL2ROOqZeLClk2PNsh4SOd45WSr+YftNzNGX4irK\/sJcVUnxnWPF1zTf3GMIvtldRoBqUJVWCChEkapekiRUKKRQglfCN9hYbSxULgbb4OLBxxJMAvNEiCmhsAJisiWlyZ6A8n+JDurhjvkyUG+\/vKl33DK2cvqYhh0+XOlHR21SumsSTRTnjcRUkDsoRAk5qTjMayxcPbsWHC0nhi3M70iXGCt2+RhzzHjKWWFct5op2pPFOJnjFLyOue\/eqSn6CbZnaK2uVlXTmgZQ2l+agKU3fm7p29mDXr8CGVGlUM9cdmDRtCfjSr+NMwfm\/WEfBQrpuVTGxrftesZUtwCx+Phv6Gj7RKQl4dTTIuoN662QEfSzN7NoTi9YduLk5PtCr2UKp5PAllY6JJKtnxNKvqn4\/nZku+5ce9R9nAXljzZmUCh\/6nz+\/SNtOtoT35SNx8KqBFAlBL7O5Hpn2jm8Wpw\/HMGKR3+\/GAHQMcitJlYyk8zE5P0epH6A40RsOxNWpm9fItLjXoELCNP5\/GEcNbt5piOXvQrlL+rtQfjp2pqT\/m2XBy8tfRFWI9uC5iuMhleLESPInQbnSxJXHI3\/Lf+wD\/KY+PhtNMdhokyz6N15C70DaDXbEr4d3wQWYt250ZzsKcOyfTWoH+7zh9HUM\/V+\/uzl8p9hhP\/NySRhYdY+4OTHsxrHB4rC+EF0dM\/65fAWESPLV2UznpkzH0tH+dfgGUuPeUlSXjWL6jLfxXfugPH\/OjwB3y46rRj4aQFw099p9x6BH\/aE8PZYwn9S8tf5DVBOVNUDZgacF6tBcNdauytXiqFIhDXrq\/FMPWCGWmZd+jGy9f6u8QqBjwQMF1kwf2pDDAKenOZgNoeRzXuW1o59uhFV8E30CJuG5zgG9CD3vrtnZp\/+iBPriDe+oUa0vIf3XtVq7PhWO4+bC1YO3blfctll3Yd9oVkbHnVt4Qxz\/Tw4wY2dvhVB4L1CEqf+411vtDn2k5y1785Ttd7e7+KtP+ATcXi7Q=","xmlFileCreated":1543258276},"37":{"desc":"eJwtzMERwjAMRNFWtoJ0wiluQNgK1iBbmawyDN3jA\/f\/fumK3Ya5XCjyIh7Rblc04+nyJdzmm8hAZNcLljqIj2UH\/ywX21DWqHpQp5KIAyvHkKwdVSaeCp5a7TBt2w\/VPypp","element":"mod_tags_similar","enabled":"1","extension_id":"317","folder":"","name":"Tags - Similar","path":"\/modules\/mod_tags_similar","title":"","type":"module","xmlFile":"\/modules\/mod_tags_similar\/mod_tags_similar.xml","xmlFileContents":"eJydVktzozgQPmd+hUan3UPAztRUzdZiZgkmjl3YuPyYypwoBWRbs0JQQsT2v5\/mGRPbZLMnJHV\/re6vH8j4fog4eqEyZbEY4L7Ww4iKIA6Z2A5wpja33\/B385NBD4qKXAepY0IHOIrDjFP8ivyi9TEKOKNCDXDKFMgiqnZxCFaSrSQhxeanG0OQiJoA9hXZpn7KIsaJNPTiGMQkA4g0J3EccfIZzWX8iwbK0Ktz0AgkJQpuHBJFzQkRGZFHdNfrfzH0lihXjZOjZNudMu16hf6w\/wTt3ld0m4O+IS+hAi3jTAYUTYlSEI6GLM5RoZ4iSVMqX2iogfnGHNjmLAA+qDmardGICioJR\/PsGY6RW4pqatAdiiXi4JP8G6WUIndsO7Olo6kDBFbbaWJ3IsK4ScKIiX9+FTRosdzWDJTSRnktubnf77VzxVwCapUPJmRH6xl6vQVJSNNAsiTny5x6Q39ljZb+cjwdu9bCf5q6\/tBZ2ovxfDX2ZoZ+qg3gDeM0hUW5ypOHyoIoCqOVW3yWbS3ZJYZeA0srMQ+pNFWUcJCUm1Pr5o7yhJ4jy01aJISIbUa2lVv1DsHFA0zF7egem8VHO3OHCQZ5qAAfRqfH9MzC66ZwLXce\/UuPAzx5dNy57zytoACA16UPzK9dx59aM2vkLFpJwEgvi1hs2LZig\/IwRXnsA5wQSaI076lGQlUleyYpC0pRJSuWN6U0IgcWZREuz8p2ZkLRLZXVGSfPlA\/wWVlMrSffte4dt9I7qYor2nkRNcobknEYDl+rA0gd9MTbuzdMpqDUb1zJd3e9apsqmjRC4OdqiCrY5ZG1guQsVe9E+DB23CF4vrIfVz\/nzgeifYu8FDkRx+qozM2NERfm0AvhGThIOMfnzVhatlzX0OO6Ay+Bwfg1sDdzusE7wjdX0Y+W+9CG530HlF\/lP5bQwfAH+X\/0e4uhsxjPRh9mvwFeIj+IM6E66S81rnJYG7e99WzVTackIoyj900trNnQm3bbKrz6rwYL33ywetF0k7bXNQyNiyOEhC9EBDS8OkU4OcaZaiW4\/AW0BFWiJ3UNryCnP7316npqT1Sr4VghXnPa0feFBwEMDRjQm0PLOwVPGAIvhLZntjet7lnWLVzsbNdaAssPHQPvfehJGcp4n8Ij6b0A4r0ISLB7b26dX21b9mNny1yHXGqWfueMvlyofWxORq53b7n+eun45bK7tnvYPPfrh+WuHX\/mVf59bPIU7PmKRW0KRRY9v\/29XWbE8Vfjacfg70RdovKvXq+LTP1CN9a74ilRPwAMvXmDm78B7vNvig==","xmlFileCreated":1543258276},"38":{"desc":"eJwLycgsVvDNTynNSVVIzMnJLy9WKMlXyMwrLgHyFIoTcwuAEimJJYl6AE43D3U=","element":"mod_sampledata","enabled":"1","extension_id":"318","folder":"","name":"Sample Data","path":"\/administrator\/modules\/mod_sampledata","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_sampledata\/mod_sampledata.xml","xmlFileContents":"eJyVVEtzmzAQPie\/YqtTewg46XSSmWKlxKauM\/gxsT2TnhgFNphUCEaIJP73XQQ4dtJLT0j7PdgXeNevuYRn1FVWqCE7dwYMUMVFkql0yGrzeHbFrvmph68GVcMBsytxyPIiqSWyN+VX54pBLDNUZshEkmcqq4wWptAMcjTbIiG7MtUiQcZPTzwlcuTkElUiLyUmwgjPtUECRU0CzW+LIpfiEyx18YSx8dwuToxYozD04rEwyG9ruYOLwfml5x7FG15R7nSWbg0f9Sf4PPpC7ME3OGtEV7AoUcGqqHWMMBPGUEkO+FKCpVegsUL9jIlD9ns78pZZTD1BPplvYIIKtZCwrB8oDGEL9e2BCyg0SMpJf4cKEcLpKJivAse8UlW9z77wIBeZ5LaJP55sD5xCp335Lbonb7TkLy8vzkdigxCty4HThJyB5\/ZXQhKsYp2VTb\/4bDGOVv5sGQZjf+1H97MwGger0d10uZ4u5p57yCXpYyaxokN7auYG7UrY1TgYKns3ZKfclp7bi44c+BZlifpfjEImqLkhE0LaCyXh9ll4OSaZAMrRZMrO\/0Ma0Moo3lDZoe1TdWRqCXa+QqW1SLs6+xsYQV8GqrPJDeP24byrkFafhtrR\/1Nb7aoP+reLrbXpEvzB3ZDd\/grCZRTcr2mXaEiriIa4CYNo5s\/9SXAX+ePZdB6F\/jpYrRm47fegHrO0azvKpIKmyUNWCi3yyralR9B0mEiehYoxadEOtseTliDFrqgNa0OH\/4cjQIoHlJT0z2kQjiM\/XFNmvxeb5nEThB3pYM2OqF1lnaLZzFbgthm7fcq2su5mW9cX7Ln7Xxj\/C9idnTo=","xmlFileCreated":1543258276},"39":{"desc":"eJwLycgsVsjNTynNSVUozsgvL1ZIVMjJLC5RyE9TKMlIBUoB2UWpyal5JQqJySWZ+XnFegD3ohMJ","element":"mod_latestactions","enabled":"1","extension_id":"319","folder":"","name":"Action Logs - Latest","path":"\/administrator\/modules\/mod_latestactions","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_latestactions\/mod_latestactions.xml","xmlFileContents":"eJydVl1z2jgUfU5\/hVZPuw\/Y0E5n2lnjrmNcSsbgTA076ZNHsS\/grix5ZDkJ\/77XXwQHCJs+Iel++Jxzr66wvjxlnDyAKlIpxnRkDCkBEcskFZsxLfV68Il+sd9Z8KRBVD5E73IY00wmJQf6HPnBGFES8xSEHlOWZKlIC62YloqSDPRWJpgu3yiWALXfXVmCZWBjlogzDYVmscY0hWXW52hnJcYo+0bKjLM\/yK2SPyHWltmeo0esgFVBE0xgz9mOvB+OPllm77hyk\/lOpZuttt1uRf50\/0Lv4UcyqINIkIMgoSxVDGTOtEZSBnE4J7V7QRQUoB4gMTD9Ph3m5mmMqoA9XazIFAQoxslteY\/HxG9MnUDkPZGKVFzV36QAIP7M9RahZ+gnJNXl2fP2MpZyu5bxn5+1BIZUm459Y907rxS3Hx8fjWPHyoJuLQb7g\/HZGFpmt0VLAkWs0rzSy54Hk8h3ll64dNzlLFiE0d3cjyZe6H6f3VYHlnnojtHrlEOBi2ZVVY40fVH3R7+y9LjYRr7NLbML7eWxt8BzUKc8JE9A2TrLOVqaDUIxOywWZ2JTsk0LrNsRzbCfQQym19Suf4xjPNizWIs24u3hxe44xfOmBlfRIv\/Bbkxvvnn+beTdLbELarFR\/pXvRXNn4Uy975Ezmc8W\/XpQYjYNLdbpppULeFKQSpwxzZliWVFdrr0FdGu7Z0UaN6bWVi+vGmssS6Fpc9Jcb1Fm96DaI87ugY\/pcX98nXn+JHKD1WKJlmvPbwMO2uRSWNVe+6g1KzlOj4\/tAZYUr8uYpkLDpkNjNvzMjuBJuix5YCKG5Cxjznay7FNuOrdnaInfNIAdv2L5I1i9QvbAta1nG\/HMEwmcAdUgiDkriqhYP\/XQaRzADCdbH5kbzNvvdKo2O9d3wjAKv96dR3o59KA0Sj4WOOIvEcChIzMcvnGkU42vwyEBHPypvITeWS2DubOcudFytqzF+9\/oX4YeoK8VxTugxWCjZJmT\/Wqwg0LIl\/03fK3\/rpqWurJkDYU8MF4ivRG1b354oWXKbjqecBqi0yLo+7SdfFbTmMXbvpIcH9ZLQrqO+222mL5FwC7k1I0c\/aYiUz+4dvxoFXpRs7yozzGufx1\/5UWLoMX3G+phN2ZwcbydVsTDdpq\/qREPok5J+Xn4anudv1w1FRwRfSbbNElAvPwIvkl4C18tT+tin9Hz6uWM7Xb1m9Y9QZa5\/19o\/wJrlQeS","xmlFileCreated":1543258276},"40":{"desc":"eJwLyUhVCCjKLEtMrlRwSSzOSMpPLEpR8M1PKc1JVSjOyC8vVsjMS8svyk0syczPU0hMyi8tUSiAaihKLSxNLS4p1gMAngIaiw==","element":"mod_privacy_dashboard","enabled":"1","extension_id":"320","folder":"","name":"Privacy Dashboard","path":"\/administrator\/modules\/mod_privacy_dashboard","title":"","type":"module","xmlFile":"\/administrator\/modules\/mod_privacy_dashboard\/mod_privacy_dashboard.xml","xmlFileContents":"eJydVk1z2zYQPTu\/AuWpPZiU0+lMMqWQ0hIjy0N9jGllnBMGIlcSU5DgAKBs\/fssSVA2K9me9CQs9u3i7dvVSv6Xp1yQPSidyWLoXLkDh0CRyDQrtkOnMpvLT84X+sGHJwNFjSHmUMLQyWVaCXCeI\/90PzskERkUZujwNM+KTBvFjVQOycHsZIrpyq3iKTj0w4Vf8BwoZmGlyvY8ObCU691acpX6XuNDDK8wTtFbKXPBfyNLJX9AYnzP3iMiUcANvj\/mBuhtVQD5OLj65Hu9+xony4PKtjtDR92J\/D76A9GDv8hlE0QWJRQklpVKgMy4MViZSwIhSAPXRIEGtYfUxfTHdJhbZAlKA3QyX5EJFKC4IMtqjdckal2dSuQjkYoI5KT+JhqARNNROI9D1zxhVV2eY+FhzjNBGy3\/+dFo4Eq17cpvvUfwSgn6+PjongJrD8IsB4qNcge+15noSUEnKitrvehsMWbLu+m3YPSdjYP45noR3I3Zwyxi4zAe3U2X99PF3PdehmCGTSZA46E91e0j7YA0g3LaYud8591yV\/pel6LNJ0UKipq8FOhpjZfv0B2IEtRJZGvopj+82FZ8awl2FjEcBxyKy8m1Q5sP9zwnHGTsjY36fyn0QZ+keTYaknUZ5F84DJ3bmzBasvDhHicDtY4ZtmQVhWwWzINJeMeC8Ww6P+2RQ7x20ItNtrUSgUg1qQUZOiVXPNf1N+\/oAWN9a66zxLq8zncWydM9LxJIW7B1N8eLFiD4QVbGaa9eboqeQ\/A1CKz06zSMxiyI7lkUfF+s6o\/rMLKgFyPWg1o5bEQ9lW0Alv8KqZZBIrjWTG+eeuwMLjaOy6LPbLSY2Xdi1r7cWqMoiGMWf314nen7oc+UyYWSjxp353sVJDzZQY+3wO36HudRMLqZzie\/wrULeeaIERteCVzqV\/YCv1i4wIZOVhjYgrK37URc+LLJTfZcVFDH0NtJtLgOIraKQ9YefU92m+NMyMChp7y+BdEqZPOF5dfPYIf2bfWYyfK+hEWVr4\/03xQxZPfTWfirOtqoc1J+HgzeEvOdQcB57leyy9IUiv8+og3+BCZvtsdC6Ct6niyEzmr2V7dqfO\/454D+BLFGgMA=","xmlFileCreated":1543258276},"41":{"desc":"eJydkDFPxDAMhf+K6QRLs6NcpZtgYDrphJiQm\/rSiDQpsUN1\/x6ndwsrmy3bn997r5imSAxnpgLHKjMlCQ4l5ARbkBkQXhYMEXKBl5x9pL1D53JNAo8n+q6hKMCdT29PvR0LmKHBGBa8QiKaQDJQwjESWFqGo3PEDBcFxlYwuVoIcF3ZGp0DCliEudDl0M0iKz8bs21b7\/f3vcuLYRIJybPZj4NcTUPdSA3UgWDxJIfuc4yYvrrhnyBrcGj6RxXYDGgZs4eQoLLegcxBjZLMebp7tywlJz\/AO5akKw\/wkSsslQVm\/KHmLhJql5M2fwNfY\/WKvoU1tciveruFGPUr63rck2+pqRCdFeAg1Ftzf\/oLX9OnCw==","element":"gmail","enabled":"0","extension_id":"400","folder":"authentication","name":"Authentication - Gmail","path":"\/plugins\/authentication\/gmail","title":"","type":"plugin","xmlFile":"\/plugins\/authentication\/gmail\/gmail.xml","xmlFileContents":"eJylVl1z4jYUfU5+heqndqbYkJ3t7GyNtwYM49QxTLxsN08eYYTRVkgeSU5Cf\/1e+StkEyhpnyzrnnuse8+RZPfT446heyIVFXxoDey+hQjPxJryfGiVetP7YH3yLl3yqAk3mCfsO3tgIb0vyNAqWJlTbqFcirIYWrjUW8I1zbAGpIV2RG\/FGuiKXOI1sbzLC5fjHfEKlqfPwWm+w5S5ThUGmIkK6V0LsWP4J7SQ4hvJtOs084DIJKkyJ1gTb0pWssRyj676\/d9c51nMYEWxlzTfam\/cjtDP418M+j3qwWPwAc0LwlEiSpkRdIO1hnJt5DOGKrhCkigi78naBvqODrgZzaBDxJvFSzQjnEjM0KJcwTSK6lDbOnSFhEQM1iR\/R4oQFIXjIE4CWz9CZS1PV3xgOuLh9Y7yP75VfbCFzNsW1NEOvJTMe3h4sF8CTQRgzRq8d3bf7rtO+wqRNVGZpIXpl7eIZunsxg+j9OtNlE6CZHwbLj6H89h1DmGQtaGMKBjUIyMbqt0wtCopLa962MW2cJ0WYhKdNtNlmOclzhua9g1pDA4kvDcbWV71sI\/ZxaacQuOaxP\/MovbqBdPTi6oNxDc0b8olbK2QKQc2AJZ4p4yxuwjRTWyFFc3qUBOrhhd1FBcF26tys6GPVj1fbylGlW4mGF4RNrSeNJmGQTRJ\/cUiukuW02n4NY38URA18AOBTicZWbucDS6ZHlr9ZgLEAXsOLco1yYlsZusiLlxRsaN7zEpicrwfP\/PFj5ZBGs8PPuc6ojXNKxyDYxwHDDdhkoTx7DTR1RlEfvSXf5c85zF+BGm8yyM6vSKRhkPxtERvVeelMIr+Y4pqZVFb8WASD1zzcfDrVR11ji4edjndwJo7IesC4DCm4nQFX4LbcHq3CILb86s4yHnNYoOTFssYVgo2jea96jZB3ai3J4qLk04EF13fBclph4Bdr+P529Qv4cxPVwxnfx\/sy3NdsEygE6PIH\/8Zhcnn8\/v4Q95RVxzXfQULJnwdCXM7v1H5EXw3iCdpNJ+F8fmLfp729iPmf+sfxP4oCib\/7oFJmLyC7JzwNIajvDrxm7fqVmgvAtfp\/oy871bkwYM=","xmlFileCreated":1543258276},"42":{"desc":"eJxVjcEKwkAMRH9l\/IH2B0qh4MGDBy8iHtM2bANrIptsxb93BS\/eZpg3MyfSNbPj6lww1dhYQxYKMQUlEvUAKc7H6YKG7Fy6YS7ox8GjmKYRNyoqmg64W8WjNn6jnUGBzNScaTP\/w89ckyhYac68wgrerfuSnJHNG94ELQu7I+ybFbgEd0P\/O\/0Aa5NByQ==","element":"ldap","enabled":"0","extension_id":"402","folder":"authentication","name":"Authentication - LDAP","path":"\/plugins\/authentication\/ldap","title":"","type":"plugin","xmlFile":"\/plugins\/authentication\/ldap\/ldap.xml","xmlFileContents":"eJzdV02T4jYQPc\/8CsWn5IBhhmJrUjHeeMDDsGUMhWGTnFwCC6MtIbkkeT7y6yP5C5gBYnPcC0jq1+2np1ZLsr6+7Qh4QVxgRvvGndkxAKJrFmEa941UbloPxlf71kJvElGN2WO75p0B5HuC+kZC0hhTA8ScpUnfgKncIirxGkqFNMAOyS2LVLgk5jBChn17Y1G4Q3ZC4vAYHJIIJlY7syqUNjJuf2NsR+AvYMbZD7SWVrsYV4g1R5njEEpk++wF7VaIg\/tOp2e1j2way5J3juOttAdlC\/w6+C1Dg5b6u3sA0wRRELCUrxGYQCnVbE3gEAIyuAAcCcRfUGSq8FU4FZvgtRII2SN\/CUaIIg4JmKUrNQy83FQqB+4B44AoTvwPIBAC3njg+oFryjc1szJONXl3BzGxYbTD9M8fmQ4m43EpQW6twEtO7NfXV\/MzUFsUrOBgd82O2bHaZVdZIiTWHCdaL3vmjUJv6MzCvydeOHSDwXw8W4ynvtU+RCmnDSZIqEbe0qsG8lzoG3ohDVv\/mslWLWkJ0G7t0s8ikMYpjIsgZQ9IqLIP0dbo0bCzP\/NMqpiYYiVa4XdtEPEuPgXad0SeO3SD42KqiEQC6Mmo1Icc7oRO6cqCZGFbQYHXuamwZc2b3LplQhr5QL6LpNpkxQCBK0T6RrUOT2PXG4bP02ARes6j6xWwg9U4DdZrV2AF\/ld9476Td9v27RlaCePHtGiqt9RFYrPpvD6xDHxAbKez5a7swLe+8aXX6\/aqSBuYEqnKzcPvxdAW06P+CyQ4UtvpA1WVY2qL9Q2FRnE1msvQ+z8VUoGy1PjePdJClS\/MLkrxvVtbCAU9kKGaaOci\/zWBQqjUkrSVVVtQtVrvSNCSXJ50NxbLPg2URCnSKtvf\/nEDq83KHXwC1FEgf3qM0TtWKXRWLopiJrFag1AS0VAx3x1NB2Nn4dYWbu\/x0+jHQo42iKtTo6l8c\/fJnc8dL6gt397jZ5FP1\/Qwv2UcqUewuFxRneXieeIunqfD2uoduJySb4VpdFEEgSBfbw37YzFwvKUbPo79YeA688HzZZGyr5wPsQzceTMF1VGFwog2O48encAd+rWVK+BXnEm5ZqGQXF1Lm3HM1QwW87E\/qs30yOkKvur04KKxnHrVggZ6lvgrCepWc4K+M6lfqCuHa+4hqtC8Mn68oT8MnrmNOEHw13Ref0tXDlfQ1JeEcJMS0lzOp6XnNZKzcjhVeDQHf8+hEX+kXxHNyLsTZ+zVZp6jT9E++HIjyimOGibvuH5CaOwpsvuPfuJ6U9VYdf\/PnglFL3tKlK8Hq109pO3\/ADahTKg=","xmlFileCreated":1543258276},"43":{"desc":"eJw9y9ENgCAQBNFWtgJ7sANaOGEJRL1L4ND2JZr4+zITml01sUNwVN2x0W9S4YWIpk51yPBiDaLpZ4mO6jwniCOKzhGjMyG\/JdbvCc1yPbg8qmwlRw==","element":"contact","enabled":"1","extension_id":"403","folder":"content","name":"Content - Contact","path":"\/plugins\/content\/contact","title":"","type":"plugin","xmlFile":"\/plugins\/content\/contact\/contact.xml","xmlFileContents":"eJydVd9v2jAQfm7\/Cs9P2wOBsk2qtOAuZRGiCj9UqLY9RSYcqTtjR7ZTyn+\/yy+gK6VTHyKffd99Ot935\/hXT2tJHsFYoVWPXngdSkAleilU2qO5W7Uu6RU79+HJgSowe+xnr0uJ22bQo5nMU6EoSY3Osx5NtEK0o2QN7l4vkSdLDV8CZednvuJrYJlM4xpVrjxxfrv0IILnGGXYjdZryT+QqdEPUPjrc0QkBrjDJH5wB+yGq5ybLel2Lr747WeuAqqzrRHpvWP9xiIf+58Q3flKWkXQJZlkoMhM5yYBMuLO4Q09EkhJSrglBiyYR1h6SL+jQ24pEiwKsMH4jgxAgeGSTPMFHpOocjXVIl2iDZGYk\/lGLACJhv1wPAs994QXa3h2dw\/XXEjGl2uhvj+UZfC0SZsKVN4d+M5IttlsvJfAwoOwOgeGgnldv91s0bMEmxiRFfVi02gQ9yfjeTiel2vQn8e\/RlH8I5z1b4fT+XAy9tuHARi\/EhIsGpVV6EeqVqh6AFWlrDa87D7z2w2sCG430b7kKs15WlM1O+I4tiCo1uCasnLxjrSNJ5TACtYx7yGwW\/uCZL+xVROplUjri4JcWlJcAvueG762RVvvPOBq34JbkVSu2leaZ5U3N5JW+2qCpLCuPpB8AbJHj+kxDW6DUXx3G8VRcB1GdcCBKG+FHYi5C17xXLrDjKqcz3xdUpJHLvM646NNsmfHz2\/rpjuOcGxgkWFN3+L5GV5Pg0F4mguKKXiLKRwFw39yKvoOxWDnrygjhfoTOx1zKbh9phE+YUL\/r0hBNAxm75GpCjwhVKc+SCS3FvvMqVb57pKd1dqCVU2mOGX46vSowK5PwZzUuEPZzXhyuu4XiPkdzl4p6t7GSSgHpt6VQ9XMkd\/e\/U\/YXzgDBaw=","xmlFileCreated":1543258276},"44":{"desc":"eJwFwcERgDAIBMBWrgKb8OfXCs6IDiOBTEDrd3e14JOgGaRTDTzPKZmSUEcLL\/HCNaMjB\/sRlXhT\/cbGj3ubOmr5AX4vGbc=","element":"emailcloak","enabled":"1","extension_id":"404","folder":"content","name":"Content - Email Cloaking","path":"\/plugins\/content\/emailcloak","title":"","type":"plugin","xmlFile":"\/plugins\/content\/emailcloak\/emailcloak.xml","xmlFileContents":"eJydVE1v2zAMPbe\/gtNpO9ROWgwoMNtdmhpBVscJ1hbYzVBsxlUnS4YsJ+m\/H\/2VdGi6w06W+B4fyEfK3s2+kLBFUwmtfDZ2RgxQpToTKvdZbTcX1+wmOPdwb1E1nCP3yhkzsK8l+qyUdS4Ug9zouvRZqhWxLYMC7bPOSKfMDc+QBednnuIFBqXMk56VYMGFTKXmvz23BYnEa0o0wQ+tC8k\/wcroF0yt5\/ZxYqQGuaU67rjFINZbLNZo4HI0+uq5f2ENV5evRuTPNpgOJ\/g8\/dKy4YI+42tYlqjgQdcmRVhwa6lLByZSQkuvwGCFZouZQ\/IHOdKWIiVjMJjFTzBDhYZLWNVrCkPUQYNjcAnagKSazDeoECGaT8P4IXTsnjobdA7Nh40tAc8Kob6\/tD442uSDBR16ID8ZGex2O+c9sUGI1tcQXDkjZ+S5w5WQDKvUiLLxK1hFs2S6jB\/D+DEJF5N5NI2Wk\/vk1yJK7sKH6c\/56nG+jD33bQ5JbITEig7dqZkhdBvhs+NwWXA8O+Vz6bkDuZFwBw1PcpXXPO8FhxtYTvuI6mJ2S0LNxzm9Q45Qgtzs0\/5To3qt3ukcL1W3U2oj8r5plFkFTSv0FLjhRdVs+gFB22NrXom0g3qsPZ51aKHphXSB7lVJUdk+IPkapc8+mM9ieRcm0eQ2jHr6m\/n8O6mZ6iFnw2tp6R\/QB2gitKo+E2RPjqaPdtWfebpVhy2XNZU6Yh\/tTryMo3l8P7mNQs\/Vw8qckBh\/KHE6v1kZcrAz2h2cbgfS39qhDXPy3MMvLPgDuSuUMA==","xmlFileCreated":1543258276},"45":{"desc":"eJyFjUEKwkAMRa\/yD1AKbr2DuHDhUuJ0qgNpZmhScJDevVM7BXHjJiGfl\/evwZ5B4KKYF0M5FImnR8k4Uqc4xW5ijxQ1WIiiDS5ZjF5HvFdgzzGpHw8z4lg\/FPcMocH\/PAybr6wbx1Iztzin1UDMGY4EmrwLfUYl1XKZJB36Iv9SUCWD29HSaMH4X2VTg439+Od2AY93Yzs=","element":"loadmodule","enabled":"1","extension_id":"406","folder":"content","name":"Content - Load Modules","path":"\/plugins\/content\/loadmodule","title":"","type":"plugin","xmlFile":"\/plugins\/content\/loadmodule\/loadmodule.xml","xmlFileContents":"eJydVMlu2zAUPKdfwfLUHiI5CQoEqKRUsVXXBb0gttPlItDSs8yAIgWKcux+fanV2aACPemRM2\/wlqGcm0PK0R5UzqRw8YU1wAhEJGMmEhcXent+jW+8dw4cNIiSc+JeWRcY6WMGLs54kTCBUaJkkbk4ksKwNUYp6J2MjU6WKBoD9t6dOYKm4GU8CRtWyCWNUxkXHBy7Ag2JFiZRed+lTDl9jxZKPkCkHbu5N4xIAdWmjhHV4M3kHtINKHQ5GHxy7GdYyZXZUbFkp71hG6EPw48VG52bz8U1mmcg0FIWKgI0pVqbLi3kc44qeo4U5KD2EFtGvpMz2pxFZjDgjWdrNAYBinK0KDbmGpEaaieGLpFUiJua1GeUAyAyGQazZWDpg+ms1emaD1LKuGdGw8SXh2oOllRJO4Ia7chrxb3Hx0frNbFEDK2pwbuyBtbAsdujQWLII8Wycl7egoxDMvdH0\/loTYLw55SEo2A5vJssVpP5zLGfck3qlnHITVBH5e5Q7QQXn5aKvVNsZbvMsVtyKWG3Gg6nIilo0gi2J6Sp8SGI8\/Et9qqP9bZ3LCaYmWKT9p8a+TF\/pXM65LWXxJYlTdPA4xyVrZgnQBVN89LhHQK6wTY0Z1ENNVgVntVoro9mSvVN\/Zw4y3VzwekGuItfLObrJCCjcLn6ZWLi3wakYT\/ZT29OudQuZUsLrl2s6aYroy71zJGVFNpTXkDLeGmSWvfeJ+sgXPm3JHBs2TrkDRFjyT+9Gt\/md5Pf89nKJ\/1Ch51Oea\/SaHK\/7NcwvysRQ9yrMl2T1WRBgn+rCSn6x3Pn\/3iuUNrfuKE2jd26pjJXc6oM2HrOsbvfsPcXQKjTtg==","xmlFileCreated":1543258276},"46":{"desc":"eJy1kkFPwzAMhf+KTxNIsN0ZIHGCSXBi0rRj2nprhBuX2GWUX4+Tjm3sMhDiUkXOy+f3nnpHxBvQGqGM6NRzAF6Bg9atfXCKFbioviSEjdcanF23SeUI1BU2NnXJQTGojK+LCJPb4TsLglETB6Ew9IvYlsjdus7bOslP03EvgaJTNQeBY+OIelhxFyrwIesWy+fZYnkPWHnlCMpMhYtjmNsdcbkzf8S01+Z6n4IICoTKS0uuxx19S3Vi4cU3rWlrjv7DsllW8gG\/xUtLFd\/1AJTRFbZolnmADl0JlDULJh8VNK5P+9HaxJhF6pXwAhwpxlT5wD3zK2gjv\/kKq3MwZzlS6JoCo4zh2MvD\/OnRSk0aL1fDfEQ6rSOU5ERuRq8d61R6UWwuEyu3M0xhMlrr9LePsu+tZP7VeR4eUpP135KtigPuykcZfqS\/ck86\/q\/FJ7g\/a\/ITC9BLIw==","element":"pagebreak","enabled":"1","extension_id":"407","folder":"content","name":"Content - Page Break","path":"\/plugins\/content\/pagebreak","title":"","type":"plugin","xmlFile":"\/plugins\/content\/pagebreak\/pagebreak.xml","xmlFileContents":"eJzdVt9v0zAQfh5\/hckTPDTpQEgI0kDXRaUjtNWaCXiK3OSWGRw7sp1t\/e8559daWAcrb5Mi5Xz33ae7z+c4\/ofbgpNrUJpJMXKO3aFDQKQyYyIfOZW5HLx1PgTPfLg1ICzmDvvaPXaI2ZQwckpe5Uw4JFeyKkdOKgWijUMKMFcyQ54yVzQDJ3h25AtaQFDyPGlRSUlzWCugP32vjiGGVpingjMpC06fk6WSPyA1vtf6EZFigsEyTqmBYC6voViDIq+Gwze+txOzWFluFMuvTDDpLPJi8rJGkwG+jt+SRQmCrGSlUiBfqDHYpEvGnJMarokCDeoaMhfpezrk5ixFXSCYzi\/IFAQoysmyWqObRE2oE4y8IlIRjjWp90QDkGg2Ceer0DW32FnH0zcfFpTxgGYFEx9\/1Dq4UuWdBE20B18oHtzc3Lh\/Am0EYW0NwWt36A59r1tiJAOdKlZavYJlNE0mi3kczuNkOZ6GJ+fh+HPy7UuUnIaryflsGc8Wc9\/bTkGGS8ZBo9FYdgtJMw84F93WOkFvuuVV6Xsd1BJ4HYPPqcgrBDZ03YoYirMIYjA9cYL65d47Py4TDJVssw6j0Bv9B83dQjfjJC5Z3jYMPNPENmKbVbTQOOMY6UJg2uCaapba+e9jtXnURA0zHJzG05woPC5Mth5O18BHzv27s5rFYRLP4ihMovFJGLU5W3v0D5l2e9vElFOtsV4jBvVpJr012IAWsue\/pBU3+MVoHbiHONkjh6GiOajW2zR85Mu6EnJNeQU2JzhbfVp89T3ZTdE9qCGiPs1Ow12UnRZUr1H5HimpMizlkDCRwe1\/SDo+j2eTKJzNT8NvBym7Q\/BUBU4MXgw7Km85HidyjM9\/SGzTt2XWV\/LGpu+U+64V09vbXYGaM\/s5SIxMDxufeDF57MDYlCc0IlZ7yvmBpw+LSsZR9OhD1+U9JSHN5rd7gTP9b8cr\/n7AjVAnbenXC2NPhH5Qhgax5xfCWquHBdKcZfhXso9hFaF453\/hMHS9lyAen6z2iH9n431d70W3rC\/\/7r73vf4nOPgFkDpOOg==","xmlFileCreated":1543258276},"47":{"desc":"eJxzzUtMykktVqjML1UoyVdITElRsEnNtfNLrShRUEvMLbBWCChKLcvMLy220QeKK6SV5iWXZObnJeZkllSCdeQpOBaVZCbnpOoBAATiGvM=","element":"pagenavigation","enabled":"1","extension_id":"408","folder":"content","name":"Content - Page Navigation","path":"\/plugins\/content\/pagenavigation","title":"","type":"plugin","xmlFile":"\/plugins\/content\/pagenavigation\/pagenavigation.xml","xmlFileContents":"eJy9VV1P2zAUfYZf4eVpeyApoE1IS8NCyaqg0EZt6dhTZZLbYOTYke0U+u9381Xo6MbWSXuKr+85x\/a51457\/pRzsgKlmRR969juWQREIlMmsr5VmuXRmXXuHbrwZEBUmGfsqX1sEbMuoG8VvMyYsEimZFn0rUQKRBuL5GDuZYo6RaZoCpZ3eOAKmoNX8GzRohYFzUDQFcuoQV3XqQEIpCWSlXclZc7pOxIr+QCJcZ12HhGJgppzSQ14V1SUVK3JSa\/3yXW2UhVUFmvFsnvjDboReT\/4UKE\/kiP8HJ+RcQGCTGWpEiDX1Bg8qE18zkkN10SBBrWC1Eb5jRxqc5agN+ANRzdkCAIU5SQu73CaRE2qM42cEKkIxz2pz0QDkCgcBKNpYJsnPFinszl7kFPGPZrmTHx5qG2wpco6B5rsBnyjuPf4+Gi\/BlYZhLV78E7tnt1znS7ETAo6Uayo\/PLiaLiI\/WEw8ufh0J+F49Hi9jpaXAbTwSSMq9h1XuKRvmQcNA6aUVU+0jQENsZWbS1vO7aL+8J1OlKjIHkKyjN5wTHTBLiE063hciqyElWaBbuIGIrtCuJoeGF59cf+dYvZTDB0u6X+g45e61daz4Fu+k4sWdaaAzzVpDpqZYyiucYLgZkuBaZN3lHNkuqybHL18KClSs1qN5vJ5gZypk07wekd8L61o5BfwyC6XMTjaViHkX8RRC3pRUn\/hFq1w4a5pCU3+Ha0E1gq7O++xdCzDFQ725zmwJX1GmRFeQkVZ1fDNYvN\/egmWOAWx99cR3bdtkOk96aIfzGeB9siVUuhsU0BdrisAK8pW8G+Lk+CCMN5sIfLG+r\/c9mfzMJBFPyrz7PgdvZ3NqdMF5yu93X5MpzGkf99D5M75i6Pe3t4\/LY5IzQnngTz35v8dq1m4eznSm253Ab4nNTPThvVT1P3GrnO5n\/u\/QBiQW2d","xmlFileCreated":1543258276},"48":{"desc":"eJxzTElRCMsvycxLV0grzUsuyczPS8zJLKlUKMlXcCwqyUzOSS3WAwAE0g3S","element":"vote","enabled":"1","extension_id":"409","folder":"content","name":"Content - Vote","path":"\/plugins\/content\/vote","title":"","type":"plugin","xmlFile":"\/plugins\/content\/vote\/vote.xml","xmlFileContents":"eJyVVMFO4zAQPcNXzPq0eyApoJWQNjFLS1V1VZpqW1Z7q9xkGowcO7KdAn+PnTihLFz2knjmvXnyvJkkuX6uBBxQG65kSs6jEQGUuSq4LFPS2P3ZFbmmpwk+W5Se88a9jM4J2JcaU1KLpuSSQKlVU6ckV9KxLYEK7YMqnE5dalYgoacniWQV0lqU28DaHpTFJG7TDmaNK9H0l1KVYF9gpdUj5jaJQ94xco3MuhvcMot0qQ5Y7VDDxWj0PYnfYZ6r6hfNywdLJ\/0Jvk6+tWw4c6\/zK8hqlLBWjc4R7pi1rr8IboSAlm5Ao0F9wCJy8oOc0xY8d5YgnS3vYYYSNROwanYuDYsO6r2CC1AahLuT\/gEGERbzyXS5nkb22XXW6wzNTyvGBWVFxeXPx9aHSOmyt6BDB\/K9FvTp6Sn6SPSIo4U70MtoFI2SuA8dUqDJNa+9X3S1mG3\/ZJvp9u\/dYns7XU9+z1ebebZM4mOWK9pzgcYdupOfGnTTT4kfJKH+GdUPdRL3hI6tRIGa2qoWDukCJxf3eolgsmxYGcT7CCxze4jybDYmtH1F\/+5OxCV3LoaC\/642L+aDwltgui2Se16GplEUBnxbbu2ZZpXxWz0gaAO2Y4bnHRSw9ngSKpXh3lHSJbuvSHBjQ0KwHYqUDFNZZeu5H8d2cTOeLgLpaDKfUf0UB+aeNcKmxKo6pLqbnSSqrYcDEw12+NsubLJVEqt+9J\/Qd8paVR1VjLPNJrt7X+Rn7NrvXIp7m1o3Q9Q63pucxMO\/hr4ClQV8gA==","xmlFileCreated":1543258276},"49":{"desc":"eJwLycyr9HV2VcgsVkhUKMhJLEnLL8pVyMxLSS1IBRJ5JQrlqUkKSYnFqSkKXollicHJRZkFJQoeIb4+CuGRwZ7hke4KrimZJflFegD0GRor","element":"tinymce","enabled":"1","extension_id":"412","folder":"editors","name":"Editor - TinyMCE","path":"\/plugins\/editors\/tinymce","title":"","type":"plugin","xmlFile":"\/plugins\/editors\/tinymce\/tinymce.xml","xmlFileContents":"eJydVU1v4jAQPbe\/wvK9MaWL1F0FV1BSQAoUFbofp8jEJrHkOJHjFPj368RJCF2kbcsFj9+bmTfjGXAfDokAb0zlPJVDeOv0IGAyTCmX0RAWendzDx\/wtcsOmsmSc+LeOX0I9DFjQ5iJIuISgkilRTaEjHKdqhyChOk4pSZOFilCGcTXV64kCcOZiIKaFWguj0nIXFQhhlFnwN+cgfPdRY1pkFAxos15QjTD\/V5vcNPv3d676Oze8Ehh8irsZXF6AI+pylJV4S6qkZbjJYQLvESjBrIXLf6qBI61zn4gtN\/vnVqrE6ZJ41AySmlpdlQ8ivWlrCfQMAUPTSsZ9qcr30WNZQDK8lDxrHTBK38abObLP8HvhR9MvPXjy3y1mT8vXdRlGacdFyw3B3sqWwjsawxhLRbiRnUWZy5qaNYnFZQpvONM0Nxg1uwiqUo699a9zOcm5v0IMGpM9KrMzrtb\/hBWHNiN1z52J2TFqjpDZFSQqK6nsYAmZhSZvJmOIa6+nAvj43DJTTdrn68EyI\/5P0FORm4fWe54VHe7bBkoO2nmnyiS5FWhDcJ0jW1JzkML1RiozsB+LMkGLuy8wDOC3bBa5LbgZdvOGTGnlEmfbJkwRFWwBkZWEGoU4etLAgl9IzJkFAJhQ7Sz9zT3\/Engj8aeH4wmP0fLR2+yGr2MFuuzeqrjlQ1mwuYBSdJCamjvrX5ZJFuj215dzrN8XYy9l+D5KVh7m7VNWzt0Zv5\/buWu1F5mVHU5hbzV8kYEp+Y34p2epNyWuzbXjhRCtxfIdu1CrbFORBCzcq8\/W+tss\/Bn3nw623y4zo5Lp8ZW7WDQ+5DePac6\/orcX\/PJZvYptdbjkthW6bvxPFnV7jXr5qL27wf\/BQeOBf4=","xmlFileCreated":1543258276},"50":{"desc":"eJxFjNEJwCAMBVd5E7hDwUWsSA0NiZhIcftWSunn3eNeJGucpiFhH+4qcAWJle5gktMWp+6UudgzLBJsrwiIf960jYbErBfJgaljpbmqWoHX8r2EG51LKkQ=","element":"article","enabled":"1","extension_id":"413","folder":"editors-xtd","name":"Button - Article","path":"\/plugins\/editors-xtd\/article","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/article\/article.xml","xmlFileContents":"eJydk8Fu2zAMhs\/rU3A6bYfITosBHSar61wjyOAmQdMCuxmqzToqZEmQ5SZ5+8qJnXYodtlJpPjxB0lR7GrXKHhB10qjEzKlMQHUpamkrhPS+afJJbniZwx3HnXPvLEXdErA7y0mxKqulppA7UxnE4KV9Ma1k52vCDToN6YKWrZ2okLCzz4xLRrkVtXFO7IQzstSIYsO0UCJLmQ6\/tuYRonPsHLmGUvPouE+EKVD4UMxN8IjX5bePKKD8zj+zqK\/Qj1q7N7JeuN5OlrwJf3a099gEo7pJSwtalibzpUIt8L70CmFa6XggLfgsEX3ghUN8ie5oK1kGYaDfLZ4gBlqdELBqnsM15AfQ+PU4ByMAxVqcj+gRYR8nmaLdUb9LjQ26px6zxohFRdVI\/XP58MYqHH1OIFj9AQ\/OMW32y39CPaRgA018Asa05hFoxsiFbalk7afF1\/ls+L67n6e5lnx5zYvbrJ1ejdf3c+XCxa9B0Pek1TYBuNo9e8Gx1VIyPCahA8GtRvLohHrk6Mxmymh607Ug9TogRdhBVFPZr8IPxz0HytDpZZhekPe\/4q0+\/aD0JsTamPR6RfwV61wGVI=","xmlFileCreated":1543258276},"51":{"desc":"eJxFjDEKw0AMBL+yXTr\/IeCPKLZ8CBRJnHQY\/z7npEi5w86skqF0JQivUeWGcogl94K8qXHONREZnr1kU16w\/p3wGAFS9VOs4fJx+5vbIW10vrVv5ZGI7jGrMotkO0ao0w7j8\/fAIcq5fAD+IzTM","element":"image","enabled":"1","extension_id":"414","folder":"editors-xtd","name":"Button - Image","path":"\/plugins\/editors-xtd\/image","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/image\/image.xml","xmlFileContents":"eJydksFu2zAMhs\/rU3A6bYfITrsBBSary1IjyJCkwbICuxmazToqZMmQ5SZ5+9FOnLZoTzuRFD\/+ICmKm31l4Al9o51N2JjHDNDmrtC2TFgbHkbX7EZeCNwHtB3zzF7xMYNwqDFhtWlLbRmU3rV1wrDQwflmtA8FgwrD1hWkVZdeFcjkxQdhVYWyNmX2gsx0pUoUUZ8jRrVU5+VP5yqjPsLau0fMg4hO70TkHlWgVm5VQDlpy7YJcBnHX0T0KtORrj54XW6DnA4efJp+7uivMCIzvoa7Gi1sXOtzhKUKgcbkMDEGerwBjw36Jyw4yZ\/lSNvonDaDcra6hxla9MrAuv1Lz7A4poaVwSU4D4Z68t+gQYTFfJquNikPe5pr0DmPnlZKG6mKStvvj\/0WuPPlsIBj9gzfeyN3ux1\/C3YZwk49yCse81hEQ0iZApvc67rbl1wvZtl8OZml2Z\/lIrtNN9Nf8\/Xv+d1KRC8xqnrQBhtyjl73aXC8goT1H8lkb3i9rUU0IF1hNFQKo2zZEnOUGSIIii4P7Wj2g8ne8HcvhWuraWunqv+TaA7NG5nngPoS0fnw5T+QgxPy","xmlFileCreated":1543258276},"52":{"desc":"eJwtzNEJwzAMhOFVboLskA2yghxfXVMjGUtuyPZ1oG\/HB\/cfw7410yFIM8IUYaBKalzUpRBpUD4PJ6KqcwTzGgtEsY+oZ+OGHd367JDW7HLcNp\/LafqqZQ4i3oQzomrxf2w68\/YDwl8uXg==","element":"pagebreak","enabled":"1","extension_id":"415","folder":"editors-xtd","name":"Button - Page Break","path":"\/plugins\/editors-xtd\/pagebreak","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/pagebreak\/pagebreak.xml","xmlFileContents":"eJydk1Fv2jAQx5\/XT3Hz0\/aAA+0mVVpwRyFCrBQQUKlvkZtcgzvHthynwLffBQjtVO1lT77z\/e6vu\/M5vtmVGl7RV8qaPuvxLgM0mc2VKfqsDs+da3YjLmLcBTQN88Ze8R6DsHfYZ07XhTIMCm9r12eYq2B91dmFnEGJYWNz0nKFlzkycfEpNrJE4XSRviNTJwt88ih\/x9EhTpysKdeLX9aWWn6GhbcvmIU4Ot0TkVFCoHJGMqAY1EVdBbjsdr\/F0V+RhrRu71WxCWLYWvBl+LWhv0OHjt41zB0aWNnaZwj3MgRqlcNAazjgFXis0L9izkn+LEfaWmU0HRTj2QOM0aCXGhb1E13D9BhqxwaXYD1oqsn\/gAoRppNhMlslPOyor1bn3HpSSqWFzEtlfr4cpsCtL9oBHKNn+MFrsd1u+UewiRB2qkFc8S7vxlHrUiTHKvPKNfMSi+k4TUaT9Xy5elyP0sVgnNwuk8Fd+ng\/TUfJaricLNaT+SyO3meRyLPSWJFxtJo3hONi0IK0b8vE2eRu4+KoRRuBqFWItTRFTeBRrvUgSFpKNJ3xLROHg\/9zibgyigZ6yvx\/mWpffZB6c6i+ODr\/DfEH32AglQ==","xmlFileCreated":1543258276},"53":{"desc":"eJwNytEJwCAMBcBV3gR2ASn0owt0g2gDSmMCGindvv4edyol4QFCmu6meEvNBSRi78BnE26oOrg7vDAit\/1iutGsM0IIcVsCqfqsti4pju41C4cf814f\/A==","element":"readmore","enabled":"1","extension_id":"416","folder":"editors-xtd","name":"Button - Readmore","path":"\/plugins\/editors-xtd\/readmore","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/readmore\/readmore.xml","xmlFileContents":"eJydk01v2zAMhs\/rr+B02g6RnRYbCkxW1yVGkCFfSFZgN0OzWUeFLBmy3CT\/vnQSpx2KXXYSKT58QVKUuNtXBp7RN9rZhA15zABt7gpty4S14XFwy+7klcB9QNsxr+wNHzIIhxoTVpu21JZB6V1bJwwLHZxvBvtQMKgwbF1BWnXpVYFMXn0QVlUoa1Nmb8jMoyoq51FExzBhqqVUL386Vxn1EVbePWEeRHS+JyKnpEDVjFVAOVc+38J1HH8V0V+BDnT1wetyG+Sot+DT6HNHf4EBHcNbWNZoYeNanyPMVQjUKId7Y+CIN+CxQf+MBSf5ixxpG53TbFBOFg8wQYteGVi1f+gaZqdQPzS4BufBUE3+GzSIMJuO0sUm5WFPbfU6l87TSmkjaSrafn86DoE7X\/b9n6IX+MEbudvt+HuwixB2rkHe8JjHIupdihTY5F7X3bzkajbJ1un9eL5cp9nv+Swbp5vRerr6NV0uRPSWpMRHbbAh42R1zwanVUhY\/5pM9havt7WIerBLj\/p8YZQtW1WexXoPgqIlRDuY\/GDyePB\/LQ3XVtMEz4n\/rdIcmndKrw5VJ6LLT5Av4poazg==","xmlFileCreated":1543258276},"54":{"desc":"eJxzzUtMykktVihOTSxKzsjMS1fIT1NwTixJTc8vqlTIzEvLL8pNLMnMz9MDAFEaD9Y=","element":"categories","enabled":"1","extension_id":"417","folder":"search","name":"Search - Categories","path":"\/plugins\/search\/categories","title":"","type":"plugin","xmlFile":"\/plugins\/search\/categories\/categories.xml","xmlFileContents":"eJzVVU1T2zAQPcOvUHVqD7ETGGaYqW0aEjc1Y5IMgU578ijOxhEjSx7JDqS\/vuvPhELLwK0Xa6V9u9F7u6s4F4+pIFvQhivp0oHVpwRkrFZcJi4t8nXvnF54xw485iBLzB57ag0oyXcZuDQTRcIlJYlWReZSA0zHG0pSyDdqhWmyRLMVUO\/4yJEsBS8TSVSDopjlkCjNwTh25UMMKzBOe1dKpYJ9IHOt7iHOHbs5R0SsgeV4izFGe1O1hXQJmpz0+2eO\/cRXYlW20zzZ5N6otcjH0acKTXq4DM7JLANJFqrQMZBrlufI0SJDIUgFN0SDAb2FlYXpu3SYW\/AYZQFvMr0jE5CgmSDzYonHJKxdrV7khChNBN5JfyYGgITByJ8ufCt\/RGZtno68nzIuPLZKufxyX+lgKZ20EtTeDnynhffw8GA9B5YehDV38E6tvtV37HaLnhWYWPOs1Mubh5No4Q9vRt+i0fDWn8xuAn8R\/bgOo7G\/GN0E89tgNnXswxDMsOYCDBq1VZaQ1O3g0n1tqbe3rWyTOXYLLlPYbQ5HMJkULGkStjuSM2xGkL3JJfWqxXqxgywuOWrZRL0vhdk9T7PfmLqh5JonDWUQK0NKIjgFTLMUqR6jp3VB3jiXzPC4nIDOV5lHtbe5h+Apz2ntqCdLFmVnN0eCLUG49Opr4Ifj6KBc9RIG18FtFA4v\/bAJOCjVa2FlibuoNStE7tKzfnOC9cG+dSmXqFN3HcN\/4Q3P6p1d0\/47N1QNn5Cn7PBV4Oo1csMwfAupEn5AJhbMGJQ\/l73qdSKd1duBkepPzv+mXNfvyFHVz5MtEwXSGFDv6qe\/cGzVTsULoD6CprOnmLLzUa3XpCs\/HF+fd2iHn+C7P36TgG3Mf6fi3sa5q0Rtt9UQt3Pr2N2\/mfcb8wkgPg==","xmlFileCreated":1543258276},"55":{"desc":"eJxzzUtMykktVihOTSxKzsjMS1fIT1MoyUhVcM7PK0lMLgHSuQX5eal5JXoAXAQP0g==","element":"contacts","enabled":"1","extension_id":"418","folder":"search","name":"Search - Contacts","path":"\/plugins\/search\/contacts","title":"","type":"plugin","xmlFile":"\/plugins\/search\/contacts\/contacts.xml","xmlFileContents":"eJzVVd9P2zAQfoa\/wvPT9tAkBSEhLTErbdYVhbaiZdqeIje9pkaOHdlOofvr5\/ykDASCt73EZ993V3\/f3bn+xUPG0Q6UZlIEuO94GIFI5JqJNMCF2fTO8QU59uHBgCgxj9hTp4+R2ecQ4JwXKRMYpUoWeYA1UJVsMcrAbOXapslTRdeAyfGRL2gGJOdpXIPiRApDE6N9t\/JYBC1slCJXUmacfkJzJe8gMb7bnFtEooAae4cRNUCmcgfZChQ68bwz333iK7Ey3yuWbg0Zthb6PPxSoVHPLv1zNMtBoIUsVALomhpjGTpowDmq4Bop0KB2sHZs+i6dzc1ZYkUBMp7eojEIUJSjebGyxyiqXa1a6ARJhbi9k\/qKNACKJsNwuggd82CZtXk68mFGGSd0nTHx7a7SwZEqbSWovR34VnFyf3\/vPAeWHgtr7kBOHc\/xfLfdWs8adKJYXupF5tE4XoSDm+GPeDibLgfD5SL+dR3Fo3AxvJnMl5PZ1HcPA2z8hnHQ1qitsoCoboUAt3XFpLWcfJv7bgssw9023udUpAVNm2TtDhlqmxBEb3yJSbU4L3SOwwSzGjYxH0mg98+TPG503UZiw9KGKvC1RiUJ2\/lU0UyXnd15wDS+FdUsqV2NrzKPam9zCc4yZnDtqIdJFGU7N0ecroAH+Or7JIxG8UGN6iWaXE+WcTS4DKMm4KBCb4WVle2iNrTgJsBnXnNiS2ObNcBMGEi762j2x97wrN655Ph1bqXAIJ6ysw8Bk2+RG0TRe0iV8AMyCadaW\/mN6FUPEuqs3h60kP9yfp1yXb8jX1Y\/j3aUF5ZGH5Or3+HCd2U7DC+APAuazp5iyqa3ar0lXflh9sn5gHb2M\/kZjt4lYBvz36n4aNu5q8az2VUj3E6t73b\/X+QvkMcbwA==","xmlFileCreated":1543258276},"56":{"desc":"eJxzzUtMykktVihOTSxKzsjMS1fIzFNwLCrJTAaK6gEArLMLCw==","element":"content","enabled":"1","extension_id":"419","folder":"search","name":"Search - Content","path":"\/plugins\/search\/content","title":"","type":"plugin","xmlFile":"\/plugins\/search\/content\/content.xml","xmlFileContents":"eJzVVU1PGzEQPcOvcH1qD9lNQEhI3ZhCsqVBSxKRULWnyNlMNkZee2V7A+mv7+wnoSBKufWSnfF7M5p5M3aCs4dUki0YK7Tq057XpQRUrFdCJX2au3XnlJ6xwwAeHKiC88g99nqUuF0GfZrJPBGKksToPOtTC9zEG0pScBu9wjRZYvgKKDs8CBRPgWUyWVSkRawVZnaBXwJI4DkGGXaldSr5BzI1+g5ixOtzZMQGuMMShtwBG+stpEsw5KjbPQn8J1jB1dnOiGTj2KCxyMfBp5JNOvjpnZJJBorMdG5iINfcOWzQI+dSkpJuiQELZgsrD9O36TC3FDFqAuxyfEsuQYHhkkzzJR6TqIIascgR0YZIrMl8JhaARKNBOJ6FnnvAzpo8bfNhyoVkfJUK9eWu1MHTJmkkqNCWfGsku7+\/954TCwRpdQ3s2Ot63cBvXERWYGMjskIvNo0uF7Pw\/GbwbTGYjOfheL74cR0thuFscDOazkeTceDv8zF8LSRYNCqrmB+pFqFP66lSVhtetskCv6EVwX4THUiukpwndarGI47jAoLqXF5QVn6851vjCSVQvzrkHfF2Z5\/leHRstUFqLZK6TZArS4oWcOe54aktdrpFwNXYklsRV1CNleZBhdY1SJEKRyugukYqLza5PpJ8CbJPX5jL11EYDevDaHQ9mi+i84swquP2hvTG6GLGbfCa59L16Um3PsEx4db2qUDBkrY4K35hvSeV57PD1ztttmG\/V3wQhH5jq43372023l6LseTW4oic6pTPFWmtzg6s0n8q0XtViGrGB4EuKyFbLnMoYtjVz3AW+Lq5LC+QukgaT55yimuBGv5N0OJH4Iv0bkWLo9H3cPgOSdvQ\/07TRxtvailx45a3vrnogd\/+2bHfbPspOA==","xmlFileCreated":1543258276},"57":{"desc":"eJxzzUtMykktVihOTSxKzsjMS1fIT1PwSy0vVkhLTU0p1gMAwrILlg==","element":"newsfeeds","enabled":"1","extension_id":"420","folder":"search","name":"Search - News Feeds","path":"\/plugins\/search\/newsfeeds","title":"","type":"plugin","xmlFile":"\/plugins\/search\/newsfeeds\/newsfeeds.xml","xmlFileContents":"eJzFVU1z2jAQPSe\/QtWpPWBDOpnJTG2nBExKxgEmJP04eYRZjDKy7JFkCP31XX+GNGmY5NKLtdK+Xfa9XQnn\/CERZANK81S6tGd1KQEZpUsuY5fmZtU5o+fesQMPBmSBecR+tnqUmF0GLs1EHnNJSazSPHOpBqaiNSUJmHW6xDRZrNgSqHd85EiWgJeJOKxAoYStXgEstWOXLoSwHMOUd5WmiWAfyEyl9xAZx67PEREpYAaLGDID3iTdQLIARU663VPHfuIrsGm2UzxeG2\/QWOTj4FOJJh1cemdkmoEk8zRXEZBrZgxStEhfCFLCNVGgQW1gaWH6Nh3mFjxCVcC7nNyRS5CgmCCzfIHHJKhcjVzkhKSKCKxJfSEagATjgT+Z+5Z5QGZNnpa8nzAuPLZMuPx6X+pgpSpuJKi8LfhOCW+73VrPgYUHYXUN3mera3Udu9miZwk6Ujwr9PJmwWU49\/s3g2\/hxP8xH\/n+cB7+vA7CoT8f3Ixnt+PpxLH3IzDBigvQaFRW0UFSDYNL285SrzWtbJ05dgMtEthNBkcwGecsrtM1O2IYDiLIzuUF9crFeml6LC456lgHvSuD3j3P8rjR1SzJFY9ruiCWmhQ0cP6ZYoku5rv1gKl9C6Z5VLlqX2keVd66CsETbmjlqK6UzIuZro8EW4Bw6dVo7AfDcK9R1RKMr8e3YdC\/8IM6YK9Lh8KK7rZRK5YL49LTbn2CzcGJdSmXBuK2HM1\/Y4Wn1c72jl\/nhqLh2\/GUHT4HPD1Erh8EbyFVwPfIRIJpjfIb2SmfJdJanR1omf7N+XXKVf+OnLT8ebJhIkcaPepd\/fLnjp02F+IFUBdBk+lTTDH2qNYh6YoPx3fnHdrhZ\/zdH75JwCbmP6hYPC2HRJyORv9Q8dHGe1dez3pXXuHm1jp2+y\/m\/QGyfB3o","xmlFileCreated":1543258276},"58":{"desc":"eJxNjjEOwkAMBL+y9CgNErwACahS3AdMYhKLyznYjkJ+z0FFvbuzk0aGbx48oT20mDVLt2HOyyAFlLOujpvqlGmHUDiXHoRu8dBJnHt4mJQB+vjfBw2OCohKv6TUYmTq2RqkUWrgMH4tYnX+UPu1nN1Fi39PVrUntKBjC6qUu1ULNt9DGNcSbIUD5\/ec1dhwBFWpU\/MB1adH\/w==","element":"p3p","enabled":"0","extension_id":"423","folder":"system","name":"System - P3P Policy","path":"\/plugins\/system\/p3p","title":"","type":"plugin","xmlFile":"\/plugins\/system\/p3p\/p3p.xml","xmlFileContents":"eJyVVEtv2zAMPq+\/gtNpO9ROGwwrMEddmhhZhjyMpC12CxSbcVTIsiDJfezXj36lLXraxSb5faTJT5Sj6+dCwSNaJ0s9YhfBgAHqtMykzkes8ofzK3bNzyJ89qhrzit3GFww8C8GR8yoKpeaQW7LyoyYe3EeCwYF+mOZURmTW5Eh42efIi0K5Eblu5a0M0MThU2QQFFRguW\/y7JQ4jMktnzA1EdhFydGalF4+vxUeORbNFRijxYuBxeDKHwH1uTSvFiZHz2f9BZ8mXwl9uAbnNdJV7A2qGFbVjZFWArvaboAxkpBQ3dg0aF9xCyg8qdyVFvJlARBPlvdwQw1WqEgqfYUhkUL9UrBJZQWFPVkf4BDhMV8Eq+2ceCfabS+zmn6uBBScZEVUv98aIQISpv3GrToiXxnFX96ego+EmuEaF0PfBgMAlKodwnJ0KVWmlovnixmu2SY7P4sF7tpvJ1s5sntfL2KwrckyjlIhY6M1qpPDdqjpxUYGsbpEZgjHWgP10lhnxUpofNK5F2J3gMvaNVQn89uGG9ewfv9CKSWJFRH\/89cMj\/kvzquXRN9kHk3FqrMQd06jSSsKFy9tScEfYfthZNpC3VYY35q0SPSulvWhtor4ukGdQEl9qhGrBf9VzyexpvdYnwTLzrGG9k\/8N6cz4l9EJXyI7Zaz2E8XcI0vodkO5YwWS9hNb6H9d0G1rebEra3CcxXU2Isu2Qn\/1J3w++tG7bDhv20jSid1wjXaxWFpz8C\/wdtVVpI","xmlFileCreated":1543258276},"59":{"desc":"eJwli9sNgDAMxFa5CZiGBSJIaaT0oSQUdXuK+DpZ9u1ZHF3vSyq6tSEnOwiDTDgmWoJPDy6QmpoVCmkV5HhY9dvM2rEMIjMO4z9YtzCqrj8mUfbtBXIwJ+A=","element":"debug","enabled":"1","extension_id":"425","folder":"system","name":"System - Debug","path":"\/plugins\/system\/debug","title":"","type":"plugin","xmlFile":"\/plugins\/system\/debug\/debug.xml","xmlFileContents":"eJzdWVtzmzgUfk5+hZan3Qdf0m47nVlM17UV6g4xLtjb5IlR7GNCRyAqIIn31+8RF4c4iTHpzM7UT0g6F+t856IjWf94H3JyCzIJRDTQzrp9jUC0FKsg8gdalq47H7SPxqkO9ylEiueB9233TCPpJoaBFvPMDyKN+FJk8UBLNkkKoUZCSG\/ECtXEvmQr0IzTEz1iIRgx972CyVvBdebrvXwZySxDEWl8ESLk7Dcyk+I7LFO9V64jx1ICS3EDY5aCMYYlhNcgyZt+\/73ee0RTvCLeyMC\/SY1RNSK\/j\/5Q3O9IBz9nH4gdQ0RckcklkAuWpmhelww5Jzl7QiQkIG9h1UX1W3WomwdLRAQMc7ogJkQgGSez7BqXiVWQKqjIGyIk4bgn+RdJAIg1GdGpS7vpPVpW6dkaT0MWcIOtwiD6+3uOQ1dIv4KgoG6ZF5Ibd3d33aeMioJs5R6Mt91+t6\/3qilSVpAsZRArvIyZZXpj+mlhepcXFo7ckTOZzSf2VO\/V2VBqHXBIcFCMlNtI4f2BlrtSM\/JPN76J9V7FogR7laTOWeRnzC\/VVDOSMow4iDrmJ83IP93dMOkGUYCAlQKtpXHyRMPDJCkCJloHfmke8FVC1PYxwJlkYaICeEuBtKRdsyRYFqSSlg9PCipajX738sxItIJSJE2GcZUv8yBJSwpn18AH2oM7zifUGntDy7K\/0bFnOvZi5nrW8BO1SomaexrllF9LsTDjaRBz3EYqMygXi70OtCBKPSYl25TrSfAvMp71i2nPOH3B1gQSFVyPrMTED8R+61zquhhqh5tVCdTsWXKWJOiLNOrkmJLtqLOBJBJbtWuGlqMxT00GH2S5WjjzRBf5Bsgt45kCQDO+XFFX74kqG55h6iPT1H7Mo2IfoXoRt1gKlRxtcZs59vnEmkzNw5F7EDkW7H5kIANI2mL3dUGdCW2RSpXAMeG28RRer8LuyptfzdriVwkdC4YhhEJu2sJ3QS9shOJg5Er+YwGNC791xFm22SLUcu4jgsuLZSBkkO6Wuea+AZHAkj+xncm8VbHbkWvqG7bIMc73oqToRsOPYc+yH0UIsW\/CO8qmURW9oI5Jp6Or\/QoZB5kesC\/qzPcrWionLVmzjSP1HQ2bDJVSyGYjHcd29iu6YzLC+1yjqm9DZ4q9wX5lkUAboVHX1EYL6X5VQbQWjYom03N7v5ry3tEYxEhqn3tLvLb54kmLkeKFuDn3RsM5Ne12jcaOXC33ijb8fWMbXtv2xgvFqnVjWdvClXdhj+mrdl+K1gzY1on+3grbVK9rcwnqQgurvVWn\/3xsPN7mZDqyFuOGgD07RBO9fEZTU6hJWEtIbjy0HNLW56NDzx3qfvaGrkvnLWJtR+6XOzMfxohage32dn5aS4jyil\/s5gmG1nBqLoYmLUBBJOoAvpxlpVIvL9P540brPKt+OK\/heDFrVSeeEf7lHNiE7c\/B+lpEjxTMJJXYBbweTnfutHps2BU8FkAVjnFnHcht+334UxciMcOx485bPHfVhI4LwxiPveD+SWPFJLBDcJzh+TW5bAtkKVVHUnAE8m3VlUhxh9M\/G187cxOSbP0zJriL81eYUEodbsLJgQel8H11UXjhnLRNU+Xx88fkC8VH+J0VoJ9VQ7pqXXpsNUeHqQ5r3K4Lrcn9RNLs71T\/\/7eAjmp4N+nN1kvtwKT\/UOdq\/rldGX8sd1Rg3sMyw7jsJD94WzjpJR0tMLrcr9bhWNaFfjkgd4rIwyz\/H63660zvbf8rNv4DY62P+g==","xmlFileCreated":1543258276},"60":{"desc":"eJwlysENAjEMBMBWtoLrgQcIJHhBA1ZsHRHBDvHmQfdE4j1zUE3cjyfk7D0GwUCr\/kpUB58GjTLf5txwIaLbEFpC67DC9kX81\/lxu0JcV1\/qQQz7zJUgyG6lSgNl336ZnidM","element":"sef","enabled":"1","extension_id":"429","folder":"system","name":"System - SEF","path":"\/plugins\/system\/sef","title":"","type":"plugin","xmlFile":"\/plugins\/system\/sef\/sef.xml","xmlFileContents":"eJyVVE1v2zAMPbe\/gtNpO1ROWwwrNkddmmRBijQNlhXYLVBsxlEhS4YkN8m\/H\/2VpshpF4vke6TFR9rx\/T7X8IbOK2v67Jr3GKBJbKpM1mdl2FzdsXtxGeM+oKk479xbfs0gHArss0KXmTIMMmfLos\/8wQfMGeQYtjalMkXmZIpMXF7ERuYoCp2tGtLK4yaO6iCBsqQEJx6tzbX8BAtnXzEJcdTGiZE4lIFeP5IBxQgTzNfo4KbX+xZHH7CKa4uDU9k2iGFnwefhl4r9Fa7ouL6D5wINLG3pEoQnGQI1x2GgNdR0Dw49ujdMOZU\/lqPaWiWkB4rJ\/AUmaNBJDYtyTWGYNVAnFNyAdaDpTu4HeESYTYfj+XLMw5466+ocmx\/nUmkh01yZn6+1Dty6rJOgQY\/kF6fFbrfj58QKIVp7B3HLe7wXR51LSIo+caqo9BKL2WS1HP9a\/X2arUbj5fD3dPFn+jyPo1MS5WyURk9GY1VDg2byNHLcMEEPXmyLOOrgKinqsmItTVbKrC3ReRAkbRqaq8kDE\/XBP64HV0aRUC39P3PJPMt\/d3yzJmajsrYt1KmH6uq01NLJ3FdLe0QwtNhaepU0UIvV5kWDppbGZFgTar6Q0unW13KNus86zUfPT4PpfDUbPIxnLeNE9TPeyXha9laZ0GfbEAr\/PYqqbcC9zAuNPLF5y6ER0Pqd3uJNapXSTp7EoqbTqGu1VqT1atU6oeLo+DcQ\/wA5+l0V","xmlFileCreated":1543258276},"61":{"desc":"eJwVydEJgFAIBdBV7gTN0goiFoIp+K5E21d\/B84ec3qCBRnWJXSViAfaJjRoJUUJz6P630p8QtqNWdZrewE2bxjD","element":"contactcreator","enabled":"0","extension_id":"431","folder":"user","name":"User - Contact Creator","path":"\/plugins\/user\/contactcreator","title":"","type":"plugin","xmlFile":"\/plugins\/user\/contactcreator\/contactcreator.xml","xmlFileContents":"eJydVE1z2jAQPZNfoerUHrBN2s6kU+PUOC4l4wDDx7Q5eYQRRhkheSQ5hP76rj8DTdJOcrJ239v1Pu2u3MuHHUf3VGkmRR\/3LAcjKhK5ZiLt49xsuhf40jtz6YOhouA8cj9aPYzMIaN9nPE8ZQKjVMk8gzBNFUY7arZyDVaWKrKm2DvruILsqJfxNC4ocSKFIYlJFCVGKtcuUWCRHCKVdy3ljpN3aKrkHU2Ma9d+YJQhUMUVMdTz8zTXBp07zhfXPkEKpswOiqVb470PPhScz6gLn94FmmRUoLnMVULRDTEGdFnI5xyVdI0UhRrv6dqCpG0SyMhZAldBveF4iYZUUEU4muYrcKOogpo7QudIKsShEvUVaUpRNArC8Ty0zAOoafK0gsMdYdwj6x0T3+5K7ZZUaSO7QlvyUnFvv99bT4kFArS6Bu+j5ViOazcmIGuqE8Wy4pa8aTSMg8l44QeLYBb6i8ks\/nUTxVfhPJiNpovRZOzax3wI3zBONRyqU9EzVPW\/j08bir1T28q2mWs3QUUqu8nlciLSnKR14sZChsAUUtEdDrBXfqwXhsdigsGV1nFvTaIP+kmiR0NX8yQ2LK3lU77WqBADK0AU2eliyFuEmhpbEc2SCqqx8tipUOia3NNVBn\/Alb9aKgM7Vzs4WVHex8806\/sojK5if7mY3PiLURD\/DAdTfxjGkT8Iozr6qH+vylEMQZ1Cs99Q0SenMm3v7AUtCcx6KtXhRMhfzlrMdeAvwuFkdvuqKpug4+Lat6kYwF3T0xqECYP162MmoAh4lv4joGhGViyz3p5ogBeMyVd0Y7ocRKP5jzf2oYk+EplwojWMkhHd8pVF7al7oFrI9h8bknPTx86\/9HeqWey4sqwG3ROeg8ge9q5vw7lry2bZnyE5QBpPTjnFIsNFVsNvN9NfLkltlYvU7I5rty3z\/gByyQAc","xmlFileCreated":1543258276},"62":{"desc":"eJwtTjsOwjAMvcpjYqMXqDojdoQY3dYkkRwHxQ6otycFtqf3P5OuwoZLKVnoaFj5QU0cV+MK23SJtWgy8lT0NM4VwzSady5MN6qaNBxwLw25mSPSi8FKs\/AKcghTZ4syntJCUnik3fXb9Mho3xk26\/XIpBQ4s\/ZMxdZb30kEUoxBHdCydCe87FqPJefTOPzffABWTkn4","element":"joomla","enabled":"1","extension_id":"432","folder":"user","name":"User - Joomla!","path":"\/plugins\/user\/joomla","title":"","type":"plugin","xmlFile":"\/plugins\/user\/joomla\/joomla.xml","xmlFileContents":"eJzVVU1v2zAMPbe\/QvNpO8ROO2woMEddmrhBCicO8gFsJ0NxGFeFLBmS3Db\/fvRn03YD1p62kyW+R4p8pGT\/8jET5B604UoOnDO37xCQidpxmQ6cwu57F84lPfXh0YIsOU\/cz+6ZQ+whh4GTiyLl0iGpVkWObga0QzKwt2qHuzzVbAcOPT3xJcuA5iKNS0p8p1QmmO9VVkRZgR6a3lTmD2Sh1R0k1vcaOzISDczi6WNmgY4hgWwLmpz3+1997xlWclV+0Dy9tfTj6FPJ+UJ6+Dm7IFEOkqxUoRMgM2YtVuSSoRCkohuiAbO7h52LQbsgGFHwBEUAOplvyAQkaCbIotiimYQ11KpDzonSRGAm+hsxACScjoL5KnDtI9bTxulKDjLGBWW7jMvvtSiu0mlbeI125I0W9OHhwX1NLBGkNTnQz27f7fteu0VkBybRPC9VootwEm9WwTK+iaJZOIx\/zMJ4HKxGy+liPY3mvndMRt89F2BwUa\/KlpG67QOnzsShTUb5be57Lal09VpfXzCZFixtArU7YhkOG8je5Mqh1cd9MSMulxx1a\/hvdTYH8yrA08bUwyL3PG3KA7EzpEweJ5tplplydjsEbINtmeFJDTVYtTypUWyJ0pBygzPg1EB9WfAycNVYBNuCGDgve3E9DcJxPNyso2Uwma7WiITDqyBsvI4681e+ZVsb10QwYzB1K3vVZSXdqncAI1V3wp4VwuKD0BjqKk98VZ1K7pkooETpzc9g5XuqHZPfkPpImkfPOeVIoF709A\/ilRMfW1V18X3izYbTcB1V9jdKd+T5\/wm3V\/iohSpVhX2fbtfRchSE0STarN8q3LHrP6zc0xqvcnXjm131KrQPge91vzz6C0UqKzQ=","xmlFileCreated":1543258276},"63":{"desc":"eJwLLU4tUggoyk\/LzElVCMgpTc\/MAwBGIAcg","element":"profile","enabled":"0","extension_id":"433","folder":"user","name":"User - Profile","path":"\/plugins\/user\/profile","title":"","type":"plugin","xmlFile":"\/plugins\/user\/profile\/profile.xml","xmlFileContents":"eJztmltzozYUx5+dT6HlqX0I2N7pTGaK2doxSZ0S4zV2L0+MDDJmKxCVRC7fvoebY5JsdyFb74N5QtI5f3H00xHGZ9A\/PEQU3REuQhaPlIHaVxCJPeaHcTBSUrk9v1A+GGc6eZAkznyefN+rAwXJx4SMlISmQRgrKOAsTUAmCFdQROSO+dBLAo59ohhnPT3GETESGriZi5twtg0p0bV8GMw4BQk3bhiLKH6HFpx9Ip7UtXIcPDxOsITbT7Ekxg2OU8wf0bDfv9C1milzZckjD4OdNH64\/DHz+Qmdw2VwgeyExMhhKfcIusVSwopUNKYU5e4CcQLR3RFfhUn3k8CMNPQAAjGu52t0TWLCMUWLdAPDyCpMFR00RIwjCpHwn5EgBFmzS3PumKp8gOVU8+xXbEY4pAb2ozD+5VO+eJXxoFp3Yd07rzk17u\/v1ZeOmQXcyhiM92pf7eta1QWLT4THwySjZCysa3ftmEt3sbSvZpbp\/nlruVPTuVzOFquZPde1Q28QZ1sloFG0si1Dxb7D\/hcbqRhlQ012ia5VboWGUZ\/wykGAtRg4sG1DQv0DQzGDyMnjOEhxUN6\/6iGJIUlJfH49UYz8oj7PLTWMQwBeChqrxaN4McNTRxRpFm\/DoOQCCxAoWzMwwRxHIsv6vYXI0rbBIvQUhH0\/NyRY7kaKlu9\/KCTHknHIvChhMYmlyJou3AZOoNQi5hMqtGLCYvZy+rzZK27ASQATEX7OyT9pyMl5fiQLj+LIigR7+yGKN4SOlBcpcTUzrak7H9+a7tK8njkrsC3Nj+vZ0swdS7lHsRAjRcJDohjRjLOvDMwFBnDcxKAWHAWfrwptPJ0uTccZuNZ4Ylql5CBvvyzMMn6v2+KUSngKlgOQAhDqSAkBfbCHVTDv6Sy\/A7rDNIWQh4pxY+cHpyI01TVWHZ5XBIMnQXEZW\/8t6INgOnPGE+v51HqRDo2hD98EfdgW+vA0oXuhfGwH\/HK2+qsx7Fx0kqCzARa3Q5095iDmprBL2Uni9lgaS942te31fLVskd2l7iSJJ0xITAE8vFW3or6wndXYAohTszH5Q+1p0t\/Ba1lL7r\/a8xbEc9VJsr4nGxHKlrT\/MCeuM1s1B74XniTzLb5jHKBvGPu7Hfir8e\/2MuM3se3fGtOvq09yC\/CGpTJqmfbjib1eubfN034vfCvzXlPmvabMe9+euWSiHe+V7TRGnWleo9w\/BuW3Q8tguZjL0KP1JI2YDy8mdcuX6Y2Xq9ml1TxhD7UHNAWhxAOYkqdVDDG5r\/WJH9YdIFzMayOvbkGDwobPNu3yaWpPGpPINKdwaouqVb1YVKtk7Wqb+PntKgt8364+Vg29rTz2LKyuOnaEX9\/PMO+KY0dk3tXGjsO5K40dNau7ythxgXeFse8Jv6uLHQt1VxY7OvKuKva9d6Ariv3vf6+fI+9qGG+B\/NQWROYfCJW9\/COi6rshXdt\/W2f8Cw5WKEY=","xmlFileCreated":1543258276},"64":{"desc":"eJwNzFENwzAMBUAqD0EJ7L8IRiBL3hJLqV3ZrtqxXw7AvYcEznl1UTRjoJZkN\/\/hdKuMEO34mqOaE3ySGmIaLwS1BYqCR5GJe1ChvFE8pU5ivXF9Dslkw9pzELubrqFtf3W+LDA=","element":"joomla","enabled":"1","extension_id":"435","folder":"content","name":"Content - Joomla","path":"\/plugins\/content\/joomla","title":"","type":"plugin","xmlFile":"\/plugins\/content\/joomla\/joomla.xml","xmlFileContents":"eJzVVU1z2jAQPYdfofrUHrBJOp3JTI1S4jiU1BgmkGl78gizGKWy5JFkCP++6y9CJrk0t55Y7Xu77L7dBf\/qKRdkB9pwJYfOuTtwCMhUrbnMhk5pN\/1L54r2fHiyICvOM\/eze+4Qeyhg6BSizLh0SKZVWQydVElkW4fkYLdqjXmKTLM1OLR35kuWAy1ElrSs5FGpXDDfqwEksBKDNL2r3R\/IXKtHSK3vtX5kpBqYxRpumAUaqx3kK9DkYnA+8L0XWMVVxUHzbGtp0FnkY\/AJ2YMvpF8FXZJZAZIsVKlTIFNmLXbokpEQpKYbosGA3sHaxfTHdJhb8BRFATqOH8gYJGgmyLxcoZtEDdSpRS6I0kRgTforMQAkmgRhvAhd+4SddXmOzYc544Kydc7lt0YeV+msk6BBj+QHLeh+v3dfEysEaW0N9LM7cFGh7onIGkyqeVHpRefROAlm8TKMl8ndbDaNRsmvaZTchIvgfjJfTmax753yMXzDBRg0GquaH2k2Yeg0xTi0LarYFr7XkapQr4v1BZNZybI2UfciluH+geyPrx1af7ivd8blkqN6bcg74s3BvMrx\/DDN\/sgNz9omQawNqVrAlWea5aba6CMCtsVWzPC0gVqsNs8aNN1C+idJcRcypTkYpwGbS8Iz4ar1CLYCMXTeGMztJIxukuB7GPxIgtEyHM\/uJ+EiiUbXYdQGn4zqX1JU424zpIIZg81Y2a\/vmhyt\/gGMVMcv2rBSWPztaB04WVzzocNR6gx0623UOPNVXRLZMVFCFUPvfocL31PdUr1BGiApnr3kVAuEutLeicjkVGWojiSRsE828G6Fw+loEiVx+DO5Dd+h7ovw\/07ZZxs3uz6A9lUfSXcXPd87\/jfQv5FH80k=","xmlFileCreated":1543258276},"65":{"desc":"eJwtjrFuwzAMRH+FSHcLQbfC9RYgQ4MEjYHMtEVbBGRRkOgo+fsqbrbjHe7xLknubCmDOgIc2LM+QQVGh2GmzfVVrViPUSwBh82cKVBCJQvH\/vQDVsZ1oaCvKi+xQgmuh3PTDglM19fCxORthsLeA8ZImKA4+odFv86Vyxko4OArFIOFjHeyb8JJ0uv1JGlBZQmACi2CSzR975xqzF\/GlFKa8tlImk3\/ax5OF783H3XaKGHadbctag12zR85pVXP","element":"languagecode","enabled":"0","extension_id":"436","folder":"system","name":"System - Language Code","path":"\/plugins\/system\/languagecode","title":"","type":"plugin","xmlFile":"\/plugins\/system\/languagecode\/languagecode.xml","xmlFileContents":"eJytU01v2zAMPbe\/gtNpO8ROWgwoMFtdlhhGhnxhaYDtZKg246iQJUOW8\/HvK1t2kqHYbReD5Ht8pGgyeD4VAg6oK65kSEbekADKVGVc5iGpzW7wRJ7pfYAng7LhXLmP3oiAOZcYklLUOZcEcq3qMiTVuTJYECjQ7FVmZcpcswwJvb8LJCuQliJPHCkRTOY1y9GWxMBvUctitc3U9KdShWCfYK3VG6Ym8Lu4ZaQambF9TJlBulQHLF5Rw8NwNAr8v7CGq8qz5vne0ElvwefJF8sefoVBk\/QEqxIlbFStU4QFM8a+0oOxENDSK9BYoT5g5ln5i5zVFjy1g0EaL7cQo0TNBKzrVxuGuYP6icEDKA3C9qS\/QYUI89kkWm4iz5zsy3qdy+OjgnFBWVZw+f2tnYOndN6PwKEX8lYLejwevY\/EBrG0rgf66A29YeD3rkUyrFLNy2ZedD2Pk82fzUu0SObjZbwdx9FkNY2S34t5Mo02k1+z9ctstQz82ySrseMCK2s4q\/mJ4FYiJLf\/l9Bbzyv3ZeD3CS5biQz1hWVRF7Al\/L5G0KOuYO+BYXZhUQ7iH9cyfuu7r\/ePpfO45Hb8XeQ\/adrYB92rU7mllDued0NDkVXQjMHeEtOsqJpb6ZHGunPgbZHu6FrUneGeZxl2kQx3rBYmJEbX2Ib8tpbvirX99C0E\/uW86Tu9ZFv0","xmlFileCreated":1543258276},"66":{"desc":"eJyFkLFuwzAMRH\/l4Dm19yIJEGTpUrRDOheMzEhCZFMQ6Rjp11dO2qBbJ+Kok3T3DiEq9rv3w\/5lh5wmH0dMygoLjMK\/J8rlEh3DBLnwhUeDZhoGLoo5xMSIhsAp62Lpo48WvxhHkbOuMPJc3Xkx09hDUo9CfRRokFlbHASeDQSNxjeLsit1c+YrTlJwlamgl4HiuIKX5Y81IRQ+bZpglvW56+Z5br2IT9w6GbrCjrK5QA2MSn1+03weE43nZvvfjXVH21uoCqJyqICWDLUEyDmZavfCPqoVsiiPQG95UYoKcGH3UZHhlUbydd4rJXb2YP30hy7dcf\/I9htFUIz\/","element":"recaptcha","enabled":"0","extension_id":"439","folder":"captcha","name":"CAPTCHA - reCAPTCHA","path":"\/plugins\/captcha\/recaptcha","title":"","type":"plugin","xmlFile":"\/plugins\/captcha\/recaptcha\/recaptcha.xml","xmlFileContents":"eJzNV1tzozYUfk5+hcpT+xB8aTuz0wJbjBmHBl8GO9m0L4wMJ5iNuFSI2Omvr8Qt9iwmZmen7ZvE+c6Rvu+cIwnl4yEi6AVoFiaxKo3koYQg9hI\/jANVytnTzQfpo3atwIFBLDBv2B\/lnyTEXlNQpZTkQRhLKKBJnqqSh1Pm7bCEImC7xOdx0oBiHyTt+kqJcQRaSgK3QrkUqpEyKGwcU62h8SXkoTKop9ziUcCMj6eYgTYFD6ItUDQejkbK4MTGsTjnq1Pt9ySJCP4OrWjyGTymDKrvDcKMcEg07Edh\/NvnAiwnNKhxpbUB31Oi7fd7+UugsIgdJukrDYMd04x6hL43fuB7HP6MbsRWP6BlCjFaJzn1AM0xY5yfjHRCUAHPEIUM6Av4MifVhOOxSejxLIA2W9yjGcRAMUGrfMs\/I7s01elBY5RQRLgS9FeUASDbMszF2pTZgStQx+Ehfcg8GqZCN21lz1xDX22MW911zHr0OLfdqbk2HGu1sZYLZXDswiM8hQQyPihHIoWorAdValIrac1QTnepMqihIsCgjsC1i5\/CoIoFxM+QwPD6whRHmSifxgKssm1xFnqlqbIVw6vSGkGW4QCk8ltZrXHC6g8Eb4GokiD+RvjBdNacqDtyP+nOwlrMXFufmHblku2SvSj\/SuhfRMsUloF2fWYTFfRkEyTM2CWbOF76SPhzcJGoBv2Ec8JUaVzv8CoL\/+ZLj6pZqdmVkhQR0QsmOZRHgNYe\/IE3WVLnvcV13OE6PnUVSecqnZUsLarafYbXE9UYP4e6VFvdT3ihu3fmH5cKd+TRpl01p\/BXHlLgRxmjeV08vGx5e6lSxig\/LU8lHtaSewRnmSqFcZqzm8OBYFpX4\/l6SWn4wju3P3vHetA3Zi\/6Ry7\/G\/5sBxH06pbNrTk3L+VcgtvYegRw\/F6fN7w726gMpbWtbNimvujupP0u5GdUq\/enW2tjdntvCfaeAyF8e4iJrRt3M1tfr7vj8IS3B3DMab92LjI6\/i9SSsTdeSal434pLUO1CmJbs9tNt5g+ps\/tzlPduesnp2iyXmKurT8v1rLAtkkZJzTC5NtoWcVq1WOxdOa63a2ml0Qp9s5kw1jOV7qx6VmieBvGPhxOnwq5eF92lqk+sRZT8\/HiSq3xbQoP3xU3Es+qdx8cHiZky8+AXreHodv2hB8MlzJp8B33xvtVcnx5nCcEh1RcP+5XETMfVxY\/sXoT\/MLv3yBKaUK\/kqbjLJ3+JE+9viXFt6bjr\/XiUV\/Nikd\/\/dZXBs2\/pfYPp54Rag==","xmlFileCreated":1543258276},"67":{"desc":"eJwLriwuSc1VKMgpTc\/MUyjJV8jITM\/IAeISheKC1OTMtMzUFIWS1KLcYj0AasgQVQ==","element":"highlight","enabled":"1","extension_id":"440","folder":"system","name":"System - Highlight","path":"\/plugins\/system\/highlight","title":"","type":"plugin","xmlFile":"\/plugins\/system\/highlight\/highlight.xml","xmlFileContents":"eJytk8Fu2zAMhs\/tU3A6bYfISYsBBWar69IgzeCkwZwC28nQbNZRIUuGLDfJ25eOY7dFd9xBhsj\/0w+SksPrfanhGV2trInYhI8ZoMlsrkwRscY\/jq7YtTgPce\/RtMwre8knDPyhwohVuimUYVA421QRqw+1x5JBiX5rc7KpCidzZOL8LDSyRFHpIu2gdKuKrablw+AoESIbOubET2tLLT\/B2tknzEg\/5YnIHEpPRdxKj+KmKZraw8V4MgmDd0pL2urgWnvxefqFmPFXGLXoFdxXaCCxjcsQltJ7aovDjdZwxGtwWKN7xpyT6WBCjlplNAkU89UDzNGgkxrWzV9KQ9xJ\/YjgAqwDTZW4b1AjnsWL6WyVzLjfUze9z9DwrJRKC5mXynx\/OvbOrSv6tjt1gB+cFrvdjn8EW4WwUw3iko\/5OAz6kJQc68ypqp2SWMfzNPmTbGbL9G4xv4tpbdLfyzi9nSXTX4v1ZnG\/CoO3J8jgUWmsadPt2luD7gFEbLhNJoYtr7ZVGPRoaxD0DqGWpmhkcbLrI\/CSHh+a0fwHE30yOMbdl\/\/rAXFlFI31hP8PQ0p8MH0NqOYwGP4L8QIkch8Q","xmlFileCreated":1543258276},"68":{"desc":"eJwdytENgCAMBcBV3gQu4QhMUKVCk9oSKFG3N3rft1aywgPh2N2CLXCJKswDs2UKRlRGOqkHElPfK8Qy35ADj09k\/y8bbfpdGWg6i9jyAvb8IQY=","element":"finder","enabled":"0","extension_id":"441","folder":"content","name":"Content - Smart Search","path":"\/plugins\/content\/finder","title":"","type":"plugin","xmlFile":"\/plugins\/content\/finder\/finder.xml","xmlFileContents":"eJydk02P2jAQhs\/lV0x9ag84sKtKK9V420KKqNiAFlbqLfImQ\/DKsSPb2YV\/X+eLbcWtJ3+8z7yZGU\/Y\/alU8IrWSaNnZEonBFBnJpe6mJHaH8Z35J6PGJ486oZ5Z2\/plIA\/VzgjlaoLqQkU1tTVjGRGB9oTKNEfTR58qsKKHAkffWBalMgrVaQ9lR6kztGyqBUCIOoQZPkvY0olPsLWmhfMPIv6+0BkFoUPOSyER77ADMtntHAzmU5Z9I\/WsKY6W1kcPZ8PO\/g0\/xzoyRcYN0F3sKlQw87UNkN4EN6HCil8Vwpa3IFFh\/YVcxrsL3bBW8ksNAX5MnmCJWq0QsG2fg7XsO6koVtwA8aCCjnZr+AQYb2ax8kupv4UKht8LsXHpZCKi7yU+ttL2wdqbDG0oFMv8JNV\/O3tjV6DjRKwPgd+Syd0wqLhGJQcXWZl1fSLb9fLdL5J9nGyT3+ukkX8mP5+WKeLeDd\/XG33q03Cor\/5UYg\/SIUuGHW75gGhG4UZ6V6V8G6l1bFi0QA1n46GWKaELmpR9EbDCbwIA4h6vPxBeLvQ66GhUsvQvj7kP+Ld2V15vB9cN0D6IIu+SFS5g6aEMPPCitKRVog6pQ0eeBZd\/hn+BxHtJQQ=","xmlFileCreated":1543258276},"69":{"desc":"eJwLycgsVijIKU3PzFPIzEtJrUgtVvDKz8\/NSVRUcE4sSU3PL8pMLdYDACDxDk8=","element":"categories","enabled":"1","extension_id":"442","folder":"finder","name":"Smart Search - Categories","path":"\/plugins\/finder\/categories","title":"","type":"plugin","xmlFile":"\/plugins\/finder\/categories\/categories.xml","xmlFileContents":"eJytk99v2jAQx5\/Xv+Lmp+0BJ7SaVGnGHYMsYqKAoJX2FnnJYVw5duQ4Bf77OoTApu5xL9H9+NxXd+cLeziUGl7R1cqaERnSmACa3BbKyBFp\/HZwTx74DcODR9MyV\/aODgn4Y4UjUulGKkNAOttUI7JVpkBHoES\/s0WQqaQTBRJ+84EZUSKvtMw6KMuFR2mdwppFp1xgRBPqHP9pbanFR1g5+4K5Z9E5HojcofChi2mo5uNGNrWH23g4ZNFfmZa01dEpufP80+RzYOIvMGjRe1hWaGBjG5cjPArvw1wUxlrDCa\/BYY3uFQsaRC8iQVGrPKwCebp4hhQNOqFh1fwOYZh3qX5HcAvWgQ6duK9QI8J8NkkWm4T6Q5im17kMnJRCaS6KUplvL6fZqXWyH7vLXuBnp\/l+v6fvwTYTsHMP\/I7GNGZR74ZMgXXuVNVuia\/mafZjtpgm62wyfkrS5XqWbLJfj\/Nsmmwm69nqabZcsOjPkqCwVRrrYHRW+2zQncCIXN+T8KtNq13Foh5uJaJeg2lhZCPkWbD3wItwgGgG6XfC+2B08rsv\/ecRUWVUWO2Z\/y+K9fG96tUJXbPo8nfwNxq+ILo=","xmlFileCreated":1543258276},"70":{"desc":"eJwLycgsVijIKU3PzFPIzEtJrUgtVvDKz8\/NSVRUcM7PK0lMLinWAwAEtg2I","element":"contacts","enabled":"1","extension_id":"443","folder":"finder","name":"Smart Search - Contacts","path":"\/plugins\/finder\/contacts","title":"","type":"plugin","xmlFile":"\/plugins\/finder\/contacts\/contacts.xml","xmlFileContents":"eJytk11v2jAUhq\/XX3Hmq+0CJ7SaVGmOOxYyxEQDKlTaXeQlh+DKsSPHKfDv6xBCV7WXu4nOx3NenQ+H3R0qBc9oG2l0RMY0JIA6N4XUZURatx3dkjt+xfDgUHfMK3tDxwTcscaI1KotpSZQWtPWEdlKXaAlUKHbmcLL1KUVBRJ+9YlpUSGvVZn1UJYb7UTuGhacMp4Qra+y\/LcxlRKfYWXNE+aOBee4J3KLwvkepsIhn7Rl2zi4DsdjFrzJdKSpj1aWO8e\/xF89E36DUYfewrJGDWvT2hzhXjjnp6IwUQpOeAMWG7TPWFAvehHxikrmfhHIZ+kjzFCjFQpW7V8fhkWfGjYE12AsKN+J\/Q4NIizmcZKuE+oOfppB5zJwUgmpuCgqqX88nWanxpbD2H32Aj9axff7PX0PdhmPnXvgNzSkIQsG12cKbHIr625LfLWYZb\/m6TR5yOJlupnEm3X2536RTZN1\/DBfbebLlAX\/Fvj6rVTYeKO3uqNBf\/6IDLckfLBovatZMIBdeTDUMyV02YryLDZ44IR\/eKhHs5+ED8Hg5Pdf+sHjoVJLv9Iz\/R\/0muN7zVfHd8yCyx\/BXwBaXhxQ","xmlFileCreated":1543258276},"71":{"desc":"eJwlzDEOwjAQRNGrDD1wB4RoKKAIHGBjT\/BK9jpyNoHjY0E3etKf5xzFucAToRb56btOuNZasuxwaq4hd3snGjc2iEH+CF0QGnse9yg16qSMqA2RmR2PuN0fl9\/zuZrTHAcMpdcYKC0kzHl9qaGsi2MkaDLm3n0Bcis0iQ==","element":"content","enabled":"1","extension_id":"444","folder":"finder","name":"Smart Search - Content","path":"\/plugins\/finder\/content","title":"","type":"plugin","xmlFile":"\/plugins\/finder\/content\/content.xml","xmlFileContents":"eJylk8Fu2zAMhs\/rU3A6bYfITosBBeao6xIvyJA6QZMCuxmazTgqZMmQ5SZ5+9GxnW7IcRdD5P\/xB0nJ0cOx1PCGrlbWTNiYhwzQZDZXppiwxu9G9+xB3ER49Gha5p2942MG\/lThhFW6KZRhUDjbVBO2UyZHx6BEv7c52VSFkzkycfMhMrJEUeki7aA0s4acfRScBQJkQ0VO\/LS21PIjrJ19xYz0Pk9E5lB6amEmPYrHpmhqD7fheBwF\/ygtaauTU8Xei0\/Tz8SEX2DUovewqtDAxjYuQ3iS3tNQHB61hjNeg8Ma3RvmnEwvJuSoVUZ7QDFPXmCOBp3UsG5+UxqWnTQsCG7BOtDUifsKNSIsF9M42cTcH2mawecycFxKpYXMS2W+vZ5n59YVw9ideoFfnBaHw4Ffg61CWN+DuOMhD6NgCEnJsc6cqtotifVynv5YJLP4OZ2ukm2cbNNfT8t0Fm+mz4v1drFKouBvnsp3SmNNh+7U3hl0lz9h\/U0y0R94ta+iYMDa4mCojrQ0RSOL3mqIwEt6dGhG8+9MDMngHHdffv1wuDKK1tnD\/29Xn+ory\/eA+o2Cy78g\/gCJ2BoY","xmlFileCreated":1543258276},"72":{"desc":"eJwLycgsVijIKU3PzFPIzEtJrUgtVvDKz8\/NSVRU8EstL1ZIS01NKdYDAB+iDg0=","element":"newsfeeds","enabled":"1","extension_id":"445","folder":"finder","name":"Smart Search - News Feeds","path":"\/plugins\/finder\/newsfeeds","title":"","type":"plugin","xmlFile":"\/plugins\/finder\/newsfeeds\/newsfeeds.xml","xmlFileContents":"eJytk8Fu2zAMhs\/rU3A6bYfITosBBaao6xI3yJC6Qb1iuxmazSgqZMmQ5SZ5+8lx7G7ojrsYJP9PP0hKZjeHSsMLukZZMyNTGhNAU9hSGTkjrd9OrskNv2B48Gg65pW9olMC\/ljjjNS6lcoQkM629YxslSnREajQ72wZbGrpRImEX7xjRlTIay3zHsoN7pstYtmw6CQFRLThmOPfrK20eA8bZ5+x8Cw61wNROBQ+NLEQHvltK9vGw2U8nbLoL6UjbX10Su48\/zD\/GJj4E0w69BoeajSQ2dYVCPfC+zAWhVut4YQ34LBB94IlDaajSXDUqgibQL5Mn2CJBp3QsGl\/hTKse2lYEVyCdaBDJ+4zNIiwXs2TNEuoP4RpBp9x4KQSSnNRVsp8eT7NTq2Tw9i9OsJPTvP9fk\/fgp0SsHMP\/IrGNGbRkAalxKZwqu62xDfrZX63ShfJY54mP7K7JFlk+c\/7db5IsvnjavN99ZCy6M8TwWCrNDYh6KPu1qB\/ADMy3ibhY0jrXc2iAe0MosGBaWFkK+TZbsjAi\/D40EyWXwkfitEp77\/0Xw+IKqPCWs\/4\/zBsjm9NX5PQM4vG\/4L\/BkBDHo4=","xmlFileCreated":1543258276},"73":{"desc":"eJwLycgsVijIKU3PzFPIzEtJrUgtVvDKz8\/NSVRUCElML9YDANA+C9g=","element":"tags","enabled":"1","extension_id":"447","folder":"finder","name":"Smart Search - Tags","path":"\/plugins\/finder\/tags","title":"","type":"plugin","xmlFile":"\/plugins\/finder\/tags\/tags.xml","xmlFileContents":"eJylkt9v2jAQx5\/Xv+Lmp+0BJxRNqjTHXQcBMVGKCkh7i9zkalw5duQ4Bf77OoTQbX3ci+W7+9zX98Ps9lBqeEVXK2sSMqQxATS5LZSRCdlupoMbcsuvGB48mpZ5Z0d0SMAfK0xIpRupDAHpbFMl5FmZAh2BEv3OFglpKulEgYRffWJGlMgrLbMOyryQNYtO3hAVTchw\/Je1pRafYeXsC+aeRWd\/IHKHwof3J8Ijn+KTa4Q7wnU8HLHor1jL2urolNx5\/mX8NTDxNxi06A08VGhgbRuXI9wL70NPFO60hhNeg8Ma3SsWNIheRIKiVnkYA\/LZcgszNOiEhlXzFNyw6EL9fOAarAMdKnHfoUaExXycLtcp9YfQT69zaTkthdJcFKUyP15O3VPrZN94F73AW6f5fr+nH8E2ErBzDXxEYxqzqDdDpMA6d6pqp8RXi1k2nS8n6WO2uZuts9\/3i2ySrseP89Vm\/rBk0Z9wyH1WGutw6W7tyqBbfELaLRLenrTaVSzqgTYt6vOYFkY2Qp5FegtCWkLQDGY\/Ce+d0cnuTvrPd6HKqDDCM\/mfWvXxo967ESpl0eXv8zfj1BMZ","xmlFileCreated":1543258276},"74":{"desc":"eJyFkDFuwzAMRa\/y4b3SXiQBsrRjMmQPaJuWhTiiIFIwcvvK6VAUQdGR5CP5yOOyyKqoykUhCQ+pBRqNYbJlYatgosGkgKrNnCwOZLGhVWMK2BHmwtO+m82yvnvPya3xFjOPkZyU4LfIf4qEha\/HnxFSOhiVwLbvrv1C6dYdvin8onaeDmjbpeUKBrnntr5vlMU7v\/WkPOKUGJcW4kyqq5QRgROXrV2hdZhB+mo6FWax7EK0ufYuin81+mjM6XLeJBwu\/70kL9x80E43tMLzrchFpth8KY3gRE\/1vya4L2BGkYo=","element":"totp","enabled":"1","extension_id":"448","folder":"twofactorauth","name":"Two Factor Authentication - Google Authenticator","path":"\/plugins\/twofactorauth\/totp","title":"","type":"plugin","xmlFile":"\/plugins\/twofactorauth\/totp\/totp.xml","xmlFileContents":"eJydVE1P4zAQPcOv8Pq0e2jSD62EtInZUrqlqLQVDdq9RSaZpkaOHdkOhX+\/k69SBCzSXlp73psXz8yzg\/OnXJJHMFZoFdKB16cEVKJTobKQlm7bO6Pn7DSAJweq4rxwR96AEvdcQEgLWWZCUZIZXRYhtc\/WQU5JDm6nU5QpMsNToOz0JFA8B1bILHZ7veWJ04aXbhc77YrAr0EkVSFt2LXWueRfyNroB0hc4LdxZCQGuMNjXHIHbFxmpXVk2B+MAv8VUjF18WxEtnNs0q3I18k3ZPe\/k16VdEZWBSiy0aVJgNxw57BEj4ylJDXdEgMWzCOkHsof5FBbigS7Amy2vCMzUGC4JOvyHsNk0UBdu8iQaEMknsn8IBaALOaT6XIz9dwT1tXpHEqf5lxIxtNcqJ8PdRc8bbKuAQ16IN8Zyfb7vfeWWCFIa8\/ARt7Q6wd+t0UkBZsYUVT9YuvFLI5+r36NJ9HqdnwXXcXRKlrHf24W8eV0M7mdr6P5ahn4xzkosRUSLC6aVTVB0tghpNVQKat+vWKH4+0IDVvLFAwrtHVCWcelREITO4JdXhzHGw1b956rrORZ++1uRxxH34LqzS4oq\/+8983mCSWw8W3af2qg0d\/ovGxsYz+1FVnbH5CpJVUH8Mpww3NbXYkDAq7F7rkVSQO1WL08aVCLVwF7T5tYcwHxegndRiS\/BxnSD8a5mU6qMcaL8cV00WYcTfTTvMoKh7QtL6XDl6AN4GzQ3yEVykEGpo0mkluLRTnVq9+HNtyUdxLo+rvkkcsSCxnQj3zYHWAzj6aBrzv\/vaMx\/FRjfHkzX\/5bZPSpyMUqunqtUbkTh9XM1O+GWs++3dX+6CwR+IdXlf0FjXXD6g==","xmlFileCreated":1543258276},"75":{"desc":"eJxdz0EKwkAMBdCrfFeurBcorkVwo4i4TNvQDmYSaTKKt3dEunEZfvI+2ZMOwo6DWRZaO3qze2JcnGdQiYk1Uk+RTJu2m7HdtR6z6bjDlWZNOq5ws4JcPDDRk0EBYaqTKcMq8O\/gIWVMClbqhIem3S7ir+DLvZIISNygzANoufHSTyBH9XB+e3DGBifOnLvac+RlLwwpP6QGGstLYjVpPgLrVn4=","element":"cookie","enabled":"1","extension_id":"449","folder":"authentication","name":"Authentication - Cookie","path":"\/plugins\/authentication\/cookie","title":"","type":"plugin","xmlFile":"\/plugins\/authentication\/cookie\/cookie.xml","xmlFileContents":"eJydVNtS2zAQfQ5foeqpfcDOhWYyU1sUgkkNJskUmGmfPIq9cQSy5MoykL+vfIWUy0CfvLvn7Epnd2Xn8CHl6A5UzqRw8cDqYwQikjETiYsLvd6f4EOy58CDBlFyHrkja4iR3mbg4owXCRMYJUoWmYtpoTcgNIuoNkyMUtAbGZtyWaJoDJjs9RxBUyAZT8JdchhJecvAsSvc8EpYKnImZcrpJ7RU8gYi7dhN3DAiBVXqCdVAzgq+RcP+YOTYO\/GSJ7OtYslGk2lroc\/TL4bd\/4r2y6QJWmQg0KUsVATogmpttFroiHNU0XOkIAd1B7FlynflTG3OItMeILP5NZqBAEU5WhYrE0ZBDbV9Q0MkFeLmTuobygFQ4E+9+aVn6Qejqq3TCfdSyjihccrE95uqB5ZUSSu\/RjvyteLk\/v7eek4sEUNr7kBGVt\/qO3brGiSGPFIsK\/tFlsEsPLq++hFOF4tz3wt\/XQThiXc5\/ekvr\/zF3LGfkk3umnHIjVFb5eBQvRAurqeJSf21sk3m2C2pTLXbXIdTkRQ0aQq1HtLUrCGI\/dkxJtXHenVnLCaY6WCT+f9l8m3+rNSjk9erJNYsaSQDj3NUCjLvgCqa5uV+dwjoBlvRnEU11GCV2avR+uyQszVolgKusfp1iSJdgWpCnK6Au\/jfGZ36XnDSOoF\/6l35F8Y4OvaCJvHJ0N6bXg69y17TgmsXj\/tNxEzO7LCLmdCQdNdT8KdgCsxj16poZNhk7xXVt7ANzTIkerMjmLNcv0fuufc7DLz5zMQ\/qPRJ5ksiB+MPi+zVk+05sjoY3VFeGCkTTCaOLdu38gLDnEUG47c5oyEmo+HbnPEBJuODXU75vkzL6\/43jtnIanEbr1rudp8du\/vPk78OEOQB","xmlFileCreated":1543258276},"76":{"desc":"eJyFjjESgzAMBL9yLzB9utRpkyKlMCJoAhYjy3j4fQyTNpNWur296zxrzSiZLUMTdi2GLM5wPa7wqhgpuhqo+MTJJZJLi5Ys6QXCs\/Ry4x2ZYzHGRDZUsqPgzSngcVYn5gENF4PWdDLvxtBGMlM\/M0bTBZP7mi9dV2sNe4tEDVGXLuD+f8xhmWg7h\/Mg\/rUdD6ymozQJpQGcTt\/PqvAB31Nl2Q==","element":"yubikey","enabled":"0","extension_id":"450","folder":"twofactorauth","name":"Two Factor Authentication - YubiKey","path":"\/plugins\/twofactorauth\/yubikey","title":"","type":"plugin","xmlFile":"\/plugins\/twofactorauth\/yubikey\/yubikey.xml","xmlFileContents":"eJydVE1z2jAQPSe\/QtWpPWDzMZ3JTI1SIC6hJcAEmDYnRtiLUSpbHkkO4d93bcukmTSZTE+W9r191u4+Kbh8TCV5AG2Eyvq047UpgSxSsciSPi3srnVBL9l5AI8WspLzxO15HUrsMYc+zWWRiIySRKsi71NzNBZSSlKwexWjTJ5oHgNl52dBxlNguUw29qB2PLJK88LuN8diK37DMfArHHllVGn2XalU8g9kodU9RDbwXRwZkQZu8SRX3AJbQo6\/3IIm3XanF\/jPwJKs8qMWyd6yUbMiH0efkN3+TFpl0gWZ55CRpSp0BOSGW4uFemQgJanohmgwoB8g9lD+JIfaUkTYG2Dj2ZqMIQPNJVkUWwyTaQ01TSNdojSReCb9hRgAMp2Mwtky9OwjltbonKoPUy4k43Eqsq\/3VSM8pZOmBzV6Iq+1ZIfDwXtJLBGkuTOwntf12oHfbBGJwURa5GW\/2GI63qx+zr8NRqv57WC9ut7crYeTH+Hd5tfNdHMVLke3k8VqMp8F\/t9pqLITEgwu6lU5R1L7ok\/ddClzCy\/f54Hf0OocJWPQzKa5RKTeoKjfqAaSZ0nBE\/eLZkcsR59C1hoPKas+3qvm8kQmsMsu8\/9l0N4vpJ42prZbthOJawbI2JCyULwoXPPUlBfhhIB12JYbEdWQw6rlWY0adD82mtax+trhpRLKRSTfguzT18e3DEfl2DbTwTCcuqS\/Jvie1HL6p8wdL6TFV8AFcE7o6j4VmYUEtItGkhuDpdmsVb0NLlwXeRao6tfkgcsCy+nQN9zXnGE5WYWBrxrX\/UOm+x6ZwdXNZPa2Tu89OsP56vq5TGlZnF09Yr+ZcWUFt6vs0jgk8E9PK\/sDftXFbQ==","xmlFileCreated":1543258276},"77":{"desc":"eJxzzUtMykktVihOTSxKzsjMS1fIzFMISUwv1gMAgi8JYw==","element":"tags","enabled":"1","extension_id":"451","folder":"search","name":"Search - Tags","path":"\/plugins\/search\/tags","title":"","type":"plugin","xmlFile":"\/plugins\/search\/tags\/tags.xml","xmlFileContents":"eJyVVMlu2zAQPSdfwfLUHizZSQMEqMTUsVXXgbwgdtD2JNDSWGZAUQJJxXG\/vqS2OEnT5SJx5r0ZzfIo7+ox4+gBpGK58PHA6WMEIs4TJlIfl3rbu8RX5NSDRw3Ccp64584AI30owMcFL1MmMEplXhY+VkBlvMMoA73LE5OmSCVNAJPTE0\/QDEjB06gmRZqmynMrr0FpaSIkucnzjNN3aCnze4i15zZ+w4glUG2+P6YayMymQGf9wUfPfQZYYl4cJEt3mozaE3o\/+mDY\/QvUs0GXaFGAQKu8lDGgGdXatOagIeeooiskQYF8gMQx6bt0JjdnsZkGkMn8Dk1AgKQcLcuNcaOwhtoxoTOUS8RNTfITUgAonI6C+Spw9KNpq83TdR5klHFCk4yJz\/fVEJxcpm3\/NdqR7yQn+\/3eeU20iKE1NZBzp+\/0Pbc1DZKAiiUr7LzIMpxEq2B4O\/oarYeTVfR9FkbjYDW6nS7X08Xcc4\/JJnbLOChzqE92c6jev4\/tMjGxT6fYFZ7bEmyY28Z5nIq0pGmTpLWQCfMxiN7kGpPq5byQicMEMzNr+P8brA6vEzwZqpaM2LK0aQ14opAt3sibSpopK98OAd1gG6pYXEMNVh1ParQpgLOMaVwD9Y0RZbYB2bg43QD38c2XaRCOo6N91K9wOpuuo3B4HYRNwNFG\/hZmN9lFbWnJtY8v+o3HrMQI08dMaEi7chT7aSq8qC2XnL7V2y7f29GmkERMgxnQcYPmwrP8eX8vhVbXvfq6+GbtSTCOputgtnq7039NcNRzzKlSZkta9KqfE+pOvQMokb8czZ8nU6\/5xMurgtAD5aVpdYDJzY9g5bl5e0d+Q+ob0nzxnGPvhBlqrSu3FValv8aqNNrK0nO7vzD5BXTMxCw=","xmlFileCreated":1543258276},"78":{"desc":"eJyNjktug0AQRK9S2UccIDtskwjLNkiMZbFCY2hDy\/NB87HF7TMgZZ9lV3U9PTGxx6ziyAYzObYD91KpBf1E\/dPjYR3CRJAvyUreWXFYYB8w9MbRWq3kB17kPFvjM9wmMrCGwOsymgEc8Gal4Ckdi42QBqQT6xOONJuBzbjlwSLOgwz0h81QOwvB8xfa1Pdp2EcfrGZPm9KGgSbv5Ui4J60k4ngjrr2SZoxr5YNbsyctHvXpp2vaRhTn7lofclFcKlF+l\/tclNWlK855eeqa6+5Y7EVSHf71v6sObfYLFmVxyg==","element":"updatenotification","enabled":"1","extension_id":"452","folder":"system","name":"System - Joomla! Update Notification","path":"\/plugins\/system\/updatenotification","title":"","type":"plugin","xmlFile":"\/plugins\/system\/updatenotification\/updatenotification.xml","xmlFileContents":"eJylVclu2zAQPSdfwfLUHiI5SV0EqMzUsVXDhbwgtov2JDDSWGZAkQJFOXG\/vqPNWYy628mcmTePfLPI3vVjKskWTC606tFzp0MJqEjHQiU9Wtj12RW9ZqcePFpQJeYJe+l8oMTuMujRTBaJUJQkRhdZj+a73EJKSQp2o2OkyRLDY6Ds9MRTPAWWySSsQWGRxRyptRVrEXGLzJ5bYRDLC8w37IvWqeRvyNzoe4is5zZ+REQGqpwhcrAJ35GLznnXc1+4S5jOdkYkG8sG7Ym8HbxDdKdLzsqkKzLLQJGFLkwEZMKtRZkO6UtJKnhODORgthA7SL+nQ24pIqwMsNF0RUagwHBJ5sUduklQh9qSkQuiDZH4JvOR5AAkGA\/86cJ37COKann2uv2UC8l4nAr16b4qgaNN0qqvo3vwykj28PDgHALLCMKaN7BLp+t0PLc1MRJDHhmRlfVi82AULr4vlv4kXM2H\/aU\/nS3Hn8eD\/nI8m4bfJkE49BeD2\/G8tD33eSoyrYWEHA\/1qewiqSejHIHXbabs0Odkm8xz2+SS0m05PclVUvAEcrLWMgbTo62HVle2FrEcJxfU2eiGsurHOTpujlACq99k\/x8VRg7onoy8HkW1FklTJJBxTkqpuELc8DSvpLQRsE3sjuciqkNNrDqe1FEoJ4HWnnodLW5r45D8DmSPHu+rP+mPgzC4CZqkZ239s9RyKPa5a15I26ONnYsf+KL3ndp02ekvVLRFCjWOphH4tXiuaN\/qv1AV9KejVX\/kh7Ov\/u3teOj\/m8JDmiNqIylAoVltrcit4VabJlb378TT1bVky2WByuhvdu7w+uls6nuubreupHSrch6pLb6kUC8quhFxDOq1jM6Lrp139117ugXHsprexqomvB1qz93\/T7CfT1v4sA==","xmlFileCreated":1543258276},"79":{"desc":"eJxFjNEJwCAMBVd5E7hDwUVSG6qQGtGE4va1UOjnHdzFMprQHCDsbqYVpih1cLelLj1cePGSVLF1K0k4IP5V0+YNJKJ3qSem+ntIWXUwLPP3CA\/wqiZS","element":"module","enabled":"1","extension_id":"453","folder":"editors-xtd","name":"Button - Module","path":"\/plugins\/editors-xtd\/module","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/module\/module.xml","xmlFileContents":"eJydkk1v2zAMhs\/rr+B02g6R0xYZCkxWtyVBkMH5wLIAuxmqzToqZMmQ5Sb596XjOO3QnXYSJT58Qb6iuD+UBp7R19rZmF3zIQO0mcu1LWLWhMfBHbuXVwIPAW3LvLK3\/AuDcKwwZpVpCm0ZFN41Vcww18H5enAIOYMSw87lpFUVXuXI5NUHYVWJsjJF+oZMS5c3BkV0ShKkGir08qdzpVEfYe3dE2ZBROd3IjKPKlAvExVQrrLgHtDDzfB6JKK\/Ui3qqqPXxS7IcR\/Bp\/FnoocjGLRFd7Cq0MLGNT5DWKgQaFAO342BE16Dxxr9M+ac5C9ypG10Rt6gnC23MEOLXhlYNw\/0DEmX6k2DG3AeDPXkv0KNCMl8PF1upjwcaLBe5zL7tFTaSJWX2n57OtnAnS96B7rsBd56I\/f7PX8PthnCzj3IWz7iQxH1V8rkWGdeV61fcp3M0sVqsk2m6Z9Fkk6mm\/Gv+fr3fLUU0VuOyh61wZqCLmq\/DbpFiFn3l0x2J692lYh6qC2N+lphlC0aVZyF+hsEReuHdjD7weTp4P9eF66tJufOZf+pUR\/rdzqvF+pMRJf9ly8jwhdF","xmlFileCreated":1543258276},"80":{"desc":"eJxNjlEKAjEMRK8y\/steQj9EEBZ6gmwbtdJNliYr9PZ2UVg\/Z3jzktDMecZY1kcW+JMcxpIMLO9cVWaW3jh5Ns\/R4ArqRH1zRVTxqqVwwtT6lnFVnQsdsFR9cXTcte5jKiCh0izbgLArbTuRJZY1McbLiO62rHLE6Rb2cCaniYzhbeG\/+AO6OyF8H9uI4QPbUVBY","element":"stats","enabled":"1","extension_id":"454","folder":"system","name":"System - Joomla! Statistics","path":"\/plugins\/system\/stats","title":"","type":"plugin","xmlFile":"\/plugins\/system\/stats\/stats.xml","xmlFileContents":"eJydVW1P2zAQ\/gy\/wvOn7QNJacWEtDSs0KjqlBZGChufItNcUyPHzmyHl\/36Xd5KS4GKSVXr8z33+Lnz+eqdPGaC3IM2XMk+PXQ6lICcq4TLtE8Luzg4pif+vgePFmSJecb2nK+U2Kcc+jQXRcolJalWRd6n5slYyCjJwC5VgjR5qlkC1N\/f8yTLwM9FGteg2FhmjedW2+hmBYZo\/4dSmWCfyIVWdzC3ntvsI2KugVkUMGQW\/Km6h+wWNOl2Dnueu+ErsSp\/0jxdWv+sXZHPZ18Q3TkiB2XQMTnPQZJIFXoOZMKsxfQcMhCCVHBDNBjQ95A4SL+iQ27B51gR8EfTKzICCZoJclHc4jYJa1dbKtIlShOBmvQ3YgBIOD4LplHg2EfMrOVZJR9kjAufJRmX3++qOjhKp20Jau8KfKWF\/\/Dw4GwDSw\/CGg1+zzlyOp7bmuhJwMw1z8t6+RfhKI5uolkwiaPZYBbFvydhPAyis8vxxWx8PvXcdTQGL7gAgwtcKZGA9hccROK5jbXmEOxJFeUVr7swurxxUjcOdkzZBdSvfpx8mSO6gZSHue1pnmAyLVgKhtRsfdru0Iq4tYhl2L4gD0an1K9+3Orbedl5Dpcc76AJ+08ONLZ4ng1Td6Jc8LRJHitlSJkcvhymWWYq8a0HbOO7ZYbPa1fjq5Z7tTdhltF6o32Eaa2qFrXmF+wWRJ\/Wluvvv8FYSP6ngJgn79HWoBWmod7qn6vp+OdVEI+HcTg4DcIGvdZE78aUndeEGP4XRRx2donnEp\/XPRMb2mVRDocdUsfTWXB5PQg\/oHQVsiYUe9SWDVkKSVeHJrBghbCYQXdXBpnCEbmuXnBjd2ifnA+DD+iu4Guan9U1G3Wz7XmqYiBYz6KsPt0eEBXVeTUc4kH4a3ATxVEwHXquamfEK0TdHUT4GQaTwS6a3g6aaXAdXL4ipxwkWPQ3b0AwY3UhNy5hyZME5Mt6dTa782h1t8+n4DuunntjVSOhnQKeu\/o\/9f8B0dlEDA==","xmlFileCreated":1543258276},"81":{"desc":"eJxFjNEJgDAMBVd5E3QHoYtUCTYYk9KkSLe3fvl7x11mb1Kmo2AfEaYIA6tTD9ykAxx0Q1gvX3i5oth68CGUkP+4WRsNRcQe1hPTxjc6qpkTotI\/Sy+USioO","element":"menu","enabled":"1","extension_id":"459","folder":"editors-xtd","name":"Button - Menu","path":"\/plugins\/editors-xtd\/menu","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/menu\/menu.xml","xmlFileContents":"eJydUslu2zAQPTdfMeWpPYhyUrQNEJppaguGA2+IbSA3gZUmMgOKFCgqtv++I9tyUiSnXqQZvgWzidtdaeAFfa2d7bNL3mOANnO5tkWfNeEpuma38kLgLqBtOa\/cb\/wng7CvsM8q0xTaMii8a6o+w1wH5+toF3IGJYaNy8mrKrzKkcmLT8KqEmVlivQNMy3RNiI+QERRDcm8vHeuNOozLLx7xiyI+PROjMyjClTJUAWUd03R1AGuepc\/RPwP0jJdtfe62AQ56CL4MvhK7N53iFrRNcwrtLB0jc8QpioE6pLDnTFwoNfgsUb\/gjkn+7MdeRud0WBQjmZrGKFFrwwsmj\/0DJMj1E0MrsB5MFSTv4EaESbjQTJbJjzsqK\/O59x6UiptpMpLbX89H6bAnS+6ARzRM3ntjdxut\/w9sUWIdqpB0tJ4T8RdSkiOdeZ11c5LLiajNBmOV\/OHZfS4GqbTZLZOH6eTdJgsBw\/jxWo8n4n4rYIMnrTBmoJj1O4PjvfQZ+1KmWy\/vNpUIu4IrSzudMIoWzSqOJl0GQRFF4g2Gv1m8vDjH10M11bT9E6i\/3Ko9\/U7l9eEqhLx+fzlXwrgFeQ=","xmlFileCreated":1543258276},"82":{"desc":"eJxFjEEKgDAMBL+yL\/AT+pFYigZDEpoU8fe2eBD2MgyzG4cLPQHC3jNNkQbWqC0hrFdMXk2TSsYQoLGWXKQu2P7YzbuDROxmPfBYn2E5zaIiz4ryfSwvPsEpcQ==","element":"contact","enabled":"1","extension_id":"460","folder":"editors-xtd","name":"Button - Contact","path":"\/plugins\/editors-xtd\/contact","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/contact\/contact.xml","xmlFileContents":"eJydU8Fu2zAMPa9fweq0HSynHbYVqK2uc4wgQ5oETQr0Zqg266iQJUOWm+TvRyd22qHYZSeTeo8P5CMd3ewqDa\/oGmVNzC74iAGa3BbKlDFr\/XNwxW7EWYQ7j6bjvHG\/8h8M\/L7GmNW6LZVhUDrb1jHDQnnrmmDnCwYV+o0tSKsunSyQibNPkZEVilqX2TtmllvjZe6j8IASS7ZU6cRvaystz2Hp7At2eP9OjNyh9NTMWHoUi9zbJ3RwObr4HoV\/QR3V1nunyo0XyRDB5+QLsUffIOiKrmBRo4GVbV2OcCe9p0k53GoNB3oDDht0r1hwkj\/JkbZWOZmDYjJ\/gAkadFLDsn2iZ5gdocE1uATrQFNP7hoaRJhNk3S+Srnf0WCDzmn2tJJKC1lUyvx8OdjArSsHB47oifzgtNhut\/wjsUOI1vcgaHF8FIVDSkiBTe5U3fkllrNJlo6n68X9Knhcj7NkMV\/fJuvs8W6WjdNVcj9drqeLeRS+LyKNZ6WxoeAYdTuE41nErN8sE33A600dhQOtKw6H6khLU7ay7KWGDLykc0QTTH4xcfjwf5wPV0aRk33d\/4o0++aD0FtCvUXh6Y8QfwCyTB0j","xmlFileCreated":1543258276},"83":{"desc":"eJw1y8kNgDAMBMBWtgKqoYEIL8SSIYftR7qHD+\/R7JXw5cEbp9LE0S0vfRC1BNQxOVInBdEg6t3K+ow40qP9aXsBus4adQ==","element":"fields","enabled":"1","extension_id":"461","folder":"system","name":"System - Fields","path":"\/plugins\/system\/fields","title":"","type":"plugin","xmlFile":"\/plugins\/system\/fields\/fields.xml","xmlFileContents":"eJyVUk2P0zAQPbO\/YvAJDk26i4CVcLxAG6qitFuRXQlOkUmmqVeOHTnOtv33TJKmC+qJk+fjvef54neHSsMzukZZE7HrYMoATW4LZcqItX47uWVwJ644HjyaDgT+WGPEat2WyrAX6rvgY0cunW3riDXHxmPFoEK\/swUp1aWTBTJx9YobWaGodZkNoGyrUBcND\/s45WVLHCe+W1tp+Ro2zj5h7nl4ihMidyg9\/TqXHsVKunwHN9PrDzz8J9EBbX10qtx5MRsteDN7S+jpe5h0pFu4r9FAaluXI6yk99RQAF+0hh7egMMG3TMWAcmf5Uhbq5wmgmKxfoQFGnRSw6b9TWFIhtQ4HLgB60BTTe4TNIiQLGfxOo0Df6C2Rp1z53EllRayqJT5\/NQPIbCuHPsfsmfwo9Niv98Hl8AuQ7BTDaLfDw9HlzIFNrlTdTcvsUkWWforfYhX2bdlnMzT7OcqyeZxOvux3Dws79c8\/BtO7K3S2JAxWN3uYLiJiA0LZWJ4g3pX83AEddRw5HItTdnK8iQ0euAlHR+ayeIrE\/0TXJxLoIyi2Z0Y\/08n70LixaF6eHg+efEHDyIRhg==","xmlFileCreated":1543258276},"84":{"desc":"eJw1y7ENgDAMBMBVvqNjGhawkgciBTuKHUG2h4b2pNvO4mh1HEVRGY5pA6lTglDe2AtrdtiOmI1YklRqlr7gC6ITfILqxdRxn+xEGh52\/VE+8dGa9WBeX71BKJk=","element":"calendar","enabled":"1","extension_id":"462","folder":"fields","name":"Fields - Calendar","path":"\/plugins\/fields\/calendar","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/calendar\/calendar.xml","xmlFileContents":"eJydU81v0zAUP7O\/4uETHJp0Q8AkHI\/Shqoo7aqVSdwik7ymnhzbsp21\/e9xkqYrGidOec+\/D\/t9hN4dagnPaJ3QKiHX0ZgAqkKXQlUJafx2dEvgjl1RPHhULQn80WBCjGwqociL9EP0uRVXVjcmIVuBsnQEavQ7XQYnU1leImFXb6jiNTIjq7wn5QWXqEpuadwhgcGboLLsh9a15G9hbfUTFp7Gp\/PAKCxyH+6dcY9syW2xg5vx9Sca\/wW0RG2OVlQ7z6ZDBO+m7wN7\/BFGregW7g0q2OjGFghL7n0oKYKJlNDRHVh0aJ+xjIL92S54S1GEniCbrx5hjgotl7BufodjyHpoaA\/cgLYgw5vsF3CIkC2m6WqTRv4Qyhp8zpWnNReS8bIW6utT14RI22qov0fP5Ecr2X6\/j14TWyTQTm9g3YRoPKQBKdEVVpi2X2ydzfPvizSbbfLpJEtXs8lD\/muZ5bN0M31YrH8u7lc0vhQE\/VZIdCHoo3Z60O9FQoahEjZEkdkZGg\/EXqVliZYZbnntAtanF4ivjbw47+Wu6z1XVcOr0\/VDBp6HtUU1mn8jrPtE\/1i0SCgRun7S\/I+BO7pXJi9JeBONzz8M+wN\/ViWh","xmlFileCreated":1543258276},"85":{"desc":"eJw1y0EOgCAMBMCv7M2br\/EDiKsQsSW0RPm9XrxOMkvKhlr6kQWFbhjaERuDE8Ibe2bZDLrDRyWmmBjPVR\/ahK8EGeDjFMsqhjuxEbGb6\/XX8In1WrU5t\/kFGBYpfg==","element":"checkboxes","enabled":"1","extension_id":"463","folder":"fields","name":"Fields - Checkboxes","path":"\/plugins\/fields\/checkboxes","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/checkboxes\/checkboxes.xml","xmlFileContents":"eJytVU1z0zAQPae\/QugEh9hpGaAzOCppakIgX9NQpjePYm8cFdnySHKb8OuRLDlJpx2mMFwSad\/b1e7TUxJdbAuO7kEqJso+Pg16GEGZioyVeR\/Xet09x+iCnESw1VBaEtK7Cvq44nXOSnxIfRt8sMm5FHXVx2sGPFMYFaA3IjOVqlzSDDA56UQlLYBUPE8cKUk3kP5ciS2oKGwww6G1yZPkqxAFp6\/QQoo7SHUU+rhhpBKoNidfUQ1kSmW6QWe90\/dR+AiwRFHtJMs3mgzbFXo9fGPYvXeoa5PO0byCEi1FLVNAU6q1GSpAA85RQ1dIggJ5D1lgyu\/LmdqcpUYVIKPZDRpBCZJytKhXJowmDmoFQmdISMRNT\/IjUgBoMh7Gs2Uc6K0Zq62znzwuKOOEZgUrP901IgRC5u38Dt2TbyQnDw8PwVOiRQzN90CaO4rCdmuQDFQqWWX1IovJKPk8jidXy2T4JR5+u5zfxsvkdjpJruLl8Hq8+D6ez6LwOMVUWDMOyizcyt4fct7o48PFYnJYB9WmisKW7DIFz0CSikpaGBP47RGii4ofxV26am6AlnlNc99Cu0OaGvtC2R1dYtJ8Bc8aLmAlM+r7rH8roXZPyxw2ylmwXLPci2TzkR3dPKJmYPso9ghoj62oYqmDPNYsOw4Vjf4Ku5h7kqperYUsfIzTFfA+fv5SF4PrwXSZzJsrXSaTwWU88XlH1\/vCbOuO\/aE7Ues+9k607QRN74FvLpBQmedJVxy6zadPZKk9jjOlfaCouWYVN2NpWbcsp4Z1hSzQhmUZlB73otkCiQbjFvPQVFKIjHKM3Jme6Ws80rRV1X7iNuRE1eaHbx\/6G01ng2n8SNhOR7FfpuLbXhsIyckfmrmnvP5v3fwYTG5e0I5rJrT6eueFTWfOoWFr0cbJfte4vTV4FO7\/J8hv7BPwfQ==","xmlFileCreated":1543258276},"86":{"desc":"eJw1y8ENgCAQRNFW5ubNamyA4CAkuEvYJUr3cvH68\/6Ri6HVcRVBpRumDsTO4ITwQSqsp0ETfDZii1q1b1g6yARfp1hRMTyZnYjDXO\/\/CqvYaE2789w\/RYYnfg==","element":"color","enabled":"1","extension_id":"464","folder":"fields","name":"Fields - Colour","path":"\/plugins\/fields\/color","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/color\/color.xml","xmlFileContents":"eJyVU0uP0zAQPrO\/YvAJDk26i4CVcLxAW6qi9KEtK3GLTDJNvXJsy3G27b9nkjRdYE+c7JnvEc8j\/O5YaXhCXytrEnYdjRmgyW2hTJmwJuxGtwzuxBXHY0DTkiCcHCbM6aZUhj1L30UfW3HpbeMStlOoi5pBhWFvC3JypZcFMnH1ihtZoXC6zHpSllttPY+7NMGyIYkX362ttHwNG28fMQ88PueJkXuUgT46lQHFUvp8Dzfj6w88\/gtoidadvCr3QUyGG7yZvCX2+D2MWtEtrB0a2NrG5whLGQLVE8EXraGj1+CxRv+ERUT2Fzvy1iqnhqCYrx5gjga91LBpflEa0h4aegM3YD1oepP\/BDUipIvJbLWdReFIZQ0+l8pnlVRayKJS5vNj14TI+nKov0cv5AevxeFwiF4SW4Ro5zeIbjw8HkJCCqxzr1zbL7FJ59m3xSydbrPJOl3fZz+XaTadbSf3i82PxXrF4z\/ZJN4pjTVd+ls7Oug3ImHdOJnojsjtHY8HSs+3ukAvQuU0IX1AhvHgyLU0ZSPLs\/0QQZC0kGhG869MdEf07wpFyijq51nw3+r6VL9weA7oNTy+\/ATiNyqgFqQ=","xmlFileCreated":1543258276},"87":{"desc":"eJw1y7ENgDAMRNFVrqNjGhaIyAUsBTuKHUG2h4b26\/3tFEer4xBFZTimDeydKQjljSKs2WEFMRuxMEtYX\/DxpBN8gupi6rhPdmIfHnb9W\/qKj9asB\/P6Am8pJ+Y=","element":"editor","enabled":"1","extension_id":"465","folder":"fields","name":"Fields - Editor","path":"\/plugins\/fields\/editor","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/editor\/editor.xml","xmlFileContents":"eJydVk1v4zYQPSe\/ghVQoD1YdlJku9jK2jq2YiuQP2ApyPYkMBYtc0GRAknFTn99RyLlOBvHzeZkcua94bzhDGXv665g6JFIRQXvOxduz0GEr0RGed53Kr3ufHbQV\/\/cIztNeA1C+qkkfadkVU6580z9w\/2zJudSVGXfWVPCMuWgguiNyCBSmUucEcc\/P\/M4Lohfsjw1oJRkVAvpdRs7+HEFHOnfClEw\/AtaSPGdrLTXtXZArCTBGk4dYU38KZarDbrsXXzyui8cNVCUT5LmG+0P2xX6bfg7oHtXqFOTPqN5STiKRSVXBE2x1iDIRQPGUANXSBJF5CPJXAi\/DwexGV1BRYg\/nt2hMeFEYoYW1QOYUWRcbXHQJRISMchJ\/oUUISgKh8EsDly9A1ltnL3yoMCU+TgrKP\/7e1MEV8i81W+8e\/CdZP52u3VfA2sPwGwOfnM\/XrfdgicjaiVpWdfLX0Tj9CYMolGcBqMwmS\/Tb9MoHQXxcBkuknA+87qHcGCvKSMKFmZV3x0yPdF3zIU6vvl1y03pdVuQYQiWEemXWOJCgc9sDzy6KNmB3dBVU3XM8wrn9uh2hzSGdiW8M76GY+sf91WDuZRTqLZl\/DxdPalXIZ43yrQbX9PcFqXmoloyDEsjtG7+vYdo63vAiq6My\/qa5Zn1VloLrhxjM6MHg0SFtTD8QFjfeX19i8FyMI3TeDK\/T6\/vkmQ+i9NocB1Elnhwm++l191g2SuGlYLsNO80A4\/2q84TUVzsD1njium+07MGuEYYgr5DuSY5kdZqxJ95okkHPWJWgcwLx7\/9J4i9rmh77gioB6DZ\/CWm7hYoo3\/+Rk03FB6iw4KavlXvLGlbjkk4Ct4u6e04ml8PojQOomCYpPF8GqTzZpLithZNd7fTojo7nVlPATWjJYPMtKxsqt035Wxppjcv9Gh4rN8p5j4cJZMPNIbhHXTE\/qover1frU3RfyGbq\/8TsCH1k\/pRBZMgHE+SD0iwxGMaLq965e7nRJjOfiGCUfVeETdhlATLD4iwxBOj+aO226EoSsEJ1xPCSiK\/fDGpJ88lh9miGXyt+o4ZK3VyTo+N4I8YibeAisLrNmGb\/nJwf5qo8JpsdMGOsuPBTTBJptHpECcFHwubBN+SN16U5zU84M07b3fNt6B9\/r3u\/t+S\/x\/DVMs2","xmlFileCreated":1543258276},"88":{"desc":"eJw1y7ENgDAMBMBVvqNjGhaI4CGWgh3FjkK2h4b2pNuyOGrplygKwzGtY29MQSgHTmE5HHYiZiUWudPFIh4LvpF0gk9QXUwdI7MRe\/ew+5\/pE++1Wgse6wvuryke","element":"imagelist","enabled":"1","extension_id":"466","folder":"fields","name":"Fields - Imagelist","path":"\/plugins\/fields\/imagelist","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/imagelist\/imagelist.xml","xmlFileContents":"eJydVV1v2zoMfW5\/ha6ftofY6T7uHXAdbVnqBRmcNqhbYHsyVJtxNMiSIclts18\/WrK9ZF\/o+hSJ55AhD0k5fvtQC3IH2nAlZ8FZOA0IyEKVXFazoLXbyZuAvKWnMTxYkB2J2H0Ds6ARbcVl8N31Zfhf51xp1TazYMtBlCYgNdidKjFSU2lWQkBPT2LJaqCNqHJPynnNKhDc2DhyEFJYi26aflSqFuwfstHqCxSI93ZkFBqYxT8+ZxbomuliR15Mz\/6NoyOgI6pmr3m1s3QxnMizxXNkT1+TSef0hlw2IEmmWl0AWTNrsaaQzIUgjm6IBgP6DsoQw4\/hMLbgBYoCdHlxQ5YgQTNBNu0tmknqoUEf8oIoTQTmpP8nBoCkq0VykSWhfcCyhjhj5UnNuKCsrLl898WJECpdDfV7dCTfaEHv7+\/Dn4kdgrQ+B+paFEfDFZESTKF50+lFN+ky\/7BK0vMsX63nyyRdZdf5p3WanyfZ4mq1uV5dXsTRoQcG2HIBBg\/+1LWP+MmYBWNbAzoew2bXxNFA9X5KlKBpwzSrDWL+eoDYuhEHdu9unPxMVi1G9gkMN2IZji7IyfJ9QN1P+KthC7nkqHzv9KQIZm9+ivL9Yvz0yS2veoE6d9IVjuvjyu3WYUTA9tgtM7zwUI+544lHS65xFZTeB97q19HL49T2ZsFuQcyCXzZ1M7+ar7P8fHWVLK4vrz7n6fx9kvaOBw1+rHs3IIP3kF3ff9Pbd7yEXCqJqVrdwqG1hC1rhT0CMEiLQ3p3TB+ZUW\/wGp3EyqVL7phooUNpFEdqmNGOEDkZ6elvNK0xKm8EHEmK7xVXj1dzfZNerzZp8jQxR+8DLQvBjMFxsHLiXlUyniZ7MFL9qMq0N+B+4DODDZAWKtB\/1OosoB8\/J9mxXD+Spki6uPw7SV33c1fCkaoWPyQMn+jHC+sM+SKdZ9nTtD0McCCv4V8xn1e9apFfxWjYRbey\/c2t9bDJcTR+Cuk3g1s02A==","xmlFileCreated":1543258276},"89":{"desc":"eJw1y7ENgDAMRNFVrkvHNCwQwQGWgh3FjiDbk4b26\/31Ekct\/RRFYTiGdWyNOQjlg0NYdocdiFGJJBo82RKmzzrAN6gupo7nYiO27mH3\/+VZvNdqLbgvH5lNKE0=","element":"integer","enabled":"1","extension_id":"467","folder":"fields","name":"Fields - Integer","path":"\/plugins\/fields\/integer","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/integer\/integer.xml","xmlFileContents":"eJylVV1v2jAUfW5\/heen7YEEOm2rtOCO0hRRBYoIlbanyCSX4MpxIttpy379nDgJVP1Y1T5h33uOc8+518Y7e8g4ugOpWC6GeOD0MQIR5wkT6RCXetM7xeiMHHvwoEFUIKR3BQxxwcuUCbynfnV+VORU5mUxxBsGPFEYZaC3eWJOKlJJE8Dk+MgTNANS8DSyoIgJDSlIz60TBkBLQ5LkKs8zTj+hhcxvIdae28QNIpZAtfnsBdVAZlTGW3TSH3z33EeJCpgXO8nSrSbjdoU+j78YdP8b6lWkU3RdgEBhXsoY0IxqbRQ5aMQ5quEKSVAg7yBxzPHdceZszmJjCZDJ\/AZNQICkHC3KtQmjwKZad9AJyiXipib5EykAFEzH\/jz0Hf1gZLXndMr9jDJOaJIx8eu2NsHJZdrqt9kOfCM5ub+\/d54Cq4yBNTWQukGe225NJgEVS1ZUfpFFMIkup35wEUbT+cqf+Mvo9yyILvxwvJwuVtPruece4g19wzgos7CrqnnITsUQNy3FpFk4xbbw3BZmOTlPQJKCSpopk7Pbg4zOCn4Qt3RVG09FWtK0+Xi7Q5qakQXRm5xjUv84T4fMYYIZxxvKO\/hqp56csd8oO3Niw9LGmIqMKtHmytRSqyvQZUA3uTVVLLapJlcvj2w2K7lmBQdsg\/YGmvvE8ibC6Rr4ED\/TxMVoOZqF0ewmWE0XgR8Fo3M\/aFgH\/XwTtxqGhhpzqpQpW4tefeNRt+rtQIm8+8KGmtqHuN8ETA\/NJdgPiI1a3UdeXteC7igvjcABJld\/\/NBz83bkngH1DWh+\/RhTjYpxkBy\/YOeGSaUfeSnKbN1V818zL6fLcPUeJy3xwMbOn8Gr\/ij21xT5ze7cF3WZnnxEVjB6n6qa96yo\/uttf6MspaH4gKxw5S\/eI6vmfbxX+3k0t71+FJpd\/XC0b4Xndn+w5B\/u6kG1","xmlFileCreated":1543258276},"90":{"desc":"eJw1y7ENgDAMRNFVrqNjGhaI4CCWgh3FjkK2h4b26\/0ti6OWfomiMBzTOvbGFIRy4BSWw2EnYlZiKeKx4MNJJ\/gE1cXUMTIbsXcPu\/8pfcV7rdaCx\/oCHVonGw==","element":"list","enabled":"1","extension_id":"468","folder":"fields","name":"Fields - List","path":"\/plugins\/fields\/list","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/list\/list.xml","xmlFileContents":"eJylVVFv0zAQfu5+hfETPDTphoBJJIGylalT2lV0Q\/AUuck19eTYke1sK7+ec+J06xhiEy+ufffd5fzdd2706a4S5Aa04UrG9DAYUQIyVwWXZUwbux4eU\/IpOYjgzoJ0IGK3NcS0Fk3JJb0PfRt8cMGlVk0d0zUHURhKKrAbVWCmutSsAJocDCLJKkhqUWYdKBPc2ChsrehlDUbo5FypSrBXZKHVNeTo93ZE5BqYxW+eMgvJjOl8Q45Gh++jcM\/hgKreal5ubHLS78jrkzeIHr0jQxd0TC5qkGSpGp0DmTFr8ToBGQtBWrghGgzoGygCTL9Lh7kFz5EPSM7mV+QMJGgmyKJZoZmknaunhhwRpYnAmvRHYgBIOj2ZzJeTwN7htfo8u5tPKsZFwoqKy8\/XLQmB0mV\/\/867A19pkdze3gZ\/Ap0HYb6GpO1OFPZH9BRgcs1rx1eySM+yr9NJerrM0unyMvsxS7PTyfLk23RxOb2YR+FDMMauuQCDm27nOkc6PcTUNZMmbg3qTR2FPcCFhX1cJJgsG1b6JP2JWIaiAzk8+0KT9id4JJOAS46cefxLg83W\/JHg\/mA6ycg1L\/3VXCRxxaPcmWaVcfLdecB634oZnncu72u3g85bNcLyWgDtjN304Cxw5S2CrUDE9HEPFuNv49kym12ll9NFOsnS8ZdJ6kMetOPfga6RPi4XzBgs2MphO6dktxtuwUi1S79mWHVMR96AfUP1xpRLCyVob+1uPIhUWwi5YaLBqx3S5PznZBmFqpfLE6ARguYX+xgnD+QuOfgLkR3W7PFomtVa6epZTF60Wl6+mMg+7gGPgm1Vg\/z4sXMlBG29gS8o0FDjW8RWAobt6gN5rvoZ6Qy9OmJqdQOPiHWZyIYXBUjv94pzCTILVe1eFZNVqmCCku6bHulz7PHYM+lW2ps6Ii2+7zvT83icj2f7qhwMDP+Fud72shmEvplPl9Fq4f\/r+D5Or55RyMBrDDl9pLf7Pc50O\/r+1D4P\/YsQhbu\/wOQ3LWslvw==","xmlFileCreated":1543258276},"91":{"desc":"eJw1y7ENgDAMRNFVrqNjGhaIyAUsBTuKHUG2h4b26\/3tFEer4xBFZTimDeydKQjljSKs2WEFMRuxXMySFnw66QSfoLqYOu6TndiHh13\/lb7iozXrwby+PtEnXw==","element":"media","enabled":"1","extension_id":"469","folder":"fields","name":"Fields - Media","path":"\/plugins\/fields\/media","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/media\/media.xml","xmlFileContents":"eJyVVdtymzAQfU6+QuWpfQg46S0zxaSOTT1k8GVsp5cnRoE1VkYgRhJ20q\/vIsCXuGmTJ6Tdc1Y6exHu1UPGyRqkYiLvWud2xyKQxyJhedq1Sr08u7TIlXfqwoOGvAIR\/VhA1yp4mbLc2lHf258rcipFWXStJQOeKItkoFciwUhFKmkClnd64uY0A6\/gaVSDogwSRl3HmNFNS6RI70aIjNM3ZCrFPcTadRo7ImIJVOOhA6rBG1EZr8hF5\/yT6xw4KqAoHiVLV9rrtyvytv8O0Z2P5KwiXZJJATmZi1LGQEZUa9Rjkx7nxMAVkaBAriGxMfw2HMbmLMaEgDcc35Ih5CApJ9PyDs0krF1tbsgFEZJwvJP8QhQACYO+P577tn5AWW2crXI\/o4x7NMlY\/vXeJMEWMm31194t+FZyb7PZ2MfAyoOw5g6eKY\/rtFv0JKBiyYoqX940HEbfAj8czKORPwh60c9RGA38eX8WTBfBZOw6+2gkLxkHhYt6VZWO1B3RtUw5Lc987GJVuE4LqfGCJyC9gkqaKfTV2z2Pzgq+Z6\/pyqSc5mlJ0+bgdkc0xVaF\/Gx4bXnmYz9tLpvlDDPdEF7NVo\/qKMJuo+pOy5csbRJSUUklGMfEyKzafusB3fjuqGJx7Wp8ZnlSexMmse2FfLRqaz12dVo4U7oxc3oHvGsdFXDam\/VG82gQzPz+YjL7FYW9az9sSHvFfAm1aoSW2d6qa7GsEt\/YVyyBKBc5XlHLEhorYkvst\/WB1fFOn5FcSFgz2BwIfrnU6cz\/Hvg\/Xi+0Je7JjDlVCiuk8zPzoG3DLWnJNaoRgmvWmusSnrjCHETWlJewwxwP15NzF5NJuAimriPa8fpbtCp\/\/w0VjMNg7P870pJyhaFuxpNDXDVoWJBnq2PqHZnMHFRI46+B4sP7sioFo97Qj\/phbz5\/faX2yXvVUuw33uNDZ9tfOzU4bWYom50Z3HZWXWf7U\/P+AO0MJw4=","xmlFileCreated":1543258276},"92":{"desc":"eJw1y7ENgDAMRNFVrqNjGhaIyAUsBTuKHUG2h4b26\/3tFEer4xBFZTimDeydKQjljSKs2WEFMRux9JTFFnw66QSfoLqYOu6TndiHh13\/lb7iozXrwby+QhInbg==","element":"radio","enabled":"1","extension_id":"470","folder":"fields","name":"Fields - Radio","path":"\/plugins\/fields\/radio","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/radio\/radio.xml","xmlFileContents":"eJytVF1v0zAUfd5+hfETPDTpNgGTSD26tlRF6YdWhniL3OQ29eTEke1sK78ef6XrmARD4iWJ7zn3+t7j4yRXjxVH9yAVE\/UAn0V9jKDORcHqcoBbve1dYnRFThN41FBbEtL7Bga44W3JavyUehF9tMmlFG0zwFsGvFAYVaB3ojCVmlLSAjA5PUlqWgFpeJl5UmYAJpLYhQ1MW5MiyVchKk7foJUUd5DrJA5xw8glUG02HVMNZE5lvkPn\/bMPSfwMsETR7CUrd5qMui\/0dvTOsPvvUc8mXaJlAzVai1bmgOZUazNPhIacI0dXSIICeQ9FZMofypnanOVGECDTxS2aQg2ScrRqNyaMUg912qBzJCTipif5CSkAlM5Gk8V6EulHM1ZX5zD5pKKME1pUrP5850SIhCy7+T16IN9KTh4eHqKXRIsYWuiBuONJ4m5pkAJULllj9SKrdJp9mU3S8Tq7GY5ny+zHPM3Gk\/XoZrb6NlsukviYbZK3jIMyH\/7LHh3yjhhgd5yYuFfU7Jok7iieL3gBkjRU0koZzC+PEF01\/Cju05WTnNZlS8uwcbdCmhqrQt2bXmPiXtHv5opYzYzSIeGfs9VevajwtFDeafWWlUEQm4rswOaauDGt7Q8I6IBtqGK5hwLmPk88KpzWCvuYv3Sq3WyFrEKM0w3wAX5xdqvhzXC+zpbu5NZZOryepCHl6BT\/nmjP\/7DVXrR6gIPNbBOR6zgKLUUSGnP36IZDzz1DIsvtTpwpHQJVyzVruBlGy7ZjeQ2sA2SFdqwooA54kMoWyDQYZ5hbpLJKFJRj5PcMzFDjmZKdlvaJu5CXUpsf2iH0SiUXw\/nkmZwnJ4r9NMUu+l0gJqd\/6OOe8vZ\/NPJ9mN6+ohPfR2xVDS6LXVPejXFnR+fasHLO7sycxIe\/PvkF+63e\/Q==","xmlFileCreated":1543258276},"93":{"desc":"eJw1y8ENgCAQRNFW5ubNamyA6CAkuIvsEqR7vXj9eX9L2VBLP7Og0A1TO\/bG4IRwIGaWw6ARPiux2F0WfDbIBB+nWFYxjMRG7N1cr\/8JX7Feqzbnsb7zlSav","element":"sql","enabled":"1","extension_id":"471","folder":"fields","name":"Fields - SQL","path":"\/plugins\/fields\/sql","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/sql\/sql.xml","xmlFileContents":"eJyVVE1T2zAQPcOvUHVqD7EDnbbM1BENwc2EcUIgZKacPIq9ccTIlpFkQv59158k0HbKJZH2vV3r7T7JO39OJXkCbYTKBvTE6VMCWaRikSUDWth174ySc3bswbOFrCQRu8thQHNZJCKjL6mfnW9lcqJVkQ\/oWoCMDSUp2I2KsVKeaB4DZcdHXsZTYLlMwpoUmkfpuVUQQV5ggmZXSqWSfyBzrR4gsp7bxJERaeAWP3nJLbAp19GGnPZPvnruAVASVb7TItlYNmpX5OPoE7L7X0ivTDoj1zlkZKEKHQGZcmtRjUOGUpKKbogGA\/oJYgfLd+WwthQRtgPYeLYkY8hAc0nmxQrDJKihtjPklChNJJ5JfycGgASTkT9b+I59RlltnU65n3IhGY9Tkf14qJrgKJ20+mu0Iy+1ZNvt1nlLLBGkNWdg1XA8t90iEoOJtMjLfrF5MA5\/TvzgchEuboLw1zQIL\/3F6HYyv5tczzx3n4upayHB4KJelYMjtRsGFEdJGf44+Sb33BauuUrGoFnONU8NYvV2D7FpLvfidbqpms2zpOBJ89F2RyxHi0LWG19QVv05h6ZyRCawww39nblmZ97kv2xM7a9sLZKmEWUiKcXi1agkllbvELANtuJGRDXUYNXyqEYfC9A7Wkfqa2bx3nH0dROUfAVyQF8NbD68HU4X4c3Sv70Pg+GFHzT0vcH9O6kcd5Oj1dbgQ9BvtjgEdO6Aar5tCfBYCA14qa0uoA667PgvktJCWpFLOFCFT4FQ\/yNpugzuJvPAf6+qLm9PWCS5QWUrm\/WqR4p0q94OTKa66muOZx7Q1x0QmYUEdBOtR3jkqeoc5InLAoWdUHZ17y88V7W35Q+kPpJm14ec0u3YudozbmuaylvNrvJfaznP7d5j9htCz8iI","xmlFileCreated":1543258276},"94":{"desc":"eJw1i0EOgCAMBL+yN2++xg8QXIQEW0JLlN\/LxdtkMnPkYmh1XEVQ6YapA7EzOCF8kArradAEn43YnK9vWHGQicUUKyqGJ7MTcZjr\/U9hGRutaXee+wcfXick","element":"text","enabled":"1","extension_id":"472","folder":"fields","name":"Fields - Text","path":"\/plugins\/fields\/text","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/text\/text.xml","xmlFileContents":"eJyVVU1v2zgQPSe\/gsvT7iFS2sV2i67MVnEUx4HsGLaC5mYw0lhmQVECSeXj33coSo6bel30YpMz743m440UfX6uJHkEbUStRvRdcE4JqLwuhCpHtLWbs4+UfGanETxbUA5E7EsDI9rIthSKvlL\/Dv515FLXbTOiGwGyMJRUYLd1gZGaUvMCKDs9iRSvgDWyXHvQ2mLsKOys6OUtMjS7qetK8j\/IQtffIEd\/b0dEroFbfOYlt8BmXOdb8v783Yco\/MHhgHXzokW5tWw8nMif478Qff4POXOkj+S2AUVWdatzIDNuLZYTkFhK0sEN0WBAP0IRYPhdOIwtRY79ADaZ35EJKNBckkX7gGaSetfQGvKe1JpIzEn\/RwwASafjZL5KAuvKHuLsKk8qLiTjRSXUl29dE4Jal0P93rsD32nJnp6egp+BzoOwPgfWTScKhyt6CjC5Fo3rF1ukk\/XVNEkvV+ssuc\/W97N0fZmsxsvpIpvezqNwH4zcjZBg8OBPbnLE62FE3TApc79Bs22icAB4dC0L0KzhmlcGff6657FVI\/fsnm66fnNVtrzsHzvciOUoU1BnkwvKur\/gjbACoQR2ucf\/Ltm8mJ8CvF6MF5naiLJvhmMSVy4uSFekE\/zOA7b3PXAjcu\/qfd3xxHuxZtQK9Sa\/bVIY2xskfwA5om9HtoiX8WyFpjRLlus0vkjSnrA3u1\/R3Mx7Vi65MZipVWfdSu+CbXgr7YjejOuqqRUoew2yAf3pk087c\/P32EcuRYGyH9G6e7rp7b7uk8hbCcJaxJxTdjO\/jcJ6UNkBjOZPiEqnF0PCffrL+OtxouEb2NpKHmSv4qvkOpulx0McLfhQWNff4yG5VG11kBun87vZcbJQFkqUySH6dJ4lk2R5PMBG1vxw5lfpbfyL1C0c7mWWvGmjW2HUNzv9H7FX\/BlfEKXd\/qB37MvDbgWOK34W36fJfJJd\/7boX5l7uvdDfW1vZw39FofDGnfb3t+6N8LwEojC3XeSfQeEl0yS","xmlFileCreated":1543258276},"95":{"desc":"eJw1i0EOgCAMBL+yN2++xg8QXIQEW0JLlN\/LxeNkZo5cDK2Oqwgq3TB1IHYGJ4QPUmE9DZrgsxGb8\/Ww9IY1BJlYTLGiYngyOxGHud7\/uFrYaE2789w\/xf0ovQ==","element":"textarea","enabled":"1","extension_id":"473","folder":"fields","name":"Fields - Textarea","path":"\/plugins\/fields\/textarea","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/textarea\/textarea.xml","xmlFileContents":"eJy1Vk1v2zgQPSe\/gtVp9xDJ7aLbopXVVRzFcSB\/wFbQ3AxGGsssKFIgqTjZX9+RKDlOqrqLFHsyOfPeeN7McGz\/y0PByT0ozaQYOm\/dgUNApDJjIh86ldmcfXTIl+DUhwcDogYR81jC0Cl5lTPhPFH\/cj\/U5FzJqhw6GwY80w4pwGxlhpHKXNEMnOD0xBe0gKDk+dqC1gZjUwXU9xoPImiFLBVcS1lw+oYslPwGqfG91o6IFPEGv\/eCGgimVKVb8m7w9m\/fe+aogbJ8VCzfmmDUncgfoz8RPXhPzmrSRzIvQZCVrFQKZEqNQUkuCTknDVwTBRrUPWQuht+Hw9icpVgTCMazGzIGAYpysqju0Exi6+rKQ94RqQjHnNRnogFIPBlFs1XkmgeU1cXZK48KynhAs4KJf741RXClyjv91rsH3yge7HY790dg7UFYm0PQdMj3uit6MtCpYmVdr2ARj9eXkyi+WK2T6DYJl1G4vp3G64toNVpOFslkPvO9QwLyN4yDxoM91d0jdi6GTtdUJ+hObrktfa8DWpbkGaigpIoWGn32euAxRckP7Jaum9pTkVc0b7++uxFDcWxBnI3PnaD5cHsGzWWCYdVbzmsC6Ef9Q5Cni7aDJzYsb4tTs0ktGx9OI7Z+CHsPmNZ3RzVLrav1NccT61Vypx1rsG9QVMUdqNbE6R3wodPXxkW4DKer9XL+dbWOw\/MobikH3fw1sZ6DPW9DK25wXQxaC7YFR3voMGEg36ek2b+Y5Xt784LTn+hKJf8tXaN5\/DpdDfH\/01XQB5z13Gx\/R9w0vI2j2Ti5epXCJ\/aBzF5RP5dh4c80cKbNf1ZwOYmTaPmq9FvqQe4pp1rjQzHirPmledm565EsSilAmCvgJahPn2z6Cb7cFntPOctwEw8d2WTQzZ59die+tRKEVYgZOMH1bO57slt6PRhFd4iKJ+ddwt27Cb8eJ2q6ga0peC97FV5GV8k0Ph7iqOC+sHWNj4ekHGe0lxvGs5vpcXI3VH30ySyJxtHyeIANl7Q\/88t4Hv4idQP9tUyiF2Wsf0lwzu0W9ro13Gzr9tZs9G6J+97+\/0\/wHb5OyIQ=","xmlFileCreated":1543258276},"96":{"desc":"eJw1y7ENgDAMRNFVrqNjEioEA0ThgEjBjmJHkO2hof16fzmToeR2JEGmG7o2xMrghPDGnpg3g+7wXohhnacBnw3SwccpllQM98lKxGau1\/+Er1grRatzG1\/fPyZS","element":"url","enabled":"1","extension_id":"474","folder":"fields","name":"Fields - URL","path":"\/plugins\/fields\/url","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/url\/url.xml","xmlFileContents":"eJyVVU1T2zAQPcOvUHVqD7EDnbbM1BENwUAYJ2Ti0GlPHuFsHHVkyyPJgfz7rj9JykDKJZH2vbe29u3K3vlTKskGtBEqG9ATp08JZLFaiiwZ0MKuemeUnLNjD54sZCWJ2G0OA5rLIhEZfZZ+dr6V4kSrIh\/QlQC5NJSkYNdqiZnyRPMlUHZ85GU8BZbLJKpJUaGl51ZBBHmBAs1ulUol\/0BmWv2B2HpuE0dGrIFbfOQlt8AmXMdrcto\/+eq5e0BJVPlWi2Rt2ahdkY+jT8jufyG9UnRG7nLISKgKHQOZcGvxNA4ZSkkquiEaDOgNLB1M36XD3FLEWA5g19N7cg0ZaC7JrHjAMAlqqK0MOSVKE4nvpL8TA0CC8cifhr5jn\/BYbZ7u5H7KhWR8mYrsx5+qCI7SSXv+Gu3I91qyx8dH5yWxRJDWvAOrzPHcdovIEkysRV7Wi82C6+hq7AeXYXQ\/D6JfkyC69MPRfDxbjO+mnrvLRelKSDC4qFelcaTuBrRZS8rwx8nXuee2cM1Vcgma5Vzz1CBWb3cQm+ZyJ17LTVVsniUFT5qHtjtiObYoZL3rC8qqP2e\/qRyRCaxwQ3+n1mzNC\/3zxtT9la1E0hSiFJLysDga1RHLVu8QsA32wI2Ia6jBquVRjZp4DSkYWsfqQZPC2CYg+QPIAf3HrtlwPpyEUTi68Sd+GAXDCz9oBDvGHZKVhjeqtJBW5BKfbXUBTbB+5SNPVdnIhssCCWtrc8puFouZ56q2QV7hmZoYvs1clQmvDuVbVemuDmfDFkLeOPDf5pVjZRVlk+E4WNztc8tGRJ\/Y8SumacDhFhvYcw0vO6H+x7a5HwwX45\/+e33rdDvGxZIbgz1ms151DZNu1duCyVSXfcXRYrztmwBWCW+nARWZhQT0m46fUHb72z9Q9j6Spq+V8XmNY1FNT7OrJqwdKs\/tvjjsL0+2Doo=","xmlFileCreated":1543258276},"97":{"desc":"eJw1y7ENgDAMRNFVrqNjGhaI4CCRgh3FtkK2h4b26\/0tF0OrcRVBpRumBvbO5IRw4Cysh0FP+GzEEsa+4MNJJvg4xYqKYWR2Yg9zvf8pfcWiNe3OY30BHiAnHg==","element":"user","enabled":"1","extension_id":"475","folder":"fields","name":"Fields - User","path":"\/plugins\/fields\/user","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/user\/user.xml","xmlFileContents":"eJyVksFy0zAQhs\/0KRad4BA7LQN0BkUFEpMJ46SZhsxw8wh746gjSxpZbpK3Z23HKdATl0Sr\/9vfu6vld8dKwxP6WlkzYdfRmAGa3BbKlBPWhN3olsGduOJ4DGhaCMLJ4YQ53ZTKsOfUd9HHNrn0tnETtlOoi5pBhWFvC3JypZcFMnH1ihtZoXC6zHooa2r0PO5uSZUNZXjx3dpKy9ew9vYR88Dj8z0RuUcZ6JszGVAspc\/3cDO+\/sDjv4QWtO7kVbkPYjqc4M30LdHj9zBqk27h3qGBjW18jrCUIVA7EXzRGjq8Bo9U3RMWEdlf7Mhbq5zmgWK+2sIcDXqpYd38omtIe2kYDdyA9aCpJv8JakRIF9NktUmicKS2Bp9L50kllRayqJT5\/NgNIbK+HPrv1Qu89VocDofoJdgqhJ1rEN3r8HgISSmwzr1y7bzEOp1n3xZJOttk203ykP1cptks2UwfFusfi\/sVj\/+EKXenNNZ06E\/ty0G\/D\/TQNC4m2t\/I7R2PB6CnrS7Qi1A5TUofkF08+HEtTdnI8mw+RBAkLSOa0fwrE91f9M\/6RMoomuWZ\/9\/k+lS\/MHgOqBYeX9Zf\/AaSohSE","xmlFileCreated":1543258276},"98":{"desc":"eJw1y7sNhEAMBcBWXkZ21VwDK3iApb215Y+47R4S0pHme0rAeh0y0JmBqYXV2ZIYvLAL+xbQHTmNWCroh2tZl8gFz2pjgv\/kCNERuE46sVak\/t7dHokyU09unxuwRysH","element":"usergrouplist","enabled":"1","extension_id":"476","folder":"fields","name":"Fields - Usergrouplist","path":"\/plugins\/fields\/usergrouplist","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/usergrouplist\/usergrouplist.xml","xmlFileContents":"eJydVMtu2zAQPCdfwfLUHiw5KdoGqMzUcVTDgfyAFQPtSWCktcyAIgWScuK\/7+rlOEhzaE\/m7syOuDtLB9fPhSR7MFZoNaIX3pASUKnOhMpHtHLbwRUl1+w8gGcHqiYRdyhhREtZ5ULRl9LP3re6ODe6Kkd0K0BmlpIC3E5nqFTmhmdA2flZoHgBrJR50pKSyoJpyqSwLvAbGGm8wlLD7rQuJP9AVkY\/Qop4l0dGaoA7\/Pgtd8Dm3KQ7cjm8+Br4r4CaqMuDEfnOsUl\/Ih8nn5A9\/EIGddEVWZagSKwrkwKZc+ewL4+MpSQN3RIDeM09ZB7KH+VQW4oUBwNsutiQKSgwXJJV9YBpErVQPyNySbQhEu9kvhMLQKLZJFzEoeeesa1e59h5WHAhGc8KoX48NkPwtMn7\/lv0SN4YyZ6enry3xBpBWncH1tgU+H2ISAY2NaKs58VW0TT5OQuj2zjZxOF6ul5uVtEsvk9+zaPkNown69nqfrZcBP5pFYpshQSLh\/ZUW0jaDUHrT+2l7FXolbsy8PuStl7LDAwrueGFRawNTxBXlPIk35bbxgqu8orn3UX6iDiOqwxqML2hrPnx3ls+TyiBTnSF\/61iD\/aN0ktg241UW5F3A6slSD0AfFZN2\/UzOSLgOuyBW5G2UIc1x7MWLSrpRCmBtsn2leKbE7rLSP4AckTftXg1Xo\/ncTLfRPezVRQm0fgmjLraE7f\/QaFemE4gldxabMGpQTMncjwNDmCVPn5ny7GPER12CfQWn8uICuUgB9Nl2xmcBbq5EdlzWWGzF5Td\/Q7jwNf9Wv6FNETSYvmaU68QTrMdut9PvTGnixoDe88C\/\/hnyP4AGqGwuA==","xmlFileCreated":1543258276},"99":{"desc":"eJx1kc1qxDAMhF9F0EMu7YbdYzE5lFLYW6F9ASfRJgbVCpbcbSj77lX+lkK3R9uab2bk9z4IDJS7EMET8Vlg5AzK0AYZyI\/gocmi\/AGngNTCuQ9ND70XqBEjhCiYFO0+aA\/aIxRPWZUjPMDLJJBiw3OCLCF28DZG9V+P8L0Q7y7mlbBRGg1nzhMF26Am8An9ztWpcqKJY1e9skioCTeIK9eHeShT5ShUruEWqxW\/v7hyPltEomutyWRttCU\/PsPelZP+D+P+xPw\/R5Asvi1hmV5aTg+eFFP0Gj4RbJizQmGkYnfTpkucBzjc9rHPWfAyB7Z9Xhssut81DqtBaQv5AQDKq1M=","element":"fields","enabled":"1","extension_id":"477","folder":"content","name":"Content - Fields","path":"\/plugins\/content\/fields","title":"","type":"plugin","xmlFile":"\/plugins\/content\/fields\/fields.xml","xmlFileContents":"eJxlkk1v2zAMhs\/rr+B02g610w5DC0xWNyRukMF1giUFdjMUm3FUyJIhy03y7yv5ayt6MqX34WuKJH04VxJe0TRCq4jcBDMCqHJdCFVGpLWH63vywK4oni0qz\/xjvwV3nraXGiNSy7YUikBpdFtHJNfK8ZZAhfaoC+dUl4YXSNjVJ6p4hayWZTZQ2UGgLBoadoIDeOuSDPutdSX5Z9gY\/YK5peFw74jcILeuigW3yB5xb1puLnA7u7mj4TvNs7q+GFEeLZuPEXyZf3X07Dtc+6R7WNeoYKtbkyM8cWvdGwP4JSV0eAMGGzSvWATOfrJz3lLkri3IlukzLFGh4RI27d5dQ9JLY7\/gFrQB6WoyP6BBhGQ1j9NtHNize9noMz0+rriQjBeVUD9fuj4E2pRjC3p1gp+NZKfTKfgIesVhQw2sGxkNx6NTCmxyI2rfL7ZJltl8ne7idJc9ruJksc3+PiXZIt7O\/6w2u9U6peH\/vEs\/CImNC\/rIzw\/6TYhIP1TC+m9QH2sajpBPDcdcNyB1EOXg4mHwjNspbnjV+JWZFLSDtueNyAcpHLXOYjh1vxidaTjtL3sDsRf8Ag==","xmlFileCreated":1543258276},"100":{"desc":"eJxVT81OhEAMfpW6B2\/C3QAe3PgKHowxBTrQZLaddDrivr2zoDHe2q\/fX8+cU8RrBoSxuKuAK7BkMq\/QVLLrBQJTnCtaTyhAM7saoBE2cP7TJ00lAcaoG8sCVy03r2lVzQS+0mHTdKO1Q5fdVJbhFU0q+a5rf4DHnfkvd+MYQdRhJDCSmYxqmbATO4TVKPQnrvhXk9b0pMlZpZ\/08pFiWeov959MW\/+7BI5O9hY0Vqf3yhMn8dPwfAzwAC+32Ny1OMAhAs57ARIcI83NNw12cFM=","element":"fields","enabled":"1","extension_id":"478","folder":"editors-xtd","name":"Button - Field","path":"\/plugins\/editors-xtd\/fields","title":"","type":"plugin","xmlFile":"\/plugins\/editors-xtd\/fields\/fields.xml","xmlFileContents":"eJydU8Fu2zAMPa9fwem0HSKnHYYWmKJuS9wgRZoETQr0Zqg246iQJUOWm+TvR8dx2qI97SRK7\/GBfKTE9a4w8IK+0s4O2DnvM0CbukzbfMDqsO5dsWt5JnAX0DacV+4Pfskg7EscsNLUubYMcu\/qcsAw08H5qrcLGYMCw8ZlpFXmXmXI5NkXYVWBsjR58oaZrDWarBLRASSSqinRy1vnCqO+wsK7Z0yDiI7vxEg9qkC1jFRAeYNPvlZ+Dxf980sRvcMariv3XuebIIddBN+G34nd\/wm9JukK5iVaWLrapwh3KgTqlMMfY+BAr8Bjhf4FM07yJznSNjolc1COZw8wRoteGVjUT\/QM0xbqXIMLcB4M1eR\/QYUI08kwni1jHnbUWadzaj4ulDZSZYW2v58PPnDn886CFj2RH7yR2+2WfyQ2CNGONUgaHO+LqLsSkmGVel02fsnFdJzEo8lqfr\/sPa5Gyc0kno6WyePdNBnFy+H9ZLGazGcieptDEmttsKKgjZoZQrsVA9YOlsn25OWmFFFHalKjLlcYZfNa5Ueh7gZB0S6i7Y3\/Mnk4+Oe7w7XV5OIx7T81qv1HndcLVSai02eQ\/wDWVhr4","xmlFileCreated":1543258276},"101":{"desc":"eJxNytENgDAIBcBV3gRdwgVcgQZSSSg0Qp3fxC\/v+847HmVJ1CXoFgNJc5mAqajhIEcXqGeRmTB2qo8v\/x5m8DZpLz7NG8w=","element":"blog","enabled":"0","extension_id":"479","folder":"sampledata","name":"Sample Data - Blog","path":"\/plugins\/sampledata\/blog","title":"","type":"plugin","xmlFile":"\/plugins\/sampledata\/blog\/blog.xml","xmlFileContents":"eJydk1Fv2jAUhZ\/XX3Hnp+2BhHaahjTjjgJCVAGi0Up7i9zkElw5tmU7Bf79nITApu5pL8T2+c6R7\/WF3h8rCW9ondBqTG6jIQFUuS6EKsek9rvBiNyzG4pHj6phruyXaETAnwyOiZF1KRSB0urajInjlZFYcM8JVOj3ughRprS8QMJuPlDFK2RGltkVzF6kLmncKoHgdXBZ9qh1JflHSK1+xdzT+HweiNwi9+EeM+6RPdbyBHfD2280\/uu84bQ5WVHuPZv2K\/g0\/Rzo4VcYNKYRbAwq2Ora5ggr7n2oMIKJlNDiDiw6tG9YRCH+EheypchDU5At1s+wQIWWS0jrl3AMSSf13YI70BZkuJP9Dg4RkuV0vt7OI38MVfU5l8LnFReS8aIS6sdr24NI27Ivv1Mv8LOV7HA4RO\/BRgnY+Q4sPFg0pHG\/DUqBLrfCNP1iabLItpNVmsxnk6dJ9pBsFtmvVZLN5tvpz2X6tNysafynIfh3QqILi27VPB50ozAmzXsS1vxGZm9o3AONLe59VHJV1rw8h\/Q78DwMH6rB4oGw9hP9Y1oioUTo3dnzPwHu5N6FXDeuGx+1E+W5RJSFg6aIMPHc8sqRVog7pTX3PI0v\/xj2G7T8JCk=","xmlFileCreated":1543258276},"102":{"desc":"eJwdjMENAjEMBFvZCmiCB18kKjDykrOUc6LYkaB7DL8daWYfn0ieuPfdzJGHJOZejQG+py0qVFIgrjiZ8gflpKt5w\/glRDDCah+lda7iRL3d+nhKx3X4y9pekuVcvlxqKeM=","element":"sessiongc","enabled":"1","extension_id":"480","folder":"system","name":"System - Session Data Purge","path":"\/plugins\/system\/sessiongc","title":"","type":"plugin","xmlFile":"\/plugins\/system\/sessiongc\/sessiongc.xml","xmlFileContents":"eJzdVttu2zAMfW6\/QvPT9hA77bCh6Bx3uXhBitxQp8OKYTAUm3E0yJIhyUnz96Nv6X1o1z4NCBKJPDwSDyki7tl1yskGlGZSdKwju20REJGMmUg6Vm5WrRPrzDt04dqAKDA32I\/2iUXMLoOOlfE8YcIiiZJ51rH0ThtILZKCWcsYabJE0Rgs7\/DAFTQFL+NJWIFCDbqgSyLXKV0IoTmGKe9cypTTd2Su5G+IjOvUdkRECqjBqAE14H2Dpcqp2pHj9tGJ69zxFViZ7RRL1sbrNyvyvv8B0e1PpFUGkVkGggQyVxGQCTUGU7RJl3NSwjVRoEFtILaRfk+H3JxFqAp4w+klGYIARTmZ50s0k3HlauQix0QqwvFO6gvRAGQ86vvTwLfNNWbW8OyT91PKuEfjlImvv0sdbKmSRoLKuwdfKu5tt1v7IbDwIKy+g4cVsz+7TrNFTww6Uiwr9PLm42EYXAULfxIGfhCMZtNhP\/wxGYcDP+hfjOYLtLjO7QgkWDEOGhfVqqggqZoBu6CprOXtl3a2zlyngRYETsPgciqSnCagyUryGFTHaixWeUCzI4Zia4JoDXuWV\/445bf9WFfZTDDUtw59BQ8aHnDdbHTVaWLFkloM4LEmRZL4OqiiqS6TaDxgat+SahZVrtpXLg8qL6q05NDcIkQpK2\/16vBNMVlbOF0C71iP1tCfdntjvzGEaBl3e\/64jrxV0GfHFx1Rh0ecao15GNEqXz\/Zr1o70ELuT1nRnBucMLUBy26KGudMmNpUqXDgyvIyZEN5DkWAd37lB64jm6Z7BNRG0HR2F1O0FurpHT5PXBxWNKaGvpHKE3\/RHXQX3VfLfZvov9A9icJMySVdMs7M7o7WIk+XoJ4hNn7mF7NetzcajxZXLxT4XvAtUR8RBxNl2Bb3L5cWE+7oKZH1Wm6L4x+839Ojn7OLX0933mnN4PxNvZhtmJbqn5UbjL6PgtnFy1VrAt9SsXb7DTW76T6csOUgrnflsG7ms+vs\/814fwCxx7tD","xmlFileCreated":1543258276},"103":{"desc":"eJwLyClNz8xTKMlXSC5KTSxJVUhUKEotALISk3JSFdLyi3IVyjNLMhSSS4tL8nMzqyDCmak5KcV6AKW9FmQ=","element":"repeatable","enabled":"1","extension_id":"481","folder":"fields","name":"Fields - Repeatable","path":"\/plugins\/fields\/repeatable","title":"","type":"plugin","xmlFile":"\/plugins\/fields\/repeatable\/repeatable.xml","xmlFileContents":"eJylU19v2jAQf14\/xc1P2wMObTWJacEdpRmiSikqrbS3yE2O4MqxLdsp8O3nJASYure9JHf3+xPfnRPf7CoJ72id0GpMLumQAKpcF0KVY1L79WBE4IZdxLjzqBoS+L3BMTGyLoUiJ+k1HTXi0urajMlaoCwcgQr9RhfByZSWF0jYxadY8QqZkWXWkTKLBrnnrxLjqMUCh9dBZ9m91pXkn2Fp9RvmPo4O9cDIbRCFL99xj2xirJBwNbwcxdFfQEPUZm9FufFs2kfwZfo1sIffYNCK4NGggpWubY7wwL0PTVGYSAkt3YFFh\/YdCxrsj3bBW4o8TAXZbPECM1RouYRl\/RrKkHZQPyC4Am1BhjPZH+AQIZ1Pk8UqoX4X2up9jp0nFReS8aIS6udbOwSqbdn336FH8ouVbLvd0o\/EBgm0wxnYNf1Oh3HUpwEp0OVWmGZebJnOsl\/zJL1bZU\/JMpk8T27TJPv9kGZ3yWr6NF8+zx8XcXQuCQ5rIdGFoIua\/UF3N8bktFjCTjE1GxNHPblTalmgZYZbXrmAdekZ4isjz+qd3LUb4KqseYkOOnRM+gppDfoMPA8XGtVgdktY+4raJ\/3nRaRCibCVg\/Z\/jNzefTA7JaGFODr+WuwP6Qg0Zg==","xmlFileCreated":1543258276},"104":{"desc":"eJwVi9ERgCAMxVZ5EziNC2CpwCktlnLn+Naf\/CTZa5sY9ypNkHKeSDB+VjPOIJXJ4qDKdB36wjX0qdbBBV45Cvshnigy7UMlhu0DOFUfIg==","element":"confirmconsent","enabled":"0","extension_id":"482","folder":"content","name":"Content - Confirm Consent","path":"\/plugins\/content\/confirmconsent","title":"","type":"plugin","xmlFile":"\/plugins\/content\/confirmconsent\/confirmconsent.xml","xmlFileContents":"eJylVF1v0zAUfWa\/wvgJHpZ0RYghEo\/SZVNR+qG1k3iL3OQu9eTEke2u7b\/nOnFKCwJN4sn349yT63NvHN3sK0leQBuh6pheBQNKoM5VIeoyplv7dHlNb9hFBHsLtcP8wn4IPlNiDw3EtJHbUtSUlFptm5jmqka0paQCu1EF8jSl5gVQdvEmqnkFrJFl5lHufBK6wsOgG4UtAIF8i8WafVeqkvwtWWj1DDnmfRwRuQZusZdbboFN+YEMB1fXUXgWdjDVHLQoN5aNe4u8G79H9OAjuWyLyLyBmizVVudAptxavGRARlKSFm6IBgP6BYoA6Y90yC1FjroAu589knuoQXNJFts1hknapXrByJAoTST2pL8QA0DSyTiZLZPA7vFSPc\/x3knFhWS8qET99bmVIFC67G\/fZY\/gRy3ZbrcL\/gS6DMJ8DwxnFgyisHcxU4DJtWicXmyR3mfj+WyVzFbuvJs8TPFYOvfHNM1uk+X4YbJYTeazKDytQ5onIcGg0VluhKRbinYbTuZL2bkfNJsmCvsiRxX2XFGLLD0ryMIQh8F145pXxm3TMQPW59bciJwSXhRtouF2E9Ow1VEYq7lVGidYNarGjxtn9osYVqoAacKOsGP39K35pvuA73ut9pnFv4J2ue4\/cAGO2+eDkq9BxvQfst5NkvQ2m81XSZaOviWpLzwR97Xlbji+eiNq+\/qyu9FjuvKVueTGxNQ0vL4a+phWOwx96hFKojcceBdHhfsc042tZBcK2cVfhGu0eOH5IePailzCmXAoPZe\/ZV6r3uhhNRmn\/yNgz3CioQGJjw1OVG\/7fmrYnflQiHMAts71WaSXBwcCJeijQk6fsF\/cdr+91+5\/v\/ZReHx12U\/lKMFT","xmlFileCreated":1543258276},"105":{"desc":"eJwdyMENgDAMBMFWrgKKoYPgXIQ\/trCTILon8FmNdqd41EQ\/iSJd3RLeMJKxYP9P7Sv++YEUw0EEp\/Jmhbbla2iwbi9GChvt","element":"actionlogs","enabled":"0","extension_id":"483","folder":"system","name":"System - User Actions Log","path":"\/plugins\/system\/actionlogs","title":"","type":"plugin","xmlFile":"\/plugins\/system\/actionlogs\/actionlogs.xml","xmlFileContents":"eJyNVE1v2zAMPbe\/gtNpO9ROOwzoMFtdkXhBhqQJmhTYToFiM44KWTIkuWn+femvtMFaYBeD5HukyEfC0c1zoeAJrZNGx+wyGDBAnZpM6jxmD6tfF9fshp9H+OxR15xX7tfgOwN\/KDFmpapyqRnk1lRlzNzBeSwYFOh3JotZVeZWZMj4+VmkRYF8MR2vl3+Xq2S2vh2uJvO76Xy8jMIGI46oKM\/y38YUSnyChTWPmPoo7OLESC0KT12MhEc+Ewe4GlxeR+FJuKaZ8mBlvvN82FvwefiF2INvcNEkwbxEDUtT2RRhJryn8QK4VQoaugOLDu0TZgGVP5aj2kqmpAjy8d0DjFGjFQoW1YbCMG2hXiq4AmNBUU\/2BzhEmE6Gyd0yCfwzDdXXOc6dFEIqLrJC6p+PjQSBsXk\/fYseyQ9W8f1+H\/xLrBGidT1w2lYwiMLeJSRDl1pZ1nq9v5D1n9l0PUqWw\/vJoo5F4dsUqrCVCh0ZrVVvD9pLiJlIa5IyuWP81Q7KXRmFPbnNNCpDy7fGFo6g1qPaYV+clqi3Mu+eQZU5qJPp6IQVhauP6oig77CNcDJtoQ5rzLMWpVZGqNDjAq00GWux9pR1VWzQdiElNqhi9r469CF1pskqWS+S+8l81CW9Eem\/UxuZj\/lbUSkfs0EXKGpBe4dkoTuKmdS+izwJJTM6rtPeww+HF87bSp8MvZNZhvqj9988iflp\/XpNrfDNfjqv2V+\/tig8\/jv4C8leXu0=","xmlFileCreated":1543258276},"106":{"desc":"eJwdi8sNgCAQBVt5FViIRztAeMRNlI274Kd7kdtkMrMwqiXUjQixihaHZjSndSjDu1Qiq2FWPfaAPhB8KouP3vXPXsRQsBLGS3gzQXLns4kxTR+iqyWc","element":"joomla","enabled":"1","extension_id":"484","folder":"actionlog","name":"Action Log - Joomla","path":"\/plugins\/actionlog\/joomla","title":"","type":"plugin","xmlFile":"\/plugins\/actionlog\/joomla\/joomla.xml","xmlFileContents":"eJxtkk1v2zAMhs\/rr+B02g610g4DOsxWF7hZkMKJg6UBdgtUm3VUyJIgy03y70vHcbqhvVF8H1L8im\/3tYYX9I2yJmFX0YgBmsKWylQJWz\/8vrxht+Iixn1A0zFv7LfoB4NwcJgwp9tKGQaVt61LmCwCEdpWDGoMW1smrHWVlyUycfEpNrJGscymm3H6MMsXWT7d3Of5PBvH\/CgRIlsK8+Le2lrLz7D09hmLEPOTn4jCo+x+uZMBxVwe4Hp0dRPz\/9wdZt3Bq2obRDpY8CX9SvToO1wegyB3aGBlW18gzGUI1GAEY63hiDfgsUH\/gmVE6c\/pKLdWBc0ExXSxhika9FLDsn0kN2S9NAwLrsF60FST\/wkNImSzdLJYTaKwp6aGPOe+J7VUWsiyVubX83EEkfXV0H2vnuG112K320XvwU4h7FSDoH1Fo5gPT1JKbAqvXDevD\/ex+TvPNneTVfpntuyUmP8bQQmelMaGjN7qlgf9KSSsL4eJU1lu62I+QF0oH2JpReZJVcDpyvj5zMQrrG\/e6A==","xmlFileCreated":1543258276},"107":{"desc":"eJw1zUEOwyAQA8Cv+NZbHlGpD6HghpUQS9klKb9vUqVXW\/bcg0lEK2OVCld0vgfNMYz9ZohajdXPxjNh4jzS1mULcaJpkTgXPD5iLnX9rQx7VuSwEVX9\/8CESccupeDJg0nSGc9YK4pe+mgpOE9K+qHoSwqXL0fFPCY=","element":"privacyconsent","enabled":"0","extension_id":"485","folder":"system","name":"System - Privacy Consent","path":"\/plugins\/system\/privacyconsent","title":"","type":"plugin","xmlFile":"\/plugins\/system\/privacyconsent\/privacyconsent.xml","xmlFileContents":"eJzNV0tz2zYQPtu\/AuWpPZiUnGnjTimmsoy4yug1ktyJTxyIXFHIgAAHAP34912+ZFK240RpZ3oSsS\/sfvthAfkfHlJB7kAbruTA6bs9h4CMVMxlMnByuz27cD4Epz48WJCFzZPtO\/d3h9jHDAZOJvKES4ckWuUZuhnQDknB7lSMqyzRLAYnOD3xJUshyEQSmkdjIQ0zze9Y9BgpaUBa3yv1aMdy9NXBJ6VSwX4iC62+QIT6Wo4WkQZmMY8rZiEYYhxBznv9C9\/rKApDlT1qnuxs8PPoF7Tp\/UrOSlMyz0CSlcp1BGTKrMXCXDIUgpTmhmjAOu4gdjHoPghGFDxCLCC4nt2Qa5CgmSCLfINiMqlUDUjknChNBGai\/yAGgEzGIzpbUdc+YDFNnH29NGVcBCxOufzzS1m6q3TSVF1p98Y3WgT39\/fuc8NCg2Z1DgH2ye35XrNETQwm0jwrUAoWk+twdbta02m4WI7\/Ho5uR3PMcLYOP08n4RVdjZbjxXo8n\/le2w2jbLkAgx\/VV9E5UvEA+dBpqxN01262y3yvcaoiKBGDDg7pUItbFlsOIm4pqjimbAuTSc6SOqdmRSxDIoM8u750gvLHfZV\/Lpcc21J7Hh8Gpc9CPS1MxUq55UmNHpZkSIEFIsc0S01xVvYasLVuwwyPHMLiuFRkzO4GjlfShRurmVUaiZpmSmISpvgMcRs8t9ZLVQzCeFXAKnodvvw8qTevygilsuBUiup8Wzz+DM9VLRRsA2LgvE6d2XxNw49jOrkKJ8NLOqn9WgT6Ru+Cf7Xzjkv7zV4fhzeTde0YCWbMwDEZk\/3zWqbVPYreNxZK4Oq8Vy+RUXhgB87OpqISeW8hxrTlkeiChpgzcaB5E7mqgOFyPR5N6DHgdQO08DMgcIRiL3XeZCPhvrOGmHcNMHGmO5IGG2wGJDjlvw5PCsYg4+dyiaE1bv9DrFrSq\/GSjtbhlK5Ww+uj4HkW4zsY9oLvf8Iz32sOfncMnD4BCw8Z1+U1Vzm+iR39vBgvh8UcrxiyousWfK\/1Dwf0RkDc6Rre5Vx9H53pbHg5oUfNgm6AVrNqtDdWnpWvDrL\/OnsEI9V+my3LBbb1EPQOgWsATnxVJkTumMix1L4TfLqlK99TzaX3glEPjWbzrk3dwddgjVi0A8tTUHn3RHSTehPd0XD0F12Pp3R+sz4G3I5\/C9st16YFGSKNq\/6et3jlZQU4Bwi\/ewHiWoJQ8RhfQQNH5unmzbFR36OHJD8SpOq3dQCOQepZkOdw9S+6gL0\/AGyPzxNiv\/1rkGnAV0D8Izgt6XQ8u7qkH+fLIydry\/9\/RKZiQ513KbTjcQzycM+vjoiXRnOzKp93zYvO9\/b\/lYJ\/AHJd24E=","xmlFileCreated":1543258276},"108":{"desc":"eJwLycgsVijIKU3PzFMoSC3KzE\/JTE7MyalUKMovSSxJLVYoriwuSc1VyMlPV0jLzEkt1gMA65ETEw==","element":"logrotation","enabled":"1","extension_id":"486","folder":"system","name":"System - Log Rotation","path":"\/plugins\/system\/logrotation","title":"","type":"plugin","xmlFile":"\/plugins\/system\/logrotation\/logrotation.xml","xmlFileContents":"eJytVU1T2zAQPcOvUHVqD9gJTGfo1BYNwZOGOiRDwkx7yij2xhGVJY8kA\/n3XX+FUGDaMj1lP94+ad+unODsIZfkDowVWoW07\/UoAZXoVKgspKVbH53SM3YYwIMDVWEesSfeJ0rctoCQFrLMhKIkM7osQmq31kFOSQ5uo1OkKTLDU6Ds8CBQPAdWyGzZgJZSY5HjDikDv04iiJdYaNil1rnk78jM6FtIXOC3cUQkBuqaC+6ATfiWHPf6p4H\/JFzBdLE1Its4Nuws8n74AdG9j+SoLiLTAhSZ69IkQCbcOezPIwMpSQ23xIAFcweph\/Q7OuSWIkFJgI2ubsgIFBguyaxcYZjETarTihwTbYjEO5nPxAKQeDyMruaR5x6wqY5n13eUcyEZT3OhvtzWEnjaZF33TXYHvjGS3d\/fe8+BVQZh7R0YjsvrBX7nYiYFmxhRVHqxWTxazn\/MF9FkGU9H19PFYDGeXi2\/T+LlRTQfXo9nlR\/4+zVIsRYSLBqNVY2PNLsQ0r3BUrbneMWmCPwOXpH4HUsgucpKnoElay1TMMjSRmh9SOcRx3E7QR2Nzimrf7yXV8oTSqDCbdkbOTD0jOfRsc2eqbXIWiFAppZUzeHD4Ibntr58lwHX5lbciqRJtbnaPGiyCU824EQOunS0STRvTSgHGZg2JvkKZEhfGd9wMPwaLcaTaHqzWMaD8yhuy\/bG+HfF1RK0tWthrAtpb3eDyusfdz7Kh5+A\/u6gNS8lAk56u3LpqsliH23kjkuR4uMIqSrzVdeazw5fkQZnY53+CVC8WRi054vptyia\/bMse6XPRek\/FeUPmvT\/nyR4ninVEz02Ik1B\/X7mC2N4VM1vFtXvNrVe6Narl77b88Df\/SGwX3QT5sc=","xmlFileCreated":1543258276},"109":{"desc":"eJwdysENgDAMBMFWrgIK4UkHJjkgUoiD7SDRPYjXzmMXetfmZa3EpoZumuhe2v6x3JIeGKsE89dr0MP\/Lw4iqRGz6lkFw2nIEjK9Hrwe4A==","element":"user","enabled":"1","extension_id":"487","folder":"privacy","name":"Privacy - User Accounts","path":"\/plugins\/privacy\/user","title":"","type":"plugin","xmlFile":"\/plugins\/privacy\/user\/user.xml","xmlFileContents":"eJyVkt9v2jAQx5\/Xv+Lmp+0BB1pN6jTjrqMRYgKKYEzbU+Ql1+DKsSPHAfLf7xII3danvSS+u899db\/E3bEwsEdfaWfHbMSHDNCmLtM2H7M6PA1u2Z28EngMaFvmhb3hIwahKXHMSlPn2jLIvatLMr3eq7RhUGDYuYx0ytyrDJm8eiOsKlCWJk\/OVFJX6EXUuSmsakrx8qtzhVFvYeXdM6ZBRGc\/EalHFaiCBxVQLlQD18PRrYj+creYKxuv812Q7ybviRl+gEGHwmOJFjau9inCQoVADXG4NwY6vAKPVNEeM06iFxFSNDqlGaCcLrcwRYteGVjVv8gN81OoHw5cg\/NgqBL\/CSpEmM8m8XIT83CkVnqdS7dxobSRKiu0\/fzcNc6dz\/ueT9ELvPVGHg4H\/hpsI4Sda5A3\/CMfiqg3KZJhlXpdtlOSq\/k0Wa1n3+8nP5PtJl4nPxbz5CHeTNaz1bfZ41JEf9KU\/KQNVvQ4vdp1wWnttF6aF5Ptl5e7UkQ90KZFfZ4wyua1ys8ivQVB0aGhHUy\/MNn9+L\/HwbXVNLVzwn9nV031SuHFoGpEdLlu+RsEvQn2","xmlFileCreated":1543258276},"110":{"desc":"eJwdi8ERhDAMxFrZCmiCBmjBBwvxkLEhNjB0fxlekh4aC+c9sHrD0fSW+UXjeTEykEUSRi5Ix48oYkvt1QHz1FUZeP3CU2if3Bqa\/SNGt2xeMYmx4pCNwx9Tuicm","element":"privacycheck","enabled":"1","extension_id":"488","folder":"quickicon","name":"Quick Icon - Joomla! Privacy Requests Notification","path":"\/plugins\/quickicon\/privacycheck","title":"","type":"plugin","xmlFile":"\/plugins\/quickicon\/privacycheck\/privacycheck.xml","xmlFileContents":"eJylk01z0zAQhs\/0Vyw6wSFyWoaZMjgqxc0Et2kSGsLAySPkraNWlows5+Pfs07itEyHEyfvx7Pv7K7W8cWmNLBCX2tnB+yU9xmgVS7XthiwJtz3ztmFOIlxE9C2zBP7jn9gELYVDlhlmkJbBoV3TTVgvxutHrVyFCkxLF1OSlXhZY5MnLyKrSxRVKbIjlxWeb2SaquWqB7jaAcQKBsq9uLaudLI1zDz7gFViKNDnAjlUQbq5koGFNeNRTjrn57H0V\/xlnPV1utiGUTSWfAmeUt0\/z30dkUwrdDC3DVeIdzKEGhODpfGwA6vwWONfoU5J\/mjHGkbrWg1KEaTBYzQopcGZs0vCsN4n+p2BmfgPBjqyX+EGhHGaTKczIc8bGiqTuc4+LCU2giZl9p+etjtgDtfdOPvs0d44Y1Yr9f8JdhmCDv0IOjZeD+OOpcyOdbK66rdl5iNR9nXRZrcpMl0ks3u0u+Xyc\/kyzC5yX7cjrOr4Ty5S2ff0ukkjp7Xkcy9NliTsbfaN4T9XdB9PHteJp57vFpWcdQVtDJRpxMbaYtGFgfRzoMg6TLR9kafmdh9+L9viWurabOH0v\/Qqbf1C60nhzqMo+MvIv4AACwkWA==","xmlFileCreated":1543258276},"111":{"desc":"eJwVysENgDAMBMFW\/ONHEXQSJSewBA74Lv2TfHf2KPRq7z1OD1O3xDdA2SByo9UeRGiJLhhdmFXIh1aiLW8un9f+A\/73G0o=","element":"terms","enabled":"0","extension_id":"489","folder":"user","name":"User - Terms and Conditions","path":"\/plugins\/user\/terms","title":"","type":"plugin","xmlFile":"\/plugins\/user\/terms\/terms.xml","xmlFileContents":"eJyVVE1v2zAMPbe\/QtNpO9ROUgzrMFtdmnpFCjcN8gHsZqg246iQJUOSm\/bfj\/5Kk3YotpNFvkeKfKQcXD4XkjyBsUKrkA69ASWgUp0JlYe0cpuzC3rJTgN4dqBqziv33BtS4l5KCGkpq1woSnKjqxLDLBhKCnBbnaFV5oZnQNnpSaB4AayUeVJTEgemsIHfOBHkFQYYdqt1IfknMjf6EVIX+J0fGakB7vDya+6A3VYKyGgwvAj8I3\/N0+WLEfnWsc+TL8gZfCVnDZXcl6DIUlcmBXLHHVZgPTKWkjR0SwxgYU+QeZh0nwQzSpFi\/8BuZmtyAwoMl2RePaCbxC3UC0NGRBsisRLzg1gAEk8n0WwZee4Ze+nz7NuNCi4k41kh1M\/HpnNPm7xvukX35LWRbLfbee+JNYK0rgZ27n33BoHfm4hkYFMjylolNo9vkvUyWiSraHG3TH7fxcl1tJwspvPV9H4W+IdcDN0ICRYP7ameFmkHHtJmgpQ1H6\/cloHfU1q+lhkY1s25sw6AjQCZHQBtuG0E5yqveN5d3FvEcVxLUGc3V5Q1H+94mzyhBKrc0f8z1r68j381bLtZaiPyTgws3pK6WXwB3PBaCQR6BFyHPXArUkp4ljVAyd02pH4zcmGd4U4bXLai1AqUs\/UxwWvwvTm\/0BlI67cJ2+xdetKcT9obmvITpR3Qzt++S4fPluPb6L2SP4AM6Zv5z+5XUfJrGsXXSTy+imLakg+24KOQenO6iK1Q7mPqr\/E6XnXsVHJrQ2pLroajzmf0Dl3f+npTLdEcDXobtwNbDenWFbKN8NnJgSjvNeHGiVQCPVQFReXyDfJ3Zdqyx4vVdBJH\/yzOcdSBPhYk\/tCwNFP19yrYHdmQiWMClsjNkacXAcWGHH+0nQ7N5vn96jUb2lnNFveLG\/j7Xzn7A8uP3Fg=","xmlFileCreated":1543258276},"112":{"desc":"eJwdysENgDAIRuFVmMBBPLoB0l9tUqECmri9jaf3Hd6C6KZR1wbazKm7CSKq7oP1YXnJ0ThRRq8bkfF\/eYDEHDSbnY2HNVmSCidPH36uIA0=","element":"contact","enabled":"1","extension_id":"490","folder":"privacy","name":"Privacy - Contacts","path":"\/plugins\/privacy\/contact","title":"","type":"plugin","xmlFile":"\/plugins\/privacy\/contact\/contact.xml","xmlFileContents":"eJydkstu2zAQRdfNV0y5ahemnBQFUlRm6iqG4cCxhdgp2pXAShOZAUUKFGVbf5+RLDkt0lVXnMeZi3kwvDkWGvboKmXNhF3yMQM0qc2UySes9k+ja3YjLkI8ejQt88p+4l8Y+KbECSt1nSvDIHe2Lsl1ai\/ThkGBfmcz0ilzJzNk4uJdaGSBotR50lNJao2XqQ+DLkOErKnKiTtrCy3fQ+zsM7b5Pk5E6lB6auJWehR3tW7ganx5HQZ\/xVvOlo1T+c6LD9FHYsafYdShsC7RwMbWLkW4l97TUBymWkOHV+CwQrfHjJPoWYQUtUppDyjmq0eYo0EnNcT1bwrD8pQaFgRXYB1o6sR9hQoRlotottrMuD\/SLIPOedxZIZUWMiuU+fbcTc6ty4ehT9kz\/Oi0OBwO\/C3YZgjrexB0Iz4Og8GlTIZV6lTZbknEy3kSPyx+TKNfSbRebafRNvl5v0xuZ5voYRFvF+tVGPxZQPVPSmNFxslqTwan609Yf0gmeoOXuzIMBqwtDobqUEuT1zLvpQYPvKRfh2Y0\/85E9\/B\/\/BSujKIN9jX\/I1A11RuRV4d6CoPzhxcv\/lsRKQ==","xmlFileCreated":1543258276},"113":{"desc":"eJwdysENgDAIRuFVmMBBPLoBtr9KUqECmri9jaf3Hd6C6KYhawNt5tTdCiJE90F5uLzkaJyoo9eNyPi\/PEDFHDSbnY2HNaFJlZOnD38qIBw=","element":"content","enabled":"1","extension_id":"491","folder":"privacy","name":"Privacy - Content","path":"\/plugins\/privacy\/content","title":"","type":"plugin","xmlFile":"\/plugins\/privacy\/content\/content.xml","xmlFileContents":"eJydkl1v2jAUhq\/XX3Hmq+0Ch3aa1GnBXUcRoqKACp22q8hLToMrx7YcB8i\/70lIaKvualc+H895dT4cXx0KDTv0pbJmxM75kAGa1GbK5CNWhcfBJbsSZzEeApqGeWG\/8G8MQu1wxJyucmUY5N5WjlyvdjKtGRQYtjYjHZd7mSETZx9iIwsUTudJRyWpNaQd4qjNECErqvLi1tpCy4+w8vYJU8p3cSJSjzJQEzcyoLitdA0Xw\/PLOHoTbzjraq\/ybRCfxp+JGX6FQYvC0qGBta18inAnQ6ChOFxrDS1egscS\/Q4zTqInEVLUKqU9oJguHmCKBr3UsKr+Uhjmx1S\/ILgA60FTJ\/47lIgwn40ni\/WEhwPN0uucxp0UUmkhs0KZH0\/t5Nz6vB\/6mD3BD16L\/X7P34NNhrCuB0E34sM46l3KZFimXrlmS2I1nyar+9mv6\/GfZLxcbCaLTfL7bp7cTNbj+9lqM1su4uh1AdU\/Ko0lGUerORkcrz9i3SGZ6Azuti6OeqwpjvrqWEuTVzLvpHoPgqRfh2Yw\/clE+\/B\/\/BSujKINdjX\/I1DW5TuRF4d6iqPThxfPV1YRgw==","xmlFileCreated":1543258276},"114":{"desc":"eJwdi8ENgCAQBFvZCizEpx2csCIJcngHJnYv8TXzmNnoTavnvRCHGpppoHuuaWp+JLwwFumMk\/egd\/+7fhJBjVhVryIYTsM1T0l0ROmyfEiFIlg=","element":"message","enabled":"1","extension_id":"492","folder":"privacy","name":"Privacy - User Messages","path":"\/plugins\/privacy\/message","title":"","type":"plugin","xmlFile":"\/plugins\/privacy\/message\/message.xml","xmlFileContents":"eJydkltv0zAUx5\/Zpzj4CR7qdENIQ7gepYuiTm1XrQzBU2SSs9STY0eO08u356RJOtB44snn8jt\/nYvFzaE0sENfa2cn7JKPGaDNXK5tMWFNeBpdsxt5IfAQ0LbMC\/uBf2IQjhVOWGWaQlsGhXdNRa7XO5UdGZQYti4nnarwKkcmL94Iq0qUlSnSnkpLrGtVoIhOGSJUQ1Ve3jlXGvUW1t49YxZE1MeJyDyqQE3cqoDyrjFHuBpfXovor3jLuerodbEN8t3sPTHjjzA6oXBfoYWNa3yGsFQh0FAcpsbACa\/BY41+hzkn0bMIKRqd0R5QJqtHSNCiVwbWzS8Kw6JLDQuCK3AeDHXiP0ONCIv5LF5tYh4ONMugcx43LpU2UuWltl+eT5Nz54th6C57hh+9kfv9nr8G2wxhfQ+SbsTHIhpcyuRYZ15X7ZbkepGk64f59+nsZ7qMN5tpEqc\/lov0Nt7MHubrb\/P7lYj+LKD6J22wJqOz2pNBd\/0J6w\/JZG\/waluJaMDa4mioFkbZoiGmkxo8CIp+HdpR8pXJ08P\/8VO4tpo22Nf8j0B9rF+JvDjUk4jOH17+BtXLEP8=","xmlFileCreated":1543258276},"115":{"desc":"eJwdyrENgDAMBMBVvqNjGDYw8ARLURxsB8H2SFx9C6NbC10rcZiDTzdPbQV5ErKlWkO1gl1S\/iEYQZ8C3fWW7YXzGoycPy\/eG98=","element":"actionlogs","enabled":"1","extension_id":"493","folder":"privacy","name":"Privacy - Action Logs","path":"\/plugins\/privacy\/actionlogs","title":"","type":"plugin","xmlFile":"\/plugins\/privacy\/actionlogs\/actionlogs.xml","xmlFileContents":"eJydk99v2jAQx5\/Xv+Lmp+0BB1pN6jTjjlGEqFJAZZ22p8hLrsGVY0eOA+S\/7wUItOqe9pT78bmv7s4XcbMrDGzQV9rZIRvwPgO0qcu0zYesDk+9a3YjLwTuAtqWObNXfMAgNCUOWWnqXFsGuXd1Sa7XG5U2DAoMa5eRTpl7lSGTFx+EVQXK0uTJkUpUGkjPuLwS0T5JkKqp0Ms75wqjPsLSu2dMg4iOcSJSj6qtu1UB5V1tGrjsD65F9Cbecq5svM7XQX4afyam\/wV6exQWJVpYudqnCPcqBJqLw8gY2OMVeKzQbzDjJHoSIUWjU1oFyun8EaZo0SsDy\/ovhSE+pLodwSU4D4Y68d+gQoR4Np7MVxMedjRLp3Mad1IobaTKCm2\/P+8n587n3dCH7Al+9EZut1v+HmwzhB17kFf8K++LqHMpk2GVel22W5LLeJosH2a\/RuM\/yWj8c7aYx4vpKvl9Hye3k9X4YbZsYyJ6XUMST9pgRcbBal8NDjcwZOfnZPJs83JdiqiDW4mo0xBG2bxW+VGw8yAoukC0vekPJvcf\/u+r4dpq2uax7D81qua9ztmhzkR0+gXkC3rdGGs=","xmlFileCreated":1543258276},"116":{"desc":"eJyFjDEOgzAQBL+ych2ZPgpIiCbpUtBHhzlsC+NDtgHx+9CkTrszs73zGV377rtnizVs1kdsmTOKY7zi7rMfAiPxz8mcdm9YoxdYLiBkXxgUxwuZdC0zn5gk4ZQtYZSFfLzBCorgQXCJp1q5UtZ8r6rjOLQVsYG1kaVKbGgtxpFCoXTd1+ozBIqzav4Vj4oa\/QXFt0fm","element":"recaptcha_invisible","enabled":"0","extension_id":"494","folder":"captcha","name":"CAPTCHA - Invisible reCAPTCHA","path":"\/plugins\/captcha\/recaptcha_invisible","title":"","type":"plugin","xmlFile":"\/plugins\/captcha\/recaptcha_invisible\/recaptcha_invisible.xml","xmlFileContents":"eJzNVsFy0zAQPdOvEDrBoXEKw9AZbIOTmGDqJpk07ZSTR7Y3rkCWjCynKV+P7MhpQ5PSNhw4Rdp9+6x9uyvF\/rjMGVqALKngDj7qdDECnoiU8szBlZofHuOP7oENSwW8xtxi33aOMVI3BTi4YFVGOUaZFFXh4IQUKrkiGOWgrkSqeYpMkhSwe\/DC5iQHt2BZZFCRhHZF+YKWNGZgWw1Ko83XXP0x22o32p5IIEqvB0SBOxILyGOQ6E336L1tbfg0llT6FNL9KkTOyEs0keI7JMq2jH2N8HNCmUvSnPJP3xtwR8isxa28a\/C5ZO719XXnPrD21CcUxY2k2ZVy++0Kveq\/1mfsvkOH9VGP0bgAjs5EJRNAp0QpnV8HeYyhBl4iCSXIBaQdndSaTnMzmuhqgDscnaMhcJCEoUkVazMKV662TOgNEhIxrYT8gEoAFAZ9f3Tmd9RSK9DyaMoUykTSotbNnYTDqO9NZv0vXjT121UwugjOgl7oR5enYTTwz\/rTYDILxiPbuhusueaUQakXq1VdSrTqEAdvKTZ2txg7xVVhW214TWq1rFpZPqeZ4QeWlqjG6C4kkuRl3WRrDyjji0lJE+2qfcbZLF+Y0Ea86Afc4JV51ddKt70xMBIDc3AtzTZJJuc9rWx04n+LQq\/nhybqjjCPiq1VXYfOScWUg81ews+KStDTpGQFxqg10ZV1cKmkHlhjLOkvffajbtfsE0bK0sGUF5U6XC4ZkZmJt3YLIulCN80+ikyDC2\/mP1OSO8H\/jSYxSVuQUYPR8pFq9LzB0H+6DquwbQrEQimRNzeCcbmrH1s0nGhBWAWbOPfhz\/TGs9n4dBoMv8xsS7TTvJOTwfyRlKH\/+S+MlDPK4W9swSgMRv4mU30v6DrtLJoiMeUpLDfqxqv6uXhc5WZeLxgN\/MunF28dua1+bSPm9a3Y\/aN1KVeQtQfc3ZAJYSwmyY9nTmjfC8Oe1z95embryAdmc9sY7k4FlkU9yNGeKfmXk2DqD\/ZI7R7Dv0tRSiH3TnA6HU\/3SW8z\/unJ3Y6cflybN9jsmje6fZpta\/2H0f0N0tcA0w==","xmlFileCreated":1543258276},"117":{"desc":"eJw9zLENgDAMRNFVPAGDULKBcQ6IFGKwDRLbY1FQ3S+eboIf2r3ODbSo0WEqcK99zaw3y0OGxoGSe17w8M\/FBhI10Ki6N\/6x5Bl6osLBwwu1FCOs","element":"consents","enabled":"1","extension_id":"495","folder":"privacy","name":"Privacy - Consents","path":"\/plugins\/privacy\/consents","title":"","type":"plugin","xmlFile":"\/plugins\/privacy\/consents\/consents.xml","xmlFileContents":"eJydkstu2zAQRdfNV0y5ahemnBQFUpRmmiqG4cCxjTgp2pXAShOZAUUKFGVbf5+RLDkt0lVXnMeZi3lQXB0KAzv0lXZ2ws75mAHa1GXa5hNWh6fRJbuSZwIPAW3LvLKf+BcGoSlxwkpT59oyyL2rS3K93qm0YVBg2LqMdMrcqwyZPHsnrCpQliZPeipJna3QhkpEXYoQVVOZl7fOFUa9h7V3z5gGEfVxIlKPKlAXNyqgvK1NAxfj80sR\/RVvOVc2XufbID\/EH4kZf4ZRh8KqRAsbV\/sU4U6FQFNxuDYGOrwCjxX6HWacRE8ipGh0SotAOVs+wgwtemVgXf+mMCyOqWFDcAHOg6FO\/FeoEGExj6fLzZSHA80y6JzGnRZKG6myQttvz93k3Pl8GPqYPcGP3sj9fs\/fgm2GsL4HSUfiYxENLmUyrFKvy3ZLcr2YJev7+Y\/r+FcSr6i35cMm+Xm3SG6mm\/h+vn6Yr5Yi+rOCBJ60wYqMo9XeDI73n7DhlEwOFi+3pYgGsC2PhnphlM1rlfdigwdB0c9DO5p9Z7J7+L9+C9dW0xb7ov9SqJq3Kq8OdSWi07eXL0SIFA8=","xmlFileCreated":1543258276},"118":{"desc":"eJxzTE5OLS7OTMpJVSjOLElVKEnNLchJBDLS8osUvPLzc3MSFRWM9Sr0FJxSU6uMdRRKMlIVPEJ8fUwVylKLijPz8\/QAIWoWtQ==","element":"beez3","enabled":"1","extension_id":"503","folder":"","name":"beez3","path":"\/templates\/beez3","title":"","type":"template","xmlFile":"\/templates\/beez3\/templateDetails.xml","xmlFileContents":"eJytWF134jYQfU5+hdZ96Z5T7JBs9qvgrQMOpXUwBadfLxxhC\/CuLbmSDNn++o5lG8zGa8OevoCluXc8czXSCHofnuIIbQkXIaN9ratfaYhQnwUhXfe1VK46b7UP5mXvxdAdeH9NbRRSIXEUoenjnTMeIK1jGL8wFkf4BbrWbw1j6A2RJHESYUkQuDMMe6IhbSNlIt4bxm630z8qvM742oCXG4EMjK7+2ihZneIVOhg0eDV5koRm4R3CvNG7GpKfE9LXSpaG\/CgkVPY1EcLIvLzoURwTc0nIvzc9Qz3DnM8JluBjCBTz+hZN2JbES8LR9dXVu55xZAY4TuWGcdOi65CgGQ7kJ9Izism92Y5xGJlY58r+U0A4TleSh1LqwR6eg\/acRx6ZmSaFJMDp1JAyVBY0Sz7zcL2R5qB8Qt8PXmYx36IOfHXfIjchFM1Zyn2CHrCUINUPaEx9HVmwWoojECeC8C0JdMh07xNeEIU+SEzM0eQRjQiFBGCB0yVMIyc3ldqja8Q4ygTnPyJBCIIisCdzW5dPsmeUfsBlgTdhqfSrnlEOwRIQ4fMwyWQ2vamzuLPtv28Wfz44i6E9H8zGU2\/sTnpGFXYJtFUYEQF8eGIR6GX6QvSM4rkyvZFxVDcfxnhNahkf8Rbn76qzRpiuU6Ae2yAYVVIhDciTnmwSMJdzR4CyPodEQgEI\/UlF1whdJJxsQ7LTE7puxcpNGi8puG5CfxQCSouuRVOkK7wNfUZ1+PgaxGdxwijssiY\/hHPGnwHygVBLmTDYo7Cu+XKWIzMgyxRS2I+PjOVD56oV0W1FXLcibloRr1oRt62I162IN62It62Id+2KnSBqu6rddlm77bp2j4U9DPLaedHpoIt7OIN8xsm+08BZtyMIR4KVDcpIadmq5IagchcjVYUAUrPKx8Gk9rfQLy86HXUqFgZRWPpaOaOp2PdEiaFXEtoZ3Wmm+jLUpy6TaKH6jx7SEE7HAn8uWXwWzxwcBrkssHFX4brYiCQKBMr2XV9LMMexUPGWFiILGw62mPokyK2FGannixyx4zhJCJ\/HIKOGClPed2matU2tmIvwkkR97XCc349tZ7j4Y2ZNp\/Zs\/mA5zsKx7mxHy\/GVw72FlfWEguRHWIi+tsVRGGT3BAiB8NAvYwjICqcRXABubwoCrLXMli2kkqwhWDVrZHo1putgDkv87ek61mxkn51uzvqGdN9cN6WLGvKN2Jpp1SxjEoRYa8zRcUdukRs6ITkFV0mhNvWze5sMZfSl9BIugC3Cz8ee7Y095wzVD5SK5HtNv1A0756npVB56\/mJVG5Ap6dSJf2PyVC8LY9e7SiPKBRteUys36cuSHxWHlVSXR5wt5RlWe+z2TEeFFP5MXbRY8o\/go2Tkj2rctV0c6mse8+eLQbuxLMnXs9gSdmUnvuIyErWeLiz792ZXe8iu++Aol+Xd8mYhKXAifasSDD8CmnehXeu6809ODhOV\/dAqWjL2Q6OmFdlCD6L0pjCzM1V3WFZDb\/svEBh\/Oz68OyHqWN59sB13NnpORzT6mqEYplycm6NFKznKzyxvMeZ3Vwc0DEEoziqoWddzJ1YTrMDnrXgZ9yZPWymQcj\/1PAg4N+aieqXUA1z\/GCN7DOreEMw3IzGyuNREZzQSn62rSHsQPXaM1rKEa3SWi7Ehu0ywlFpvg8rsTWcdkvsf1pzltKgpqKPppqzubMGv45m7uNkuDizuL\/moK7MvyOkLPKTsy7WEu5\/6ppYjNRdsrw99oz9ny3mfxHxctM=","xmlFileCreated":1543258276},"119":{"desc":"eJwljEEOwjAMBL+y\/QB\/QL0gruUDjuNSS05cxc7\/KXBczcw+KA8f0AB1ELNEaDHBvTbtGjkoL5zSTqMU7Nd4ujejBa9DsLr5HFi3DbuaBPh7Y+EoghlSfwXPSG\/gv1wG9ar9ffsA+zAs2g==","element":"hathor","enabled":"1","extension_id":"504","folder":"","name":"Hathor Administrator template","path":"\/administrator\/templates\/hathor","title":"","type":"template","xmlFile":"\/administrator\/templates\/hathor\/templateDetails.xml","xmlFileContents":"eJzNVkuT4jYQPk9+hdanpCpYzG4ltZUYb3g4wBaDp8BTu3uihC2wtmTJJckw\/Pu0X4Az2DObUy6g7u\/rVqu71bLz6Tnh6ECVZlIMrHu7byEqQhkxsR9Ymdn1Plqf3J+cdxN\/HHx79BAT2hDO0ePTaDEfI6uH8WcpE07eoXv7d4wnwQQZmqScGAqaPsbe0kJWbEyq\/8D4eDza3wu+LdUew+Y4MhHOTWurXrWFDYAFW9NnQ0UeHjKnlA6smmddwv5g31so5IwKM7BIlDDBtFHESAUO7hxBEurGxMRSObgQQBkqSgxYT8CV+0BO6H3\/vu\/ghhpoJMvN3KGIAEABUeCi0p1RLyGMu8W+f10OV\/NKNN9RpifF9rFxx\/UK\/Tz+BTbu\/4Z6+f4fkZ9SgdYyUyFFD8QYOOGvaC5CGw0h6YWNRopqqg40siHcs0\/YgLMQMkXd6fIJTamgikCdsi2o0aKE6pSh90gqlGdR\/Yk0pQhq6S3Xnm2ejYNrP+Cy4rsf7L4N2alFQCKqQ8XSPFdu8LjYzIbBzF9tvj4sNhNvPV7NH4O5v3TwNQ\/MdoxTDYtyVRQjlEkqBdTOTuPUwWd9k5QSQXkXgyolVRdhRw4slMKGnzYKExF97vLB5Z6JLkIjkbcpdQNPqIHO0DZcgteom1TRA6NHOxX7V7kmzpKtANe32JJHVLmh1gCU6yt1bIpQXuhZQvb0psX3m1pOxD4DkyusjAMqD8tUapb3Q9kHteQmVGQOPosNTGfbLthIybdEtcLMcNrq2hCT6TY075g2LEw3Oqact+N5z7ahRSu1gRHdZvs2cCclXNwGehHypCKnrkCZ4lpChsBUp6I3HVnnIuFCLn9tk\/JNOSltGKIwCirSf3ejT\/qFq4ugy8EodmxfdTPlkUZ5vw6slCiS6HyEnxFqKmxLNAtLqMKK5V2J6lge18zQJUhWCZSPhyIRk5WGky3lA+tqeK1n\/pfNeh54m+XwwdsshiNvUZGvxliXST76KouQE60hUCN6eyWzFJ1XvRPVQp4d70jG4d3qV4ryTHeOLDZDB8IzCPzecj9\/89YOlvUovUHqA2npNzn5xYPs5BfvZqqgDeXfcDUbaUpoxEhrmhb+1H9TcgpikRLUyMm\/j17KuDXGUHJ4EsexhIepESeHd741zLG\/8J\/gb+bDTH5TvE2Lq1q+KBIMM7iCA+soVdRZN8tt9b8OhsvJcDXprmkMrztcEPicgaO2O5vNpzNQLYPVcB10e9wqeRQdrkYr\/8vyFRfw2+Vh8eT9WBdu4Z0I4EvvBy7ryF9MNoH3NXhTaS\/s\/\/EVvaxh0BXzsJKKmVmPSQefP4ndfwDPRqmu","xmlFileCreated":1543258276},"120":{"desc":"eJxNjtEKgkAQRX\/lPiqEFNEP1JNCEIQfMOpsLu3uyOxI+PepEPRw4XLhHO5Nkvk0+\/SCjYw8Uc9bi4ziKYHUrWE4lYhTdQSlAXcf3suHlt96KQ94qJhkI4XPu6kRiYFwRva2GjlOgdbSUeYBknAVsWxK067ciEBz6keI++fbzIo6GavbngXfKemComnrsvoCpkpB+g==","element":"protostar","enabled":"1","extension_id":"506","folder":"","name":"protostar","path":"\/templates\/protostar","title":"","type":"template","xmlFile":"\/templates\/protostar\/templateDetails.xml","xmlFileContents":"eJytV1lz2zYQfrZ\/BYK+NJOIkHwkboZiqrtyaFFj0TPNkwYiIQopCHAISLb\/fcFLh00LStoXCtj9dvfbxeKQ\/fUpZmBDUkkFb8OW1YSA8ECElEdtuFbLxg386pzb7\/pez\/8+HQDKpcKMgelD1x33AGwgdCtEzPA7cGFdI9T3+0CROGFYEaDdITSYQABXSiXyC0KPj4\/WjxxviTRCOjgKVYgy08qqUYawtALq0ORJEZ7R29G8tFoQqOeEtGFlBUHAKOGqDSXVM+f8zOY4Jk6SCiW0v9RG+VzLSzeOZmejaqLlQUqw0uO+dudcocsmumi2Lmx0INc4vFYrkTrfnhkBLgkXRCmi3ZfiLWAQY8ocHMaU\/7lLucIV2iyqSJ5TGq2U06tG4Pfee3DRbF6Dhv5p3QAvIRzMxDoNCLjDWTj5EYx5YIGOXorcRoKUSJJuSGhpxlufOkBIZJDSJMvA8afufHrv+d7M79zP\/75z5\/3BrHc\/nvpjb2Kjfai2XFJGpB4Uo7x8gYgTwXWdrWSV2GgrPwCRNBXpMYBYLhnl5BhkiTc0ENzSn7cglIfk6ZiPqjf6ROliS0t3mwk6T1KyoeTRSnhkxKrVOl5w7boOLVhIUieQUiuK8Z54pXIqr+Q0xhGptaBxVCf+UQtmmEdr7alWRw4oFbSzVbYTobeOXvpiyauZs8CcZ\/29FRxoQ7JYR28pq0GjaUS0jIgLI+LSiLgyIq6NiE9GxGcj4saI+MNcsROKaq5qy1zWlrmurTcLuxRCveie3SRvu6pZJSiasg0rCcxdVTOgsL6SCG+MutDJf1D+tVTC5ttj3qKc2qiy+RUH8lm+crKbyOLM5ksalacCYaEE2b5vwwSnOJY57UpDVKnD4QbzgISFtlSDfHxWIKpzpSeYSGGpKm65YF\/E8IKwNjw8y3ue693P3U534MICtneY14Ozo7\/yGTAsZRtW05As8Zrpy\/S35k2v8IeccxPxLg7+iVKx5uEvpdDt9L6N7r2HSf\/nsnlld1Jiw6vhp+FnY25MRGKoT8jDZGISUnw0GdcbeacmkGNPIW1km719FFUZ3QO+Sj+iXtC9Hblet+PO\/bHvDuo43g7HA7c\/77j+fNoZDQrgi5QOeJ3pm0Rl+1eqVD8fy3gGtnshT+e892ipZV7CZg\/dvwad\/ngyKqr7\/7COhIgYGQqu4D7dFIdUwCMdMfQm\/qkdkWP3OJcNsVC8kW2wBGxHjWciuXiZWqsUFGfNmS3yKGCD2ZpkWuf2+2BmI1E99WpATQ2aeIeY7LGgy3FKbSZ6Dk3rWZP0pHP3ssmOVyk3OGXzZI\/oDzPMZelYrsRj5nPH+UvLvPpLtqb6eOP6RalfRT\/ZAe7DuH9ycjn4P\/RA09QDNfGMLXFooz\/+uPdGj+zG+hLM78pylt+n1RVqo+3\/O+dfXHJnRQ==","xmlFileCreated":1543258276},"121":{"desc":"eJxNjEEKwkAQBL\/SxwQkIqIPUAQTzz5gzE6SgezMsjs5+HsTQfDQl66uvpq66CI6wifGbXwnF1KMFvZrApeygcioHhOnLBiyRRyaE0gD7uST5V93rndoixTIV0JnFmfCERSiqBTP5OvaOaaZnPGiwgGmuJj5RtP3dFNnWrSfYMP\/0bNwRqvOeaB+3cgrU36j6p5t3XwAKipGpA==","element":"isis","enabled":"1","extension_id":"507","folder":"","name":"Isis Administrator template","path":"\/administrator\/templates\/isis","title":"","type":"template","xmlFile":"\/administrator\/templates\/isis\/templateDetails.xml","xmlFileContents":"eJzdWG1zozYQ\/pz+Ch390pupkV8ml9wN5uoXkuPimExMZppPHhlkrIuQGCSc+N9XCHDsxCSc2+lM+8VIu88uz66W1SbW16eYgjVOBeGsb3TMtgEwC3hIWNQ3MrlsnRtf7V+sD2Nv5N\/fOIAwIRGl4OZuOHFHwGhB+J3zmKIPoGueQjj2x0DiOKFIYqDcQehMDWCspEzEFwgfHx\/NHxpv8jSC6uUwlCHMTSurVvkKUykM9Wr8JDHL6T3T7JkdA8hNgvtGZWWAgBLMZN9AYUwYETJFkqfKwYnFUIxtIoiwoF4qUenKVgwtWG2UPEgxkmo9Vi7tHuy1Ybfd6VpwT65wKJMrntpXG4rBBIcLLCVOLViKtwAnRoTamtEfz2FXuEKbv5Unm5REK2mPqhX4bfQRdNvtU9BSj8458BLMwIxnaYDBNcpfJ34HLgtMMFDHoW0ESLHA6RqHpmK89aleEGIRpCTJI7D9m8ncnbmz+Z\/Xk\/nYmY1u3Rvf9aYW3EUpoyWhWKhFsdKZC3iccKbSbCarxIJb+T4oQQzTtxBLtCYBZ6b6qYMQFuKnt3xQHhH2FqCqjDGWKs3CVLX2HnSepHhN8KOZsOhdrFxl8YIp14fQnIY4tQOhSq5c74hXUlN5JScxivBBCxJHh8Q\/DoIpYlGmPO3otiq8x6hgnZ+xlXBB8oMvDrza2TFmmQW32z2dyBZvqSXndIHSWjWRFNe6lkhmok6b106dLkjmYoUprdfnxVmnXXApeVynXXKuv\/LDWl2QdcoQL7JoT\/m80fmvDk2A4nT6RiUxtKdqByRSjRmz1uXQsPUD6l9TJnSe9zhTNT8LVvCftBWb1\/bPG1H0KrYkUflNYBoKkFd930hQimKhyVYaLEsdCteIBThv57m61AO9Pikg1Wc14lR17VJVtPhgV0TRAtO+sW1iI2\/i3c4ng6EzMQrEThd7hcvbXeUpoEiIvlFtQ7xEGVX3x6+ddrfbc0pva0RJqHhVNLQU1sexwkid3nFRfHMGY6d5MCW8WUyD3vmnsyNjEkSVLzoyqJk7doaD5lFV+EZh9dpnHfT5yLAoYQ9Hlps7vWockAb\/C9Hk7WeIgoco5RkLjwzMu3Sn8+FgdHV5691Nx82DfGmoA36vKM9OP52Pjo+XX6jbaz\/GGIcE1cWoSHoNItKwBvwLNXjvTCZHEVXZbE63Av8jpPW0Os9vdmHsMk5RSLhxmPCF60zG88H4WjG5dqZ3swa8X9u8pr+QrJXXcwK2q9YGC8aNF2F1SoGaZ2R+eRImcYTLKjqxi4fFNQegSi3DuY39\/d6ZWZBXI+8BUFuBpt4+Jh+bVNbqUxgSoS6zzTd9F+yf+1tZbNz\/dzv\/\/yFfxbh3QZ7UiLCXLar+jqtJ1swf+I3qrATuJOvvZuGl66Hn+971u3l5aeZ7Nz+dJxI8bPxisG5eVzPfHV3dN0qVBv4n66rcqKFTz6blTs+v1chqwe3\/Euy\/APmg8Jw=","xmlFileCreated":1543258276},"122":{"desc":"eJytU21P2zAQ\/iu3D6Ob1sWISZOG0kyigMYG2rT2O3Kca+zW9hnbURt+PZcW2m7iI1KkJPfcPffcW6m\/VD+nV3CHjZEXtCkFG8pQXZoUrOwTuAGAD8bJFtMYFlYmPYaeutzVOIaHzqhVNg4Bsyo+gvEgQXUpkzOPsrbIFms8QqDQhaIUYWC\/8cp2DSb2zUQ2mwCLzqtsyL+4TP9eXd7MZ+dlHUFUcCETNkDM7humTMFE\/q\/7otgFdLYqranmxvd3XE7dwx1tDCpqED6DzjmcC5EZdQoL9wIVilwpOG6IvTWtzpA1OjzOADNrXE2b4XOqo+HSgka4wN6mA\/V6vS4a05osrZFFjXvWmZYNrV+j3QLc8gOJW5qlVKvEXWBhIm09OLU4sD10iI\/4Gt0OeRb6Q0ZpG\/hlYlLaYzzk2Ikc0KJBESItUWWR9tHiv37M37gfc80LM4SfFadbCmp6uDW+sdj\/Gz4MqLc75DAoMUw6cFup4wLXFFewNlmDtBYcR0QPdaR1wjioub6Gs09juLmCr\/z6HTBK+MZfM7mQ0YyHAsjxGk+lM562m8T7f0l+lGFBsUVeCIJSgo64mIxYDG6KoMN3CsOyTljWfbBdy\/05WRibMd7nPuAk9SmjO0koo9KTpcL3Z6fbS+LKR5BNtjgZ\/elqa5IeVWXKkXxbhZ0Bjg\/yXSme0VLIaneez4aplr5FS+3ehSveaz3q5JLIWanIZ+SnMZli4ZGn3oVAMYuIFvm+klAvjIIlH+mVQycmo\/vaSr\/a69\/nH1Vvlmwo8gm+p57b","element":"jcemediabox","enabled":"0","extension_id":"10000","folder":"system","name":"System - JCE MediaBox","path":"\/plugins\/system\/jcemediabox","title":"","type":"plugin","xmlFile":"\/plugins\/system\/jcemediabox\/jcemediabox.xml","xmlFileContents":"eJztWm1v2zYQ\/rwB+w+sBhQbMFuO16TpYLtTZMVxq1hG7LTJhsGgJVpmS4mCSCf2sB8\/6jVSKslSvAENUH+wJfK5493D49uZvbdbh4A75DNM3b501O5IALkmtbBr96UNX7VOpbeDH77voS1HbgDKgk8kwHce6kse2djYlYDt043Xl9iOceRIwEF8TS2hx7N9aCFJKALi03OhgwazEARa4J2qgUtkYXhGtz05rItxcCPk\/cHVDrpgiBwH+T05LosRpo8gF9YMIUeDznGr86rV7Ry97sm5igRMvZ2P7TUfqMkT+En9GXQ7nRNhhxA8AZm22kAhBIQwBnzEkH+HLKE51RKrJdgU1KDBaHItj6Y6+BARBLqA+oCI9n2hfM2595ss39\/ft21306a+LcdyTLY90uq2O+01d0gvKc5zoDkQkwF2V\/T3T5Q6BJrUFR3CBW2c+m0X8YSZCJkTvvbJIGh4j2QAi+XiPh4ctbvtNz05eY1rLcRMH3sBvYOpPlrMbmdz7XIh+vFSG46VM+NmcXOpL4baTO3JWfAP36c94a6wHesLS1YYEYuBoPdFOEEfOkzK1GcwiMcoG7nIhySNuuT9kdiDaCzH18hBSeSuKLGQTzDjErCwj0xByi4JaCZHkSx\/MoWIiNAl3cqhOJPAGlto4VI30OhvUFxgoRXcEJ6Uoa1JNpaA\/GQy9g927J9FMwmEceha0LckESVLRPpSlsH5hXgOwCl9BfUBxRKQ93ks2vUgXyc+czGYJcDw3+L5uJMxqMJroaLQzPGlMtKmyvyiwtQUE5orp2FQam\/Y6goSsoTm58RqMYNgmjG2U2hP+HCu6PqZor6XgEkgY31pyd1WGCUgfWrtEHNphdU5TaHlBTSHptNQGtxBshF2HkmDrJpbbdaTaRL\/NeQ7efmJUSHek0PaajLKEAnje28cwI2g+pc7Ec+0nOSZpmvq3LjaR2GCK+n82AUxrPcMd496Gy8d7NFbeeBHHjIPmsjPeJa1bmpMr6c1Rs9KLF3MQ8jK85bqPO4Uh+K5IlyeatqwgqEUk7JTaQozIXmSLTNV0fca8wCqZw0V6wKBu7IBelRoifFBu9KV24OGZqzjqx+UddijIkQxT0mMV6J0kmufVrFoTBV1PL\/dT1UMbMCY8LjTkKO2YFl8NZXqBlLdplK\/BlK\/NpV6FUi9aip1HEgdN5U6CaROmkq9DqReN5U6DaROm0q9CaTeNJMSfVzVw82C36Tk8XKUhv6PnfCTThQxtnwwqIZeuRplYTU3TvfYerxtSu0rNOXjeFi5FQrraza+RsEpo0nrF9p4dDGvaD4C1GxfHHnE1qDZ7H6lzcZ\/aAdN7pGK5z23m4QyVDKldwuJU3Vjpi0UdT42JhXkZGFPpyjScnY9nxuTZlx1yxUl4+tw9rA4HrJmcTdWjcnsoLALNTzvqAsOoHT5SezxS9kr3h1ejIeacfZObNMP4zCj53kzKfyjhGDXLuNxhbeo+Nw+U68MXZ8as\/GeoZwHNuArMi7vdKSsGW+RDzk15+MbbfgfTH\/U8aiL3Ic4LD1qFk+GxuXUmGiTIBzLp8IUVHM9c5C7SewJnnGYo2Qc8jAIszY54hd7JADGT4nxR2Vph8l15UF4ct3AykWcNvo\/rV1oN6oujNpjdQKrab21E7\/YXCRJsiaz0PB2olyO1TCxddg8lNP0vGcigmxolh6xi4nUtZGiHnbCjlQ8c+qC7fOSbhuSF+yQxcNh9MVKnjeBbA0tet+YwdmFMjQ+HkphquXZcbh3caSfMRJTvIf9XeH6uH95NN6PNTEzT8dXVbmfHK58Ai+w90WrlTXZptQmaHGH0T3ymwXDyDBGurb4MNY+alWH8xzu6+7yVmsvibWT2pzSYMVO09rJ+0GJ7blh6PNxndS2aCocoiVJhtS6ov+nokZUXZlV7dKysHpZZdHg03KicVP7c6J54Lec6Lec6FeRExWBX\/XXztFx8QwbR\/O+P3eysNoD0aMMB6pKRuKyOB8bN1XjDPwI2WAo8kcH4Lkx1bXzebN+4\/4XSq6CnVtDLeYXWlRxLL3SmqlZPvLozJjPjcvmTi39Ij1P8GtpFina61r9aKerlVgJ2WJbFvEnVeF1Y5yfz7SqbHceWH\/1ic3aPcms27pm3VaYVbh\/SAqTazhyeovmu7hkhQliILrSUnWbIzvGQiEQYftSDpR5aXtrL2ifoJxo2NIAWhZ1maiOXr8EmKyqFhHRjMurINixK2o\/VYlGmYgKQOiiR+AuuF2WQ0UOswzBBLr2BtoZkqHlYFfMij7k1JeTehm5rdFZjuakCnBo96W4Pvxpe8ReRJ20yFIu9PZSjYepEkWF6h4KkqiKyzeeBXl05c0PCehFz\/GISG8DSsDzMfXFZi1MSkVjKHuhD1xHmqRB78Wf6lCZK38GV+FYfBeu5EqajF0LhUH3Nppn+iZ1FrFRL4NzSD96ebmivgN5f+uQl0Fn9bNei8K\/\/hr05Mj01OXHvvXk1J3Bv1\/OkN0=","xmlFileCreated":1496065591},"123":{"desc":"eJylUstO6zAQ\/ZVhlV28R8YSqgpqEYurC0JdITeZJm4Tj689Js0n8Rt8GU4CFCggpLv0PM6c43OkU8vZHEwADXerv4u71SXMS8PkYb5ntMGQhU16LYnaRsNaBywh1a5pb7CgErMAUkPtcXOW1czuVAg2tm8LzNvXmbygNgPWvkI+y+7Xjba7DIS6SYPXs7kUWgGOV3MpnJITqY5iU4IlBtybwNAZrikycI0BofKoGZynLRYcTuXaJ0AZGyUboz4z6rou344KcvLVERU1qTsZiEgx7H+B8TtV7zV9C7X9F9H3X+8v\/wy9H9fTfDQ7wwOAOEa4XVwZ\/gBwEauIsCjIBpiR672paoanxyPnXN7HEHe4063pdastTjfUaizD1aE+mnbeNDCCBfDJFP+AZWoMJhxsTNkqk7mF5pQcJmh72Ojk4eT1RcqWhk1MQEWtbYUNVRAQB2qfA3OgGj54mnSlqPJLgiyyCNE58izeIMXUzNT\/bE9\/6tQzn+AflA==","element":"com_jce","enabled":"1","extension_id":"10001","folder":"","name":"JCE Editor","path":"\/administrator\/components\/com_jce","title":"JCE Editor","type":"component","xmlFile":"\/administrator\/components\/com_jce\/jce.xml","xmlFileContents":"eJytVlFz2zYMfm5+BaeHXvcg0fGu6bLJalLHzWXnOFmy7PbmYyVEZkeRKkk5dn\/9KFKSJceysy2+i00SHz6AAAgk\/LjKGFqCVFTwkXccDDwEPBYJ5enIK\/Sj\/7OHPkZHIaw08BKE9DqHkReLLBccuPY22sPgvYcy0AuRGN08lSQBLzpC5hNykkE0vrme\/zaehNjunIAUBi+juzXh6AKyDGSIqzMHiCUQbfgviIZocOoPfvKHg+MPIe4IKqzI15KmCx2N6xV6N\/4RDQeDE+SjUg+1LAXonDFkYQpJUCCXkBjihsWxMhqbu0N0OXvAl7dT9Ke7MBoiIREz1qXhXmid\/4Lx09NTkPIiEDLFlZ7Cac78YTAIFjpjYX3cuf8kI5RFZ2fgl4uzszoG7ryNfJAsKo18FSJjJBbc5EVDQrWQAQddK5Ywp1alJxoGJ8FpiOutEyagYknzMox1duZ\/XU\/nF5P78d3V7R9XN7MQt0FHTu+RMlDoUbAEZKsYlIldNv8a12l3WIuKnI8hrrbP5JkBkH7xksKT2iU2nkSUJ7CqwmsPtuTGoyBf5LuFNh8GoFe6DXBrZW78JvzB99F16R\/y\/Upq3W0iYHe4vDgy0dKU28ocebtDQU3atu4SYktRx5cRnhYkbcW4PsHA\/ctPbdJagjQxb7YS25+gykZAOTV1V+E2qpXlxlhz1\/vfp+hbAXKNXKK1QLCCuNCATN1TrjRhzF5xE5DqtOWY+tbaNfFG8YJIBdq2F9NdEkmXNoRrg\/ci84XtMjB\/2wl7GQn9vyxGR8mlY3Hr\/0rzvZDwGjzkVYhyoXRq+lwd581+F12ImwSGuMlu1YuSzNSU0pLopplUz4IXqHyrpivkhAPzEM3SXS3CFTw2UlwqYSZSEeQ89RCj\/O+RJ2zDGTUNpRkeJbryw5VZ8cUddeKww5G9vPPryexhPr49n02mtY1eQsEfaY+jb0mW\/2phFWrLwM3s89XlIQO5FPbhHTLR4LpGbu9uPl9NJ\/fbZkxG61h1e+CmzbQSKyTe29idtuthMSPKTLrn\/bkDMsNKCsZgxxRo44BBVtrcj1oAy80s2w+iPGZFcsixntHTgYgE2AEa94b2ADT5wg750jPnmlRFJI5BqWD1fNZtMJtI7xp7HZwp0f1c\/bO1jbHdYb+xniG8AfQMYgtohnFz8nxEdmu3d2B2tP\/90HypulqrPoruyHUn2x01xM2\/3NE\/abaNyg==","xmlFileCreated":1489488055},"124":{"desc":"eJzzcnZVcE3JLMkvUgjIKU3PzAMAMM4F6Q==","element":"jce","enabled":"1","extension_id":"10002","folder":"editors","name":"Editor - JCE","path":"\/plugins\/editors\/jce","title":"","type":"plugin","xmlFile":"\/plugins\/editors\/jce\/jce.xml","xmlFileContents":"eJydU99v0zAQft9fcfITPMTOilQYcj2gLdWkaUxjhcfKSq6uJ8e2bGdd\/3vcJilhQkIiD4nvvu++++ELv35pDDxjiNrZGbmkJQG0lau1VTPSpm3xgVyLC44vCe2RM+ZOCaSDxxnxplXaElDBtX5GsNbJhUigwbRzddbxKsgaibiA\/HArGxTeqE1P3DxVyNnJ2xH6HGJCp\/SKs8HswCqgTNlcyISivCrKd8WkvHzP2R9Ax5VtLiCIh4O0sMCmwcBZ7xsTlo3URmi7dZ+enGuMrJzN\/aauPmoxDWEdcxy7DkbsUvIfGdvv9\/Qf8Ud234bzh6DVLon5cII387cwKcspFHBsCUZ1U\/hsDJxoEQJGDM9Y557PKp2q0VW+JxSruzVb3d\/Cj250MAEXwOTBhKw9KlfZlrqgWB8XmfKmmNCS7lJj+ODuxWuMVdD+OGPx8+tmubh5\/Pawub9dr27uNovl9zlnY0oXtNUGI2ydqTEMmxJZf\/Ms33y\/FWcydJwZOWH5Rf3Oc3aEesnTOQ4dS6taqUY5ZN1oq2MKMqdgA87QFqsv42QDAknmXe\/h04e+Wk6a9fhZ6f8k4iH+Tea3nRvi7PyfiV\/ChC\/Z","xmlFileCreated":1489488055},"125":{"desc":"eJwDAAAAAAE=","element":"aso","enabled":"1","extension_id":"10004","folder":"","name":"aso","path":"\/templates\/aso","title":"","type":"template","xmlFile":"\/templates\/aso\/templateDetails.xml","xmlFileContents":"eJzNW01z4zYSPTtV+Q8YHia7VZEoUN8ZidmM7UyccrLe2HPIKUWRkIQZiGBI0Brn128DpPgBSjIrgWXpIJNEA3jdr7tFPVOz779sGHokcUJ5OLdwt2chEvo8oOFqbqVi2ZlY37tffzV7c\/Xfy4ff764RDRPhMYbuPr6\/vblEVse2f+Z8w7w3qN\/t2fbVwxUSZBMxTxCE5ZXrXy1krYWIvrPt7Xbb\/aTMuzxe2bC5HYjAxt2RvZvUyXfowoAltyZfBAklvhJnv4stJJ4iMrd20yzkM0pCMbcSCmcwEcFrFnob4noJn9nqKL+aL+T2u87M3p3kY35MPAHnV7Co+3PKnr5FTg\/3Z3ZtIDf2UrHmsZuINKCceYsYNun6fDOz85Ga3fXGo8xN0ijisfjPwUmZWW3mx5i5eQgPTpM2Ox949BTT1Vq4l7sj5QTqoD3TS+t8OqM+RJy4H379aH+4u53Zuwtff3UxC0jixzSSkXBndvVMji4pI4k8yg5V0GkYkC\/daB3N7OJa3WLpPVKfh114O2gDUCMeAsNHVyJxzOPje6WhL+EmR60SRsG1Nd8et+I+9dhRk11+\/iHW6WYRArPdKFw9a35FBJgmXaiQhi1nAYkhHaB4YCw7q474SbJ\/gG68FTkw9unA9SUPxf4R8LocuJDk2wX7s4hDGcooZ1N2p+4CiijwYwhFMrOLq3UbwaODYxsSpgcHl5wLEneO2jCyFAcHVRUcHC1y4qBFmpAYHx11Do4WVVi3KM+ywEKZLOlqlzWEBQmSqTG3Ig8qOrGQFwTqeuSJ9dwq2mpi+4xAq7OBNktNly\/1N1+HiHwlL3j0Qp9A991ZZOaZXW4EZc8ZA6p2jZjRRFgoIEsvZdCFnwhggTZD2Nx67\/mfkeDogUfofSoED6Vh0Tjm1nXoLRhBPEYBTdRhdcpCTemihzVNUEz+TGlMEvTpfymJn1DE0hUNuxaC3APy59aWx0Hh4IyrHdCjx1KSgXKzzWY2L7rWHsuQW+5VhkWzlFkOYXAvitee6DC+4jIsB4KjCrEIzy0YowdlXYvK5ZrzhCCxJmoVxJfqWK6NnniKtl4oZIwgZkDxU8sYZHu7N\/IPkls\/EwkBn7+W+wDv+6wr0VAXUCMMuxBsSEC9us83WRhqTt8x4oHTfua7FyKFt4tulvt8VgHhUDY09FgWmWXMN1nM8sz\/Vt4ZQDaBS5eweAyLBggOHrPQZngXzAs\/QwRtd48b8o5CUMEAa3HX8aXK56UqLY3Q3KTpG1So9CVGcl2kFkZrEgNQKr5JACd72vlHAkQzxwMefiNQKqfn3gEhyuGMjwr7iYjh9u2ILxLUIVesi9yJewnuqoSv+fJD1QlAXRlUznTRrQoxFVlsc9JkQR2EmgPNcHkJdCQrH7B3Lcot+pHetbLuXHBwv2vW6J6IFFreRXZzo25wqgGRnxY0KLMUziBzIDwbiAeNmAxRnAL1Cf0LjnGvEqxeuR3sZP8EW6JiYy1g94QRX6BfYAO0lRGSEVEAJZ1JOcstgeq12LPcDqrvgjqVikSFh3lZVqKa9\/YQ6imjc29nWnoB2RPDH8pph1pUsXLWrJbQzDXH2nQntb\/7I7w\/05bUuparINZMy46E1OmbTgfd395cXSOMOp1mniWR58vazeLzlol36z50DEi\/+ds\/Uy7eJemis4a7FkjU7MLblXin9kVYmtvrvryiJXG2nOpwuAho1nSx1hL3hrTofHvXvaXh53JZeYYq34hkQdcX\/fjb7S7pdpzE2fpoS+HbHKOV7lfb6dJTS5Sb5Rfq+3lwW1epam9J5O0poPA5S+D7GhRKzLdwNKy2mmZHySD5XrWP\/PTwyy2CL4R8S4ISY0mrY5xWpxWtjkarY4ZWp06r86K0Og1anXOhtW+c1n4rWvsarX0ztPbrtPZflNZ+g9b+q9Gaf1qXxA6MEztoRexAI3ZghthBndjBixI7aBA7OJd6HRqnddiK1qFG69AMrcM6rUNDtO69Bc25HDbIHZ4LuSPj5I5akTvSyB2ZIXdUJ3d0AnJHDXJH50Lu2Di541bkjjVyx2bIHdfJHZ+A3HGD3PErkqvROzFO76QVvRON3okZeid1eicnoHfSoHdyLrU7NU7utBW5U43cqRlyp3Vypycgd9ogd3ou5OKeecWi106y6OmaRc+QaNHTVIveCSiubFqoF72zIfkFZKmWulRDmDKlTOnSlClt6ijJeySqs9GosHmRCrdTqbAuU2FDOhXWhCpsSqk6SnJTsMJno1hh85IVbqdZYV20woZUK6zJVtiUbnWU5KZ8hV9Pv9JJNi9f4Xb6FdYFLGxIwcKahIVNaVhHSW5KWfhstCxsXszC7dQsrMtZ2JCehTVBC59C0cJNSQufjaaFzYtauJ2qhXVZCxvStbAmbOFTKFu4KW3hs9G2sHlxC7dTt7Aub2FD+hbWBC58CoULNyUu\/JoaV51k8xIXbqdxYV3kwoZULqzJXPgUOhduCl34bJQubF7qwu20LqyLXdiQ2oU1uQufQu\/CTcELn43i5ZhXvJx2ipejK16OIcXL0RQv5xSKl9NUvJxXVrzKR\/gu5L8o9j7Cpx6nLx8\/U6foxudhUj6LXHM3M6k\/DSXpDuhjPT+U3R+4TI4fIaMWnH9WyQHmWXYcJkY6K8nJXPwXJd+h\/AcZy3wl+WMKWz7j3ZXY\/l08f3kAsNMGsFMCfthSAWT9c7wiW0hBbYW03wZpv0T6gfMVI38L6HNQBm2gDEoov\/NUpIuXwTJsg2VYYrmK6WKxeKHAjNqAGVXSXz4S\/feS6Tko4zZQxiWUOxpCOpJEvAiaSRs0kyoa30u8F4EybQNlWkKRc+CjJ3wRMJX\/iRxrmL0Szm8kCOg\/I6n+IbD75UT+hFg+5qofveQ\/c4GRmV38AND9P03v75w=","xmlFileCreated":1431976909},"126":{"desc":"eJytV9tuI8cRfY6\/ovwikgjFEaUVEmspAhtvEu0m6yxgLQwDCxjNmSanrZ7pSXcPGfry7znVl+FQazsJEEAC2Jeqrqpz6jKrh+X6ve53qqW\/GrPTshEdXdIremtMowV14WxV4NqqWz\/WyhH+9tI6ZVq6Xiz\/SGZLvpbpZtJCUONoa2zWs1zc\/p5a4dVezvPeNe+Jtsrrm8VVXLu+64z1QT7pe8f6Xr1\/c3o63Lyh6UpQbeX2flJ7390VRWkqudgFqUVpmkK1XhetLkSnXMFmFV7axi1q3+gJeWF30t9Pvtto0T5N1um5R76yKsR6tlgV3XpVX6\/ftM4LrVcFfiMUb3vnaWfIm2x+I9ue\/vwvL1s20MGLTdhKgsWHVsVfNOVozAje\/cJ1mbcQw1bspIWNGxpEOWgFR2qGPTqa3pKoGtUq5y3CC7ES2gycpw+dNqIKccriI6AOytf0g+out0oDk+dY9U4Sn8R7b5e3\/ByLt6KRQedIYjDqudj17Xdvb67GoovVxlIBJsn2vwtfYue7FAx+ues3Wrk66Dwjb6BJRKxbv9oC6HxXtbux8\/HlsCEsrMJN94zImyOVWpVPLGlGrp\/dWtCDtJJhoFK05KQPh5Xcil77k8rTIwGNbZA4iNazGRyzMc3B1BHNWT6dMv+f5PE\/cz5wPfHgVzkObY6+jJcC1YNt+eEb2shSsGnJh\/89zypT9oDQB1oW34u9cKVVnS96Byh\/JQHDGWnVKB+DtVFaAwO2cEBWH8TRkWzFBn6c0JgPNgf28QGyyeYqdoKB3kdWyOoMOhU9bQySZUcNZ\/hGkpWN2eMm6O5r4cdXUAqt7LQo04tiVP6GwvFgDhnlEb1USFSw3eeK8m2ypOvjGz\/iEej5Oao+o9DxUDPtTjr4Z0qkO\/z2FuSG62xzIzj7wmILURLWq5IzHqB1poVwjHNjql5Lt6Bvh4hw+ETTYTfcOMOTc6I5gumNIae8vPuEIF6W9cJKiNhFK\/2nUD+7MEZ4tVl\/WcvyKQSCiZJZOPjrZUMupDACIfDfmnhRqydJF9q\/5DpzsfMv52HlOtHyikNyAadethvXvQS+\/iBRin6kn\/kkFaqgSABb39s2Vaw3KWmNfUqI9Dbd5FRg7qFmWTmQhAFy7cQzXjT5aD\/jCOwc5UcivIS6zSVmbEgu7JVA6RdOhgdOhXOo4DAlNlnACL9b+fmq2KxTCN\/4gCKsMm0J8\/xBgaZMCMNGGqqUA3WP4Ln2qmNGqJaVxN4NeAUB2ZbpnKPecW7yg5XabuEgtrQpAx8iRXBxq3Z97ETgUrLlAyf1HWVKEwJY+fp+cnt1Nfn4Uy3VrgYvXoSVFvh5e724ur2+WV7zhmlxtnjx4g\/LF0usYxx+ANnvJzdYQ+HjsZP3k6+Fl6gVXmKTCX8\/cXui19\/8g9fGsJf3k7iMOhphn6S9n7BWodUO75TwSdoJQIhXpjvjE7H2Sh7Ocyi4HMtDQDTyxQ1Y8l6IKHNuxEgmLpe3DNuCvpaI3JkupwU63Efo2ga8GHbVSfr40ywFNedpWYt2JwPLPmk3d6ter1darUPA5xRD\/Tu4dABLJYr9qRMJ7WvT72oug2wdQkZAS+t5Ij5zmYsCpJg1SN5VAdWsXjNd4ADAC\/yIqWpspTDzSTfcY9QyLXOUrmgKJusq9p\/lFzStpBeYIaoZEyhJJpSz8FfGwjS+GjrtbE4D+nN6OG6squY8xVmufjxoAbJ6pC4UROUGYyMV5jF5D2g55GrU7dT4mbOpwG8QEGPQ+FEPQlyqEJfcyzk+LMH65\/Q9t5AwFDAdL\/7ZG4AfJoD0SGs85UScD4JsWBgjkP\/5FA1IbDI5ctKBErDkg+th1JGCVtPrigOEdlONs5xZW1VWOsfhqBFKC+o9LTDqDwt+tzPOKW6ruV9tOdL+LhA4VXi++yopS0Wdtx7DT\/LKaxk3+BcTnhdfgZKsoxC8s6DXIW78yrQyaMdyRhwf6T4fYc6gZJhMJ9s8xql2aw6qrQDRdJnHrTBRl9okw8d3rnhaVl5xnEYsqJQNqhEZ1szWY0uWsaCx5\/GYrOk9UsyH2jiaevIUOeL6mGSx6HzKMxarBcAUlO8capnbAsdEuRP3gsS0GuL18Pju77PhkYxqekQMMAc2ClvWv5mRT6hsg2hvNYsJwm6Y4rGI3xAo7wT2WabSKClYLPePZGngV4pYfKXgGhRr1p8kJvHqvEilsdrSXuheBkcAKMpiFYrUMJGiuI2n5PSR6J4P2NP99ezsGzUk3HR\/c7Z7ExIY6Re+DHCAec7LmJhDW93gOEsMnxV\/YfeQuqMnOekx\/Tybb35zGiqiK5fsSvF6PFhdmu1lbPCXwxd5cXpsdBxpeBkoGYbpNQ8dPEYlUy\/CjPOsXeRvlNTaU0j5swKOvctYggmxo5\/OHaXhd+Q5PpLOZ1pejb5HOW23aTA9TZZW7nAsU+6Nv27+BjP+Xx8342+bOIn8Gxvp5zQ=","element":"plugin_googlemap2","enabled":"1","extension_id":"10005","folder":"system","name":"Google Maps","path":"\/plugins\/system\/plugin_googlemap2","title":"","type":"plugin","xmlFile":"\/plugins\/system\/plugin_googlemap2\/plugin_googlemap2.xml","xmlFileContents":"eJztfXtz20iS59+9EfsdsJrY8+56REl+dPf0uLUHkZCENknoSFCye29DUSSKZFl4cPAQJY33W903uC92WQBB4lFgZUk0Y2\/GPTEySWT9kJmVlZn1\/vDvD56r3dMwYoH\/68FJ6\/hAo\/4kcJg\/+\/UgiaeHPx\/8++k\/\/sMH+hBTnxMViX\/k5PHjgv56sHCTGfMPtFkYJItfD6LHKKbegebReB44gLSYhcShBwD1wwefePT0IghmLtV6ZBF9OEp\/4Y9IAvThaY\/dUW1AE4+GH45Wv\/HHk5CSGF7eITE9\/S3xqfbm+OTNh6PS7ylhsHgM2Wwen\/5L+19TojXc5hEndNkE5KKn8zhe\/HJ0tFwuWzM\/aQXhLCV06TQ+mi3c1jwGPV30R0cXV90PR3mpDcuGR5h7GtPJ\/H+G6YtaPo1z3rOHG+JRmJG26qT8ESdcafn0Tevk5w9H+Tf+xKHRJGQLLu7pVXd0YfZvLyzromvc9vSr4a3ZH9p6t6vbptX\/cFQk5oWnzKUR\/5R95HrXsqrLq\/B2llaMRxZvDk5rP7UW88WHo7xoGahOfTun7gLkUyu0CIOHR8Uy8ZLFMQ1v7zx3a0lelfFD3Pic+Q59SCu7TJJ9SzX3waMOI9o0cB0a\/nqQfjvQQNEx81MjFGoye01a5jRiMQXA7Avi\/T\/84z9o8N+Ho\/RdmdkSf5aQWcYRf5b\/oMUEGi71Dy\/ODk7zH4\/S762FO7vNGuZtvWKZz8CuVwV2hgoPMMgsPjTtAnL6\/cX8PgMVyS+NDo1hURP8+8v1q46K5HcaHp4PCsjp9xfz+wxUIb+bb9HKeftTNstbBnWdSOPtANoVCYkXZY0pf0Tj1cPMCYIPvD3Th2Z7RbUiywGSsZtHLIhHLDjQIvYEX054C56SxI3Tz\/RhEYTxr6+OX2kuGVP314MrKMmiOXXSpp771OJbbfu2bfXPzYvbq9FZ1xxeGp2chx8+BCm5dk\/cJH3b6WcKYS9YO2YB0fHBaT+o0HCnANKIRHPoOJmJZNNKwh1vhDtZC7cWYpjFkI5xNrpoEnTIJS2Q7VHGzJ4gO6G5oDHkJWs53x0XBPWCCCxOVJUFSbL42bY6xlZpi2RHIsbGIZnc0TiS6\/+vEo7OBnr7o2EPt\/KzJmpQ618PTv\/6XxLV\/8fB6X\/8p4RmHMTzg1MBd7dnln2Jr7cs17vVr8zbVSYjrL\/3BT29bT1INJV9BMxrYzCEZGerxurEwnqM5sFSXocn8jZ0O7y0bmQtKCPaY\/uBBjFxSRTJWw9CwnZXH2430wKVUNucnTIzBPL4Ay0MlhFYwIE2CVz4UGLs6N+08yDUmDfTmK\/Fc6oBihZSL7in2jgIIaWK\/qhFc+IEyz9qfgCPQ\/AZGvGd7NvD4ZI58fx\/\/OHk7Z\/\/7Sj9p8UhOOJf068818qQftGOFw9\/Lvz4cJghVx5k76j9uHrVL\/Bi6Kn8E\/O4RokfZzT\/lf5N\/4BQPQI9nigJaSqTw0I64SqNNFCJBuoPlrmwJc4LhBvmJy4lwDvvu4heNQxc0BVk2WMIyhFX42QeBtARgBx6nr6FNwMtmJZZ0SCkL1LyaeK6Wl2LxFkcLlwygUgf3hXYSSm1X7ST4+N\/ztiRtOz0T1tuXCsioW25AXG8IIgDMKGXt+iupXduTPuyZ1m2ZXW3c1Yjbm7hW16R\/yv3AFtAbLNnmH3bGFzrXbybiJlHmQ\/dKXiH2FUUVPf++FhSnUUmtiquTCis1kIkuaOPAuYOfgR2oOllX968fy90akI+OehH4\/NWFtc027jrwduYiMeie3svdG+yljHq2iaK0QqlkN0kdCF9hm4rIm\/k4yO38yCKJRyOBt0b42xo2tszqgJZg2H\/FgSeS0rWvSl0+5tl9bq6pG1seD69tO2r20traONbQdZrWdIx767nCoI+QCzUDzjmqJUVaU0CT+JPso8YRZUpxYK+qrz81enIB54dbRiTmEbaoZYOa62fa\/\/Sydj+1+0KlONWCNTgWmT66lSfzubEB60Sv44HFAqQJAI4j4ZsAlhD4gWkgkgk6VQZzQE03wnCsAbjKMCwuEUCjjQL3CpQ+kxVZywFS5hbg8seq+KFgBfOqM9Hr0SAoYrOPA7mUZ\/VdKZsGwlAJVEcErcGlj1X4StegdX5ilVgngDmiYZjwr7UzJU8KSCNwVTPyJx4pNqKxio2yhUxnqdQIWGiBjSeq8I5HM6fuQSc0lyEqGL940dAoy4Jk5qcjyowNIWZscSrwlBV+Z5SKHDgItlU6jAtAE37LHDZvdBGxyqNe0w4VMSbDu+rXNLwic6C+3qrHBMlJlvjJQeOoyURNHB4qioyOIyzkDwxVySxire4n3EkFjOws2uW9tLMyAXhq7ZyP1Pl0efIiU+ZiEdfpVY4j4k7I3XXMVbhasw4DrDkVFkaq3jsO2jsbeKNA6fGzp1SSyccxydOzSKUjMsFlDlza03JVQHxU5C6bapUE6\/XCbTFduAG3ljYGCdqkbY1ueNwwV2DTaYUioghR4RMRxtAiiLAU2k8EzCo9v\/9PzF00P\/3K\/M+gF56FVHFsOactzAgcU13cyWuuKIhcreTsbAOVIL2BDx1+4lO5tqA8nF7NqkiKnlriGsd6rU4WCsf22gHkJZVUVXim3PHUf10wKMM46gYh\/MFYL6wcZDEVffgfFHBgfyrE3jMr9uXo5qAOcEGy2+sgpRQEZlOXp0ak4RAbi2AoxNVOHDRxuxxEYvAVCNHdA9gLvQe3PsG\/qJ7BUgKiYsRxUE9IaaqiQuFHNaI5yxYCN0bVUlkp2An59Rp5R05aA49NgkDn0Y18Kmq4UzBmM\/ZF1HonaoY85RxHJ873ypLKp5tCp7tPCT+pOofpyqObQYauyCC0DJTUc8MzOGCBpDq1GBUzMFJYUKP+I\/VVq5qVTNIKC7mosyQP1MFgxq7YGPossVE1HRmKvU2g3q7CCmt1dtMqd7cDEVkRjOVNGW2ACDwWdQNkkWNpYWqpuIULaYeEXbjZyqteTbjYDT0I1q1h5mq\/5s9cqzHBoNQ6bPNQcRLwmoBba4i2hySw8vAd5Kw1lGeq+aH87sUa6Z95H\/q0s1VIvYckpzLxId+QVXlc5Uch0WvTs0JFRgnUxsHaDHQlOnXuwXpI0UoJ4USRoP0sYqA4KrMUCigiqti4H4hD6dppKoNvTC1ENViLkcLCa13YeGZ0uAeAMXErdoAU7FxbntfQL7fiEdE\/QL+VE2+LwuOthCMqMIjBagvUHm\/0bDuVr6o1N0XSCR\/C0Knxs4XlcTxDpzcR\/JE7uaCoeI7FTd397QNSW0EqHUHKvpI\/UdBO7lTUdIdhM6PLGRjUnOYdypR04WOfZcEVWfpqnTr3XuOEdfHtFyV1Bc04IJ369IoiOe1ThZ\/qNhGXAhNXTYWqJo\/U5GPcSDoWPIVzTGtjZu6SgqPOVg8T0g9x3dV3IALEaWbPFAPeoFhNT65KkHFW7467UFesaxakqc61uc9ZkiPokDAH6twdZ9iOey+NnPkqdiVF6c4cZUhT0XZXsJBkpDFtYFpT2mMgmvhAbDoA5vUjZw\/VOEKAm8vcJ3gviacSsz1fA7jz4L6zImnkgp4UYoTRzQMSbV37SnmJx7hYGEwEagJHirq3Ae0PvGYeKjPV4HzQw6VhEkFyFcd9\/Ih6vbpgojGxX2VsOu7HCie01A08OgrDa4GLf+Joy213ykRZGEpgaqg4D\/7kKmEZJYI1a86B+nPOOCM1sfYs6cquks4VFLtoPmqjdqfAk4QTgM3HwAWcaYyO+0HKeKSVJMpX3X8jE\/EW55wvlx5Cn4BnaIrctc0\/75QG+KGAoTj+ZDKitBUm\/nikaOFYGZVpWVPVeEgWbuitZaePVLFmgPWnLlssWC+aC0EUChALsBnX7F4QljYNAu2UPHdC\/AhV4HAbhcq7mMRc5QwTmY1r7ZQ7eIswM9eJTSMAz79IYqVC1WP+xcwtv9FxGNNf1GyNXBA0nkBFTcUghsaJFE9bQpVHFEIidxgCXVYQ1FJ5CKw1CFhfqxdUr6hqIIVqY7y3U9yvGvmTyj8y62Mq+0iBHinoTncq4zrLyP+jvoKnqVK1hHFHCTQbL62lfN4FQLDrDZ6F6mackQ4cOIwTQ+JOAWJVMwvgsY\/pD6tt7JIpc2HXGk0rDMUKmmNVy99nMyp69YqMlKdnImgZQ2ZPyOLoD5BmT5XBRwDIJ\/lDZr8ZEalliQ98RoNkniu6dNQODn7pLjq4i7MET+C5KLhARVv50KYHoZM6xL\/rtbLVI3R8ZdXpzb5whqjfqwyTQOixOBh7Dlh4vwyVnEwMcQtm3lBqHUp9M0raLFK8IpBZ3ZwR11SDfixisbigMOABVdBVNK2GFyRDd6HOcRJXZEdjEktxMQqjiiGLNBOwju+2k5Qj7HimOE9JPWj1rC1fSVOSqgGnIAHGM0EQSx9poBF6Hr9KXe7muGxULAMlahmcgkkmaMwaUgyE7Uks5VAd2v0NKYNjQueq6yQgjTimvgJiasmfK\/WoWndg\/Kuqf+UUMF8EzxVzQEgYl0zGkOiLwr1ihMOT2DKv4smV9NniliQM\/3OvDEZL+vxBp6qoPHEacnip6wjXkVTcWuUh+ZFfYmmbINXOTJTzg91aBUlUqm+eMm9P1vWPYba6GAruVu3x48Q4Z2gbgpAU8GUrrdPN8CjdiQIt+kWFs+b\/Y7xyexv38e6JhLL\/E124UXxo0sdj29Ofd7WkOaNu0P7c9fowEf51qkCqXBzCHHZzBdueyju\/uH5Pw0xrOld82L7Hs0CWYOi+Y620o6QTZGucV7d21EtveJVXL5t8I1HEoT02JAGgIF5cSnjgO8DbCjet\/oG3oT4fnleM4L6KbWRbOvK1mbS1fsXI\/3CuLWubNku2iptg5jpW08r77A\/Xxm3fBOLREdfgsCbsmguBuD7fs7NYXXvcRUkiSoVvQYYDaW1nB0\/IC6e7fBXqyjpXmdkDaGqpqE1p3swhYycHDdt5mtuyzdmx76Ut+UVmZChOU3bkpSjdziOLg3e\/OQs5XRCnuh0SiexPPKkzRjBlHF+brQRTK3olJxGVkbgNarF50HIngI\/Jm4TyKU1+F0Cck\/DGLrFjRDXxmDrzrrVl4jGq++NZ3d0rbZe9C2V1tRgMcXW9P5N6\/in9+9\/RuzS520LUT8pUcMuY\/FJBiWG3rXevzt5f\/IWxY8kX9kQCfnJQhxKTRhusqCI0lGBdBtnGH0pcIbRVoFUnOg4TkgbzkT4WTUB0zsDA7NxPacTWxWJWZw4lDlCpt6qMsUPA7NHHcPsoGx9TbuVOQ60k6MyNu\/sGMM2nsOU+lul7T\/8sEX0SRCEzo6O2smlaVvWQKF6MvI9dlpy2adB6O1Y9HNr0MNLnlJ\/U8HxwQqyQXtgdYWxCrLIOAzcYpZe1lfR5Y1MlNPLXscTUYTbKxA3aALeWovnhWL6yLZ6oPW2arJdBRLk3Fss7Qk6AHaj1krJ4dvOoUvCGSoZgz95dUl1V6BtkLmbvrYm9KZgVx9cyFKzoUdcQUq1ARn29G713I4qyFoHW3DedjDs5EjDawTW8FqOFsnke9vBSNgXJsAbFLWuc3S\/apk7Cl7Da7RZbUj3GrZ4g5KeX3GCctm\/Q\/dbLmdK1STinw5OT\/4kEfHkZyD6WUb0ExD9JCP6EYh+lBG9B6L3MqJ3QPRORvQWiN7KiN4A0RsZEdjCyYmMCGzh5FhCBAqX6RvULdM2KFuma1C1TNOgaJmeQc0yLYOSZToGFUs1DLqTN7Wqdrd4lkkQopoaqqW1oVOOamw54RYTeY2xkdcII3mNsJLXCDN5jbCT1whDeY2wlNcIU3mNsJXXzzCWKskh4BzKcA6BoUMZQ4cg2aFMskNQ0aFMRYeg60OZrg+h0g5llXYItX8oq\/1DMKNDmRkdgj0eyuzxkJv2Yc20tx1\/yPzdNdCe2cc10Jzwe0D8HhD\/vgKiRx5wueefcB24T8gGtyL83uC+N7i\/rwYXBnF6A8GOurYDy9alc8Jlyr13bH2KOLAZ3bftG9JDmzeEexx95ZLezClFDFrgkhdrNDRuLg0DMxi2od2jxHf0cRyQnQ2zfzQ+n1k6ZoR9TblHYT2yaB7x\/FNB1n4QevxMXtRwJ26cOCdsHHxL3ygafuPF+tagVztauDbOSWLqutVFIUWYoW4b3a58ccjl4zhkTiPM5eezgdmRYNh8OyPzG0FsYzDQzb4ExSBh5Wz8IoahD1TOx+fnbYMNNM8VlN110Ys3jUpeWjdoEygSNxv0llcgliGcbAXgSxB6Rn8kj6nbQExjgAB5uxWEr2QQgEgqL2slPUkVKg4sA1NZ82quwbwaC7R7dFtc8nXb3r3wa6eAk39DvmcVZE5p9\/Jn3gwn\/Ip2z5KvXOnuRV\/5YJzsOfGehU8jwO5FT0MHTvCMdM9iRxPiIuRFZWXDtt7FxKeUbI9yBvc0vGc761lYEFSuTUzXYk2JD8N5kY451M+6hiz7EcThHMHoYwAEMbgC0O5awxrMVm2jRokOUQvorGvcINGK7vusiThD2tusyfdJk\/\/mkyY+uU+b2o58YV+\/7upnmHGHNeUeHb8TktmsYfeRejjvDPSLC9kOpDKlghgofWwddAjv+NadnWQuZv\/cujH7nW2XnuUSF2hzvqQxalPGgu5mVUhpkNwUlwcn\/PI\/s92wTp1NhOuc0\/1c0ruJhErmr4K\/Pdk2kBKdcP0u5615N8hbVZbkW0FKdI0sbdkPoswTYjNImbCRK+JP5kH4sBu29H770hp8QvC1ppQwJroA69mMbb9PqkLZyFh2P96zL+bawuXwUt\/qXtZM5oQSHnfYCLI3YptCiVrC5C6bRfZedOMokzfyyfxpsNNmwn01vqmUqBFM7qjJbF6LaTYl6kYm45D40YKE1BdV+Ivbjz3Q+8MrfWD0MbVfom7Wq0dmFLOT+UeFPSuFGNaT7GSukh6phvCu\/tkYDIVBHKpjOmWIPS6ovBf0eX5uIra3cELz221sEQvqRwyx7xEraH9oInaM5YR7lHTMJo+TnY1enZntz23M+FVOuEdJF8QPQuJx8Xa1m\/VK71sDvWdacoE3pA3SiPe0rov1LYk2hPsK1sXlWwoWwSJxiWDXyhrjyroadXWFbStc48Wh4KLr\/vkl6sbN4VXIhR6bs5jeayw3ipWCWPyoxKs16BgDBWYz+rySNE1cTZyL5ppKMVbVZdqfqzVfA00W\/G7gW4eI5qPLqKMrfqFuR6\/NS0vsAMK0yAyKWcZ7lItZs9PTtydDAmqhCTwGSZyMER4Qa6afrZE9OkMYaE64rUXL3WDmOFQ84ZLdMfHe3mdIe2N+NDHnHnCqhs3GkUd8SJoQbRBlIXoHtdt42yXU32A5ywPIKWsBqOF8ne8QQ5h+TtewS39C3IiScDLfkdb5KQXdoaEP2ohjMIrEe6wFqALqR8J4pHKuEGjW6A+3N\/A1jXjr\/5z4PhXdJK5+wNHqTe1Lvd\/HDCJX6YUMZidPjcmu2mT2\/UxHRMIN6T6ncdOmkE20SeqE+S7DucbMwLvm0EYuOqrQC2sm4zTmu1Ib+ic\/FZi9HbvEv1Nhtv\/R5ptZEb2VWomGqljxUF9iVCl\/1tX7HyXVehtRdyqHGhrdcxlSHCzkQLZ1JcNZDU9IobKRA1WT5PPAkD\/tajVFyhNuOrhAi56T2JSBxIv\/ozwtsUHoWyKALVkNJfyCgB05rBtDty8xiXtOuEdntZJ04gbJrhYDr6Rod60RYkFwiXr\/gvOhyx01iJUkfDQSLXZKvH+pY+otEh8zKDWhbsSSSEF+2+hdjfqYIapqgQYRcxZq7Ts3HaM7NEdDiaKmZA6+dU6ZwL2ugM71S3Crl4ap4FlXCl0y38Ep9M5T0CWfVFXS5bpAgxbg7U3Sf6z6x2rZ5qLSksylzfXXM7tGtfaeOWXcMQdGm++UEY85O2zt0l+2OxXeg1h1YDZ6ckGwAurnrfPmMn+yjUFf72aP1FeYFSDgo\/oCbyjU5fNYZ9Yn+fqoLYVR\/L8XQlh9+KSwEoWFuIWlHaQ54LLynLBBtI5QNF6iMzCvzX71ZMxq+ZvG8jd696O8\/Flj+dUYu6T8oLH8ajZCoXt9HzBnzmbzJXmMRNX0jLGca8vsXIKp3eifMaM6JfI9rhwC2+SkHki5G8F587iyzZ75O85E18T7FZq4MQ19EvMr7HYmuN5N\/ZptXhuIOq8W2KMC+OLvQnzawVJ3VJDKCRs7VfXs8mVyEp95KDlxbbpv9lBy5oQrlmrTFiJJa0SC6LvCrffta4UFcXdV+MyybZXeKVdhtKBUdH5laQwYZSqcieGVYSD6agVS8fA7X7GQxEEUk3BXE978nfyovKGtDxB5cJl8j+2Xy97UAyh3AJgbeBRcHapTxeXB9QDWlE2p\/+a9p1uKfzS7Vo\/v0pR1qOpJfRVKmtiXNcjPviyZ9cucPz\/JEmnXG9I9GgwXF52GYsNdumELm4quib+V1MJjBbjclUOBX17Regd5MnCReP+VvTuBUUEvJ8T3QlclpCtEBJFwVfR8UAtliB7oqrBdfe82hwuBZhJ4C8TWiXHAl6IinC0EjrbVu8LMfK1JldbgrIvdIjr7FOLo2GXR3BNOCmywDIh2Z7JFOTMK6nK28nRhwIeOjK1Um1tQIJ1R2JzPr3DgsbO+xnHKeIeA1+syX\/D4Vnh1C\/X\/bM+pFtK\/JPxWM0dbLc8iQJzwFwWxNqaaw6KFSx6p87W9\/nlGfcqvudIIvCGBf6GhppctTpKQT8VoaSqT3ilG4f8rv0Wjr8M4pJTf0UiX8JZ7AJlRjUUpKLnnl7WN3RwNfk7Bv34OEm1O7jmrZDIHRh+DJOSmFjM\/PVnmaxpUV3+n8ddNzN58\/Lr6wfRTvCVz3QyvjjaMg8XXTggdqq9XnG8t\/azFATDmusEyK5HxNkj\/Dnn8\/XpOovhrjzos8b4OXb7efOsNGukffkMGD\/yICfs1pTCJjB\/igqd8hjl0WEgn\/O3RLxpqSaVpdw2UP91QNnE+oy9k\/gKMaiMAap3kCHoPfRT\/BdImAaZh8JKmiNL3J5sHCZzGC7RNLMfBt2fYtrDsrii3mDZ3Ii\/gWM98ENK2P9npLj+e8qDYL1A3iXDrgBdh5Yt3lLWej3jmUHhRVkOheGnWBRoFIvfVkcaXyKTzoUttg4gSTXFwsl6iUbglce92VFs3ORRKpNWYM0qYNW2jGJXF5dWtEBLOz\/LSKM7RS8+LtI2cVzYAKHJu56Vxfgq9PaBA28h5dRhakXVrVTzLMJAS4EeqS8TNbVswqqwoR5oaaWUgXKNWGnyuFRDKBAFkxeGORg14fIWgZZzroy7CcMrk6LU4pWL1bp68d1ksL+hjbr35Mg6KMffFyw9tCxdO15R7XOCRC7u7k5hzKXArvUrUTXJ\/PyL2+xGx20j+\/z0iFiLOrtL7P\/wBG2Wy4UzMGRHFUFMvJb61MdxRhwUESkdHpkHiO\/+EW40OLA4GwCxmJfqGVrxM3mXUh\/55gBtwzxato\/yjgdxDlhM2jc9lb6xFvlWxW9TimHQvRjNGuldiN0ut8jU74psk+bb6cfCwm\/Hu9avkQ0sVpvayv\/chror7jEZiLaivbXBw3WG0XkrE4k0844cJSQF2spGke\/aprctvPK7RNvG22wt2u2fIK3bXhE18Ye\/Z\/QnLGPam3Q1lY3Xu9rJSXkv4+0rL1BIWd3Vr6ealqGteS9RNLKLyaCRzuAw6J2zwTnXnvirAO0W92hrI77n399z7bzb3xmcrQ3tgGHbx7M\/KrYXSqIfdwzy8Riy6u27akHePDHQnx8f\/jOMGGenWhA18YQPdW1ygG15jA92GsoGzRyI6D6vCFpKpzzqi87Qia2BnweIJogKRDF2ZNmYP9JqwgaliFGvmCccScsffiq6BIb54I71OZWdnHV\/zBQjpRSmY3bFF6j32FUDw5pVPz7odFb3waUP6TeXFu+TS8drlIQd+9HfMPBokYo\/zruwJMZpK32abPcMaIZxOmVo8LsKZHKfnveyqNtO3nqVHoyAqtES9RxvOBE+Y6zB\/hhAdXz1nI7PbMfsXaOHX9PsWPwwKJ3DsQvSBhTpppEC7b5Hj1b0uOxRaeg1BuTnu4x4CvPv62BNfTH\/nuSH1wStsto+X+o3F9fn4QUZ428DoQ1PHbCMvEisONhaKosYbZzR48AQDjkUcw\/rUky1OJOFkxgRbRAs4+qB9YSosJ4eKiJhTPHfkxbk9cDM0O7ijR4q0wgDC+Rsj0\/03uCC3eScy668VaOJ0Grg80AULKvQAz7gxrNc9t7o8dvETp1GcFun36P1A+jnY0c7EvgSFo+RNCfcraOPtI8+SFHn\/yJpyv7JyW\/ZoPA\/k+00mLpugDr4BUfiEmnEtOwW2Tt0gV\/ZqkV9cF213zbbsrBtn7CKQOtborGtg8LwgiShf9rwdML3ckN9fgoFzgqXg2rgaXMe6qZ1Qv92ox1GA2Y6mEgWsga0UCQr0DSoQ7xcol0XsGSDRRIaiD9sya6FylI5Rg9leDbudEwRm8NNfReL9OhkP+vp8Z++u7tmEKuCX6aF6\/EXi\/Uqduhq+ASK7BGNnox0gzcod4DY258T7lZ4PtlUEf9kKLD6S1tMHH1HDAkXi73NA3+eA\/tbngIR5ncPuKy2wfB+B8qj3JV8kdW6Z\/Y6Jmd8pkzd1qvilBNSPXebfoR2lSpgwPtltq29jc9FKkf06Ta4EpYiBVUTmC\/nRiSglFMj3r4BtJ3EWZc9OrsRmSfhTOMvkDaI1HJtZKgspOjQAWz+TqKnpOM8SWN+4EYLJ9Yns3q07R6oW1TPsSwtz6bmgkHJ\/r4rw4m5fFXBXvb8q7m46gUJU5b5g5l7c4o17jTfVIGeW0j1m1pXeNu3PGZOYLbD1Mk1RosDyxCWROKKpL9DjHLS7+nCoxHOpRBPHi8B9\/GYqvrK6ny9QywpFhaQsfxMVq\/FcLiK+aiIMHh531KuCtnU1sD5tv2ipTJmzhAiML4uLHnmYuEkUU9EYvtK9Uumfdnc0tI1BT\/+E7k4JiogPOQ+ZE1W2yr2Uz4uB2RmitsLVCgh59Ji\/Sq+2KfXNM5Vq9pWVWigiZpg88PPRI35I7zaW3z2PZZ6iQ8VCTMFszxMWathqkLLKuebnwopHf543wFxkApl81IuopR618i9LPGpwO0k7aqg7SDrEmGopx8oUiuuvdpKGrnjjgz2QGiOGw6oFnmUDeemdWEAOtsv6zzF3V\/slxGfVfeZyUevIT35UimLcdeJW49WLfB8a\/D40+Lc+NIhfzNOG5mH1bHMzCV3e4sVcyk+OEmcfPyufJwPvSW\/GRGzc2pCKTzgAzsqjHC9nDZtYFGkbmQsWZJJecydbxonlbtWjw7G3Jm7kb8x3o+6ow8ffeGaN+piVfEXa5ppl\/u728afVZfZxAaNIvOKufhquKFbUqUTBok4lihZ1KlG4qFOJ4kWdShQw6lSiiFGnEoWMOpUoZtSpREGjRiWIGjUaQdio0QjiRo1GEDhqNILIUaMRhI4ajSB2iA5Sluu6Hj1ERz6r7Ozn7ZHg9gNCy8A2SB25K7BI\/L1Bfm+Qf48NEp\/PpVeW8\/4f5E7CjC69WT0JG29NfOZN8Py1q7+jwfZTZAtU4vvfOYeie26VhhOzt2xfIrWmaeZDnL8p87E9a1vTbNHHIz9ivWF2uHjj7II9UFd2TNdK8M\/8rPLtKVuZsqE7Mg1JempnaSxhVc1Q7nygp1cTSTo1K87FGFfmJ6PbtAZeeNp2qrbmVebKVShfWF6ia67KLRtKlZlC7CUtEzazRfzJPAh31O70fvvSGmBa35pSxtmOWmL2Pkx7XFPKONt9y8xejW2dRer\/3i0UH8fsG9O2N7t4ygnpksXpiYSeeNLpR4Xu6+o9t329t322qUwo7rhmfMVLSuOG5VfFVPk9kjX7xjAkdlAl3cYemzScOlIO+EcedRg5WrjJjPm32a4pjyzeHEUspkd2hnW0wryFJ7ccuLWQHpKa82q2JfPCZcJtImVXCcu2Ev1hOj2G\/6ay9UP5e\/lEF4rBjFDGYHMoKs47vlNgTh6RBNTb2EyPfHeDiXzp4PEf4X9IVtMLabpWG8XphvhImPrmX\/mXD0dgcVM2Sz8nC4fENKLhPciRkWZfVrKAKNSPuAvUFiELQhY\/pmNvmQKuUjPXLnIz10YpnDYEYz84ncfx4pejo5hO5q2QJh4NWz6Nj7JXCprI+l2tB8\/9cJTxkXFcZhO84ocN9en\/A+dGA\/M=","xmlFileCreated":1468307688},"127":{"desc":"eJwDAAAAAAE=","element":"readlesstext","enabled":"1","extension_id":"10006","folder":"content","name":"Content - Read Less - Text","path":"\/plugins\/content\/readlesstext","title":"","type":"plugin","xmlFile":"\/plugins\/content\/readlesstext\/readlesstext.xml","xmlFileContents":"eJztXHtzm0gS\/z+fguOq9lFlW7aT3N5ubO0RhCR2EegAxcldXVFEjCQSxLAD+HFb+91vHkhCskADCCe+WldZCJhuph8z\/euZFlc\/3y8D4Rag2IfhtXhxdi4KIJxCzw\/n12KazE7\/Lv7cffHiCtwnICSNhOQhAtdiFKRzPxSFOYJpdC1OYYjvJ+KG1eXZa1FYgmQBPcwomiPXA2L3hSBche4SdGVGIJwKJnA9QQNxjL\/b+DFXHdqAtMyYdW9fn10K36HLH159f9VZXSQNAn+KewW6A30iDBRdMSVNGE\/eaqos4H9FtxThHWsuvDwRLn8UfklDIFyen\/+AqQVhkSTRT53O3d3d2TxMzyCadzKOcWceBWeLZBmQx6yu0me6KZYJdSMX3abxVSc73dxRlq4fdC9en5\/\/A4RYRwCgsylcrlqy25vmExR0s358gnAZuFj5gHZlPutECH4C06QzTRM4m3VWPAgN4TCF0QPy54sEqzP7Jnwnf48FvDg\/xR+vzgQpCAR6IxYQiAG6Bd7ZVWdDSNkg4CZYRz03AV0d3oLlR4AIk1e4Zf4e9oO\/nJ5iijTy8Dllh+Iu1eUVO8vcY+0uohAhHyI\/ecAuIQrEtNfirsnxYcI4ihV0wR6In37V2e3P6WlXYAoKZ\/486+DMB4EXZ13A5nOXschurW+CJLvthzO4vrm6nd3DGvEC3PkE97wH4inyo4RKykSPI3cKkCgE7kcQXItjbeDIhm4ruu2YitTTFMuylfe201Ms2VTHtmrootBZd6Sz6klR1wLsVcmiqHNLP\/SX6ZJoVWMNs26R3oqCB2ZuGiTX4g94oM\/8IAGICJuAOU+XR6qujiYjh55oij6wh4TlWgXVSLc00M0ELxALG92YzQ5K9bqOVPLEdox+v45Ue0irSLXrMgvc7QSlIOcPOxTM+JPQT1a0gR\/nNTBduGijgzuIvMMKyDo+0VU751b4yZDKL9y6QQoy1t1iXQwl86rDSEq40C4Vc7kxzB4HlxiQ8DEFJZwshVyUFQ5uZDLAASpalLAbS6Y0MKXx8DG\/ciNvTNZgssiZqGDiaOxaCCSuH94sYABusI3iFQccuH2Y87A6Q8xUbEnVnZuhoSnUxBbvCHtMuT3Aio16IXZ\/+aBYHOY\/xy11o6pd62g4jnAEU+7xkMX4ikTBJURA88PPBaP5YqPrOEGYhkfV1liRbUd5r1q2qg\/o3ZFhKo6m6r\/uqL1d\/T1qmCnAWsA7NUwQLBluKzGsoXGj6rZZ2Twlym4wDsu1yx3TC0L73QKEp+408W9BUXx3UeJPA6CnBKNZn\/1IhmmYFITDOkNVMm1VxmNNn4zeKqZj\/aqOccOJbvOO2EIGVSLjtpgY8uLZvm1Jh4aJGzUTNs+jXSTgBnfuQyxRZ+lDNEhBnBx1zpa0G+mD5Uiyrb5TnL5hOoOJYtnWl5xz9wrdYDgXydhWjMV5YARDjF0snIGBgknfnU5x\/MVzlg1plnxP7FoN0cnGaGzo5LIlG2OFG85uk+1EWpb7FdiTWaYMjlGOTOFrs5NErdhH9ini4ANkGYMEMjPbBmv33ubxxxDg1PEgd115p+wBuSunXZ0XpGbQSwPQsuVHRm+C56NKZs\/T8KKrevb+P7L1saYEEvML3KHOrH0zVHReu5O2vPY+L8v8jNHI0J2JJQ14sq2LMtVjdKX2VbmI2aHwEMA74OUxgouAKwpTGMTX4kusUATv8Le\/5bRcHWJLmmbcKD1ujMCaV4EDnh8\/kSw91aoozoaiikQhTEB8Xlca5N4dFkU3bMU65xWDtW4Xo2EzTiGZa44Iy7D6ZQPPTF8Shq3karL6mYlxNKSVT7IK0qtkgdOJ0PWDouSKLnYDe91s\/7RMZmwnZjkJGaAVoRk+sxXHHuKMQZdUrcyOIeTNrGmfVpnjwZmITvwM9PLy3shbib0j6b1VVqTsWdg7sOq7bY8G7rar9bYAfuCHnx\/5z+6wv6gx7OnywsZpOCe5baqvZeVsPQ5tPwkKsTBbAciaVBtjG4lt1da4cfAO2TGgkW7scuXBwnnRS4ZbtvbAOitZNZ4UITDz78tWvU2lr76vx9wP8WgAVjorf4SqYy\/F2cekX\/tJ8aFnVGDO4bpjGPv5SWjHcwMwS2p5rDM2LJXNSBUcdk3F66+0f8W6mozHOCxrSt\/mWdElm8gHmZnqYLiH29HhFrPAev61wTIKcAApWDOsAZaVvjTRtiYKZTTWcGQ5COgLutZo\/7ioM20Ft2xvWV26c3Dje4W7sC8vG+wtqyOc+Dk3aq\/63nKOtAquz4s1BNShW5NrqJChUE8wRltXMpOUcRStnp9dNCkHYN0zJdylepJR0nZTMTpxlzntxeXLGipgM3Alb82RVBGZClDqnk0kqOaXeZpKVRwIRkOI\/P\/CMHGDFsKobBpjB2cb6r\/wXUmrHFCL6I8UWil7zsg6JRUOpfUWhJlMihx4yi4OBWrKrSBO781Lyzn1J5rGfLx6zgejd4Ag4IMeksColoO8Uwhyrusej6h5nYN094DabGP89K7xESYJXB5i99awbWN0POdgs0f7oJDOmyMX0WrV\/WF924li3jlzJJkDlW\/eZs9vAPbyT2wL3rHcxvU8ioX3quq0ztJFlqVIPbJVUzG1YUSV4+RbbEeASsN9bUHeGmYP5zQ1Yn6esqZIMgwgKhDpr1P6Vz2t2eqdbGiGWUsuSllTLit5KFwJimHgV15m3eqZZX+ouAq0Rck7wXt4IiULpD165JgqPTdeUAJ65FnooKroWuTAwx+mH8kSUo8eOQjmCEKygjygRy5Y4c1xe5McuJaEYoBRiEoOHM1hmtD2Bj1yxZ4Q90bHn7UWduTAjeOjrRYwR5I1yeKudsyRPEE6JLvTBbD9ZdECyeWrix8vz+tkhpkckjwky5OjimNvQ1cp2XXvaaKrQdcrEapWoiu9zzJVzZB6lSTaQ1oqVG4bi10orxhcLeAW7Id73pg1KNnJynaNKs6vODBni8N\/bmCVFCSsDNCkRm2t6baAXxoDtO0nrezPTywcUFc+U663TY8aKC73vPY1R+qKYxv20yCQ2PbNMTf986KQPT2LVDzRNCrbBOKdjg4y+lr2CKvbYk6KQZ\/AjWmFKKcf5\/rUwJHzT2zLk3M9bdeVt4Rp5MuHOT1fZ2Zxnfzosg\/R0i1a8v336ET4ZP2nogf3yB5R3zBHEveKb46EF74UVeGsNmsLI6aa3zduowSHRNStXednAmEYbwcHHScrEXCWboghL3JY64rQBgeD9UgZSToGqaZjULt+7aAq7yINodV2+UGLOGGfW\/MFqG\/cZfRmAYLAj97UwVw7vn4Yeh1JvY8f\/lT6fQI0ti1Xc1DGwe9rCWcUK3wRd2Yhv5I\/P+psYyD2JB79qNtPgcqO6NPcDL8Wp65uohq\/2fO8w7DmcJSvAXf+xDnPEuccBeG0H3prRYEgeRMJU7Lifv0tyn6d\/e038+QNuePiJ4PZ9be\/pyj4g16l74whbX4Sfk9IZewfpF3H7dJDRJrUwUb8oOg4cOipjPEECOho0Oc5hAcaj5+nn7NQXAEtHQknPQFAejpodDxM9By8vbo52KrOs16wYheKlq1mVCzyKpGipas75EYRQLY7L4B351WR240p0fp5W+Kum8mRVPj9Ch\/wy8CY2M2+8FQg+LdiF39wvdJpyrBd9oWHJHJJe\/xZ1cEzWx13w3+l+0pb\/ltELW\/6IzeMya8OJM+jdZVHfV+IbUq6RX9+QIq2iARf9FUhj4VtUn73WLbmcS2bb\/bSYVdErgWCmRzAmLwVwZ0X+elHdILZngj+cl7dZfG\/KTmWovWxAxoWfZeCNOB23gLylt98E0XBQ38zHR+\/tmE81j5kwYO85KnMjVtPhgMYzh0QwnRe9na6ouRTM7BJFN2YDCoXYu+ouUkSuqPP1gpY8SCxoQmWpIZt\/2CpNUioS2OkZioj4x1\/LdMWVaW6yJwcN36yyN6VWzQBxKR28gTT3p4ISxCmJ8IMQizgicC6iacHnFOQq2iJm0F2takanBvVHq4a8he4lfCooqL4txSnXjb8DMJDJq8uqPXPiWQquJu\/KnoNwxeQNxWPwxOOJmo943Ixq\/bWVxQ8tGRkeWLiSamujfdTN5StFQsX9LSWgXl4cZcH5M\/JGXkrNXtb8wuqqgCs3ixNvhOlCeyl49tvYBa7+bOzaBERpoygOv2UlMQ2ZQLucUbiNeWyAAHOUJpyWbp+2JQHLRbezwQGHkDdwA3nqUsqwLMLL5hpMxOSM+Ze5FKXfWX8cpep2VecYoFxwrAuu5KBsHULAUdJjJPD08FbsUsPHfp5FgVzJ3sdvbPlGvFDfOaH\/lVnxaIxx8PcwuBU18QuPXToZ9P+VeH4iNvmLCYvc++sX9Pe\/R+u0dni","xmlFileCreated":1433142402},"128":{"desc":"eJwLzyzJUAgKdssvylUMKMpXqMwvVUhOzFMoLM1Mzs6pVEhMSVFIA0oWK5SAJYsUvPLzc3MSFRXKU5OKM0tS9QATJxef","element":"com_rsform","enabled":"1","extension_id":"10007","folder":"","name":"RSForm! Pro","path":"\/administrator\/components\/com_rsform","title":"RSForm! Pro","type":"component","xmlFile":"\/administrator\/components\/com_rsform\/rsform.xml","xmlFileContents":"eJy1V8934jYQPrPv7f\/g+NQesJL0sHl9xltCWF62AVIIh578FFuAtrKlSnIS\/vuO5B8YYmezNZsDQZqZb0aj0TeD\/\/klYc4TkYrydOBeeOeuQ9KIxzTdDNxMr\/tX7ufg4wefvGiSGiVH7wQZuBFPBE9Jqt299W\/eJ2OfEL3lMViLjcQxccG856c4IQEYhVKtuUx8ZDeMJJIEa7C\/wZoEUyyjrXN5fnHlowOB0cQZAMtgsfzKecLwmY+Knb1wnGDKApUJwaX+Q6pvVtMDx6VyrrG3WEkWPD8\/e026RmZD5GIn6Warg19Gv0J055\/6JkTntd1e09gxGkHSSLDVWvyOkFHfpJnH5cYqMrLWaCOYt9VwCZPZCk3u73xUWjkGokhucOmdexeXPirXRhYTFUkqTI6C0XwaLpZf5otpeDtbPgzv7sKb8XLko7qSMcpXa8pIkH\/18hvxxFb4qCb9+MGoZyKG9CsijWPYc4o\/P98qqqGqDtcRknJJ9Q6KyXXMJQ9ciAscnDn3krs2F6pIRj13qPCE9kWCRmWR1TY9KFiI03ov4vHRcZQ9EzpNlcbM3iAc+9\/8S88\/6\/ed6W75153T7xdb5rxOLClYD9xkB7quE22xVETbR3DlBrCHrARFmEUZs5WpPNjwUZGuH0cqjxeaLIZrSlj8UyAhOfiUuCcN8qThdY4sjam52TAmGnjiVHDdcdZ0cxKM7rmOqSSR5nJ3IpiT1D1Jut+WYZeOEAkWAjpnRxTBVddCFpILIjXt+lRV9phQZZg9jDjLkq6VXMN7wiw7XXgdgbTEqWojddMxTHE4CieCEfU\/G0dhfQQPvSxvTT7aNyzbedOf1MAq4PZI6r7NhtFRkAMWGweK6nyqA4HdCrACTwqw8mVdBLyjJWcMGnOjfEuYaJMlPCasWZQJxnHcLHui5PlYAgcoRtAynHzgqQSHajSNyYudy1pVJM\/0d1Dqk1VdJV9Vg0pCYoodGNQ0TW0J2vG6mHfcKu1W7TDvkWrOAE3whjSLvrVlpu3IPrKOi0pgON1kBvygGlC5XYRXLh2N4WcESfuTazew\/5D99GrzHE2pX9nnDisnhVMcJ6Cl4JGWY6xJWpoF+WQJc6UJEtb5SwFSKBc9mA7NwjE1MXAtxbv1YXk6nA0n49B8X9ZAjuxqPNNkvVxdT2+Xy9v57A2MquE1IdzcLsajh\/ni7\/dh5c08y\/NxgDeaz77cTlaL4QMgtAM84uifTEgoOS7JAcD1cPTn6j5cjJcQzrgdoRi5D2xX9zfDh3E9bh\/Vb6MquH312Kt1g14ufItQvssob1JKJWR4Bw+3RdhAOJUsJ8sGgcaPjLQYvaai2ouzZ\/faSOKItczw9vKKjt7LbO+htncQV11Hc84esWyPv8ZyvQNWOLr9I\/LoyB4\/aK92qgHjkIJg+YqBfFT95g3+Ax1Zq58=","xmlFileCreated":1544536031},"129":{"MANIFESTERROR":true,"desc":"eJwDAAAAAAE=","element":"tcpdf","enabled":"1","extension_id":"10008","folder":"","name":"TCPDF","path":"","title":"","type":"library","xmlFile":""},"130":{"desc":"eJw1zLEOwjAMhOFXue4srLAzgVSRJ0jBbSJaG8W2SoR4d1Ihthvu\/84S74prOElZur4ItqFYs6XMiFxxEzZi2yFUtvg64F10bCfsP0dc4oOgXghVHE8f5qwJluhPYjNDVaMF\/exTQwdq+S9wJWTrvmvBL1I=","element":"rsform","enabled":"0","extension_id":"10009","folder":"system","name":"System - RSForm! Pro","path":"\/plugins\/system\/rsform","title":"","type":"plugin","xmlFile":"\/plugins\/system\/rsform\/rsform.xml","xmlFileContents":"eJyVkk1vGjEQhs\/NrzA+tQd2AbVqD16nKVCkKkkRmxyqKFo5u8Piyl\/yegP8+85+QVBOPdkz7\/OOx2Oz64NW5BV8Ja1J6DSaUAImt4U0ZULrsB1\/o9f8isEhgGmYMzuLvlASjg4S6lRdSkNJ6W3tElodqwCaEg1hZwss40ovCqD86gMzQgNPW4CMySb9ab0ekbW3LG4lRESNNs836S9rtRIjFvcZ1HIPIuDxCxGA39tX0C\/gyWwynbH4QmtY645elrvAP84\/ITP5Om5Ast\/vI1\/9bYtHudXoPJFoUzLHqwJf3T+SFRjwQpF1\/YJpcttJLB6YU7dLLaTiVe2c9eH7ZfW3xMnw6BV\/38hZQ7CfNJ9Gn6MJi4cQlQKq3EvXXJaz0dN8cfNw87S+XWXpn\/RheZfhWH9v7rLFMp0\/P3MWv+XRvpUKKtx0u2bspHvBhPpqiw9CebdGbudYPEAXDi5NAYdoF7S6ILqgagcpTFmLEiqytaoAn9AhE4MZr37QtuCQI0Hgj+uFdomcKrPuL2V9P9JIHH7v+H87Ru9KnANsmsWnj87\/AdzPDiI=","xmlFileCreated":1433425088},"131":{"desc":"eJw1zTEOwkAMBMCv7AMQn6BBCLoUtCY4OUuxfTo74ftcgqisXWnWQ5HA6Frd2BIzZeEWEJu8KaW4YWqu2KiJr4Gbuy6Ey18EyN7HgCwc6Fo7TgchJFmpnhBrrd5SbMbLs3SB6\/C4YxP+HLwXz55\/L\/eDYGpjAdssxnH+AlAjPPM=","element":"com_sitemap","enabled":"1","extension_id":"10010","folder":"","name":"Qlue Sitemap","path":"\/administrator\/components\/com_sitemap","title":"Qlue Sitemap","type":"component","xmlFile":"\/administrator\/components\/com_sitemap\/sitemap.xml","xmlFileContents":"eJylVclu2zAQPTtA\/oHgPWLS9pADzTSLYbjI4jTJ2WCksU2UIhWS8vL3JanFciIDBnIRxHlv3ozejCR6tcklWoGxQqshvkjOMQKV6kyoxRCXbn52ia\/Y6QmFjQMVSMhtCxjiVOeFVqAc3mX\/xCgHt9SZzywWhmeAferpyYAqngO7fXqYvUxeRw\/XU0piJEAZ2NSIwnmFLmN2N3q5\/TuZvk6eHinpkkJSXZL5filpDgHgpa9v2B\/f540uHUhJSR3bwW9GsvV6nXzIEpJUJ+W\/hhSQHW+UcyGZLYtCG\/c7soWa64ZcwYGeGuChtzvugD2lTr+DQT\/OL35RsgcFrhSpNxLY+PGNjKf3lDSBKKSLrRGLpWPXUqJ4Z5EBC2YFGXIaPfsm0L3LEq\/cciuPhbKOS1mdBtR+xN783VxIQJkR3qchzrcewChdcmPBxRFfYuZjpM5PrHCQ8yLxMUpCbpShpBIMlUi3VBUq1XfLtwrHNLBfrgoGpkVzLbNQKIjgppkAxYUTKoNNsnR5rdxsYYfSVC+WxUFOqpUzWkowX2gVMTbBcp2BtB6ujl1oJWDdj0iuFiVfQAeMjxwfrz40HBszI9wNxQ3OcqGEdYbXL02skYMq99\/DGGlN\/OxiR0Wbxs6jzDrG9OMdbd3Z8fbdawlLkMVBsGcgLVZtWw\/g+Lu3pB\/7PMZqUTuj6szqsKmDDg057j+8oM7GN7jdBRLP1dV\/sPJZ47vX2Y3+W0p2a3vUvu4V6VmsiIQLJe1vgv0H3UD+5w==","xmlFileCreated":1435844046},"132":{"desc":"eJwDAAAAAAE=","element":"categories","enabled":"0","extension_id":"10011","folder":"qmap","name":"QMap - Categories","path":"\/plugins\/qmap\/categories","title":"","type":"plugin","xmlFile":"\/plugins\/qmap\/categories\/categories.xml","xmlFileContents":"eJxVkdFOwyAUhq818R0I9+vp1BhjKDNOs2jUzIs9AGnPWiIFRsFsby90Y9W7c87\/8R\/4YYt9r8gPukEaXdF5UVKCujaN1G1Fg9\/O7umCX10y3HvUCZrgG0r8wWJFrQqt1JS0zgRb0V0vLCU9+s400cO2TjRIo8kF06JH\/vUhLJmRpfDYGidxYDDOEyBCPOX4W9zzZIJHpRicZkmuHQoflz\/Hs7y8g3kJ1+X8lsE\/YTJ66YVUfAjWGucfdypgIfXWZM+jPOEbp3jnvX0AGNnaFOE7w0kc72Dswcm283yZK\/I6mk5K4pSsY2LIV58bWK3fGeRBEk8h8hg4g9wkocGhdtKmt3AGf7ukbqXCIVXHMsVGjulXtD7nSflUF7azDDI8mkB2YXD+Vf4L9weuYQ==","xmlFileCreated":1435844053},"133":{"desc":"eJwDAAAAAAE=","element":"content","enabled":"0","extension_id":"10012","folder":"qmap","name":"QMap - Content","path":"\/plugins\/qmap\/content","title":"","type":"plugin","xmlFile":"\/plugins\/qmap\/content\/content.xml","xmlFileContents":"eJxVkdFOwyAUhq818R0I9+vp1BhjKDNOs2jU6MUegLRnLZECo2C2txfaYfXucL7\/\/Ad+2OrQK\/KNbpBGV3RZlJSgrk0jdVvR4HeLW7riF+cMDx51Es3iK0r80WJFrQqt1JS0zgRb0X0vLCU9+s400cO2TjRIo8kZ06JH\/vkmLFmQtdHR0jMYm4mKEEccf4lLHkzwqBSDUy\/h2qHwcfOj8MjLG1iWcFkurxn8A7PRUy+k4kOw1jh\/v1cBC6l3JntOeJZvneKd9\/YOYNTWpghfWZzgeAdjj062nefrXJHn0XQmSadkHeNCvnnfwubjlUFuJHhKkMe0GeRDAg0OtZM2vYUz+HtKdCcVDqmayhQbmaKvaD2FSfmpKGxnGWTZOA55nsHvZ\/Iflimq4A==","xmlFileCreated":1435844053},"134":{"desc":"eJwDAAAAAAE=","element":"menu","enabled":"1","extension_id":"10013","folder":"qmap","name":"QMap - Menu","path":"\/plugins\/qmap\/menu","title":"","type":"plugin","xmlFile":"\/plugins\/qmap\/menu\/menu.xml","xmlFileContents":"eJxVkd9OwyAUxq818R0I9+vp1BhjKDP+yaJxRi\/2AKQ9bYkUGAWzvb3QDas35HB+H9+BD7baD4p8oxul0RVdFiUlqGvTSN1VNPh2cUtX\/OKc4d6jTqJZfEWJP1isqFWhk5qSzplgK7obhKVkQN+bJnrYzokGaTQ5Y1oMyD83wpIF2aAODKZOQiJEveOvccKDCR6VYnDqJVw7FD6OfRIeeXkDyxIuy+U1g39gNnoehFR8DNYa5+93KmAhdWuy5xHP8q1TvPfe3gFM2toU4SuLE5zuYOzBya73\/DFX5GUynUnSKVnHrJCv37ew\/nhjkBsJnuLjMWoGeZNAg2PtpE1v4Qz+7hJtpcIxVccyxUaOuVd0iElSntbC9pZBFkwHIZ9k8PuH\/AcjGKcO","xmlFileCreated":1435844053},"136":{"desc":"eJwtTckNAjEMfLNVTAGQQuiAZ5S1wJJjo8QRSvfYgvnNfeCPh62BZqrU3AZ4Qu0D1ulVhE7cMoHTQnYoheKWtOr2F+sTJJMij51Dd7MuFZOdrngL1fAG+Rqatb5\/fmnWk8etsy4qpRyXL+\/IMcA=","element":"bfnetwork","enabled":"0","extension_id":"10015","folder":"system","name":"manage.myJoomla.com Secure Plugin","path":"\/plugins\/system\/bfnetwork","title":"","type":"plugin","xmlFile":"\/plugins\/system\/bfnetwork\/bfnetwork.xml","xmlFileContents":"eJx1U01vEzEQPZNfMfgEUrNuApEK8rqEFCpQhSLRHlDVg9mdbCy8tmV7m+6\/r73OxxaEDyN75j2\/0fOYXT61Ch7ReWl0SWbFOQHUlamlbkoivZleXCw+TGfkkk8YPgXUCXgizIsFgdBbLIlVXSM1gcaZzpbE9z5gS6DFsDV1STrbOFEj4ROIi2nRIm+FFg0Wbf\/dmFaJojIt\/MSqcwjr4TZGB1ymiC7e5Phn1SF8VTEP327hJtQFo\/tSxlUORYjdXYmAfH4+WzD6IrVHGds72WwDXx128Gb1FiJhdpbifIjvhvh+iAv4VxuWSsHA9uDQo3vEGiist1LBreiVcbG9k1bWVrKKRiLfhmA\/Urrb7YpGd4VxzQBVuAm0sarYhvg41z\/u6PX6htEDa+zGl1ZIxW1U+5TCNGTJaOTBlIwYc+6c4knyP4RUzvD9K3NNBaOHQy7V6CsnbfKUs9f3q6vl7fJ+KKX1y3QOKqM1VsE4kB602YHUPgiloj\/ThIDaxHQAjTETTDoK3YdtnDxA5THioU8X5eEALwOegVUoYs1h6JxOtBfDE89RNkjdYVEUk1cPD5zRca+5+41U6Pmx3eGcBg3yDJfk90Zj2Bn3h\/DjNvplGT1Ax2yjanQnYATlTBajIzWWO0kZvrej+EtghMgUK5xoPY3\/jx4\/IH8G8EQ5Zg==","xmlFileCreated":1468407784},"137":{"desc":"eJzzcnZVCK4sLknNVQjIKU3PzAMAMmwGBw==","element":"jce","enabled":"1","extension_id":"10020","folder":"system","name":"System - JCE","path":"\/plugins\/system\/jce","title":"","type":"plugin","xmlFile":"\/plugins\/system\/jce\/jce.xml","xmlFileContents":"eJydU0tv2zAMvvdXED5tB0tuBmTroKjbkiDokHZB0w7byRBsRlEhS4YsN82\/n\/xKXOxQoBdb5PeQSFHs+qXQ8IyuUtbMokuSRIAms7kychbVfhd\/ia75BcMXj6bhjLnTCPyxxFlU6loqE4F0ti5nUXWsPBYRFOj3Ng82pXQix4hfADAjCuSllmnHSp8yZLRNNmjvzidkSq4YHcIGyhwKH4KF8MiTqzj5FE+Sy8+MvgIapqjDvo7fH4WBBRYFOkb73BleFkJprszOfnuyttAisybU6DFX3jpi0A+ijnlWPjrN996XXyk9HA7kDXXDbo9vy6NTcu\/5fFjBh\/lHmCTJFGJoSoHRiQl81xpaWgUOK3TPmIdaTy6Np1ZZuBXkq7tHutqs4XfXLpiAdaBDO1xwHh1VmppYJ2mvq6gsdTwhCdn7QrMh3VrnWGVOlU1f+Wa9Srd\/tw\/L2\/TnfJn+uV2ni+V2fn+zebj5dcfomNtod0pjBTurc3TDcFS0u28a7rsdhJ4HHTyL2nz4kHJfMtpArVe7qrpqhZG1kCNrkRfKqMo7EZpOB5yiiVc\/+k1GOvAizHQPtj\/yeg5JMGMnm3fow\/J\/j3MUymD09JL4P8t9LMw=","xmlFileCreated":1489488056},"138":{"desc":"eJwdjTEOg0AMBL+y6aN8gi51eICFzWHJnJHPB+L3AerRzPwWbdisF60gMz8aTu9IB\/tRzYnRN6aUBtaQKe3EHL7i674avd4oukt9pIV2gdSUEEYugsnjVjA+BQzOgutzo8HrrKUHpfp1DqHPHxJOMvQ=","element":"rsform","enabled":"1","extension_id":"10021","folder":"installer","name":"Installer - RSForm! Pro","path":"\/plugins\/installer\/rsform","title":"","type":"plugin","xmlFile":"\/plugins\/installer\/rsform\/rsform.xml","xmlFileContents":"eJylk11v2yAUhq83af+BcbVdFNJKlaYJ0300i1K5aeS00u4sZGPMhAEBXpJ\/X7DjelF7txvDged9D5yDyc2hU+Avd14ancFLtICA68rUUosM9qG5+AJv6If3hB8C1wma4St0DUE4Wp5Bq3ohNQTCmd5mUGofmFLcQdDx0Jo6WlnhWM1h9HpHNOs4tUqUL2DpfGNcR\/CwlZjKcRZinlsWOL3r1RFcLS6vCT5bTyDrYwZHi92dMZ1iHwk+rcyby45JRX1vrXHhm\/N\/BhJVppvgkZgVT07RNgTrv2K83+\/RW5rEDCc19uikaAP9VH0eTgleS2YoSZSsYjX5kOKUQegeGScGUPEmYGEVakPszmrzhFfbnOBJBZLFqQ00tgwtCJ7CtFVzXzlpU5XoNl+V683u8XueL4uy2P16KO7L3\/d5ebvc\/SzW28f1w4bgfxXJoZGK+zQbp6kpYOxxBsdOQTqOyLaW4Ak6l1Cpa34YLnGOjJEfS8G06JngHjRG1dxlcFqBo9sUgsDik+T6YvUD0mHAwxe99ZCQ1DIW7CT9HyN\/9K\/N5ihdguCXv4M+Ax3oHfE=","xmlFileCreated":1544536031},"139":{"desc":"eJxFi8EKwjAQBX\/lefFUCl6VngRPHsR+wZJsTCBNanarltJ\/t7YHbzMwc81kBff2kku3w61kuIUE76A+JFDRYCJLhXZMSp8jpiK\/Aoe5xpkSpGcT3AgXOFq8KA4sWE71jD6SYZ8j2wr8qP\/vVifquNk\/h6yn1dd58\/kLLnw2zg==","element":"rsform","enabled":"1","extension_id":"10022","folder":"content","name":"Content - RSForm! Pro","path":"\/plugins\/content\/rsform","title":"","type":"plugin","xmlFile":"\/plugins\/content\/rsform\/rsform.xml","xmlFileContents":"eJydU11v2jAUfd6k\/Qfjp+2BGCqhTZPjrgOGVHUUAX2qKpQlJnhKbMt2Bvz7XscJCe3b8uL43nNOzv0IvT2VBfrHjRVKxngcjTDiMlWZkHmMK7cffsO37NNHyk+OSw\/qwDfRBCN31jzGuqhyITHKjap0jFMlAe0wKrk7qAyEdG6SjGNQ+kBlUnI2DRA0ROvNL2XKAVoZRUmd86CkAqZh6829UmWRDChpIj6ZGp448DBLHGf3leToZjSeUHIVr4FKn43ID459nn4B0Ojr0CPR8XiMjP1bS0epKoF6QXpeIVKolrPF8gktuOQmKdCq+gNh9BBSlLSYzu28TETBbKW1Mu7HtX4f0TGeTMHee+lyHtn0m42jCYyHkvbuczY1Qru9KDgLr5E+aEp6YUB5YKUz6InlxrMhiJqHhlAzxsuQMdJGKCPcGXYCIz+VGPcGBWNrB7gKo2cH57T9TsjbckjzaehwuTN2DxIkcCzRRb5rdiWCPQTjtZvGHyVvXdelZDyU53tAB8\/T2d327nn1sNhNH5fb+XK7A5+P69+72XwzfXlhlPQJXsD3pVYLr744FBY4xsEgZuEM3WxB1xQmZMZP0cF5331IuNmwR4nMqyTnFu1VkXET4zZCuBwufuKg2QaRS+CvazL1EfVa1HQvElLA9jWU\/xGwZ\/tepLt565RcdoG9Au6jYfg=","xmlFileCreated":1489483161},"140":{"desc":"eJzzcnZVcM7PK0nNK1EIyClNz8wDADfvBl0=","element":"jce","enabled":"1","extension_id":"10023","folder":"content","name":"Content - JCE","path":"\/plugins\/content\/jce","title":"","type":"plugin","xmlFile":"\/plugins\/content\/jce\/jce.xml","xmlFileContents":"eJydU02P0zAQvfdXjHKCQ+xskAqLXC\/QVtWi0q2WLuIWWck09cqxI9vZbv89Tpq0AQ5IXBLPvDdvPjxmd6+Vghe0Tho9i25IEgHq3BRSl7Oo8fv4Q3THJwxfPeqWM+ZOI\/CnGmdRrZpS6ghKa5p6FuVGB7aPoEJ\/MEXQqUsrCoz4BIBpUSGvVZn1tOw5R0Y7bwv3+jwlU3LL6GC2UG5R+GAshEee3MbJuzhNbt4z+hvQMkUTElv+eBIaFlhVaBntfVd4WQmpuNR78+nZmEqJviAspDeWaPRD0Jl5jXyyih+8rz9SejweyT+iW3ZXvqlPVpYHz+fDCd7M30KaJFOIoW0FRhUT+KwUdDQHFh3aFyxCrxeVVlPJPNwL8tXmia62a\/hxHhekYCyoMA4blEellrohxpa0j3O0rFWckoQcfKXY4O6kC3S5lXU7V75dr7L5w2a33Oyyr\/Nl9vPbOlssv88f77e7+4cNo2NyG7yXCh3sjSrQDvvhaD8iGm6824WeCGd8FnX+8CH1oWa0hQZWJ8Rz54L7fG6zdBTHJ90khC4bUY6yiqKSWjpvRbgQOuAUdbz60qcfxYEXYeN7sPuRP5aUBDV20fkfAXdyf4tcrdAJo5eXxn8BR9k2qA==","xmlFileCreated":1489488055},"141":{"desc":"eJzzcnZV8MwrLknMyUktUgjIKU3PzAMARqkHMA==","element":"jce","enabled":"1","extension_id":"10024","folder":"installer","name":"Installer - JCE","path":"\/plugins\/installer\/jce","title":"","type":"plugin","xmlFile":"\/plugins\/installer\/jce\/jce.xml","xmlFileContents":"eJydU11v2jAUfR6\/wvLT9hA7UKlbJ+OuA4SYGEO0nfYWWckluHLsyHZK+fe1AwlUfai0PCS+Puee+xl2+1Ip9AzWSaPHeEhSjEDnppC6HOPGb5Nv+JYPGLx40JFz5l6RIUb+UMMY16oppcaotKapx1hq54VSYDGqwO9MEZTq0ooCMB98YlpUwGtVZj0ve8qB0fY+4KcIfESuyQ2jnTlAiOUWhA\/GVHjg6U2SXiWjdPiV0TdAZIomBLZ8cxAaTaGqwDJ6ujvDs0pIxaXemh9PxlRK5EaHOj0U0htLNPjO6cg8ez5axXfe198p3e\/35APvyG7TN\/XBynLn+aQ7oc+TL2iUptcoQbEUdJExQXdKoZbmkAUH9hmKUGuvEjWVzMNkgM9Xj3S+XqK\/x3ahETIWqdAOG5QvUi11Q4wt6cnP0bJWyYikZOcrxbrrOIcCXG5lHdvK18t5tljdP9wtl7NN9msyy\/79XmbT2f1ks1g\/LP6sGL2kB++tVODQ1qgCbLchjvYjp2HkcRuOxDh6dOSMcYuEF6l3NaMdHDVbw8WTErpsRHkRQRSV1NJ5K0LzaYdT0Mn8J46dik\/vh7wI+30C2w95t5Ek6LFe6f8k3MG9lzlboRZG+3+LvwImzDTp","xmlFileCreated":1489488056},"142":{"desc":"eJzzcnZVcK0oSc0rzszPUwjIKU3PzAMAR08HPw==","element":"jce","enabled":"1","extension_id":"10025","folder":"extension","name":"Extension - JCE","path":"\/plugins\/extension\/jce","title":"","type":"plugin","xmlFile":"\/plugins\/extension\/jce\/jce.xml","xmlFileContents":"eJydUk1v2zAMPS+\/gtBpO1hyUqBbB0XdlgRBhywL+jH0Zgg246iQJUOW2+bfV3JiJ0MPA+aDbfI9PlGP5NevlYZndI2yZkrGNCWAJreFMuWUtH6bfCHXYsTx1aOJnBP3go4J+H2NU1LrtlSGQOlsW0\/JQCZQod\/ZIijVpZMFEjH6wI2sUNS6zAZe9pQjZ10+4McTxIRe0ivO+nAEwHOH0odgLj2K9CpJL5JJOv7M2V9AZMo2HOzE7V4amGNVoePsmDvBi0oqLZTZ2m9P1lZa5taEljwWyltHDfq+6MA8VT44LXbe118Ze3l5of+ojuyufVvvnSp3Xsz6P\/g4+wSTNL2EBOJV4KxjCt+1ho7WgMMG3TMW4a6DStTUKg8moliuH9hys4I\/B7tgAtaBDna4oHzWamlaal3JjnUNK2udTGhKd77SvE\/HORTY5E7V0VaxWS2zxeP9Yn1383ud\/Zwtssdfq2y+uJvd3mzuQ46zc3qo3iqNDWytLtD1G9KwYeQsjDxuw4EYRw8HzpR0SHjReldz1sNRswua+KelKVtZnp0gi0oZ1Xgng\/msxxmaZPmDRKfiM9SBl2G\/j2D3oe82kgY9Pij9n0Szb97LnKJwF37yRLwBs9s1Qw==","xmlFileCreated":1489488056},"143":{"desc":"eJzzcnZVcMvMSVVwKsovL04tUggszUzOVvBMzs8DAHslCT0=","element":"jce","enabled":"1","extension_id":"10026","folder":"quickicon","name":"Quick Icon - JCE File Browser","path":"\/plugins\/quickicon\/jce","title":"","type":"plugin","xmlFile":"\/plugins\/quickicon\/jce\/jce.xml","xmlFileContents":"eJydU81v0zAUP7O\/wsoJDrHTTFQTcj0grapC15VBEbfIJK+uh2Mbx1nX\/x4nbdKiiQs5JPH7fby8j9Db50qhJ3C1NHoSjXASIdCFKaUWk6jx2\/gmumVXFJ496JZz5qb4bYT8wcIksqoRUkdIONPYSfS7kcUvWZgQqcDvTBmcrHC8hIhdvaKaV8CsEvnAyx8LoKSLB5w3QePYw4FrNIWqAkfJKRbQwgH34QOm3AO7HsXJTZwmozElfwEt0diDk2LnWda\/odfZG5QmyRjFqBWhixwYfVAKdbQaOajBPUEZXAeXYKlkEboAbL7akPl6ib4fe4FSZBxSIa8Lxjvv7TtC9vs9FrrBxgly0tVEWBWnOME7Xynah881zyouFZN6a94\/GlMpHnoT+u6hlN44rMH3nTgyB+HGKdYmbFVc\/VPV0oLmNEKW4jFOYutM\/BM8v6akBwKnhLpw0rYNZevlPP+yWWSfF9n9Kv+UzfIfd8t8OvuaPSzW3xb3K0ou6UG9lQpqtDWqBNevR02GeZMw73YVjsR27ujImUQdEm7Y7iwlPdx6doe6GwPXouHiIgMvK6ll7R0PFZMeJ6Dj+ceQCHXXoEOeh+U+gd0Dv1hHHPzo4PR\/FvWhfmlzPoVaKBl+LPYH8yk0iQ==","xmlFileCreated":1489488056},"145":{"desc":"eJwFwcEJwDAMA8BV1HX67QSmSUDg2GArj27fu2e+p6gPFgNHdMqKFlCmN1YW7sztdqGpCRubwVaZsvoH5cgXtg==","element":"com_admintools","enabled":"1","extension_id":"10029","folder":"","name":"Admintools","path":"\/administrator\/components\/com_admintools","title":"Admin Tools","type":"component","xmlFile":"\/administrator\/components\/com_admintools\/admintools.xml","xmlFileContents":"eJytVktT2zAQPpNfIXxqD7YSWlqm45jyDLS8ZoBeGcVeOxpkyZVkIP++K79wQgJM2xwSeffb1bdPJ9x9ygV5AG24kmNvFAw9AjJWCZfZ2Ctt6u94u9EghCcL0mGInRcw9mKVF0qCtN6z8Vaw7cxzsDOVoHGRaZaAFw02QslyiPaSnEurlDAhrQSoiDUwi9aHzEK0NRx99Yfb\/mgnpAsKBLISverogsczJZghPwNyiOq5UYUqhUKXDaLDHuWMi0g2Bt\/ZPcCUTVl8XxYB0m8NalhndatFNLO2+Ebp4+NjsM7KwRx9Vcw1z2Y2OmhP5EP8EQMZ+i4a8grfZ1t0JHiM+YXoZsYN6ZJLuCQaBDADCSllAprYGZDJxS2dXJ2Rh09EaSIwQ\/hdOwhp6wmdNpWJPgdbwTCk7SNqEjCx5oVLcHQNcam5nRMm8RLLBbdMc4aVdqUiKV7xQ6lcsE1iuAXCXBm5sZpZpTGOvq8B+t70fXJVTpEHSbXCIAD9plyAIb7vLq\/PqRIYz9irMAhxfYK6SorZlFYrIUCHtBH1tIfcFMzGs9Xac5WAWKX4xeHxWT4gzafiU\/Uj6xo0KGYFQlsFkq4eTBfgcRcZ5kEaUfXqQpSCyaxkWS\/SVkIXQ27FxDIcOZD+ZN+Lqh9afbu2u+tRw+RjlRujilp3VUdvr18j4trXd1wNxBXPmmGvkHVbvLB12BxkWRtshNX5AdOIC6BgEoSH0g2eZ9VC6JGkOSScUZ47VvRZ7o++BIXMvOjg8vxu7\/D89OLm8vLsOqTOs2NfU9hvCfcSutw3Lqg2h12JmTFgTb\/4b7TUGz3VqUFmXMJK1bHS+UrFCYhijbsqPSs1L7q30xTYZOm6u8zv1UY3mPUpW01izTwszUQcgzEBviX687AGu3Z+VuMPTvYuJkdnl5P3wWMlU569j0qq0vcBm6X4YuD7E7\/UlGsm\/tWRX+zWfx35v3Bh5v\/FjZvTl36WVxBdXi3NWjqVxjLRpI7iG433BVcnV6R+lbQ7tH5yOY7q4zKdqmo91CCk3T+V6A\/h+eeU","xmlFileCreated":1496065625},"147":{"desc":"eJwVzLENAjEMRuE6meIf4BiCjoIKwQDGdkR0iY3Ovv0JzWue9NVSbmQyNPB63HGo9EM5u1tAtHVTQTdcZa4+3UdsaGoS8NbAPqcbKJN4j1rKokBn+qRcYmjEkpD0Hor\/Y+KPgoeSXc5vLT\/kQCvi","element":"admintools","enabled":"1","extension_id":"10031","folder":"system","name":"System - Admin Tools","path":"\/plugins\/system\/admintools","title":"","type":"plugin","xmlFile":"\/plugins\/system\/admintools\/admintools.xml","xmlFileContents":"eJzFWFFz2jgQfk5\/hcZPdzMFQ5pcOx3j1gEf4UogBdJpnxhhL6CpbLmWnIT79beWbWISMHC54V7A0n67\/na\/XWFjfXoMOLmHWDIRtoxmvWEQCD3hs3DRMhI1r30wPtlvLHhUEKaYJ+x5\/TJFq1UELSPiyYKFBlnEIolahlxJBYFBAlBL4WOgaBFTHwz7zZkV0gDssQaQGnH8gIVkIgSXlqlNCKEJusX2gHlLwakkX+qkg\/dcSRGJhAtE5og11g0o43aYO3ymPwFmdEa9n0lU90RQOGSwtdddzO2lUtFH03x4eKjv8kph6OOJaBWzxVLZ7eKK\/Ob9ft5oNmr48Z5U8H3yxUCceVhMsLuDO9KFEGLKyW0yw23Sz0xFlcm7t0TEhFMFsWUWfimXGKhCQActdnrzWuOy1vyANyobEJgHsi\/q5\/WGZRZLtPggvZhFKlueXdPQ5yDJ3ahPYvBZDF5qksSHOQvBJyhTSay3ZA6hL4mYzwmWKkCuVCksncRYGIpg6USAJCSRIHUuis44kNTmUW8JxONAw1oSIRdzk4w1Z0glZaWv0rYgWYe1DJpyUCkFw366rkfLyDIL8AGeyI4LbMl4m6fgaChFR3u2VbLOsc5JDNtMiWK8tJ9Fl1p5Gi4SusCiZNaWUewYOkCxwlrh+EFY614Ztv4y9Wc94otpNlzTUvIsZNgdue9rAuHOi2BPC5lNQThni7zCwLEF0rrhCUBjGkidRmEBldtmVDIvM+W23FBEngpszJjhCZGfJwoPHCNtPZpw1TIMItnfuH1p4CzMgLcMp3PTG0yGw\/542ncG3Tun606H39zRqNdxp\/2rfuq8bqk98I47bhvE3MLvs4yoB3HBqliVeOV0nt1OR3sZDidBICLAXNYxOZPlTBvbMhy74+HtpDqtHKNzyTI5s4SGkXvKE0hD238NhGWK9cy\/xDQR8wPkJihtYExiS32yhKbzGH7tUO6PRqV2Oes\/R+7Xg9LTwLVe\/7Fg29LTh9TRarX7rjNwR3tTKnAnV+11kh2m14nF0j8q\/0KuttO+dg8SbAN5Wsl0clWiNS8uqmXT5A8QroQ7rXTwGOFDx\/HKud9ve6M9Z\/4G8n9QDnN7xcRp9kj+UPXW0NMJmI4dPktER8mXTtLEvbndk9IadmLhipxeo9ya+wHSbWJPpp0PHBSwkOLz\/v1R89dx++7E7Q2c9qT3bc8EPsNWS7nbbzAcuHtVrnKf6Ctn4naqw5xXhbnqD9tf9kV4VxlhOLk+tBE3BZr6dCV3dOP7ymZ8LoHzY3ycZqnDydoyoI9cLCBUMYNd+W7tyhvne3\/YdQeTUc\/dk+AmtPwakKuBrzD6TSdf6beh4gXIMtd\/itj\/ABJiavg=","xmlFileCreated":1496065626},"148":{"desc":"eJxVzrFOxEAMBNBfGSqau\/xDRAUNiOMHnF0nseLYYb3LKX9PjlQUo6lG8\/pWfaUqiVR3mFcZhQO3tnFBn1cxiVqoegnQ4K3C+I4fLiFuAR\/x5r4qPXV4taQtH2OCii24z5Lmy1FsSCpp4XwB\/ftTnwJiqI7dW0FI5efAQGm5smXQkQMyelkDdWa0bSqUjw6x6fThy10DH8VHjoeKtMMnfzcpfI5ue1ReccW7MV4eEvSp\/vk3bdP5PzC2NqjEzLn7BfFyZX8=","element":"atoolsjupdatecheck","enabled":"0","extension_id":"10032","folder":"system","name":"System - Admin Tools Joomla! Update Email","path":"\/plugins\/system\/atoolsjupdatecheck","title":"","type":"plugin","xmlFile":"\/plugins\/system\/atoolsjupdatecheck\/atoolsjupdatecheck.xml","xmlFileContents":"eJytVF1z0zAQfKa\/QugJZoidFAIMY7ukiSekNUmmTXj1KPbFEZUljyzThl\/P+UNJhkKBGV4SSbe7ur072bt4yAX5BrrkSvp04PQpAZmolMvMp5XZ9t7Ti+DMgwcDssYcsefOsEabfQE+LUSVcUlJplVV+LTclwZySnIwO5WiUJFplgINzp55kuUQ3DYA0iOjNOeSrJQSJblSKhfsOVkXKTNAwpxx4bkNHnmsQi0dzHmyU4KV5NohE0xkX6pCVUKVntshDthGIJAd4WN6inZysIQWdmCttQh2xhQfXPf+\/t5hdwAbtmHJXVU4icotq4YhJ1HFXvNsZ4KxXZEXycvz\/qDfw5935Il8j1wUEjzBCkMwna\/JFCRoJsiy2uAxidqQLT15\/YooTQTWSHuu5dW5aGAGAROMBHj5oNcf9s7f4kWnAQR2QgG223PtBs9TKBPNixoaLKNpPFotFtHt1Xo5Ga3C8adwfB1PwtvxzWy5mi3mnnuKR\/qWCyhx0a7qvpF2LnzKTN3hr1XT2WQHyR0NHp85xa7wXEuuJV2r6Qkms4plUJKtEilon9oT2lxpd8QwnFyQveklDZo\/t\/l1CpHF7VzGv7iZS4617DT+hyBGHokeN42lgmmWtwVrlqR2ffQVK2yN5vhsukdm8BVSksKWVcL4lJKSf8fjIUWFZ4TgRGxA+PQ3nYtG8+l6NA3jxZfw5mY2CePoMrLUk07+g0A9DNRtjB284IuQW551YwAiLTtbLaJplo2A6WIbVvKkDXWxLgD12\/yD\/zf4FXraevh5NIsOdv\/acEs7mPw5N3zURlfSZrfjaQryJL++TXAw7Pj1OLe+m\/J0u6Z+tmqee\/jUBj8AjpjUxQ==","xmlFileCreated":1496065626},"150":{"MANIFESTERROR":true,"desc":"eJwDAAAAAAE=","element":"lib_fof30","enabled":"1","extension_id":"10034","folder":"","name":"FOF30","path":"","title":"","type":"library","xmlFile":""},"151":{"desc":"eJwVzTEOwkAMRNGrDF1oOAZ1BFzAYR2w5LWjtVdRbp9NN\/rFm89fApv2nxjGMubCBas3vN5Pb\/WGuTnSQT29UsqXVA8UVk6Ga+GG6EuVCHELTLIiL9O3HAE7Bdho0aGOC7Ljwuv9cQJ3OivH","element":"rsformdeletesubmissions","enabled":"1","extension_id":"10035","folder":"system","name":"System - RSForm! Pro Delete Submissions","path":"\/plugins\/system\/rsformdeletesubmissions","title":"","type":"plugin","xmlFile":"\/plugins\/system\/rsformdeletesubmissions\/rsformdeletesubmissions.xml","xmlFileContents":"eJytk8Fv2jAUxs+r1P\/B+LQdSOh2aA+OOwoZ6gQtInCYqipyySN4cmzLdgr897MTaIqq3nZK\/L7v\/fLszyG3+0qgVzCWK5ngq2iAEci1KrgsE1y7Tf8G39LLCwJ7BzKYOvOP6DrY3UFDgrWoSy4xKo2qdYLtwTqoMKrAbVXhSbo0rADsUV+IZBXQrHGgPlpkv5SpemhuFBqDAAcoq18qbsNXLIkbd2hjtWcZush+K1UJ1iPxsRLEtQHmfMOYOaBDbbhA3wdXNyQ+Exqn0gfDy62jX0ffvGlw3Q9OtNvtImP\/NuxorSrf+uYMfYKv\/QkAnTys0AQkGCbQvH7xZTRtJRKfPN24acW4oLbWWhn385z\/3tF1rIygH2fptOA8ZkB9XtGAxKdlkAqwa8N12DIlvafReLgcPs2nkzz7ky3TWe6P+3ExG6fTdJlmq7vZfZbdPz5k+TjNRs\/PlMTvAZcXAbnhAmyAt68hENTmnWBjNz69osnNdrFh+okQ6a0m8QlzDqVcFrCPtq4S55Z2ZdsYmCxrVoJFGyUKMAk+VWKQ\/ckdbpmnInLMX+Sj0jwiLcq8vZ\/5Z0NyyX2YR8T\/AHr5I7Rbha2R+O0fo\/8Akas3Xw==","xmlFileCreated":1544536031},"152":{"desc":"eJwLCnbLL8pVDCjKV9BVKEp1dgwIcfZwVCgzUijIKU3PzFNIzMnJLy9WqMwvVSjJV0hMSUFVVVyQmKtQUJRfkppckpmfB1IDVFqkkAY0VQ8AoSoflQ==","element":"rsfprecaptchav2","enabled":"1","extension_id":"10036","folder":"system","name":"System - RSForm! Pro reCAPTCHA v2","path":"\/plugins\/system\/rsfprecaptchav2","title":"","type":"plugin","xmlFile":"\/plugins\/system\/rsfprecaptchav2\/rsfprecaptchav2.xml","xmlFileContents":"eJytVFFv2jAQfu6k\/Qfjp+2BuKBVqibHHaOMaeomVOikqaoiLzHBlZN4tkPLv985TiBQ9WnjIdh333139\/lsevVcKLQVxsqqjPEoOsdIlGmVyTKPce3Ww0t8xd6+oeLZidKDDuBxdIGR22kRY63qXJYY5aaqdYztzjpRYFQIt6ky4NG54ZnAQHRGS14ItmwQaIhul18qUwzQwlTIiOlksZp+naDtmJIG5wN4DSyG3S6\/VVWh+ICS1uKdqRHcQTnX3Ak20UYqND4fXVJy5GiQld4ZmW8cezd970Efhh6Jnp6eImMfG+4orQoI3SN9nJIpdC7Y\/McdmotSGK7Qov4NZnQTXJR0mEO5s4JLxWytdWXcp2P+PuIQcWcUe1nLweeRrfZsFF2MoxEl3d77MmFTI7XvmdHB\/fR6sprcL27myfLXcjX7noDSi9tZq\/DPcXI9W04fHhgl\/UBPFHZrqQQLy0hvNCU9M6A8sNYZiGuF8WWAEbU\/GkztbOwnByM4nspIt4NBw8ifb4z75z88mgC0CEPFNs5p+5GQU3FImx\/Oq0iMXQMPCTGWaJUnRqRcu3TDt+MIphw6aMpqC6XktPymJwh2XDVqgxJ\/wuKM+rZRZiRAY1zswIERMBsrXHNNLjEDG2k8pOWIYE1JJ9gZ5A90lPSS0Lr8Hyn3LK8n7SfyBo+xAbSuVAbChNCwDnaA+GNC4X7HGFTWPVkxOzGESenCjkmYLDPxHG1coY4hYbc\/gUJkkiMYSifL5gb75yVPwpuSnFaAQr2gkA\/DR\/082n47lDSQLo3iZV7zXNg9Q2dpSbotchyeQlEO558xa\/5I841eryqSpYRHoSX4dzowv6Q87Lx0lOzvGfsL2Y\/qWA==","xmlFileCreated":1544536048}}";}PK��#]5��8DD(system/bfnetwork/bfnetwork/tmp/.htaccessnu�[���<Files ~ "^.*$">
Order deny,allow
Deny from all
Satisfy all
</Files>PK��#]�J_;@�@�*system/bfnetwork/bfnetwork/tmp/tmp.patternnu�[���RC4:fDvf94MVLTKu8oZge4i7dEyKK7UoofI8qSh0/4AunPyIeHBc12TluYTqeQFULig0Lag80r5Oue8FssCKPX8IeLmxhPCEHKrcQ4bXC1u3b6zubJCZGzhIZIuJ5+MdzqQtF4qom99qyjhgkWPkP/dhiS6Fruc/qEMYzXNLpzxOQYPHkH3tIrzEX8wmwujRVsinpWwZ7xaxp/97xSfBhu1qekb/6uoIWfux2ecjVjQrGTL5/CnzWGKYFd/jakp56twffUZrsn6oGIuxqsOdUX/8QyQVf2rbAxZGyBZhj6S9fsKZzFLlFfEaAM8JjkAMwSPROi/gHo0EE0ro+c7gRkK7WW/Ut+jxnB/UIVYlhTafUMs5Qsk869baCxoSgCLMT6/8ohdPBUoTrJmitH/4VmCKk6tMqQuC34bDYUYbdeOpCfFjGsEFJzClaPZA+0PhJmF4DBqh5q3RLfRKKwGKvqOunhzOlGemaTbPrQ9ePh7nAPFQy9w4MDD/VVm8yzl6WAZpH32H8I4+Qw7bAGh22EPpCgHXaEHZJTsT2kweIsRtpZslAWPMG7C6wZBfk+vYc1lGUv9EVKWTro/r9pb/4aAaVbb6ztcT1oxGTYXBLfaRzvr4HIdZ37YujbphxI0e+eUdfTXVgWpi0+E73DlFi1gDw1aCYGfShNiKGJnBoeaOgl4lekKIqhPWgZm00+JcW64glSot3tRgiKfPaKqbS4BRSOyFd6lrLJtu9s0tqeZncvHlQXC88nxIVaTYieI6P8ZOKlAr+o4Js6EWNf5FklofPwaJstv1BfTILBpJmpqka+1UT7CgdsrlOEMPEs3bDAeL4MWTX6ex65pxYdI7hoIvXcNACAB1Tg8r8kG5nGTaaovj3TOp3OQgUX7hP702a/zXpcaQuMixrXlMqlrxJ+7GlSeibzlfMqifWqABgtrGtdWuiqwOjBlEXcN0WH2/Icwmj5F7cRPWQjlFlbvYLqsKPOg4BDGvajAhr1CAmfcH+i6VKXeoHFVZZDO4NzeMDK6y12UPKubpDIYdsPh2D1lTC/tfTskobBdhgVbbY1yPFJaaDjkS42kRW+3vgdMJJyYdAhnwDe3ocz3X3ZSDowtiVjLlyfDtgwDxNznsr2j5F2QfomZq6FvvPEAKVdrgpXJBUdo3nyKnO0jo+MpHlTHQCOwxBrjp5BEOL0fKNLfzCoOCT9SVVfwcFffXPQNBKMGmCF1exw4wwJyzJL6RdNWvoALZ/GnlKNHPMzEBLkaa43oOW8ryObJvMgso7PMfOm3uwvyc67uLDRs7WH+vgQCKc0v2/Qp/UleJZCwuz4TosmgvNWmNTJIxhW2zRNBvGo27Q7NOlunhgaKwz/vh8NJ/Qdnj3ZaEbwlkPT434kvPqNOPp8qKOANClewSbgH3jD5rfiyIMvOcnvVbpFJsmt3fWeZvgLtN0PUJZ/fsNfdDyHgtrm1mXyk+mPSowy6fgEFeGfAf8ZOEoZ7SXAXVwFi3fconfQQ9mwiZvgvmBeEj/lNIdedwJ4u0zvaFitkNilmGDzB+5YU5CQhoFP83AB98KhgGAerVmFEqX7AUyh7N5dgUwuH6liCDLiNZvGhOHurl6Zt0xQGR9cPJ1efIyAgZaN3nhw6jWNlFYUAomn8u1i81JEl1lgYX9l/fCrOPEudVPMi7pKSyPxt79T0Z5NdNxIcRlyOOoaoc/MzeLsC0K/mo8Y36EosHLpAJJaZ9ey2UbjEQSmRGFPb6ay8gLw+ITTHtBLVHIu/O0Pk/zVgB9vkejX0ndzcCW8oI+/0kAO+dtFeyUysdInKVSNSVa0ILBTs79RJORtgBfPmxBRlXWbTYd1sVB8KeZb0W33Zy1jVs9FHc9up3pzRq8fdsDok7Ffk6VKzdmKMmAbiWPYIUI99DOxum0dVu+PpqvzC+2maIE9wtIQyO5nVLQTgYMtM7g7evkzrJG/IzfmQ6PxWtQBTfBQtUFLcXxwjgS7+XmH9nW8y1WKx6t124txEvnqKGBDJZe1YjvGyPcnjVAy808a7w5/k+FFvB4NVMJ84Msdl9kbde8L0OSddHTPwk8EbY9PfheRnbJQtM2UzNurw5O64l/MZ4ueoD8T52Z2G4jjpkSXFjzWun67ZjGocNyQhdTAjiCTvpxfp4ZzFFuFYq2YNxa/A6csByshf/rbqAXnGcrUtqKF+IzBvUmuptEASCxwOCtWZduXz6Dv+nHdX8UsZWZY58lXd654hFmbk3JfAiS75tEs/vQIQQuBNpzL7x0NRIWfFoPxSTmUEDR71SQarRyCgGFS+hoEHZxT6bWXMWaCpftzssuasrkYa1Th3xDCfjstXCVn95PGjQNL7hIZHNZez7nmzFsPQHVCl4u5wefgTeGuNdM8WEzWyzOigplSrzB+9HxBDYFKm6CZT5u3M0FWHKYJbHb29WRHgDlNddMvrR6fU4D8vJ9LHyj5Fo9ztZQsNixrqqKZFt/RodNhNVNCWFplAoo+iB0h7sxWqx2BXb3GqDdtaf21it5qbGIB0YyAFChjSFH/yK0yyw5IIzDNdNw8KsHBFStvGuDDkfT8rCNaFO9GMDCvS2Ybe+BMnnr3cLm7+x6ORUDO438V3YRvLL1nJWbNwOQ+HCVIrYHeMXR608yc6meeEy3f8To2kmUhvuZLnqnxZKLbQjlXJunWmHF9vVn+/N+Q7AQ3kjH1Z8wFryVwl/kCSfhRSQqD/yxfaaY4fxKC0PE/JEmUOh8qA2ZQ2TUIUClhz4TSJnE7/x3gsH/1wfYmD8Z751ShWbw4yh8uHp4hRh1g0LVNAwmyCTev4MwaWSebqBdZmNhkwc/J7+IZ4vwCtNFTyLRfNS17MUH+mBTV3dTfvEh+I2x/QySJDQgqUYrKApYd/IsHKsVBFw6AkEAxsAVdPX0D1ZZtm5Gx8ptC4kBwdqv01P/gJfCdSYbxiCyu4gsPP2uC4sqih7tzpCgwAn6qohHwBKZNHeeGnMlxzHwL0SZ9zhiQDP1b95KNnRyLKR0iYXq32Nt5OdbdoetjElnbi598cSnfxaIGV7BB3kjNbyk7IcvO+Aut2kE9GmIuiSGF4Z+TQZu8vOj3TzWG22qwQ3pdAtZIn07AvYHE/xXNdcH8CE1bdNQ/ZEgGkEy9aCABDx6Du3TSRf4RWM+3mYR+kS0ZSix/clL9hbbSXLf5mggArxD19uV0A3djq4qBXqeNf6Fweu7Xn//RjHx8WqaP6hPRuPaN8t7KqJT1oBmeqa2b6ppU0tpyw6ar8Bp/nMw3eIUkTXjodsragLvgUtAXgSyByVttYjiPDVUA3LC9jyehvnBF/sgxArfVN2olCupHq72HhVSW7AMy+4n6yviKZ/hQqSEqSk+eL1tgtcuC/IYnCZjZFvbY4oSv9yFhd7F21PSYIVq+cWEVr1TXwUAMw8kM0zl8J5YaC3uEikDpzAH8vCM0J5HSwMU8p+68mT/GJAiAjAu2QfKtp1w/CGbY7cNAZ1tt4znmZ83vXhxIZ0XF1kz8QutDB7rIo3s9maYY+ZzJQtYbQR1Z2i3ZpuMMYYBbbzTMxTqMdqwrGkqBThX3Q1gLsBidlzD58lk6Dy85OGt8FwwT2+3JYZlKgd3wehkajSSyV6lnEPnXXmdRIQ9MXtQQhuskzt9QtSRt+3aIpUH+eff8+Cm9uYDXdnmGWUYQpLuhD5TtcmeiQqnzZLi6lid1YLmCAPeHBNFRDyx8gsDduUldXnVxUp5Sy6XFSxA6eIjCGt7vOOTjXY7rxofaHz8+eHniYGC2zcNpnsYZIx73+CqMhDZ4S0e+Qvwk9YiFgEBH4anKKlWSVYxCbYugvFTu19H3/6f2HEh+YK3lS+z8rZ4L7lvtwF1SLuqvapVq9TD4JSGNuDln2ZHZN2VqCqpMgXkp4Lihod8zkzJFNUKTCRNPHgiEh33MGJ8oMkxLqxo4jUIQJnz6R89Lbn0VImKmre91CjDCxiLmYx9hPPrEOfgQdXxVLqG8i4UHwRuP4Shj5xpb8yJ1WeHO8QIpqur3NKfVWHPdMQ1ZxPqUmDNXjsuXnJk9Ym3u3tyds2Sw1hoa0tCseBY3lcFThLodYD3hhzslGmOCHNz1HlK1foI6EgvE6qkgLxtFr6Q0nQol2AgjPnHZ9dWZIvoWU6hu24QDhWV5yGE1KrCykqLxMP/oOAZixC6GzxjFneqxAfgpSbyv+pnW5yyiixqUHbqqiZEiAzZthHybqddebYGyl1L1tyvzNA+1kmoFpfQRqXJ0QYwcWCefdCj2L/6mGfazipRrQZZLxmiOkTGar72k7BCuzxOvO0wcsPNfxRCGkerOlhnx9HapeIqSlsGEuFximvOzHl/bqKIXkPY40mQwoM7rbgpCiyAr2yJHDMJiMqT66nn/y56Gprlsxq5ZaHM7nBcwBspx+dhMjIv9E+5bR1op2E67bJ/dGIOeOdo0oF6wQG/sr8EBE6y3HdkxGui55Wb5di1U5SaEkpPyME07CC0woR0FUr8JkgKACoqlP/e7bdWRgcJMLQ81yQu3ErursPlMY4pUIaktCm9CNz7u03jsfVBt/+wrsTxEcRyFcultikxdBWlNIkIb8LyQVKwy63weijOFxPh3huO9sWUpDWSwtzwhGv4dXKyMG+qqqYYiI8KMoqnmLSpHZUa2jJYWhdr7FZFAN/d6NfuQInfQWY3A1Km0DnM2L4ndQeV0Ic/UNJ6ydvczAe9H8AxDjNwgOXuDU7QhGS9qh4F/TYyudMvOqnnGA/NpmlKnBT6zLqAxzANCl2MZErq7Cph8pdqFsQqHk405jhJuoOJpUnpHz80ZA0HAMiSVWYHC96G4ajQxrhYxjHZ23gfSrDEW2Q2J/dEJJb5wJhCkEicKb1JtXxZyi0ui10QgnIV6wt6jVaGjqxH/ooyUW38NdDyiL3XrnRFTm1LryHWTgk82r97WRZte/65JLIC8X2kh/3Zk6sJ3Y32IjwDwoLbTN1d5s4DYF8HpbbkzJID9BBFAmMASScCVD56oJmlVE8WG68PhIWOa5GzrkWOaGm3zJduKOtX5lKyuJMutjo9qeCvXJy3S3oGxTM2lrVXodVL5RgG5RjvIXSO0K1Kw8nTGui6WqzBpdvlpUwCj/oqRKRJplvC2QAQRFvhlr8vDQg3Qf2evglKDKpQXjg86Key0x+s3zvfo0dbO2dYkqc+XzP6sfFIctAzFEy4uhqAXdFaRsvG7sA9pfBxKOAf/Xjwg6L8fsdOccXh3hvRdkwBAWjAl3AHnx109uXexIhUp0ftD1eCnc6+4YIiBWSklNB+JX7XMgzAWbqnAb2z+eqwzsV0bpcJ+Ul0GEv267KIETM8CPy/utunyWzAzvp7n6MntiXGbwRa+aIO4kaGXHr5pRGBm3ReQuMEyDSBda5Kt8ioUO6OmYEv/hLV6cn49ufO3PSA7N0oPuzLHI+mQZj4ElmC3kyatpmxRqjQe6gXxQLUPomkykw6iYTzErEU572Tm5e4JSKGwY3tiKuMfQW17kAWac7ny0fbpGkPfpoo5jJljF2CWcnBl8M7vrsn68Z6xUlz9A0M/Eedgk/mPAEPkklCG0OJtENQKHTK0MY4o+Lj4xNYziEZjsPt1pp4jpgKgUTKrYIyj9cGJU/IzZ0PzNZOniGeazXU+Lc0S07YbhQGPNf5nPLW0KMypSSXSi7EupxJMY7RhmoYFn9kpkOY/fNGddm2ypPFCNieRJ1fABRkP3zaNs5XqqGwdKCRqcQWKYDebKoEyaXzRAPBcta+GMRbV7iVfFs9IFiTaTiFD40AO0i+0VzouWRFYTFMsLlwi/cSXoFyaKpDymtMFmdY+ftImXDclX0OKaswbhqI5RGzoViLoRy5SMxu0+sA5xgpcnLflcCh6WpgmkORmRuHZzvc+CCVXULonZY2/34dmoh5fgIAOPDf8F9QStBJZknUtSQzTtZUoyKdsrXdm+O4UcBnSizK6WVCdIV1lEATyZqQapxAG90i4vo/8Q8nqHvwQnSFWYTdvdX8X5EBigDceisDJhcMlYXMenXrQ0lbwc+9sof7bSnw6DhCZYvwCke8kmxN4a4o+J8mrSZYAhSwXKyTGloz7tHC3dGdjbg1BO3pqMBu2MCfisc7IRut2OH5DW2GsiPf3Vfw+KTCNYqmjgivDn93eRqGQ02bxVcRVXQHT0iOf6hLQSZN6mBZBT6u3ybFhBQ+337/h6rZM/8K+eaAIggCpuiD7Qx6q6ohpoQRa8xFtUjVEX1yq6BeTopP/Q7KioLqf5TQmQ9CVhB+RlqnPj6/XkLwG/yjQpbVhfepHCqLj2hnRrzJf9rfin/bS4I9jWhoIVILVbEuaD+cM1mF/6s+qvebFrG9WAg4UZlLeXpUTEWaXqTsr7a+tJdYnCO4+c1gj6VoS/AVt+oFzg4D3N2pdjbnPtF3w67njfotPhhxKGAjl3gGcTU+hhmi92Au6nGbJGRQPDURaBOPSubgl0uPtOqIxA86LpC8MCpNTW8hsgroNREHgNJOWSWI9s6kc4TC6PyoRlZy6m55ndAHnvlmRhYotDsYFn48wYNXlONsE6q2ulfp1Nj8lrkMoIVziLy3O07FhWcbpsBZYDI2Jkf8YatF6UnHbRvyILcwkIH4uZBU1lzM2reu9MvnKZY68BGN7PYiqTigPKX7asCQrYRvcIvDHnFtjAbSE7Wqj0TS+reaUsYEllvegewQEDQ+ucqvTjK+l4MiOXcEBDqgot9MgGScwM7of5H07fJRxy2EOAh8tqjo3fMqnD4bxg7JkxYaWn3ZoY3cjQ6D53nZP4tkgUOqwhXe5be3FzIXHKyPQYR8AWPRhRoPhu0DIIk/zJIBw0qSYvC7tu88+JkdYe/jd/TG0SRFGBU66IYAdknqOLlL/EUbhpj/W2xeP+DKhSDMqObJ0Dj3YWWt+UzCc8UTjc2ZZPWXMvpNs2R9c+DONyqsAxZDAItVkd1aFVyM+6CCGFdg34CbwM8fUEy1ysdH5Z1wtB2FKA1qvvq7RQ9YnZxrDD7cHNPjx/GQ83XK8Dbtr29mVKFGKMk9etA15kMdUh9nNmgKtpEQ/VQdf1rL1sbpFbEFoVRDWpfUBFZ84T8qj5uAFz5FOhPkoBXfGqiqMdmUFHE/dGwsc1uh5ONdPCLpJKw1pocMthHQh7IzhZvKQDQqnEL5wJpVdSDZ6nCvpeXsflfyxgzsj2Chxgc1AawpW9DeXT6mbsZSMaCNoNKGmAThWUPaN3qoWCEXUIHhAq0AOOSc7jLBdk+a6xUTtEel3bPFFHb7wF8Heq0gtbDc4M/vMAowt2JDS3hm/rD1JwGXZOd1R063Y6Rx13jNQsVY8VsY8scb8n0zvNQ3qpGUozHOyGckkbnw82CNz1BLZ2voz9FNCWBRiSTQNSKfs6sO0REd9hm8hJ63nCybhh1C/1BwDtnq5cprYV2npH9tK3PPGuepXAv//GpgN7S1TJwnYdW43SPBBmWoLBJwKZlNXb5yjMAujc/mYDdaxlwdR4RCn9BcIZMDZ2OY94hOjzHwN2Po4Jco/0p1teiDsbb73Ok2DLnmpsuZMkbBh3iObJBvej/T2yGnEa27p891P+WPYDb3X8yezR6d+mTEGktsRy1H26vcw2tUWJJlRNoD77T7p2crc7HyBeGaqPi3nrqlD4GIQwXsklfggYybg1ATIGcASCJc+G2ESi8aNqV8MEUEt1oT/sGvwkpjAX0pQPpLF1lYC5f+Se3HphFzAVugfcQAww7TpMUmEG4keZJFaqCfI9Ceh6KYr5C1sdwYRHVOIm5ibAdSl2s95YcVJV1Bafbk+dw7N7HXqvI5FMvcPldd7tAfw0h9mC1mvKY4XdPiDeyxCpAb48DRV+V8PakfGsAAtHuJ5VNKes3jZegWBOMBsEjkky/dFoM4IMj7CVx8+gKOW0+aU3EWeLRyQPwBAOB6/YfVfBCKZp7CNDDds6Q2lrMchEokXAZInxbUcWevP0Hu7rieSyJDI36RJPjPhWRnPlJB3MLVBBulicRUWj6amJmjJL26NEN1RnvHBkKQU/0geyDkYzetfsGRIoKxR6Dsk7vNJXv6W+wkaZQYIfy3FZv0Vzc0/8GbdjzZshVbatJm0RdCgT2zPAXSQ2ysDhyOWSC9MIw64dGK/IcKM1aH3XdiQuqcpQl6nE8sOlusaWqfo8R6iOsLJBURJOY4b6PJtwJUcQ9ZKslOtFjwLgnWEpxhSYNuYw10WHpplB9gSfWC5YUwhJyyTfZCUb5CY+pAWOXSpmQ5RXCG1YRYtmjI/RGOfxz+4THcjcZLfYDOHBjU+O/abywycZ7wk0+tSt7SpV1jzKbJAvXESmOLJ2AznnHooiocxfKSPy1xXvUWAkRRrGurRsPn9MMX6b6Eu/kcA0wR0XvzNsULEIjX5P/88JieuQymWgOqYlEIrdRrWJ+bPadVEUn27C63TCvCVsVbn6h+ZMgUCCWKrC4fvx5G8Z79g7zEamT8T4KvOrqEAk2Ms/YD4y5XbnPvEEmsknbt7uOLwoFbYj8FEf9R2y3HYfOtwB8baI+DOynh4N8S13MqThum5yWoebo4hAOODdnHleNBxesvp+m9xZEzIPyJc3m9tW7/b0pzCpJylyAgWFnsXQg9thqgxEkK98m9c/IJlCP5v/HJk+PvEvyViqDuiDZ2W6tJVpC0FxLtuzmUQ6Wh67/tw4GlVbiZFyJbf6HWYkxlNlYEkAbKrJiD1l9wbfVzyUIH6R3YzoI/FbnJ1/Sg1222D3dnMjUEpf3D6C9/8gAiMkVb+2rX0z+fs55r7NnIYrDZh4WiSqR7AZCw7JHr/Ax7JdZb03zln7MM08v3aB82zfKp9aRkvh6X9nY0Iaf5kmQ10OBREO1QBt99ku/dL6SAYQBBOtSCkFg+8YSp6LFjaoLmQegCLBkRVq++jGMzzVqj3ziu38Iz9adkjs1TVONQI2UXvwJQeIhsrq/zc3klDmkjNp/IizifMd8ccOfFowUo5Sdqvr+8Ok74ebHVdBU6dWtuLYeF2q9jSFrasyrhE4y73EykgVQUlPy7QtICf6WcqTIhv7a7Bq4Y6EV0l7crALxOdFuSZwE3zSMOwGctuJ0bDLg8zjhwNF0R85FkvB/quCN/gTtoWaX3Lk4+oYGfgw5KtFr0CGNwOU91QuFe3nYp17uZjZdhBjMT2oqbeuShPapibWpjPGk9s7JJRn3cIW221YcMVFyMrkAVw3JCbstVlCaJnLRj5UaB6ZtGHTEaEvJ4/RkZd/Sj+svpbZuVPRbVq+KsXif6Nzkcltith7EdLzTQwY7b/Aoo0SOCWx82O3TVZHIkPj7D2/6XAr0HuV4Wb/pXUu2PA491H01KWCO3d/fcYm7Skov3aI3pjHjpNiCbA1lX02vbErR0umCVYNmlOmbEWQ59Os30YTcOgjB8zPuKzUvvJsXEcWjW7skZo2F93/H3whXO0W1Ph2UZWPbvt8yKwb7c6CS4PJGWE8dL5yBAY5nWohO3d5t1xOOKbtMmOvR8OoX+U/Zsml2gk5BZsLAzCSM6+LBBcp9r9ekfzLHH9B7RLOkMGGGX7NwVki+HHvZ252bCFFc0kCndeCx64QVyJfS5/ysVke8vvf7GPIP84x6H+AexqfRDUVcJOK09NQAoRMgDb5gSe8EKjPZrFgJ9xhyJaHwfjEHeCVPQLs2RsAcDIh8LrgqMHvCXfmpY4V7Lqq8G+/Zgh9kVyQufSDFLgbkJ7A6n667pvkWWQAYrkzCrIFeUl0Fsb7TngPMh5EtTVM3Qn57MAFW7ozLe4wfndvoTodYrP/UuHshqcmo2nPWRARObVmVWEYdvcrJpP7MokZOUJEQKuNtwwvZvnA1Hp+gTGF0n8mXmi+VOvA97vjpYdXKa/8T4ZHODLUHEt3HaiMbsGtKOvOWE36fwBDv0RObmz7ggY7C9hbNGIpNltExo4orsLJoYfbAQSHG9LCGWofW6xN76/gYnTyDwXK3OHwizYiCp2iM4N6fD4E4W3krEbYdSf/O/kVRzXJ7UX1+WRnNGxH3Nw7M2ldt1gMa7GoUyBOFaQHcAEOlN9fg2D75DZJajjdXtsPmsH3r1ReHNllgHIs6shlRZA9PtUsrB2x4T9TPha41rx8vb0n2GUgrrGVoxvmK9RREuXICc96gONq+Cg24CbS/FLMTJRifm/7wbELaO2ECuHOAhCW/3iXesZHkP8zC3wP1EFQHRZm6Iea1i0ISCwy9XHIhBE4qvPrKLac6uFQna4mtdFKgDTl02iwaO22nto9KSfDMYHTYieGkRHscRo7J6C/gPunwLIY0z+DOGGen1mbf+ti+fvdFEcFaUEok4qzMm4FUAlp70FIBqnP8dawQfOf7DZoE4IJ5AyB/D0xYjSFSzPDwj18ysqu8bsxYY79Cws7+BcHLo/1Pk6Ic9GZMNBgJCZ3BbNh8xi1tNSdreqe1sOjYf/D+3k9ye/2lCptksAl1FxGoifF8Sjx1GjJ2BrXMQQzD22pq0Mosqpll7ojB9+Vv1qC95O59IYK0KXDydafhBg7E0+ccFn2c7puSVozw6mQEgm+acW5jgm4v933JQPaiU1Qnwkf/zk9sNarh5Tnz+fR0sAS0Gb+HMezg3yal9uyS34sUEI4lnAPtdZp83kotliaKldcDSgLY68V+W9vPbERoZrU9f8MiffDw8ZvySE16kbOuUK9h6WpkUtSTt7lMrFT60s93SwpJLigpR+OsmQ+dySXBrr39XoeAQA5L6SfBu+ZTPEP+Wbmj3TIXDv20Vi3oORw367ZWvBKqZokgrO5tvuhTKbo28kUg+puAOXfTSF2JnQEIQZXl+Ivu1ugIkxG8mfc+rPR+nqmtFTPSBqbYg36UqpSQN/MEnvXcbr5M1k4saqJsolzKxj49lkiEtRnoeaIXDvNt4LHh7nDfJS6K7ba04FaoUiecwbu0DZZ9YTN3VSfsE0BoH6UdsVQN+6MX/fVqD/eAwIjPf4MtLBNnGDcumwQC54vrNh4QuXSo6VFtQh68I2T9q7LTiuYEwYUcs8Qnj20YBhxtCqmP3GqkY46Br5iyxgSEFFCPPL6/6zUE2UxKOJ6+Zje99G8Goo0OwDg/cpswR8Sydm1fz4zIbaImTHC83w54+xmVTlaTajD8D+RX3LnK+kgU7lytomyOKOaWtuXChC+P65X/Ki5R/L3uycHAHFOBuLsSpiln2N4/9PmMzWvE9dEGxNiyavqCHHUA3UOeHBZFAdK/cNnVcAhqaLTEkpe/jvlGs3rwkCDvwBpuUSowp2QSgg84MTDNvQJJUJWGRc8Ti3RSJ7cPBHkz7XielBfDFWCWNMn9iP/z8nJq7or6q58IEBobmBeLlroS5yo4/3EnqxB0MZoiZs7nGKY3EYTuwkLey6VNE8ZRqXaMebM4CkmCswtx5dRCfpx/wC5PWfXQYLOWnXGIZc2ZCj1QgVJP98ArcLyRUD69hwfruPnl46yhK/4RBIWSAuOp1HGiVPIxEy1QpKDG5/vM9hyMDowwQBZWJVggDwf2UgO5J8EzBZpzdYaVZ5c7S5SQ6+kf9xbYJqnUMzpijOkMz2fhS/z6qNVqhmzefq7l4L+vHsEy3vbmDTv+lZyA1xJS5assZjh+8//KYtb32TDqa8V9KMoHS2UMey4+9B+f32++C6lleyz741oawkMmj3EkLTuK52n//PNzK1ILiZfe3W6b5ER8wToC5iiy4GyDtr6PEdL0+YcRNMuhPbpv57EtnYM3fNF7hNeYb5eGt2/U/MzR3fLBWyiNsnz+3JnujVyQ3k+uteYxZk+dyGM6S/1OEBbf0KZL1QNYl/W6QTx9dccOa+GLlTL6+rHt43Z/xOOj9DC2D4aj2f0vFeQH2Ra6qEkb2i7/nSEbMh6PI/TVu6ql/Q+Vcgo9nerJ9YvQjP3ebqWb5nj5jdVweKOKJr1SzK2Tqoi7To/tTXVCxZJLpAtGz7Ba2srSphnkjMNZw8uFKq/EywEeD+qh0JJq/2+2j+ccfe4cF12wPXQPzMA4LeztjbkBiTv2hrsAOfgALeFFsKWyjoPDyAwJtmV9ZbJQwo36S537YVubj6NmMUGuRosfz1fezb8jeNx6dML1YIIQxN/VlQfQKYV9EMXdrSrXTfXvlXEp/JeKzUVFsUHyyYCyppudXEV1KrqoGgU4/pXWwKKqFfvEGOm374PhmtEPtGh1QjTB5GmNQBoeMGnHa5C8mOG3se+UJvToo1jmFA69fsvnuSa1rWqouvi8vWz/xB2lirnm/RkmLTXwCNLr7J/WdAm2dhiiEaC4mYvCvKalTXhSC9KEXEmVSW515hpPjWBaiQd0+/D4NQZhTWl9v73PAavU7P/1+aOX3/Yt1n1/tOzkx5tBmkwjOxeRG3uvuPtxwwK1e4D/wOqQgZjMKmY8lMEsqZNTyVe7bA91T4eaQyqnU9oJee5C25HZRr35ZKQ4p0QSwaecNFjjgJwNALgy92gqlIXck/0HMeIz90YfE48wi0vdNqRuOQvurPaWObKtWJG2km7Slw0tmsuRrTTgBtSnfOdswGGMig6n7Nh+Ch62fhYDd7reovQ1fwTx1kArR0WPoJzpkBbmd/NZXqH9ru3Ly3C/P2SIEZuM9dIijt21AwIJxpZD+GJ8EAoOZMG9eqEGsr//KtYmwS4g1OwlX4tjUx9mGU78lyw0decBOGzekRvvZAp47g+FED/SHlaEvbbbtB3neSs5NkpABolpiKbOGIuIWGBJg27GRhkT+YszUB/aROdJrL7uwy3THfBYUEIJRlA+rtNBUBDh7nT9Lrmm0GqL+YUkzu2q54EdY4hqdf8N/zX3GeVNlKtdR2ue4EtTuNMRpUDB22AqDYn+wz8x9T2hg/MwSltEV4XgcKOiNgnMs9lEqgMho6uHexiL9OCI3vBZvNffQQpKwVed0B7G9bifmlSJwRrzCaqfCd32aPhaHrW0dzzWoxEcKxaODhRF6Zok4qhikYNuqdG+VvqW1mynQAeN2NaPgkQgKEB7txTS2sONJcOcYAqPex92rsq2kGG1mx26744k//RV0+jPfqQADy0a7hmwdUBwiZg7LvAsq6//4sLjXydueIR8K26P84VyDykZ5+hS3pCIezkVJxiA9ONBVZpqyP4L4C529yhLLCDoD3BkgOjLcjBL4cZPGED2tZfYMLQDplQ23CcuP8mp6hkHr8Ic+Vxl83odig5YYtyAmH9ZsWKnz8z70IClj0+lLr6RhNDdDlBRy2WE+kxPZzfjCnv+4e1xHZIGgWpPosMNYWcxOta2TSfHlj3EsU6yXTNJpXmpuooJBI2RG02dXbfWgqIVHYgs8nmE/bEvO2t3UEzJqubWg+qE9uCFMXE/sapihLkovDBZZsrVIqHQMJOsTNMAjqbPJsVhpQ3jVLXYeCwZQO8SAtXOPlx4MmOjn1WNtDY42iaM7RWlC8hZYfpIl5uzxpPu8+qoxWafQ8Wsaxg3oLk27smQ3OgLJNwgL9yB4sBFl/o+P3lLI16BNx3+GiFq7jnF7e4lom60W/ifgrgGvlD6XiTbihvYLjZ+oQDx7rJMgIHfkp0OIqWSjmVCk/lcKebq4TI1KS/z020Mwcvp6Kj6jTUpPDa4wK1IjcrofDJew7B+KyyXex//T5fB7Q+1D+lgyaj30cAosXareIjLfwgfu+Og8ECKojsoCWRDSPOBaQ8HzkStzFCToI51pI/N2N406Fs3uBtXTmJ0Fv9qJXc0FBOCgPycUrNzKRpcXuawMz2pFn0SKkyWAgBp86ulKe+pKoAF5sX+1EG5Jtu9C2vV0pSIhPDdCuneBdAXNJXId2flttIy91SRedGGUnr2BVNj6EkTaLwt1acdK0LU90+NXoLX8dfssu7radiH0JxU7oHNKNfy4U/F9G2aQaeyR+OQi2bRjvz7AUnCslXuK0DPfrPlziCGVaoGR320HzNL4F1qP8ckVdOR/EZtCleabgaUdMQqPi1+VJodYxrdea+d0fxBVtt01xkSaauCoU8/FX8yOtbffPrlDLEmpioIaaRpc2hmScPfGLrNGuh5HUy5LNJ89gxN8a2KSHveVemtaFoSm5xSDeYDjGseMngreudhfefzd9MKRelCQq9Qa3Tc9IMKaKcwP5bHDOKF0ulLq2hz/Hmw0v3NvD7sZc9QEY9PEqN2VafxTZ5oiL8njBdcSu4rKzZxO8hH2N0S8u4upDvMRfE2oZKcFPSlY4oCgrmcTXTUuiMXZErAm5zIr+O+oaZqDvmnsH83KuWmuk9/EZAFkE6BaYpj5AnwUCcSNv4MwEMAt8KXAiYC3XFiqwLpaE9EJdvrXE0KBJ/RLw1F96Vg/YrQ8ttl3pfSFOA/uclKkQ4w4UyoulA6Mw+PTTmO9T2kF002D8M7JW/dMHFg9LaiHKMIUFPcNy7BE/O2xC0KMYkGf9xNW7frm+/whUiLzErhJ79hT5ZVZ0am3ASl1QiiAGCHybeoOnat2RKD4DNppvq5ay9KbqycPVOya1MLgGAyW/vCQLvaCZ6CKaTEXWzGCuObXqfAFfhW/LTOnI59oVFy17X80RlK+8s6GUOexcmKyj2fthDE/MAr1kRArkeNXD4Vg+WdgXDbFQcNjSapoppr7cudGgls8RFZRjEcfdJZHHHrttJofpdhVJcN32+ht94ES9zfqw9VGm4MXjmJJGVfWVMZZl7X/zE009c54BtkWLGMyKxUQFDlDJrwcY0JPQnXf0kmFr+OoGSill9hlQ6sf+jtaz6BP2dcatP26wL4LI18NZsXoKEPSbk/Bi1E0kR9awWCHU06MYlNZg2S9fxMJCQy9wsPyaWTSsrA26dE3/gdWAhYdNMgaD1kakl3Pcvltpq9tg1bkqhZjDRdteAKgvyuFGimlaTWGtviXFia/AhXPIB3IM7Y79yaY2RS0fpoPaf9hgBd3Qv6JTA+lLQ/7Z0446eJUlIJhrJRF/rsg/Ff7z7JNUEPTh5fFA42RWyuxlVUHozRTaQ3oetWU9A4r4JIFGMZhRe72q9qfwO7cRNQXGl6Gj2vAiAEYG0SraIbey8FzFi5twclrDueEjb85dTIi0+O++aXIChQzJ62kph6yzlGhOgxikUkmg2X3ePQ/6vDJZD6d5vBHNecdCTdDhnxHnDukBrmqRjarLxW02EZhCCu7QVL85Fo/6q6Rz6wWAVYZ17zWw9Br1bBqua08peiL/69rVrn5SIDmQBf1so1uOed3HQRFkDBuV1XClG/uuy7aB7V0mvmK5xAOb1i4GSDIgERM1KFJF2FqpGTcBxfNBHryuC9+irWXsM8kEm7CRtdsmM5LY6Q7EZ83IMWNVhmbq8DL/pSeZmTZ8NHx3YH3gc11Nm1lwlvS4XCJGamdQhJ60p5iae6azMqgy+vRgX9MvIjp4lAp70pM6bfqBmao/GsgBsQmPpUqw3d5/GfG3bARXSsJ3A3LHvvLAKIfVN48CryN7brwHBZ0RUCiG1vxrOeY6XaF1j/QPGfpx0Xw1JCe1B4sZ+LZqIVy9ov9jxjRAuEHL20ZM4PzVFtUqAoFkdF0Xa4bnMnt8sALnLK8iL1Nvm5OMHlFJefIs9FiPfQNapnBS1qgnr09qE6Gxu459HFjPcnfieyXnylms2Z+cJx8JuKlCRiB/+KVOJdcG7i+GRyYrTBgzj7qa99vJubd8quQnYjYTkGfpen/Z8xCVoYwIApG4RkTmuH/aEvNkNDHX3miRoabQXMHbkqnD+nyqFmVbFqd3iRyzv4EjNwKJb9VYAH++C7cjCKqDAyCcsWyVkgHRIhGxZQ1eisBHLcDrdBxoyIIh92v6CKy8chj0U7moWwF/5UhrxmSbltOfz02jaHMrEd962yLUK3DAmbb31+iqSZIRkOwvdG55e4VV0eH8t4K3im4RPLMhTON6+uKUCJfBI0tx3ftNKPVGMmeNRP0EsVa8Nck7xaUOAY5dRdAwFptduBShQxcZ6D5U9B+shET9/fQI/nkUtktwMzSGHThuh80Wob0+P9QS9eOpUVvOLyQVNHz9MF7kL2BQFOOhkSWrHEqvglXxUYEQXeQc+vTelfCqhPs3hegyqMYCCwEQFFNMknI4z2weMd5Qn/dj4DPqkGTCUSUBXxwALhOHOmdNT4bBjOGckh/P6D4xKI/zcEZFeLy+AZDZ/MwL76o+gU9PPYLBUyJBZ3tdkTp4MRgnUPu3cDNeQoIdyrh0xKZWXvF2cKkKomtUOGu+/eXKv8DV5apz2ImlVSF0k7JUp7baCxDbGJL79JKgJCDWae4UzQmNJK/DNR/HCZ04q/F5u1IDH2CwnBDBG1wpI7GTa690XrmzvfY5v6XYGs171Toa6QfP2J5QWq1fAKa/M+HM1wtbiLBrSQyeBVkVNMJvK3Myx7YNEwSH3xFXeMGYF+r0Wk7UN27QEZFMMryKdPMENvrp2IUE5hN24ZbRwYptuGQIURNVc1YcTK+4lzP2uJmh5mn9jxg5ZGCv7pX53ZSruNheDpP7BDdQR3FQsOR50xJo0SY1/w8pFi38W5Rv/HV7NPKPG2YqR1Ly0eYw/9qIUXK6fQvgsjk3/fZVD1Wi77ebUG/6j4Vyqo1XginT2E92+rMrusJYQghZBiJQSF3TsvNyOj4k7u+vP9wDoTFU8NtmT15x0yQP0Gt76JYrw1PQN/JPO+kcB2yXbURK1Ateyq1NQIFgPJDf1VB8TzglDQZy0x36mjA/T7m7WRvPJBkGs1svSRn1/9chBrIzI8HeMu2TBnvZ4LtKZgsjllhVh5GegO3cZnbh8OEW2nOjL/+Wk6QjnH9BBiWtQ9zNtekQ0RDsNL7QGFFWFJARvr5PGWEfIJetbHQX7G1Peqtlkr4o399BwsG8073bXu7OcGxPDjZEprcm/B+lUOyG5gkEzaEF7lpmkg0z30x+C+EEum9mezMZ2tUXOb1M+HSl0BZJHsx2bqXRFutoFmFeAk532XCtBmwfNGUUAY5i2mbSip7+v5HApoBRh2DlYLANdc7FffKnF6OBxIfwcwFTbYwO76j2Jduoly6Af7SnKwhNvP86kmZWkoC7nRPMvEY4ublwxxNtXIN+5kBUqmnnhGvzVuHV5b/i6jwQGYfdcDZ1wtYtBnFnvrf4us4t3xuvjjBF2QQjMceV9oj1O2a1nb9F9x4r0IpSg38U5gQMUxfC0fRqr9Mfb3eWwQ0ONZdFG7ku3dbTA889j0P4yPO85ew1OTvFoUeDVQ+7J7RLMOHzE4Dl/5MkgnMQ4WHkFOirmshT6aODFMEaHSiXrVqPFv4rzu4oA45Nujj8U4HjLe5pXdDFEOJhIBYsSBV0eXoqZQ4nbdpFLo5PpbpgnzCpPgB6B6xvPLSJ+w1YqXNWrH7q7mdVWZ0IaEK2Eu78CdRJITr3o0vtChwJpW/qnDvMbaZlCuhwhzI+KNIlWVfsx/CbEni7wKl90tpunXEV7AMJzcO071ZRBKrow0CXq8ZPYZ7gWdpNiJMkfAG0lre7BjscshBCFYszjLk170WFgP0iW1jCQpZtzmE0LgkHIGqgxE8R5+xzYYsKp/rCzIlzo38+TBjRt68uAsoQ2K53B2ud1VZy/mlJnvKWxnTssDIuZSH6MC5VzjDgmRNXj/LTguaYpsHWggvEqZK8HeHB3oWzT3D9EmO8eXzolfSwkB0YDDQ68jj2zIKAmHCR+ZLcqOv7qWyg+rSRrl7bHfvWDzkfj53swq07DDxal8dlIsvOm6aWgjYkZRcBn6xjXgcXwK5o0C8YF8VmWjybU9fPOd+4+369Esu7ZY2T2lI9eE/S9Y4LY10bK6xi7EAQRGLpVp0qrZ4ZKrG4tAMPq3Vvr4UjZylQBn25yx7GOaK5g3gnVBJPtjBGoGfMpQ7u3KCR1Wr+TALuLkCuwGoWUUeBW4f8s0LRFb1LndKdOUExxbBr9oGWGdzYo/a0uC8yUFBapl0df5Qs65dpzyVLVWw6P37elkMO82qjjXIj/fFDGDtzseWX2P8Nb7l2h3d665jAt33HLTm+RR8ZOtKOSJnRU1pc/SsPe/x1dr7szwDcAJFghYrtGgnxz8dJLxIShq/C44VD109cw6WDpjO598+ZQrZuxJ4vxdoYsDtoW/H2amoAeCr/0hC4WvaWnMEEvhkpyog68t4xrwKneH4bHd2XpJuSr3psDH7XoXsHIH4kOkO2AYpKNZnfAOuqY4knkCs4nIu/9bqIbsLtW0ncpbVC5d6o13NYKx3Jo8GZeC+XdQBhjnr5uLzttqM0LJPPTzBH6cjGqNeCJt3MohR/U1iX9yROvv9Z+/3Mk26u8z7lKxxJ4x0eEAdsxIgfHtGaqqoiKkehC9JKGgA5qHVgwX4YtVaAXwTkEDDFAi7/bCsQqYtdmFw6alAsP7x0rh71c5UsyQ2cCnztMMZ5D9W0XCCwoG6vJZgJWhXtKG/P73WMAJgSkJnKj/xtp2vXmWI4OfxohK6sICWy0AjWmxssd6pdJOC9PAAENhpxBVpvsoveVG+vaFN0z8YrYB4TfFvyZncDZPnSkBfdu4OjYzgBmwcSRETc/G6ZJ9zYhl3Mpin1MSYHHxVe7fqUxpqd6psZxyZsQZSsK4ayeHqndBOh70aHc8CHtmpo2b3PfDqrzC2QIftPZtnT/GJqoe8ivA1XkDtK/sd6Oal/8a457xZqCYa+gfo5FZo0HQt70J8ShNtbtB7omjZZS2djfFOzmpeRjCjypH5XkPJHO7Ve5XG1ab9IygQfScC6H3936ex4SJENRgFfcz0sIOTNIpEeAbmiTo7PUk1GNhyuT6H+cX3jd1V+BpKZCMCVdYh7VbouYvF2DtRqICYeGne0bmnVZfZqUZkCQvHJL634EGr+vKv2TlJF8BFAmNqoPpwIUFQpH4sTEOifxKhK+vvhlcP6srm170qQTMdydaKgaSDeelE7Jozf9g1ZGilCNvKMUnzwwAgawD5Srmezf6etdmTKfT4pZEeHOEK+WcNlzTQ7xTtEuSDIkzDWXOH7CRBptdFv8zQ2zky48wJYCu43l+OL48HnS8N32/ko/ynRSVJomp4+7UP2VGbHjmgvgERAokAXULuqZErBO9VXUZO63PevRfxHARVQBdTyJcDZxo+6rRrIsou7bHawDkNPSmDiV5dbKGFdUMP90aE0HI9NYJCPRUdm3bIBh72+oI/iNec5ADnHy7hYREU358HvcBW2WRXEkmCO3lCUQ7Xc/OujAl8d/r6LAJn5BRfRIsBivltI9J5wdsPGrbOW6/k9HLoqWtVLjtr0Ljgg7OHYFU7yrH2XoalfkLO5Flw0JTnZgBoCqBVe9R7tmDx7K4loYcWXgYwwnefnarRxklzHUhNA5iShIEr95XH4lRzuLIBu+B/dd6OvgvzXpMEw6PxCLBcgVT/bT7LaDanCjtIQCce0aG5zFrYuYy6/Gei4OWEg+C1E4lfW+ce4BgAFGuQQkOJnFOrilhguwuycUe37/U4kvqEZD+eMLG3XRaNAyv1bIz+wUp2AQmpBuc6/ZQ319/PcxQDOXLcOkeCZtBDOW3NUCBvFuKxQ2uu2bPkVslcjqyUCWaga6RDxdKo+mraYjyhXT2gyLzr2bzvI2WPLwu9fvnoJTOMF7CY8xXPjpDVWVYbO+I2qc8to2sMcnsVxSFWZomPS0sN1gDRUyMxETHLoTs8BRbxdXWr6cwPW4XedBfHp/s5R9MfgudWbdYWopH5MvQsDQevpzfd5BeU8Wya0cTw1b9OzcU4W5DDv6/aHC8j0f83eoelZF11vPCRZG/S1kwEWjNzWakQAG1dgpiLKvq3I7KXwK/ufmiCQOKW1bwELU38oxEx4DVHWqqylcFhD3kVtJvne9YBceI/FzpBFuHRvEZ551SDr8Y4Hb6f8lCj/nI4LyQY3kGvuivlqAvja2htW+XDdvwiMtb4ZRRgMDuhMbyXOjxcg2bUyaCzqf+pYSLiFXVTVNKVVrHWZ5GCUcsaCUqEFWPgizxbCVKX0KOiJOkDdwfK//NfTyU/4w3cOE8osHFFGIZOeC4EubVijS5u7qYMbahoUo4dTvMBhUP54F9We5RJITc8p2eppcvGDaQCrkA04PSvZcMtl4Fu1XRh3NUxrRqDA0ylbvsI449/lLV7GOVer50DoNVEWhZ1oHWAoH/cTEcLKeQy9nNGCD3mSVVUOY71eaItlYUQOBYLB7WOVjjDgznmJ/z7Fq5INaV2s2XRe/7T7rEhoM80czqaeYx5Ko7yngBzKJ4/0JDv4ZogDStP9A3Fi+qEhoHw4b3R29ZcszqXW6exL3qEp8DMtsMcqUIi6xfp6SfYk56bqoczRawnfu8hM8usBVbrHaQnSrB51KSfHHgZfwPAn8tXQBgfLrNVy7LtLb9D7I477/DoZecIT/wkC8sV0PvxiPGEc2b3lxEpVOG60I4lSDDAGflRnaVQnBXk1EVPaTiECna9MVC78ODfu28GZlxvCH9UnN/+66mpcLMs0OmK7N9lncv1ipLoQ8sslv97pvy+JDjXMmzi0GkcUOrhMZ2Jv4EbG4BTs0QSJZ2i5o5P2fgzyl9Ye4d6JfLpfakAlVutF+IEAkGxnPwt2Q1eDWzOqz1Yfa7hr35S9QTOqt6nLCxa2/VyZjAvFF/agBCwI4xuHV+SWQOZbPLJXvufJQoTH7PWpguLlsv1tBhbbaOcX9GmTMQYN6B1g/ec2MT0fdR63OSEj0A5u6kBhUcNXlVgfIlvXxFfviS7TUGvdThp9nEGzEyvDGZM1gb0fC/6BkT9eVXrp/HrKpXcVBY1R8KGnmCSB71GJy0TCZZF71A3lLyRpSw7r5X+vuUYvORSbiQhs9UkLgDafi8jbVzjJMcy6FYzj2m0jAOUzAdcd+Bdt6Va4bCqqfdyQQukyoyN/+zjDjWa3HEFbVm9L3tyO7MSiaBKnZ7OutNUqrKKZcEJqgHbblXnqpG5k5kXyx7h5YpQ2rpmGa6aJgNIQDMPJjuSSZrl3CqloWy8R9G1kDDeEsGtlYtHwTOTTEGWa0hkK+AUFhYJWsOCnLokVERmw5740utoEYx93iRi61oGu24AwvU6ogyBJizzw8puqPxjzlaUkAAr58b7Y8h+QoXLJ8IGHyu0EHpL8PEFCtCSXXiX8vScuLBleMuCrPwrdMtdD9rWC5jrndUfh4NMIaRg4TDvF9QNSwznaWZumjGzDO9Xvy/zxjPhxlqapWUrfQPSvRGFcxh64M2UXYv3pVRZBZceam8wBOu1ue9NZ7C5VcmLfc/wQl3JK57NU6xW41Ox6gB0QflsP0N4ESxVvOX9us7zOGWI0zn92yzKQKQy1hKeaaFa632zazyW76kC5mY8k8RIn+JFt/da6MIlvzgGIkQhhdiod4weK7KLOp+ChVSTCe+FwOtjk/CY4hDJ18gwXkV0kFiTTXOf6TksS/b2ltMJNKBza59h17bSvFmNNn9L+2opYq3KPPD6zTU+cLBxUJFyWEXGvFf2PYmzl8TafLRHRY+UNjLchDBQCSYPME+yhnZnKb/zFaAbOCMMSgsxQXQEGa23wSsjhEmnFC5+yhjTzRDHDV5qCfNWtCE5wtHKJWS+nlEe3q5J3+rrs5yHmcpYqWYOgvLKLfUXwiR0Y9VCg0MEEZ1FuexMVk8FMUj0fQrBUPQhkSfsIld8jNEjqA2LtVk2KXkS1+JpuWckEOjY/pFFCkAL3EzYHRebIxejsr8IW8ftQ9ta388sIkSAH0mJWY2LzJaK2IWDnRw8aX779l+ZPxsHb3O1ejIODvyAJnC3pK/CYBkIpyjISPFaOhzEK21ehIsilSyBhpc19pze71M3pWGOtTwKXzQ0GriVRwJ5kdZxFYWFQNrHUdKnwaYi0UT3NYaFraVz2M5VElfVu7LuFd/SietCP6fAqpLNJjL4Hr0pSq19DHrvCBkw4WNHdE2iRiEGeIydtMlugDnfH0X8wa64M7iPJLpMUEvQkU2sAIaafxOCE44lToZgTfVqmLoFKYbAGGfFfpH6kP4yI/3Gdukas/evCbu2jD+MW8rDkPACqUjTKvTNdVTazla1+0FNW4fpxbkWobZrtkSXrxPCFV/9D3ZrmdoS7A48A60V/PPg47b4XcAeQVUkJTI8sRlFWgcR8/EAWHMYbgnSTlNaAxcVzpW+vAYlOwOr4x1+ZVpVYJxqak+UgPZ9Zjvp5836/BOUWzVRIMiV3AW8F1iYkGWEEcI2UhgcWMee28jmaoaTOXsG3XuLrzBxbafPvbUkjODYZ1y6nncWuKg6etdDPLvQLanOOH/Z4D1NULIaP78Q+8eNkMzJqBNnRj6ROcFzqdOq4pu/guuImd6YVg3gGFUrQqYdlIcOjwz1YgLu1mwvvbwwTCij8RB4mExTL9hLxbTOTshBPfxHuevWnIK00JIjkB0Y3098M72pt1+2z+/wxH+aJqdmEk39GSRqB3PhZ8RaXqJ9QMH6+KRA5xNhCmZVlWo+1n9neDIEH2XyYlBZzBYT4hjRAap3MiHavQVfN1Znw1OnhkGNS8wqocGb6e4CeQPIe3SnCsyqUOgN97gFH7GjpYAKFsrEXl3T1AQymn/EgBFtlp92jMH9HlB0pX1+ASkfIExtd1ROqmRuaj38gOoV7KtbMDDxIIqOvwADYXmMuR7jFZJSUvbJk+55BNRt+FBBMI7Yc9cDAvRzjZly5BUUosL717N62eJ673aKoOlaElLhzSSdPESuyyAqfHN3GhCXEV5w3vt8ZZB3PFDXmvycY+qyCW5y0KYGFWsX3feplshtNRWtsXOX3L7BGplo2GMOITgvOS/NyseEswkQP/7ezlqPdbJXwQbQjwoUC7QajwP7O2fVa4Zt1H7AU1VrAzzxY8uJxiBY+TnN4WVBNmaxSKsNJ8BgdD8hWUOcqVMNojYfnemiS+kHxKdNEX5Aute1XYSerKNpISKi6Vo2IsEkdIdeBnwfswB/zA7do8go7Eh2plsCQgsVU4k/K9zdTu81CXOPdrg3UwyM5o2qWJ/appl4UTjvqcbGJiB6j1I0sn0d7In0buvl/jEZBAFn3leEWz487YN3bQmY9wkDz20rSZaNKoOFqn3o26l4pKKZXyVf42UhH/AXFVDSNTgjvg8sD3I8cV43RjrQ5wZKtLtgQG4+iGVGGJVGEeVMT0D0fsydJe8FAJsBTsvivq4YHGgHakSE6CIn8PXkb8TW7r44DWFWGAfcXVTs8q3V3dlffvikmgs0Eb9TRQYtyRNRSrwuU61HOaRs7WqJixmaHTLe4vtJ1h1vnakTJsA/biRlBgnpwUMBoE7zp6QZlZ5JZ8SEgadmtGvSzSoRno+N21d4MtHi6DjoitAdlONdzvF4jjKC8ky/RvGAIzYOa52OvgTu4Ad8l1rLNIw24kP3cUbyoe0RFbVNOaZL2lx5jDDW7jlKk4n6SLxQPC7eIHzaLLAE49aCvdMx23mUAKjNVfFnxAajFieE/fAETGN5Z6ULQtpZ+2L/YoBVOfxTzMTfxUSHW/w2dRQFjGz2dlFHrhouNH4oSpbL2KZE+qBlqbQIFOs5sUwFhA1pp+J27BO2TrikB2KmNc2n1+WMO06gzrLIcaLftABXNfyQc4bwNAz1Fs9us2AMheS4zepIYaqF71w7o/eLehsrkOQuEiNUz5wIe03XubRcR5SR/OWyFt5E8/vtuLMeNj5KkEyAUJ5oKcTB/p+QBYt94H+sL+Cnp4zx7BCiSmKnXY+7ErTKdGFDLcV8IFgt/Uz6FtRwl9C0RhxZfPsKHUlE86TRt2tCSNz2UAmazYSlgH1lBik6QR/y3hCT+ZcikLRhmMgJr1FnATT8GYtsJM7xOKT1M1U/G+TlRj/29EKDrqHHMuzY5j+OJJa96MS1a1ccpHgf5jI8K/qCfRMhjVCulYmhVjmQ/JFnEfFjybynt4qHX1vx/OBJQ+mw0iK4pdJ1TdEcuBjps//V0pVxfmIkC/fCUxXVigRTnPeXU+UJNIMm5uWTcImd7X5T0G+Yd2jpQcbm5CtZ/BrbFDsSq3cIIRGkO+sdK0H+YPU7TVSmSlU+02zbBUyADWItyjVg3M5DdUyTtd0BvH/3GsCcir5vVXjvK0PKnWL37KXUp9KzHBLT3Tq70JSM1yFPC5F6i9crMBKOR6MBzispuEfigcNvjOo263PyulYdMkHnFr5LANySAwSCPJi552P7k6RU9cA68Fr7/kSCmx+sxyAEl8N9VV/RRluXbxO8/jFS0V/FXcBYnm4HEzwq4qqCT6izrMxk3ksbAwselj6TdWsGEqFoUkYkO9qjVZHt0gVA2fdXLlTe24sjq+2J12GVaE831cqE2/w54CqbZrHVXgjfEBm4oeMSnRYbxPiLzr3NjiH5h9J3V6zkAm906WuDgig11BDZuOQHbDEqc7aSjhkt4/vqpuVA4D/kw7A0nDVKCkFPKH1Tpst6wkyPDHofWyMPhsXstNXJC1/ffVttc1wBGhgTynPV9/rTipHItQ1JRd4utbWYgElihi6MYSNJ4DTUd/om4CHtAhESr997eNI/3nhFaGXhrK3L0h1+5VpnlSmve9E4dtmR8NXtyXU6a9iuU7LToNTRmUkwyNU0sjLVDSTlGcafW2tYuOH5vkIFkqwOH2QP+BXmazyROA8GrU2Z/cIYtXoQM0EhoiIXGaHAED5j+rA4YqYE/r3d/9nKiodNdvjoyz0J3+IgvIlofFkjMbQcuJ/AL/UdTUb7fItMCIN2fkx+elcx6LSb6C9l9M3eT773rEZ7vX+J0M3+5Kard9mvbtc41tlEjeobUIh5nse+AwSwuaWnK97ktNwOF5mtnyfexuLpyhlWEWjDOfvcTlBwMoRgjFwKPHRor6p4/DRYO1fu83eiSKFm23KMu3R89T4qKI6IeWIfPW8PZn2AvB+HZP0BRt3khYEfIEGu0+cHxPOczJJk2xSYA5AKxrB5v4h6quLDNg2Zfq29dTawaZuCNkkz9YNLQzm9jwMJrQ263R9R+sV8SnptBtoOGSttuVR30BRh7di3QoVzvSMTw+cMWVihJ0clFiwlJCGJqJJVYxeFXUUenDXXiuXh2AIHghVRAhJLyqO3B3sG4QlJF5RgugTnWlbtoAuaSjleHUpuoQ+y+PbdUzMVmAFP1lP3c1PhV7ICALgIR3p4z+iLdDRRtLB5YAP/qziZOZS/5FMikWQ9gmeza+exWb4BDkCfAEbpQYbkNWumByJeA8C6xzC0PMSg5L06R1o/6nhdq6vhP+YlM7cIV1LOSKNVCPO8cJEw6/JOy54ZXcpG+iUk5LzMhRo4l2KvceKgYLn9wIfCvmmyi8oIzBCHq2b6Y3iFhG4Td6e/je49MxiKZcyLC9UphjPhAOForOUbchoANr853G62BHwEZJtPDkHabCXb894PbcNbWNptWPb2jXqztPufmYrEvElLhSh+wp5g+MLjUgZ2Bm7p+6X/WLWIrjxHpZDspE5MKijmuQLnymQwBRGUp1iR+DRAF/+jHA/6tH6+XM6jT9cDTKFG9R+msztWWW6kv4gxX8vMMQEYKfx4QzsaqIDwZUqDXIcQzqp3cGcwjhgOp/QK+0+OiyJxb6MadYYvhi6rSXhtbG5kVt2PxgFZiYWBKcKCcefNVtn2L+ZRdr1xAB+RZtw4acfGH5/OwSft1g+WjIfwpCG+mHEof6uZsasmsOXid35Q0wRNdBhWM8oCodlnNVkkZcazvalytdqfeFUI3OCP50aPZilXAVx+pSenJqhn879Np4kPKmyw+AK3I6qeJPeyLS1vf3qhUPtyDRZeNOX7x8NaeNLkNE6ImzOIALWP3T+zadPeCmTWMatOyDaCrqZEWYOK+WT7DZG4cQoy6KSyIx3pXvuMFZhQIXGjf3rxZ1urfSzQ9nQ1KwfG7MrMlQtlKUVfkRGeHE2gVciXNGI40hd0paT0rGbYKNeQ4O8DPgAIj9V97gU+oJ64F3u0+RPfnxyMPp1i5S3b/BAhw7OHHiaAUwioMjYH5hDXe+pQoB86hCYUlrd+sFMGDtR4MzbkayWTeUSkJ+qQIigi9ZsDppOJCqcVyx61dV5wNia5FGB9N6lMkLmPngCw2jTOJp2NVfiLtv/DHvEfL41V9hLP60DVFbcQ/5XegwOlhIJ7RuaNw/SSm8YYrCSzFejO81hP55GqTUXSAK51CDYen1Vfq7aPGRsKrAYHzP497Nhpb1ZFOREjWTeOAXe/NNM98ep9DaD/rWnp4KmFBPHXdJ8axAlowXAS43aYy47pPAJ8zg52W99LKv/eDmuX51XSKSlld7Xv1x+iUNdlTgyMCzhKe67jSwjjiaYsJgyLUKrMAD/CV+gaSbKlI5nU41FH2j6CpGxMbdo5SyNa2K8l/zP1a/QaJakEn6kOGG/giSbB19l8CV2AAAGD55f934WjZ4JJqVDdoMMbtBD6166NPB0fslNksPvLMyPIkSG41QX3VaSM6bMhgB3ZgdI1IWFpk+Y6o7p1+GsfoN7tZuDgoJA0f7xoy3W3e/5albbRTHC0HDEGkw52ULLOdMRskSQfR8RONIzocwo2x+xAgtz8WMXpmsmwji9VYfubqaIdf3OdjwUmVJwZeG71Q6W3fCJSSTyFQZ0y2n6udM606j3vmsbskjcgNd96JUzjbcrwN+3Hij1IQIU1S4DGSEKI/Ckj65Sx/zRdt/WI0nzRkReA5VTMUL0d/l/rVDYMmWsryfLkvsAa/aWcFvhCy/0p2OjKUje7FrweKATAAuC3+/4bsXM+jWVjYZVPIQl/wwyjij6+BmIWlykAX4RetfZQcjoTr33+awiQL9EW1BOS3/bBX6XdBXt6ClSugVL0adHKuR77iUcLZKs1zyGpK1LyFxI0gQQxNboAdYQ7VLIBJKjxy/ZjWfPLxDNKQFgnksrMQEb25b65U6F56jeCcNokMwvGIpPpAR8pCLl0TCxiV5t7YgB/kZACmojF0kTdOwi6s0YM8bAxJyGbhwCY/loCSLIhVh2PNsjs/126JXvvXRAm4BqtjbfA4I+pn2SCvPIRLcHy8kUeimHSjLwvwWiB4AXND31FP45CKBGNGNGM8UUDnzkEu6dwa6YTDxebixEny7ve2PwzKyNtuXuGTSps35vAIJqlY4XdeLgtSOFI8roTNDNu0ma8DVMbnPjxgvvvXJETvFhMQYkyxG2bDLBmAZuP3rqJxs48xtoiBKRjMCZygE6Uuk7XBF12kr+xM7dWqmY8DMTvNcLG+UebOTmCzBULFphFs6MQHxFl+26O357flUqOXzHtuno+s6hjECUww75pSkXxPCo/EXduiakcKDM3f9O8MHQoEFnIF8ZsU9WNjRf2qJ/uKLfxh8Mh7JrBTtanAk0lYLdd+ScwH581K3BdmiqI1Sveoezxc5qFXr+fyshwHIEe/RHJ5yrfwcCOIkvY2NgfkyWfZWrup1S++H9FKD2JHdPjRrIite5xx/Efa6SYcsMD6zneMxtYQa3+tFQAqdAj6ZLcoXsqakIKYNolySpouarXXZNINBvuu7pfyQ/zrOb4MkZVSB75/3+7SOwJT84YQs/dzoGT6Kk71fjwAfMyLGPTUmwoVrTok2+sJM2if0gdhNL1ZnB27v4J6poyzMbbkoJwbmWm+NJsnb/XhVtMN3n/5Mgcc8wgs9GopvQLyc1ZvS/euLULHuOFWam7H6qodrekZxpCWFGYsgbevMMEjG6j5uZDWJDyCXBK1bDaOrn/KouPsCi/U083/F2llptHjcRDKD9r3ZYwtZjO7J3FQds1fO4CYLFpviTskcPvPsCXwHjSwJMYg55OKFoLuMKegi/f9+jcKr0V30+SYsaCXbSnN+Fu0Xo+01Pu7a9yRdZ0+VtiA8X6DE0zGsu/lURvg0Qq9ROh6bZ04+VX0NjHKfTgVYUOWdQI+BkTyVoCbdjT3oN8t44rgzEWtHz90lrbD4b3YgRNnFc5gtglxaNQU+cZjqoD/vXcx3zpOEs5xDFWdnNZdHJpoK9ugMpLG/fFavevB1EvqZaPqIKsjFhSsZYwrKPw+ddHty5tWFylIzs7Vir+yDw7/3bXnauc7d4eA4tDZ974e9+vqGfFRmLVT8A3uOhcxFNT1n84X2gSn58LzXwA8qfFzYj39w73UGspbm7rgqzfZlRbuPW4HQ3kg1rmIfsar7R1r3SwmcojEfAH6JjIsaSLAAuek6XR/oYLs0GpAL4s41mZhAfv18oc+UKnnU5FGytLdH8fCp4VIzC22AP4lheCRE4/mSyPXu3tYo3srZN+AZSvfGzN0NstTpiqM1QUEjA3VZK/oC3iVT7qaLUAz+pL3eBxCNqptIHFqIinToJk8a2B3B05bccq/ONJunPZrQg1/95TVldant6EZRy8NI4GvedvCxa/jOOUaVYeQHvEwu2smQmW45SJPoeirVhIH0EcGWMnqqx4Fv1sKeV4m5p/RpLePfhhKFLWWqgyQhZCeqWdj9p0rhUTZ3XsIomAiyqJxstF0EtvvWR+In3gBsqU6IjcMaI7nGVHYsq9OWF26CNypxgVqzYOlOby54cBxN9CBnGdubJZnVEt2DkuvzAP9a/zGsZcfbW9xZLBc0oT2YSLWJZu4gj3WWHvtbILsnJi4rQlm+RRo/OpVAgPVlvI3Y035fpa0mPfxKqGs9eZMmd1GfYpCxyeiAGP1ET3zrLirXFspiRBlA/RUmxUTmHdUhnvagy4mGU1fqQzm/iVUXJafSj8ssqLcLfRxWizTYdrxlMmCE8D5wMfm2GseAaRbry10SgClPKeKoR+w0JNVpNv1ChjCyN5smdhaDSmsOPdJSJYgvAMaAyVTSoHtgN7ZpZr61f3rc1HIZoc6TyhhYj1OFEY0Clmn2mOcMIi2mEvcBYTgp3fvv2ClAQ5tA3q9KFVCTJWc95RoLpwf53FSiiJc7luCzLnN3FB+5BCwX6zdx6xMPJw8N+eBHAg60mCBRp5Edze4NStmH2R5d/T2AR6xqJUrPGyqA6egGi7098Da4K6Uqctau6x+i6wunZDMaBYZShaJg4MfmTJEmr883feoADxSlv1EDTHxIdJKwYxmqC5qXxf4pNgj9DiNQjSY5JSmPtRaFzmQuXYwLJitm8IKBRRFd7D6xHhEBa6CdzEEZ83X9fWT9DTICNNUjmYqiPCDgk3M9uBgFE7HCExST9KITLcm2MeoICE7Qu/I3JvIqpVsObc1X7V77EGzwYk8iq4H56BT830/MIV6ealD+qHhIXfTrNdtpjj7OCvDJWskmRB7/VqZJRo9oQMRDLQB8WWsxfy+PwXmm171pr3I+EK1RqZlPblYyTYGQ5BKgqEEVfO77rjAJnGsAOtSz2/rbiOBXiSaIoGg81rFqnJGdW+YX8Db13cz1ArpLlX8TjOifvUz+kDznXKCdnNSKD3cbmJfaBwX34n/cne3mrDfSMDp9KKV35gD9HDp9SaK/zLRijSJRmmLgwQcsJrjxLAwbSi2ZWJN1axXN5okFExb9bJTL3kPDY2Dm3oKHsdBaogUl16tN/hghBQ1dbyb4vZ1W0qhzFPDIWnRO+QMuakzuq/t06d1dJbm9ouNs3c2YsRhJBpKcMr5DtZjOLwwQIPzA0z4N+oeAbiMTQkV0Jomzk6cBadP2kq3mfSzkdrmFkqbkjNMU9ySwb6CunTIJaaKBPwbvjpzWgNMiP//MSK8MQ+Cm0yMA7w8anJKnLAIkQl+dNnQLaVunvEeLkuTfcRYELI24ytQTEkloXn+JqVYtEgHxVeoU1qcI1v7cnoIiUHC4lgIYpTBhXHEg+Hwg00mQHLE4aeES715PuuMpP/tYnIjE8/62uicOBZsuQaHir8fVAgdHPZkWJvHlV5hAUSLeC5RSBY5dHpBfMfuUFvN3SSYHXZWaGvvy/XmRKYK+d+VSrgnyd5po91huyO5pV+wOb57UiuPWimYIYGcWdBj7hkIyQAGTf+TdCX3I6HDVvzl4PG2kqIbKrD9W9aKDmgH7uzQoTUTPVGZRaU/Ac7U2lTs1ODufobTVi62ZuWUGJipK+jBSOMkz2OKbfZjgFHd6W1Kcl4m+meUzUsam0XGAQq/24BJ8+zc55gM2bstfTWj53vQDlX6hFjFdllXkrN1iz+eArSWxzvE225unJDsv1lHL/mgwFFqTTjxbUNbMb+oFEzqWxYQ8jg7amGdokyZwgGLLJ0v2Dupm4WMW1lbM+H0ptcVugYPlTZkjl2uSzJvT32V2IjX8lQtkVe2sHDJn3RRrZlIBhEbQVuuaJYqC8WNREifJfTNtFRInUaXdv5aMM3IJnIED34bmySYDuDJ/GBPQAKsXOX56tsYvhwPs0vZPjJL0ZcFPA8h/oUforzLck3szk7dvAMs/rx0KTcyHeNxxzhnzoQHAe0l1UxveXUnZ+j0ypucm3wYeqg444wXXKu4k3FOj9+D56Qszi1nMQ9RF7DLJSOQ6jo7fzDNnraQ2cN8ptWZk7ucYyKlbZXeh6aSVh5WcQNSL5S4i6Y/qIxCARMRemyR7mKmrauO9K5lmJsO19ZNVt9uxT4u/Z/Wrg1OEpUQHSRqV71MGX/enMnSak6yaRPGKDDf18amrP+W7xadF+e+DRWjPO0sj6/zpsjmHZb33m+fx9rB9dwGIvACd2pRwJysh1aiRXbsOp14uQ9GL26SqlDoGkl3jF2g0oDznejN6x5EpjhIdltKj+L9S0BCQoset7KAk/iBUhiGSDFBbcoFGdAobZr2a+vbDTN2mPbzqWr8NegHCZbwtit6hRsmB19e1t4aWTQd/EJ2nz1LZ4kbcfM8X/DbFUqNZJGwtSS5NaWFItG82I2DS6OmV4FjeeMXI+zUEFh09k+syM0tkdeAFi3b2LYl4ZJsCU1K1pEW6101Mz5SFk7+0FkUzk/EKrzUXdi/118xV7HMVrch/BUZa9k113DOCXtx0de/8jzRsZT88dsd6P1A+BvXesRsvjGeDkYV8DZ78YZq+gzTTFJ73yBbepa2DAstGyL9pWTnixZzEpAbe8qQEKQHP1ZdtoDcxY3CPe2zhie1khET9xGZhFzbrMBrUbgYtB9aZuLWKxUX0DtbH+xFAKRWC7uinLzhw7yhQ3zovimYlFd4d6OowwyZRu/0um0uRDsKV6Zg+NN8D3NyL6DpkSp6G4/1ctTLaIRc2NjEf87vcjzueqeyJJM/Zjt+G4ygEBkbSWYgNwFCp1DKLKZAIA0GzlxU/uN3IXVdnrwyc7FW9ApCRYOKHEdzeYMRYDu41XThrt1JNONxxIfLYnzqUga7jIjJy0nt4LHbz8g5qLwLZn7BRPDq98Zicl2dePP49sk3KaSMeZNIUNQXvud/fqxcNECvwEAweIlypjqxQFlqSDGwdoUlnyPdsz6nxHwoJprDq8Si73DZhhNWqT/poE5PCRPZZGbmR+eUU6N2KOZhj0ji2K9LzNxk8fkQOQeBADoGqR0e8H9sK8bM1lyj07eU8AD40S3Q2uK0hWmRMFuhLAplPjYodZ9GLQdWSk1dqmvB5j1Bh36U7hTm+9WhmW5zMSTwyA+3D6oQHWIyf4gPhREW/OuMmvLTKCgpHH+RS6nSuPMXxQ5dyJjUfhZ3VUKOi+v4/S5rKMbZzvyg3Qa/RsTLtuY+OzhdzAHl4+gGWlnpAnLs6wMwqUtKjYn3Zq/z+BOoLsQbZ8jWyE9SqmL9374l3CgBKRcSPlr1mu2sNgIhLPw+Fu3s7fpxgulidnK1nh0Jalcro0I7ptY0Y8UCDpOJNVsJbAO32sj51ePTn5WttedcFCrUrv95AQFBpuxYA27L2rT1f6fa+xIM1RwgKC7Sl1ikp0OpoJmm+lJLU99yXnu0SJ0NqN86Q8zm/kScHBXVSAj/n8epcZ+9TA3k3PUQvb40e3URUutu6nGf9EcglAQjQtMAuWXFw465KkerWkX8wRvm3LgwCbN+SVOf565FIHFAAtSa51RwUNjKbiqWY4fzQu55hVX4fXStyzUONWt318iEaVpD6zZXIrWEClcmpDOpYrllgbE99/dEAGnSg+q73MnH7EI4fWlJ2QM9/8WF2ZX2p9SXmVQjnrLtxthf8h+mA1TkpA0PKqtIHOpM6OLPgFlnepSs2/7i7AaZzl9s8aBnWTpLpF9GSoxtJC6DZitznbWvn2+vU3pXIq6D5UZ/H6aEIPhtszN87oUD/ECJzYCWDAaAEZ5jIWnBE0g/pjAtEcJZ/KWbhGE43WSI1u0yK/euQdtk0X8ScjX8dPNNp+IHMuxV0weUBXF84COVR15sK+QNVFm9c7aQOHJ51o+eMxFgSiGv8km1Nfio1oRVgO/Ul5X38+kV798+tgMeQSnwgNorNZvMjUhE6AQoKfuxkAq14NLlWGEfuFreCyONwLDrXpctZYGBCqP7iWET+pmh+dAAAy411aOSq+TWwQwG4KGi0asfnwBwVBivOGOE0zLGjF87yeJiu9SoZSf7MnliWyzLec3nzPz/G4ndSrklXiGh3NY9C3qbwHrOXQplrgxtcJgnp9v6Upr7QLGjorZOup2BWJFu+4uekb2AnvytP4bYJVbOjMlZYDGRNUo1XK7llHNr7gLZ0/rqbooVF6Mb7a8WB1rEQataNZ7rMjhQuEbkLgeuSHI8RD14NqNTYicQvjp1cC3BRyWQpScrpUW8MVvK/fUOIjqcvsbWM5vMMbUr023B1qNdBQ2jJm6w9EmTF38j0+khxEGv4lhNqLB+umzjhrCjxw5a9gKvFqDn1qrIH05jGNruJMFaa9V02GFXlF00YjFPDEGQMOObB0iwgoXMlz8pmSd44/VP037UgBx+OOsnE50RQBpx3c8Z8sbuXzmQqV5B2SpOG4Zrqn0preJjoWuaw9juupIb4PN6IxUp7dx6j/1lv5DLjYD/oZkmrFlWK25AIvdyBZEM3stXOacUvf5el3LfT5QFUB4kmufmGd6+jd6V/rb93siOgUjV0vYUTihiH7M8zqmr87gYDKDShVQ+hr5SM3fCrmktFr6dj8ZH8w9MpxpfC0JCr+ZK8bnRHqK7nzVqOwTzZ1G36I/Ox5LMHRv8/lvKPx2+gi+1ESBG6SRNvFltdprDz0O8Y4gFChCXriThEuhjOo5CIIfXLgKERJHqjsLI/hLRA3tnAa6dyQwZvywnETJK2/YC33W6dpz2Vh2cQnSjrEx9V9Q10xJe0KEZVmN/fEgsq/VGK8M03WeP5BEfo8lvLR+WEJS8PkWBwX0nizevavopJ9UhZKEi6zMj9jolFYfhuSPJMBvZYumO7a1ZQ0HUjR/wEv6KlkZCc6mtHrKbdhAc7XheIS7EaGPaIyGMYr6KYupp1oTiFBTiimJMUvgSMEnnOcsz+rQpP8UOeaqw49f1hBVcj1+kFZknyByAhV/JGcnjTHngtRo8ERhGcgWV8QrlS50tV7SN/91Zd/rcmQsCbr6WPZT4OEzwk/8iOmO129DhYqHDYQoHOIRCKdTNC3gdasHjt531b4lxHo5fkMDBXWZAwTsRPO/L7S0ainwxxjXavmidzBo3/E87nXp4qHQEhVgH1NlvRmqgQh3tkms6euJtuI0mFhgmwUT2UA1m0zgW//pmqb82+efttFc8mFSyT2m2fhsVY/+iFbZdgD6ICcqtOtFB+ArQVSDU4HgIPCC9GSGFZ4R5t84sEhLEKDWFUdGhpUY/hXMqQv1p24yRanjqyW7w+lbH0fdeZAfWRQ7NtD0S4zXM5EWxCvqfFJ+i9TqqmiCkeStm80urvD03EsOp7uEZGMRPklTM+cHXzVGeO80JNgE9aiHJ+pPtKGaCdxCiQFduByhS89AWejDWsy8j5BV+uTWmhsh1tIda417oqFFfukUv61ugzj3VhkIDR3Ic3TfszjK75vxYr/+uoYOvB/B/m61Hcfv/7Uk51F/oeRplTR4LLyvN4aPRvkqtvjIVtxeOWS+Z498hplDRKizGjqQ4TRlvhKVW2ifhQHzniqFlkvlH1Yd4yAtnlctzj8KN/ulK3Df9nxcxXOkEGsSv7l0uQubl4AVWtRrMxud5b3MejACGKNLP3AeQM50cHQAiihjK25tIe3tiYvBPDsUsWeaUAiwp7SKI/KWt1Lsq8ZqDy4CPH4TNaQ/X3DlaaZZcZoc1DIYcj3d265VSc8fTz/PEORvMdU0jAJ6QUkm8WrPQOKyUyXrzXWBkWlLXijZWxDbzloVycfKudqu2gJCqAl/DFk/aHgzvudg5b99mSvSkBgc+4FksIHfWw9r4wjrQkVhWqLpDUsOVqJiP6E4FENSkUGlivALXEt7ezABM8apr3k6Bk97nC07398iZUSogTJ76ag/szXpIbm2pdEAppQOSIHUPtUsK/1crmS2/9QLhLDumaghvtKJ12zEwypUeUfVtNJgdnLNyGZC1O6QFCsyjuUn59aVxhgG49mBHafwusYao3K4OSED+Eb+9n0DxIdfmfKJfqfhrnc+8sdZ4vfCYCgdAn1bJi9PMpiH4o2ds1oIiuz20a515bWVn1K9YWEIEJfuRbzu/g/R9cAoU/eRublKcxTXU7k5Na+wGbWdvEZWlUX66YhLOojFqqxdE8VQDALU3/5kCTE5ceS2IDgDyzRC2QlHkBbhoxTP5Da7EOwWi8/jMPkIBnDPQDKgt772DDj8D8rP2Ku9O1mNjO8i15i0BLKMoAZ0UKEgPGztxYQc/hpiZAXYjMkuDBMC3Hhrbgt1KW+nP6HSmpWGMpH9qw/9+RCMaUVOi5BB4zPaElj+PyK1Jbc25EsOaD51FHS1GouzpXfF3Yh/wgclDVbRU0wm5DiigyEpuxSvC9dEeK6PH0j6F4LmxvM+T7H8tIX202IHnN7o4rDX2rBYpfan4HLLqiqpgaXbTg3l1mqvI591TwdXVkmA5k3U0V3aknkjiij7c6q86QabKMQPs/Hs6aiwGz4SGf7fdiF55xMcW2sefEd1z66Us53xl4P1Kf6Iuj7ZFetZ1kSJbE6cGnj8CL1Z8LiDMfmhjf8rfIKuIl3kR0LretVOkOLeY/962DQPgu8GOU3Or9IhpNpSA74mNzrl/eRcBIx6qeLt0UJmXrWhUT9XZgc79waPy18yP6MPV5ii3SjMnvaIiuXPmXpwErZN6uRovvwe01doFQYaZVEgjQvCRMQLZDYDBu3VrinTs+hxcNMCeLUS2GkqF9uRcGdx3dLcd2YeGSK6Y6wLTYQD8/nK3qMR/RyyushWEdvJnSyNy5wPU5Lwpq91uoa9jyX0tMG9/ZLHNwdeGBcY0iu9QNh2xx299sNPuCUEiwKO1/Ys4OH259j3t+lV8sYbWGq4P/kOQELtRqJxHO/MOi8C23Qmz9/Vf31C6cDoW/D6vIr/r5kdnWvtqwOKj/AJVj3O3nZHIk7nVLmp7CztGNgUB0/uxsTYCOzZSLWAk9uosG6JEml+XT+BCpkDUlu9t+tJY9q23FDnRAr2esf6fDgn/+DmvUYL5cqMItUUmC8FldIaPCt9Wikrl306dK7NOh6D0qaC1U45KRnesOWtfhTpariXYDu+ksvK5+WlpSviq3QNzCOjMK+kVW4k1WpkwYior7dnGTpjKjyId5Kf5FkC0YXCBXexTGadJ56elDCdg/cIjlwrmSF5VJBkMMle88FxgkceaXoOp2ByPZZ1AXXPfRUl65KKkA7jr7Y2co5KBQ/XffulUK9ufXMOWIx6T0JY5RFdFsX9RsVZVDt1Ehiq4eKX8JWSP5iiP/xlPspUBxHkZ+NVrpxLHn5hB7VEXtrqNhVUhzNTUlMGg+YcyE1jbPYpr1y20Jhw+7R+vBfHD7QimiXP/uoXz89MzdejoJxe5MMymDzfID99hbFXMHJRKY5RUNU8A9oJ4fl/POg26eUvS9z7z9JBjaE/kZB2JOdOWsDViFz9VGFBKvo43a+Bc28/fc8QgzTDCKoiJJYFFcQXcVCah1uj6+CFtYPHLpIgCSJY3yHcB5sRpmTWbJZbWx9Ibe/YT9t1kgQ3dMgUlNKLbd+/568ONTtlRq3SsTQvwYznarsdQdnUhjwifxuYzhDtx+gG0caiw6cZMDZfjsi3aTiUe/vtU0xV/cqTZSI51cxySyF6BpwmyV0lzg4A9lpGBpg+9JE02tvIzCye8l9ip+v4Eid6VbTuyJhKl4guTd9qnVC4yWOwRBwYtcNhvF6HUb66EEwqNzenrI33ULJaGhTKmKmWfj0dxCwKcdqvddncpE/3+Gc5Axc+WaTJE2rAhC/5SMk6zGqKPvIAfSTyTP/A16HIBNcRuGEAFHZWGLNU6w/uSLVyitZreBjReHkZZL0Nb9poXIHjuWxqyzJoHCTEAAKVpWbgegfM5s9PnT4PsITYyeqFqIokbMgl5Hmud/p7Z8LJOBoHBV9XE/acg/RzROwYNKulkgLDMP/d/R/Uyppdl7oncYnfwoI3uza1H3R6eZEjY/3GZLh2dKJLDDVkWy8NliENHX6oXs9YmRX3bGSEEdBskyVtm4SiVhteXDoxCRN3aCLd98N7xt71mqemAmiokKWoT73dPxNvS2NsHyVEggYm+8SFoDa8FJOzrJDCQphDFDNOUjy10/MMjiKuvtGOr7TwTyWBZxAUDkLVjRMsjOZwgta3FcGtTUPBAhS2D67AvMbBQN8i6eKX7bSzu5X4lL7dr2MSEpZoB3efKFY5WGa2OrHhqe8R5jTQFZLBOTK5fJpn2PQzeIXSCr3sMQhq9Z4S/a3vpucx9e+cw/L9ixSb/bAZlw+lWyFzKCyGhzzOoxeUcPK2cMCfVwiWLuAJwBFtGLFhzWDVmR4xJ71HWafo/kO8mNfI0kK6uD8RYF0ZXe8uvKfwh6BCNqHuegH0sv+2E9U7TrS/i7WPxek3s/GiN9ux0zvRG0/0/k01dE1ZgWXeS1gEnaqPaDOTevOXr9XgoD0qL9lDUrPTypaTjiJiKGvHrR3ws7g4Ui9OfWT8Sxj8pLLjGxvDQHbgtcEsZl/k3oOGd3dcholAo7RleCQJmR2dGWZwKj3aaiAR3Ppsqr5C4VszDeLX03D3AXsBXkYqEmwUTd6GR9C617uSkr2QQnTRujKpxGAFjw1YTDw0hmrti9i2u64OWRz9H/XEhQX8w+8/WqbGN4Kk/qbIrpziXLNSgeu0F+bASfNXpJvAafYhPDqcvSp5oha6P6uJBXlH0P+RQrS6igtGlH1udljQwFEqy5C3Mt4nsHXWq0aV3UF9rIpEh1jh59XyAkKiVdyxHmoFHzD1t5I/o41ZZqr3jDd69QCorlhp4voOVmNrS7Iw8K6NlXoxlMAJGZ0XHThUaRL/MLOKfzKzhiIQ4sxf4pNJ830RxIgQ48ZIf28EhW+pmcOQOWRCG2HiPzRF9/TZvvLRDNMXfWceHQ8NBZ0bIcy0u8BjcYCpWvNhvE+F0JMqCgOvIjUqrnN4ZO68hcSxJ3AzfCtl69N1Im93ENsoC057RQSpfeMb9324K7vYVYf5zWdVf4edwzYjLgmmZDGqC2K88Dbu9QsI6un35TJfWqC/2C93m4ekPSBeEyWtsWhOSa0n+/RRaqVu1f4z+sbB7uxseQf6sRPaMS8L32/gvoRn28Fsnu87upeb6AaTOF0cso0D8ZPAYxXWDIE/ZH8ZKB7OqJuVwKZWiZYAG6o4XM2YycOWVhoV+rBUBpeFqHz42ko/aHbf6gkIcg0RwKI7UNPKCLMge/wgXXlS4pKDVSVOpNU2x5lVkXH0m9Tk1axqjh61zuIaTHyLGKrHeTluJppKoP9Wwbfov6P3wQUG1ARL3Lhz7n8dAg2siDusOh+Mj/SpF2hntobSURWngaAOYhRIxdkiui5qeNo6CBRVpyerEXxqKMR3uAhan82yQG3ZoQA0T9TPK��#]�\���0system/bfnetwork/bfnetwork/tmp/bfLocalConfig.phpnu�[���<?php
header('HTTP/1.0 404 Not Found');
die();
?>
{"_BF_LOG":false,"JCEEditor":1,"InstallFromWeb":1,"Weblinks":1,"RegularLabs":1,"AdminTools":1,"Akeeba":1}PK��#]�L(�QQ(system/bfnetwork/bfnetwork/bfUpgrade.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

// Decrypt or die
require 'bfEncrypt.php';

/*
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below......
 */

define('BFUPGRADE_RELEASE_TYPE', 'lts'); // test lts sts

require './lib/autoloader.php';
new AcuAutoloader();

class bfUpgrade
{
    /**
     * We pass the command to run as a simple integer in our encrypted
     * request this is mainly to speed up the decryption process, plus its a
     * single digit(or 2) rather than a huge string to remember :-).
     */
    private $_methods = array(
        1 => 'getAllUpdates',
        2 => 'downloadFile',
        3 => 'createRestorationFile',
        4 => 'extractUpdate',
        5 => 'finishup',
    );

    /**
     * PHP 5 Constructor,
     * I inject the request to the object.
     *
     * @param stdClass $dataObj
     */
    public function __construct($dataObj)
    {
        // init Joomla
        require 'bfInitJoomla.php';

        // Set the request vars
        $this->_dataObj = $dataObj;
    }

    /**
     * I'm the controller - I run methods based on the request integer.
     */
    public function run()
    {
        if (property_exists($this->_dataObj, 'c')) {
            $c = (int) $this->_dataObj->c;
            if (array_key_exists($c, $this->_methods)) {
                // call the right method
                $this->{$this->_methods[$c]} ();
            } else {
                // Die if an unknown function
                bfEncrypt::reply('error', 'No Such method #err1 - '.$c);
            }
        } else {
            // Die if an unknown function
            bfEncrypt::reply('error', 'No Such method #err2');
        }
    }

    /**
     * I tick over to download the correct package file.
     */
    public function downloadFile()
    {
        // Use Akeeba - We love you Nicolas!
        $api = new AcuDownload();

        // init array
        $params = array();

        // tell it which file to use
        $params['file'] = $this->_dataObj->fileUrl;
        bfLog::log('Downloading from file: '.$this->_dataObj->fileUrl);

        // make sure we resume a part downloaded file if any
        if ($this->_dataObj->frag) {
            $params['frag'] = $this->_dataObj->frag;
        } else {
            $params['frag'] = -1;
        }

        bfLog::log('Downloading from frag: '.$params['frag']);

        // get the frag needed
        $retArray = $api->importFromURL($params);

        // tock back to myjoomla
        bfEncrypt::reply('success', json_encode($retArray));
    }

    /**
     * Create the restore ini file, thats actually a PHP file :-).
     */
    public function createRestorationFile()
    {
        $res = $this->createRestorationINI();
        bfEncrypt::reply('success', $res);
    }

    /**
     * Creates the restoration.ini file which is used during the update
     * package's extraction. This file tells Akeeba Restore which package to
     * read and where and how to extract it.
     *
     * @return bool True on success
     */
    public function createRestorationINI()
    {
        // Get a password
        $password = $this->getRandomString(64);

        $this->setState('update_password', $password);

        // Get the absolute path to site's root
        $siteroot = JPATH_SITE;
        $siteroot = str_replace('\\', '/', $siteroot);

        $jreg    = JFactory::getConfig();
        $tempdir = dirname(__FILE__).'/tmp';
        $file    = dirname(__FILE__).'/tmp/myjoomla-upgradefile.zip';

        $data = "<?php\ndefined('_AKEEBA_RESTORATION') or die();\n";
        $data .= '$restoration_setup = array('."\n";

        $ftpOptions = $this->getFTPOptions();
        $engine     = $ftpOptions['enable'] ? 'hybrid' : 'direct';

        $data .= <<<ENDDATA
    'kickstart.security.password' => '$password',
    'kickstart.tuning.max_exec_time' => '5',
    'kickstart.tuning.run_time_bias' => '75',
    'kickstart.tuning.min_exec_time' => '0',
    'kickstart.procengine' => '$engine',
    'kickstart.setup.sourcefile' => '{$tempdir}/myjoomla-upgradefile.zip',
    'kickstart.setup.destdir' => '$siteroot',
    'kickstart.setup.restoreperms' => '0',
    'kickstart.setup.filetype' => 'zip',
    'kickstart.setup.dryrun' => '0'
ENDDATA;

        if ($ftpOptions['enable']) {
            // Get an instance of the FTP client
            JLoader::import('joomla.client.ftp');

            if (version_compare(JVERSION, '3.0', 'ge')) {
                $ftp = JClientFTP::getInstance(
                    $ftpOptions['host'], $ftpOptions['port'], array('type' => FTP_BINARY),
                    $ftpOptions['user'], $ftpOptions['pass']
                );
            } else {
                $ftp = JFTP::getInstance(
                    $ftpOptions['host'], $ftpOptions['port'], array('type' => FTP_BINARY),
                    $ftpOptions['user'], $ftpOptions['pass']
                );
            }

            // Is the tempdir really writable?
            $writable = @is_writeable($tempdir);

            if ($writable) {
                // Let's be REALLY sure
                $fp = @fopen($tempdir.'/test.txt', 'w');
                if (false === $fp) {
                    $writable = false;
                } else {
                    fclose($fp);
                    unlink($tempdir.'/test.txt');
                }
            }

            // If the tempdir is not writable, create a new writable subdirectory
            if (!$writable) {
                JLoader::import('joomla.filesystem.folder');

                $dest = JPath::clean(str_replace(JPATH_ROOT, $ftpOptions['root'], $tempdir.'/cmsupdate'), '/');

                if (!@mkdir($tempdir.'/cmsupdate')) {
                    $ftp->mkdir($dest);
                }

                if (!@chmod($tempdir.'/cmsupdate', 511)) {
                    $ftp->chmod($dest, 511);
                }

                $tempdir .= '/cmsupdate';
            }

            // Just in case the temp-directory was off-root, try using the default tmp directory
            $writable = @is_writeable($tempdir);

            if (!$writable) {
                $tempdir = JPATH_ROOT.'/tmp';

                // Does the JPATH_ROOT/tmp directory exist?
                if (!is_dir($tempdir)) {
                    JLoader::import('joomla.filesystem.file');
                    JFolder::create($tempdir, 511);

                    $htAccessContents = "order deny,allow\ndeny from all\nallow from none\n";
                    JFile::write($tempdir.'/.htaccess', $htAccessContents);
                }

                // If it exists and it is unwritable, try creating a writable cmsupdate subdirectory
                if (!is_writable($tempdir)) {
                    JLoader::import('joomla.filesystem.folder');

                    $dest = JPath::clean(str_replace(JPATH_ROOT, $ftpOptions['root'], $tempdir.'/cmsupdate'), '/');
                    if (!@mkdir($tempdir.'/cmsupdate')) {
                        $ftp->mkdir($dest);
                    }
                    if (!@chmod($tempdir.'/cmsupdate', 511)) {
                        $ftp->chmod($dest, 511);
                    }

                    $tempdir .= '/cmsupdate';
                }
            }

            // If we still have no writable directory, we'll try /tmp and the system's temp-directory
            $writable = @is_writeable($tempdir);

            if (!$writable) {
                if (@is_dir('/tmp') && @is_writable('/tmp')) {
                    $tempdir = '/tmp';
                } else {
                    // Try to find the system temp path
                    $tmpfile = @tempnam('dummy', '');
                    $systemp = @dirname($tmpfile);
                    @unlink($tmpfile);

                    if (!empty($systemp)) {
                        if (@is_dir($systemp) && @is_writable($systemp)) {
                            $tempdir = $systemp;
                        }
                    }
                }
            }

            $data .= <<<ENDDATA
    ,
    'kickstart.ftp.ssl' => '0',
    'kickstart.ftp.passive' => '1',
    'kickstart.ftp.host' => '{$ftpOptions['host']}',
    'kickstart.ftp.port' => '{$ftpOptions['port']}',
    'kickstart.ftp.user' => '{$ftpOptions['user']}',
    'kickstart.ftp.pass' => '{$ftpOptions['pass']}',
    'kickstart.ftp.dir' => '{$ftpOptions['root']}',
    'kickstart.ftp.tempdir' => '$tempdir'
ENDDATA;
        }

        $data .= ');';

        // Remove the old file, if it's there...
        JLoader::import('joomla.filesystem.file');

        $componentPaths          = array();
        $componentPaths['admin'] = dirname(__FILE__).'/tmp';

        $configpath = $componentPaths['admin'].'/restoration.php';

        if (file_exists($configpath)) {
            if (!@unlink($configpath)) {
                JFile::delete($configpath);
            }
        }

        // Write the new file. First try directly.
        if (function_exists('file_put_contents')) {
            $result = @file_put_contents($configpath, $data);
            if (false !== $result) {
                $result = true;
            }
        } else {
            $fp = @fopen($configpath, 'wt');
            if (false !== $fp) {
                $result = @fwrite($fp, $data);
                if (false !== $result) {
                    $result = true;
                }
                @fclose($fp);
            }
        }

        if (false === $result) {
            $result = JFile::write($configpath, $data);
        }

        return $password;
    }

    /**
     * Create a (semi-)random string.
     *
     * @param int    $l Length of the random string, default 32 characters
     * @param string $c Character set to pick characters from
     *
     * @return string Your random string
     */
    protected function getRandomString($l = 32, $c = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890')
    {
        for ($s = '', $cl = strlen($c) - 1, $i = 0; $i < $l; $s .= $c[mt_rand(0, $cl)], ++$i) {
        }

        return $s;
    }

    /**
     * Confuse FOF integration.
     *
     * @return bool
     */
    protected function setState()
    {
        return true;
    }

    /**
     * Returns an array with the configured FTP options.
     *
     * @return array
     */
    public function getFTPOptions()
    {
        // Initialise from Joomla! Global Configuration
        $config   = JFactory::getConfig();
        $retArray = array(
            'enable'  => $config->get('ftp_enable', 0),
            'host'    => $config->get('ftp_host', 'localhost'),
            'port'    => $config->get('ftp_port', '21'),
            'user'    => $config->get('ftp_user', ''),
            'pass'    => $config->get('ftp_pass', ''),
            'root'    => $config->get('ftp_root', ''),
            'tempdir' => $config->get('tmp_path', ''),
        );

        // Get the username and password from the state variables, if it exists
        $stateUser = ''; //$this->getState('user', '', 'raw');
        $statePass = ''; //$this->getState('pass', '', 'raw');

        if (!empty($stateUser)) {
            $retArray['user'] = $stateUser;
        }

        if (!empty($statePass)) {
            $retArray['pass'] = $statePass;
        }

        // Apply the FTP credentials to Joomla! itself
        JLoader::import('joomla.client.helper');
        JClientHelper::setCredentials('ftp', $retArray['user'], $retArray['pass']);

        return $retArray;
    }

    /**
     * Purges the Joomla! update cache. We ARE NOT using this cache, but the CMS
     * does. We want to bust the cache to provent Joomla! from reporting updates
     * after we install an update through our component.
     *
     * @return bool True on success
     */
    public function purgeJoomlaUpdateCache()
    {
        bfLog::log('running purgeJoomlaUpdateCache');

        $db = JFactory::getDbo();

        // Modify the database record
        $update_site                       = new stdClass();
        $update_site->last_check_timestamp = 0;
        $update_site->enabled              = 1;
        $update_site->update_site_id       = 1;
        $db->updateObject('#__update_sites', $update_site, 'update_site_id');

        $query = $db->getQuery(true)
            ->delete($db->quoteName('#__updates'))
            ->where($db->quoteName('update_site_id').' = '.$db->quote('1'));
        $db->setQuery($query);

        if (method_exists($db, 'execute')) {
            if ($db->execute()) {
                return true;
            } else {
                return false;
            }
        } else {
            if ($db->query()) {
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * Make sure the db schema is updated - even Akeeba doesnt do this :-).
     */
    public function finishup()
    {
        require 'bfInitJoomla.php';
        jimport('joomla.filesystem.file');
        jimport('joomla.filesystem.folder');

        // Because of the crappy Joomla early days of updates in 3.1.0
        $sql = "CREATE TABLE IF NOT EXISTS `#__content_types` (
                  `type_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
                  `type_title` varchar(255) NOT NULL DEFAULT '',
                  `type_alias` varchar(255) NOT NULL DEFAULT '',
                  `table` varchar(255) NOT NULL DEFAULT '',
                  `rules` text NOT NULL,
                   `field_mappings` text NOT NULL,
                   `router` varchar(255) NOT NULL  DEFAULT '',
                  PRIMARY KEY (`type_id`),
                  KEY `idx_alias` (`type_alias`)
                ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=10000;";
        $db = JFactory::getDbo();
        $db->setQuery($sql);

        if (method_exists($db, 'execute')) {
            $db->execute();
        } else {
            $db->query();
        }

        if (file_exists(JPATH_ROOT.'/administrator/components/com_joomlaupdate/models/default.php')) {
            require_once JPATH_ROOT.'/administrator/components/com_joomlaupdate/models/default.php';
            $model = new JoomlaupdateModelDefault();
            if (method_exists($model, 'finaliseUpgrade')) {
                $model->finaliseUpgrade();
            }
        } else {
            // Let Joomla handle the grunt work
            $filePath = JPATH_ROOT.'/administrator/components/com_admin/script.php';
            if (file_exists($filePath)) {
                require_once $filePath;

                $o = new JoomlaInstallerScript();
                if (method_exists($o, 'preflight')) {
                    $o->preflight('update', null);
                }

                if (method_exists($o, 'update')) {
                    $o->update(null);
                }

                // need to upgrade db as well.
                require_once JPATH_ROOT.'/administrator/components/com_installer/models/database.php';
                $model = new InstallerModelDatabase();
                $model->fix();
            }
        }
        @unlink(dirname(__FILE__).'/tmp/myjoomla-upgradefile.zip');
        @unlink(dirname(__FILE__).'/tmp/restoration.php');

        bfEncrypt::reply('success', array(
            'msg' => json_encode(true),
        ));
    }

    /**
     * Returns the (cached) list of updates for every section: installed version, current
     * branch updates, sts/lts updates, testing updates.
     *
     * @param bool $force Should I forcibly reload the update information, refreshing the cache?
     *
     * @return array|null The updates array, null if crap hits the fan
     */
    public function getAllUpdates($force = false)
    {
        // This works for Joomla 3.5.0 //////
        if (file_exists(JPATH_ADMINISTRATOR.'/components/com_joomlaupdate/models/default.php')) {
            require JPATH_ADMINISTRATOR.'/components/com_joomlaupdate/models/default.php';
            $model = new JoomlaupdateModelDefault();
            $model->applyUpdateSite();
            $model->refreshUpdates(true);
            $info = $model->getUpdateInformation();

            $updateInfo                = array();
            $updateInfo['downloadurl'] = $info['object']->downloadurl->_data;
            $updateInfo['php_minimum'] = $info['object']->php_minimum->_data;
            $updateInfo['infourl']     = $info['object']->get('infourl')->_data;
            $updateInfo['version']     = $info['latest'];
            $updateInfo['installed']   = $info['installed'];
        // END This works for Joomla 3.5.0 //////
        } else {
            // This works for Joomla 2.5.0 //////
            require JPATH_ADMINISTRATOR.'/components/com_installer/models/update.php';
            jimport('joomla.application.component.helper');

            $updater = JUpdater::getInstance();
            $updater->findUpdates(700, 60);

            $mdl                = new InstallerModelUpdate();
            $JUpdaterupdateInfo = $mdl->getItems();

            $update   = new JUpdate();
            $instance = JTable::getInstance('update');
            $instance->load($JUpdaterupdateInfo[0]->update_id);
            $update->loadFromXML($instance->detailsurl);
            $updateInfo['version']     = $JUpdaterupdateInfo[0]->version;
            $updateInfo['installed']   = JVERSION;
            $updateInfo['infourl']     = $update->get('infourl')->_data;
            $updateInfo['downloadurl'] = $update->get('downloadurl')->_data;
            // END This works for Joomla 2.5.0 //////
        }

        if ($this->hasAkeebaBackup()) {
            $db    = JFactory::getDbo();
            $query = $db->getQuery(true)
                ->select('MAX(id)')
                ->from('#__ak_stats')
                ->where('`origin` != "restorepoint"');
            $db->setQuery($query);
            $lastBackup = $db->loadResult();

            if ($lastBackup > 0) {
                $query = 'SELECT *
                            FROM
                                #__ak_stats
                            WHERE
                                tag <> "restorepoint"
                            ORDER BY `backupstart` DESC LIMIT 1 ';

                $db->setQuery($query);
                $lastBackup = $db->loadObjectList();
            }
        } else {
            $lastBackup = '';
        }

        $data = array($updateInfo,
            'Currently_Installed_Version' => JVERSION,
            'PHP_VERSION'                 => PHP_VERSION,
            'hasAkeebaBackup'             => $this->hasAkeebaBackup(),
            'lastBackupDetails'           => $lastBackup, );

        bfEncrypt::reply('success', array(
            'msg' => json_encode($data),
        ));
    }

    /**
     * Checks if the site has Akeeba Backup 3.1 or later installed.
     *
     * @return bool True if Akeeba Backup is installed and enabled
     */
    public function hasAkeebaBackup()
    {
        // Is the component installed, at all?
        JLoader::import('joomla.filesystem.folder');

        if (!JFolder::exists(JPATH_ADMINISTRATOR.'/components/com_akeeba')) {
            return false;
        }

        // Make sure the component is enabled
        JLoader::import('cms.component.helper');
        $component = JComponentHelper::getComponent('com_akeeba', true);

        if (!$component->enabled) {
            return false;
        }

        return true;
    }
}

// init this class
$upgradeController = new bfUpgrade($dataObj);

$upgradeController->run();
PK��#]�����1system/bfnetwork/bfnetwork/bfUpgradeConnector.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

define('_BF_IN_UPGRADE', 1);

try {
    require 'bfEncrypt.php';

    /*
     * If we have got here then we have already passed through decrypting
     * the encrypted header and so we are sure we are now secure and no one
     * else cannot run the code below.
     */

    // need Zip to decompress
    if (!class_exists('Bf_Zip')) {
        require 'bfZip.php';
    }

    // attempt to ensure our folder is writable
    if (!is_writeable('.')) {
        @chmod('.', 0755);
    }

    /*
     * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
     * We tried 755 and that never worked so we are forced into this :-(
     */
    if (!is_writeable('.')) {
        @chmod('.', 0777);
    }

    // Give Up!
    if (!is_writeable('.')) {
        throw new Exception('bfNetwork Folder not writeable');
    }

    // check file is from myJoomla.com for security

    // Allow for local development with a local endpoint
    switch ($_POST['APPLICATION_ENV']) { // Switch from insecure $_POST to a known clean value locally
        case'development':
        case 'local':
            // Never used on public servers
            $upgradeFile = 'https://local-maintain.myjoomla.com/public/connector';
            break;
        case 'staging':
            // staging Mode Endpoint - by invitation only - email phil@phil-taylor.com for early access!
            $upgradeFile = 'https://staging.myjoomla.com/public/connector';
            break;
        default:
            // Production Mode Endpoint... ...
            $upgradeFile = 'https://cdn.myjoomla.com/public/connector';
            break;
    }

    $method = 'F';
    // Attempt to download using file_get_contents - quickest and easiest and works well on *most* servers!!
    $upgradeFileContent = file_get_contents($upgradeFile);

    if (!$upgradeFileContent) {
        $method = 'C';

        $ch = curl_init();

        // Set up bare minimum CURL Options needed for myJoomla.com
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_URL, $upgradeFile);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to TRUE
        $upgradeFileContent = curl_exec($ch);

        // Did we succeed in getting something?????
        if (!$upgradeFileContent) {
            $method = 'CV';
            /*
             * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
             *
             * Ok try without validation of the SSL (gulp) but this is needed on some servers without a pem file
             * and we need to be compatible as possible - even on crappy webhosts when they need us most ;-(
             */
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

            //  Second Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to FALSE (gulp)
            $upgradeFileContent = curl_exec($ch);
        }

        curl_close($ch);
    }

    // Did we succeed in getting something?
    if (!$upgradeFileContent) {
        throw new Exception('Could not download connector upgrade file using file_get_contents or curl functions - contact Phil for support');
    }

    // Remember: The upgrade file DOESN'T contain any security keys! This is a good thing!

    // Save the Zip File - first removing any existing file
    @unlink('upgrade.zip');
    if (!file_put_contents('upgrade.zip', $upgradeFileContent)) {
        throw new Exception('Could not auto upgrade (save upgrade file failed) - you need to install a new connector manually (Debug: '.$method.'|'.is_writable('.').'|'.file_exists('upgrade.zip').'|'.strlen($upgradeFileContent).')');
    }

    // Load the Zip file
    $zip = new Bf_Zip('upgrade.zip');

    // Extract the Zip file
    if (!$zip->extract(PCLZIP_OPT_PATH, './', PCLZIP_OPT_REMOVE_PATH, 'bfnetwork', PCLZIP_OPT_REPLACE_NEWER)) {
        throw new Exception('Could not auto upgrade (Extract Error) - you need to install a new connector manually');
    }

    // .. @todo check each file is valid against some kind of hash to prevent modifications client side

    // cleanup old files
    $oldFiles = array(
        'upgrade.zip',
        './bfViewLog.php',
        './bfDev.php',
        './bfDb.php',
        './bfMysql.php',
        './j25_30_bfnetwork.xml', // dont get confused with the one in the folder above this.
        './install.bfnetwork.php',
        './bfnetwork.xml',
        './bfJson.php',
        './tmp/log.tmp',
        './tmp/tmp.ob',
    );

    foreach ($oldFiles as $file) {
        if (file_exists($file)) {
            @unlink($file);
        }
    }

    // cleanup
    if (file_exists('../j25_30_bfnetwork.xml')) {
        @copy('../j25_30_bfnetwork.xml', '../bfnetwork.xml');
        @unlink('../j25_30_bfnetwork.xml');
    }

    // Reply with a great big high five!
    bfEncrypt::reply(bfReply::SUCCESS, array(
        'version' => file_get_contents('VERSION'),
    ));
} catch (Exception $e) {
    bfEncrypt::reply(bfReply::ERROR, 'EXCEPTION: '.$e->getMessage());
}
PK��#]m���O O ,system/bfnetwork/bfnetwork/bfActivitylog.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require_once 'bfPreferences.php';

class bfActivitylog
{
    /**
     * @var
     */
    protected static $instance;

    /**
     * @var
     */
    private $db;

    /**
     * @var string
     */
    private $table_create = 'CREATE TABLE IF NOT EXISTS `bf_activitylog` (
                              `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
                              `who` varchar(255) DEFAULT NULL,
                              `who_id` int(11) DEFAULT NULL,
                              `what` varchar(255) DEFAULT NULL,
                              `when` datetime DEFAULT NULL,
                              `where` varchar(255) DEFAULT NULL,
                              `where_id` int(11) DEFAULT NULL,
                              `ip` varchar(20) DEFAULT NULL,
                              `useragent` varchar(255) DEFAULT NULL,
                              `meta` text,
                              `action` varchar(255) DEFAULT NULL,
                              PRIMARY KEY (`id`),
                              KEY `who` (`who`),
                              KEY `who_id` (`who_id`),
                              KEY `when` (`when`)
                            ) DEFAULT CHARSET=utf8';

    private $table_insert = 'INSERT INTO `bf_activitylog`
                              (`id`, `who`, `who_id`, `what`, `when`, `where`, `where_id`, `ip`, `useragent`, `meta`,`action`) 
                              VALUES 
                             (NULL, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)';

    /**
     * @var mixed|stdClass
     */
    private $prefs;

    /**
     * bfActivitylog constructor.
     */
    public function __construct()
    {
        $preferences = new bfPreferences();
        $this->prefs = $preferences->getPreferences();
        $this->db    = JFactory::getDBO();
        $this->ensureTableCreated();
    }

    public function ensureTableCreated()
    {
        $this->db->setQuery($this->table_create);
        if (method_exists($this->db, 'query')) {
            $this->db->query();
        } else {
            $this->db->execute();
        }
    }

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

        return self::$instance;
    }

    /**
     * If we get here we are "inside" the Joomla Application API and so all Joomla functions available.
     *
     * @param string $who
     * @param int    $who_id
     * @param string $what
     * @param string $where
     * @param int    $where_id
     * @param null   $ip
     * @param null   $userAgent
     *
     * @since version
     */
    public function log($who = 'not me!', $who_id = 0, $what = 'dunno', $where = 'er?', $where_id = 0, $ip = null, $userAgent = null, $meta = '{}', $action = '', $alertName = '')
    {
        $when = JFactory::getDate()->format('Y-m-d H:i:s', true);

        if (null == $ip) {
            $ip = str_replace('::ffff:', '', (@getenv('HTTP_X_FORWARDED_FOR') ? @getenv('HTTP_X_FORWARDED_FOR') : @$_SERVER['REMOTE_ADDR']));
        }
        if ('system' == $ip) {
            $ip = '';
        }

        $sql = sprintf($this->table_insert,
            $this->db->quote($who),
            $this->db->quote($who_id),
            $this->db->quote($what),
            $this->db->quote($when),
            $this->db->quote($where),
            $this->db->quote($where_id),
            $this->db->quote($ip),
            $this->db->quote(null),
            $this->db->quote($meta),
            $this->db->quote($action)
        );

        $this->db->setQuery($sql);
        if (method_exists($this->db, 'execute')) {
            $this->db->execute();
        } else {
            $this->db->query();
        }

        if (property_exists($this->prefs, $alertName) && $this->prefs->$alertName == 1) {
            $this->sendLogAlert($who, $who_id, $what, $when, $where, $where_id, $ip, $userAgent, $meta, $action, $alertName);
        }
    }

    /**
     * @param string $who
     * @param int    $who_id
     * @param string $what
     * @param        $when
     * @param string $where
     * @param int    $where_id
     * @param null   $ip
     * @param null   $userAgent
     * @param string $meta
     * @param string $action
     * @param string $alertName
     *
     * @return string|void
     */
    public function sendLogAlert($who = 'not me!', $who_id = 0, $what = 'dunno', $when, $where = 'er?', $where_id = 0, $ip = null, $userAgent = null, $meta = '{}', $action = '', $alertName = '')
    {
        $host_id = $this->getHostID();

        if (!$host_id) {
            return;
        }

        $postdata = http_build_query(
            array(
                'HOST_ID'    => $host_id,
                'who'        => $who,
                'who_id'     => $who_id,
                'what'       => $what,
                'what'       => $what,
                'when'       => $when,
                'where'      => $where,
                'where_id'   => $where_id,
                'ip'         => $ip,
                'userAgent'  => $userAgent,
                'meta'       => $meta,
                'action'     => $action,
                'alert_name' => $alertName,
            )
        );

        $opts = array('http' => array(
                              'content'       => $postdata,
                              'method'        => 'POST',
                              'user_agent'    => JURI::base(),
                              'max_redirects' => 1,
                              'header'        => 'Content-type: application/x-www-form-urlencoded',
                              'proxy'         => ('local' == getenv('APPLICATION_ENV') ? 'tcp://127.0.0.1:8888' : ''),
                              'timeout'       => 5, //so we don't destroy live sites if the service is offline
                          ),
        );

        if ('local' == getenv('APPLICATION_ENV')) {
            $opts = array_merge($opts, array(
                    'ssl' => array(
                        'verify_peer'      => false,
                        'verify_peer_name' => false,
                    ), )
            );

            return @file_get_contents('https://local-maintain.myjoomla.com/api/log', false, stream_context_create($opts));
        } else {
            // Using @ so we don't destroy live sites if the service is offline
            return @file_get_contents('https://manage.myjoomla.com/api/log', false, stream_context_create($opts));
        }
    }

    /**
     * @return string
     */
    public function getHostID()
    {
        $files = array(
            str_replace('/administrator', '', JPATH_BASE.'/plugins/system/bfnetwork/HOST_ID'),         //Joomla 1.5 gulp
            str_replace('/administrator', '', JPATH_BASE.'/plugins/system/bfnetwork/bfnetwork/HOST_ID'), //Joomla 2+
        );

        foreach ($files as $file) {
            if (file_exists($file)) {
                return file_get_contents($file);
            }
        }
    }
}
PK��#]!ȩn��5system/bfnetwork/bfnetwork/bfPHPFiveThreePlusOnly.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * This file contains code that can only be run on PHP 5.3.0+ servers.
 *
 * As myJoomla.com service has to support PHP 5.2 for idiot servers with crappy
 * webhosting the main connector needs to be fully PHP 5.2 compliant most of the time
 *
 * The following code will ONLY run with a decent PHP version.
 */
final class bfPHPFiveThreePlusOnly
{
    public function getAkeebaConfig($configConfiguration)
    {
        $key = Akeeba\Engine\Factory::getSecureSettings()->getKey();

        return Akeeba\Engine\Factory::getSecureSettings()->decryptSettings($configConfiguration, $key);
    }
}
PK��#]�A�%system/bfnetwork/bfnetwork/bfPref.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require 'bfEncrypt.php';

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */
$preferences = new bfPreferences($dataObj);

$preferences->run($dataObj->preferencesaction);

bfEncrypt::reply(bfReply::SUCCESS, $preferences->getPreferences());
PK��#]�C��=
=
*system/bfnetwork/bfnetwork/bfAutologin.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require 'bfEncrypt.php';

/*
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */

// Pretend we are /administrator/index.php
define('_JEXEC', 1);

// Joomla 2.5.0 an onwards - auto login for Joomla 1.5 sites not a feature of myJoomla.com
define('JPATH_BASE', realpath(__DIR__.'/../../../../administrator/'));

require_once JPATH_BASE.'/includes/defines.php';
require_once JPATH_BASE.'/includes/framework.php';

// Load the application, instantiate things
$app = JFactory::getApplication('administrator');

// Load Joomla 2.5 dependances
if (function_exists('jimport')) {
    jimport('joomla.user.authentication');
}

// Load more dependances to instantiate them
JAuthentication::getInstance();

// Load Joomla 2.5 dependances
if (class_exists('JPluginHelper')) {
    JPluginHelper::importPlugin('user');
}

// Populate the \Joomla\CMS\User\User user object with user data
$user = JFactory::getUser();
$user->load((int) $dataObj->id);

$subfolderIfAny = null;

if (is_array($_SERVER) && array_key_exists('REQUEST_URI', $_SERVER)) {
    $subfolderIfAny = str_replace('/plugins/system/bfnetwork/bfnetwork/bfAutologin.php', '', $_SERVER['REQUEST_URI']);
}

// Load the required user from the database - Bail out if that user doesnt exist
if (!$user->id) {
    header('Location: '.$subfolderIfAny.'/');
    die;
}

// Construct a faked response-object
$response = new JAuthenticationResponse();

$response->type          = 'Joomla'; // ?
$response->email         = $user->email;
$response->fullname      = $user->name;
$response->username      = $user->username;
$response->password      = 'Not Actually Needed';
$response->language      = $user->getParam('language'); // Not tested
$response->status        = JAuthentication::STATUS_SUCCESS; // Woot Woot!
$response->error_message = null; // to be sure

// Pass control to plugins to do the actual login
$app->triggerEvent('onUserLogin', array((array) $response, array('action' => 'core.login.admin')));

// redirect to allow user access
header('Location: '.$subfolderIfAny.'/administrator/index.php?'.$dataObj->adminUrlAppend);
PK��#]T�;(system/bfnetwork/bfnetwork/bfUpdates.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */
final class bfUpdates
{
    /**
     * @param bool $returnCount
     * @param int  $dontEnableUpdateSites
     *
     * @return bool|int|string
     */
    public function getUpdates($returnCount = false, $dontEnableUpdateSites = 0)
    {
        if (
            // If Joomla 1.5 - No concept of updates
            !file_exists(JPATH_LIBRARIES.'/joomla/updater/updater.php')
            &&
            // Joomla 3.8.0 Moved the file to this location
            !file_exists(JPATH_LIBRARIES.'/src/Updater/Updater.php')
        ) {
            return false;
        }

        // Joomla 1.7.x has to be a pain in the arse!
        if (!class_exists('JUpdater')) {
            require JPATH_LIBRARIES.'/joomla/updater/updater.php';
        }

        // clear cache and enable disabled sites again
        $db = JFactory::getDbo();
        if (1 === $dontEnableUpdateSites) {
            $db->setQuery('update #__update_sites SET last_check_timestamp = 0');
        } else {
            $db->setQuery('update #__update_sites SET last_check_timestamp = 0, enabled = 1');
        }

        $db->query();
        $db->setQuery('TRUNCATE #__updates');
        $db->query();

        // Let Joomla to the caching of the latest version of updates available from vendors
        $updater = JUpdater::getInstance();
        $updater->findUpdates();

        // get the resultant list of updates available
        $db->setQuery('SELECT * from #__updates');
        $updates = $db->LoadObjectList();

        // reformat into a useable array with the extension_id as the array key
        $extensionUpdatesAvailable = array();
        foreach ($updates as $update) {
            $extensionUpdatesAvailable[$update->extension_id] = $update;
        }

        // get all the installed extensions from the site
        $db->setQuery('SELECT * from #__extensions');
        $items = $db->LoadObjectList();

        // init what we will return, a neat and tidy array
        $updatesAvailable = array();

        // for all installed items...
        foreach ($items as $item) {
            // merge by inject all known info into this item
            if (!array_key_exists($item->extension_id, $extensionUpdatesAvailable)) {
                continue;
            }

            foreach ($extensionUpdatesAvailable[$item->extension_id] as $k => $v) {
                $item->$k = $v;
            }

            // Crappy Joomla
            $item->current_version = array_key_exists(@$item->extension_id, @$extensionUpdatesAvailable) ? @$extensionUpdatesAvailable[@$item->extension_id]->version : @$item->version;

            // if there is a newer version we want that!
            if (null !== $item->current_version) {
                // compose a nice new class, doesnt matter as we are json_encoding later anyway
                $i                  = new stdClass();
                $i->name            = $item->name;
                $i->eid             = $item->extension_id;
                $i->current_version = $item->current_version;
                $i->infourl         = $item->infourl;

                // inject to our array we will return
                $updatesAvailable[] = $i;
            }
        }

        // Harvest update sites for better features in the future
        $db->setQuery('SELECT * from #__update_sites');
        $updateSites = $db->LoadObjectList();

        // if we are in bfAuditor then we want just a count of the items or the actual items?
        if (false === $returnCount) {
            $data            = array();
            $data['updates'] = $updatesAvailable;
            $data['sites']   = json_encode($updateSites);

            return $data;
        } else {
            return count($updatesAvailable);
        }
    }
}
PK��#]�ph��'system/bfnetwork/bfnetwork/bfBackup.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

require 'bfEncrypt.php';

/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.
 */
final class bfBackup
{
    /**
     * We pass the command to run as a simple integer in our encrypted
     * request this is mainly to speed up the decryption process, plus its a
     * single digit(or 2) rather than a huge string to remember :-).
     */
    private $_methods = array(
        1 => 'enableAkeebaFrontendBackup',
    );

    /**
     * Pointer to the Joomla Database Object.
     *
     * @var JDatabaseMysql
     */
    private $_db;

    /**
     * Incoming decrypted vars from the request.
     *
     * @var stdClass
     */
    private $_dataObj;

    /**
     * PHP 5 Constructor,
     * I inject the request to the object.
     *
     * @param stdClass $dataObj
     */
    public function __construct($dataObj)
    {
        // init Joomla
        require 'bfInitJoomla.php';

        // Set the request vars
        $this->_dataObj = $dataObj;
    }

    /**
     * I'm the controller - I run methods based on the request integer.
     */
    public function run()
    {
        if (property_exists($this->_dataObj, 'c')) {
            $c = (int) $this->_dataObj->c;
            if (array_key_exists($c, $this->_methods)) {
                // call the right method
                $this->{$this->_methods[$c]} ();
            } else {
                // Die if an unknown function
                bfEncrypt::reply('error', 'No Such method #err1 - '.$c);
            }
        } else {
            // Die if an unknown function
            bfEncrypt::reply('error', 'No Such method #err2');
        }
    }

    /**
     * If not enabled, then enable the Akeeba API Frontend using a secure secret word.
     */
    private function enableAkeebaFrontendBackup()
    {
        // load mini-Joomla
        require 'bfInitJoomla.php';

        $this->_db = JFactory::getDBO();

        // Get some Joomla version
        $VERSION = new JVersion();

        switch ($VERSION->RELEASE) {
            case '1.5':

                $params = JComponentHelper::getParams('com_akeeba');
                if (!count($params->toArray())) {
                    // send back the totals
                    bfEncrypt::reply('success', array(
                        'akeeba_installed' => false,
                    ));
                }

                $frontend_enable      = $params->get('frontend_enable');
                $frontend_secret_word = $params->get('frontend_secret_word');

                if (1 != $frontend_enable) {
                    $params->set('frontend_enable', 1);
                    $saveChanges = true;
                }

                // Get a complex unique non-crypto string from myJoomla.com
                $string = file_get_contents('https://manage.myjoomla.com/public/rand?'.time());

                $params->set('frontend_secret_word', $string);
                $saveChanges = true;

                $secretWord = $params->get('frontend_secret_word');

                if (true == $saveChanges) {
                    $params = $params->toString();
                    $sql    = 'UPDATE #__components SET params = \'%s\' WHERE `OPTION` = "com_akeeba"';
                    $sql    = sprintf($sql, addslashes($params));
                    $this->_db->setQuery($sql);
                    $this->_db->query();
                }
                break;
            default:
            case '2.5':

                $this->_db->setQuery('SELECT extension_id, params FROM #__extensions WHERE NAME="akeeba" AND element = "com_akeeba"');
                $data = $this->_db->loadObject();

                if (!$data) {
                    // send back the totals
                    bfEncrypt::reply('success', array(
                        'akeeba_installed' => false,
                    ));
                }

                $params = json_decode($data->params);

                if (!$params) {
                    bfEncrypt::reply('success', array(
                        'akeeba_installed' => false,
                    ));
                }

                // is it encrypted? Akeeba 5.5.2 onwards
                if (file_exists(JPATH_ADMINISTRATOR.'/components/com_akeeba/BackupEngine/Util/SecureSettings.php')) {
                    /*
                     * As Akeeba provides no API for enabling front end feature we have to fudge it
                     * This is done seamlessly as to allow easy integration rather than getting a user
                     * to copy and paste his secret string.
                     */

                    define('AKEEBAENGINE', 1);

                    require JPATH_BASE.'/libraries/fof30/Autoloader/Autoloader.php';
                    require JPATH_ADMINISTRATOR.'/components/com_akeeba/BackupEngine/Autoloader.php';

                    \Akeeba\Engine\Platform::addPlatform('joomla3x', JPATH_ADMINISTRATOR.'/components/com_akeeba/BackupPlatform/Joomla3x');

                    $secretWord                   = (new \Akeeba\Engine\Util\RandomValue())->generateString(32);
                    $params->frontend_secret_word = (new \Akeeba\Engine\Util\SecureSettings())->encryptSettings($secretWord);
                } else {
                    if (!$params->frontend_secret_word || preg_match('/\&/', $params->frontend_secret_word)) {
                        // Get a complex unique non-crypto string from myJoomla.com
                        $string                       = file_get_contents('https://manage.myjoomla.com/public/rand?'.time());
                        $params->frontend_secret_word = $string;
                        $secretWord                   = $params->frontend_secret_word;
                    }
                }

                $params->frontend_enable = 1;
                $params                  = json_encode($params);

                $sql = 'UPDATE #__extensions SET params = \'%s\' WHERE extension_id = %s';
                $sql = sprintf($sql, addslashes($params), $data->extension_id);
                $this->_db->setQuery($sql);

                if (method_exists($this->_db, 'execute')) {
                    $this->_db->execute();
                } else {
                    $this->_db->query();
                }

                break;
        }

        bfEncrypt::reply('success', array(
            'akeeba_installed' => true,
            'secret'           => $secretWord,
        ));
    }
}

// init this class
$backupController = new bfBackup($dataObj);

// Run the tool method
$backupController->run();
PK��#]��imm(system/bfnetwork/bfnetwork/bfRestore.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */
define('_AKEEBA_RESTORATION', 1);
defined('DS') or define('DS', DIRECTORY_SEPARATOR);

// Unarchiver run states
define('AK_STATE_NOFILE', 0); // File header not read yet
define('AK_STATE_HEADER', 1); // File header read; ready to process data
define('AK_STATE_DATA', 2); // Processing file data
define('AK_STATE_DATAREAD', 3); // Finished processing file data; ready to post-process
define('AK_STATE_POSTPROC', 4); // Post-processing
define('AK_STATE_DONE', 5); // Done with post-processing

/* Windows system detection */
if (!defined('_AKEEBA_IS_WINDOWS')) {
    if (function_exists('php_uname')) {
        define('_AKEEBA_IS_WINDOWS', stristr(php_uname(), 'windows'));
    } else {
        define('_AKEEBA_IS_WINDOWS', DIRECTORY_SEPARATOR == '\\');
    }
}

// Get the file's root
if (!defined('KSROOTDIR')) {
    define('KSROOTDIR', dirname(__FILE__));
}
if (!defined('KSLANGDIR')) {
    define('KSLANGDIR', KSROOTDIR);
}

// Make sure the locale is correct for basename() to work
if (function_exists('setlocale')) {
    @setlocale(LC_ALL, 'en_US.UTF8');
}

// fnmatch not available on non-POSIX systems
// Thanks to soywiz@php.net for this usefull alternative function [http://gr2.php.net/fnmatch]
if (!function_exists('fnmatch')) {
    function fnmatch($pattern, $string)
    {
        return @preg_match(
            '/^'.strtr(addcslashes($pattern, '/\\.+^$(){}=!<>|'),
                array('*' => '.*', '?' => '.?')).'$/i', $string
        );
    }
}

// Unicode-safe binary data length function
if (!function_exists('akstringlen')) {
    if (function_exists('mb_strlen')) {
        function akstringlen($string)
        {
            return mb_strlen($string, '8bit');
        }
    } else {
        function akstringlen($string)
        {
            return strlen($string);
        }
    }
}

/**
 * Gets a query parameter from GET or POST data.
 *
 * @param $key
 * @param $default
 */
function getQueryParam($key, $default = null)
{
    $value = $default;

    if (array_key_exists($key, $_REQUEST)) {
        $value = $_REQUEST[$key];
    }

    if (get_magic_quotes_gpc() && !is_null($value)) {
        $value = stripslashes($value);
    }

    return $value;
}

// Debugging function
function debugMsg($msg)
{
    if (!defined('KSDEBUG')) {
        return;
    }

    $fp = fopen('debug.txt', 'at');

    fwrite($fp, $msg."\n");
    fclose($fp);
}

/*
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 * @package     akeebabackup
 * @subpackage  kickstart
 */

/*
 * Akeeba Backup's JSON compatibility layer
 *
 * On systems where json_encode and json_decode are not available, Akeeba
 * Backup will attempt to use PEAR's Services_JSON library to emulate them.
 * A copy of this library is included in this file and will be used if and
 * only if it isn't already loaded, e.g. due to PEAR's auto-loading, or a
 * 3PD extension loading it for its own purposes.
 */

/*
 * Converts to and from JSON format.
 *
 * JSON (JavaScript Object Notation) is a lightweight data-interchange
 * format. It is easy for humans to read and write. It is easy for machines
 * to parse and generate. It is based on a subset of the JavaScript
 * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
 * This feature can also be found in  Python. JSON is a text format that is
 * completely language independent but uses conventions that are familiar
 * to programmers of the C-family of languages, including C, C++, C#, Java,
 * JavaScript, Perl, TCL, and many others. These properties make JSON an
 * ideal data-interchange language.
 *
 * This package provides a simple encoder and decoder for JSON notation. It
 * is intended for use with client-side Javascript applications that make
 * use of HTTPRequest to perform server communication functions - data can
 * be encoded into JSON notation for use in a client-side javascript, or
 * decoded from incoming Javascript requests. JSON format is native to
 * Javascript, and can be directly eval()'ed with no further parsing
 * overhead
 *
 * All strings should be in ASCII or UTF-8 format!
 *
 * LICENSE: Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met: Redistributions of source code must retain the
 * above copyright notice, this list of conditions and the following
 * disclaimer. Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * @category
 * @package     Services_JSON
 * @author      Michal Migurski <mike-json@teczno.com>
 * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
 * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
 * @copyright   2005 Michal Migurski
 * @version     CVS: $Id: restore.php 612 2011-05-19 08:26:26Z nikosdion $
 * @license     http://www.opensource.org/licenses/bsd-license.php
 * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
 */

if (!defined('JSON_FORCE_OBJECT')) {
    define('JSON_FORCE_OBJECT', 1);
}

if (!defined('SERVICES_JSON_SLICE')) {
    /*
     * Marker constant for Services_JSON::decode(), used to flag stack state
     */
    define('SERVICES_JSON_SLICE', 1);

    /*
     * Marker constant for Services_JSON::decode(), used to flag stack state
     */
    define('SERVICES_JSON_IN_STR', 2);

    /*
     * Marker constant for Services_JSON::decode(), used to flag stack state
     */
    define('SERVICES_JSON_IN_ARR', 3);

    /*
     * Marker constant for Services_JSON::decode(), used to flag stack state
     */
    define('SERVICES_JSON_IN_OBJ', 4);

    /*
     * Marker constant for Services_JSON::decode(), used to flag stack state
     */
    define('SERVICES_JSON_IN_CMT', 5);

    /*
     * Behavior switch for Services_JSON::decode()
     */
    define('SERVICES_JSON_LOOSE_TYPE', 16);

    /*
     * Behavior switch for Services_JSON::decode()
     */
    define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
}

/*
 * Converts to and from JSON format.
 *
 * Brief example of use:
 *
 * <code>
 * // create a new instance of Services_JSON
 * $json = new Services_JSON();
 *
 * // convert a complexe value to JSON notation, and send it to the browser
 * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
 * $output = $json->encode($value);
 *
 * print($output);
 * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
 *
 * // accept incoming POST data, assumed to be in JSON notation
 * $input = file_get_contents('php://input', 1000000);
 * $value = $json->decode($input);
 * </code>
 */
if (!class_exists('Akeeba_Services_JSON')) {
    class Akeeba_Services_JSON
    {
        /**
         * constructs a new JSON instance.
         *
         * @param int $use object behavior flags; combine with boolean-OR
         *
         *                           possible values:
         *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
         *                                   "{...}" syntax creates associative arrays
         *                                   instead of objects in decode().
         *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression.
         *                                   Values which can't be encoded (e.g. resources)
         *                                   appear as NULL instead of throwing errors.
         *                                   By default, a deeply-nested resource will
         *                                   bubble up with an error, so all return values
         *                                   from encode() should be checked with isError()
         */
        public function __construct($use = 0)
        {
            $this->use = $use;
        }

        /**
         * convert a string from one UTF-16 char to one UTF-8 char.
         *
         * Normally should be handled by mb_convert_encoding, but
         * provides a slower PHP-only method for installations
         * that lack the multibye string extension.
         *
         * @param string $utf16 UTF-16 character
         *
         * @return string UTF-8 character
         */
        public function utf162utf8($utf16)
        {
            // oh please oh please oh please oh please oh please
            if (function_exists('mb_convert_encoding')) {
                return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
            }

            $bytes = (ord($utf16[0]) << 8) | ord($utf16[1]);

            switch (true) {
                case (0x7F & $bytes) == $bytes:
                    // this case should never be reached, because we are in ASCII range
                    // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                    return chr(0x7F & $bytes);

                case (0x07FF & $bytes) == $bytes:
                    // return a 2-byte UTF-8 character
                    // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                    return chr(0xC0 | (($bytes >> 6) & 0x1F))
                    .chr(0x80 | ($bytes & 0x3F));

                case (0xFFFF & $bytes) == $bytes:
                    // return a 3-byte UTF-8 character
                    // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                    return chr(0xE0 | (($bytes >> 12) & 0x0F))
                    .chr(0x80 | (($bytes >> 6) & 0x3F))
                    .chr(0x80 | ($bytes & 0x3F));
            }

            // ignoring UTF-32 for now, sorry
            return '';
        }

        /**
         * convert a string from one UTF-8 char to one UTF-16 char.
         *
         * Normally should be handled by mb_convert_encoding, but
         * provides a slower PHP-only method for installations
         * that lack the multibye string extension.
         *
         * @param string $utf8 UTF-8 character
         *
         * @return string UTF-16 character
         */
        public function utf82utf16($utf8)
        {
            // oh please oh please oh please oh please oh please
            if (function_exists('mb_convert_encoding')) {
                return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
            }

            switch (strlen($utf8)) {
                case 1:
                    // this case should never be reached, because we are in ASCII range
                    // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                    return $utf8;

                case 2:
                    // return a UTF-16 character from a 2-byte UTF-8 char
                    // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                    return chr(0x07 & (ord($utf8[0]) >> 2))
                    .chr((0xC0 & (ord($utf8[0]) << 6))
                        | (0x3F & ord($utf8[1])));

                case 3:
                    // return a UTF-16 character from a 3-byte UTF-8 char
                    // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                    return chr((0xF0 & (ord($utf8[0]) << 4))
                        | (0x0F & (ord($utf8[1]) >> 2)))
                    .chr((0xC0 & (ord($utf8[1]) << 6))
                        | (0x7F & ord($utf8[2])));
            }

            // ignoring UTF-32 for now, sorry
            return '';
        }

        /**
         * encodes an arbitrary variable into JSON format.
         *
         * @param mixed $var any number, boolean, string, array, or object to be encoded.
         *                   see argument 1 to Services_JSON() above for array-parsing behavior.
         *                   if var is a strng, note that encode() always expects it
         *                   to be in ASCII or UTF-8 format!
         *
         * @return mixed JSON string representation of input var or an error if a problem occurs
         */
        public function encode($var)
        {
            switch (gettype($var)) {
                case 'boolean':
                    return $var ? 'true' : 'false';

                case 'NULL':
                    return 'null';

                case 'integer':
                    return (int) $var;

                case 'double':
                case 'float':
                    return (float) $var;

                case 'string':
                    // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
                    $ascii      = '';
                    $strlen_var = strlen($var);

                    /*
                    * Iterate over every character in the string,
                    * escaping with a slash or encoding to UTF-8 where necessary
                    */
                    for ($c = 0; $c < $strlen_var; ++$c) {
                        $ord_var_c = ord($var[$c]);

                        switch (true) {
                            case 0x08 == $ord_var_c:
                                $ascii .= '\b';
                                break;
                            case 0x09 == $ord_var_c:
                                $ascii .= '\t';
                                break;
                            case 0x0A == $ord_var_c:
                                $ascii .= '\n';
                                break;
                            case 0x0C == $ord_var_c:
                                $ascii .= '\f';
                                break;
                            case 0x0D == $ord_var_c:
                                $ascii .= '\r';
                                break;

                            case 0x22 == $ord_var_c:
                            case 0x2F == $ord_var_c:
                            case 0x5C == $ord_var_c:
                                // double quote, slash, slosh
                                $ascii .= '\\'.$var[$c];
                                break;

                            case ($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F):
                                // characters U-00000000 - U-0000007F (same as ASCII)
                                $ascii .= $var[$c];
                                break;

                            case 0xC0 == ($ord_var_c & 0xE0):
                                // characters U-00000080 - U-000007FF, mask 110XXXXX
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                $char = pack('C*', $ord_var_c, ord($var[$c + 1]));
                                ++$c;
                                $utf16 = $this->utf82utf16($char);
                                $ascii .= sprintf('\u%04s', bin2hex($utf16));
                                break;

                            case 0xE0 == ($ord_var_c & 0xF0):
                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                $char = pack('C*', $ord_var_c,
                                    ord($var[$c + 1]),
                                    ord($var[$c + 2]));
                                $c += 2;
                                $utf16 = $this->utf82utf16($char);
                                $ascii .= sprintf('\u%04s', bin2hex($utf16));
                                break;

                            case 0xF0 == ($ord_var_c & 0xF8):
                                // characters U-00010000 - U-001FFFFF, mask 11110XXX
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                $char = pack('C*', $ord_var_c,
                                    ord($var[$c + 1]),
                                    ord($var[$c + 2]),
                                    ord($var[$c + 3]));
                                $c += 3;
                                $utf16 = $this->utf82utf16($char);
                                $ascii .= sprintf('\u%04s', bin2hex($utf16));
                                break;

                            case 0xF8 == ($ord_var_c & 0xFC):
                                // characters U-00200000 - U-03FFFFFF, mask 111110XX
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                $char = pack('C*', $ord_var_c,
                                    ord($var[$c + 1]),
                                    ord($var[$c + 2]),
                                    ord($var[$c + 3]),
                                    ord($var[$c + 4]));
                                $c += 4;
                                $utf16 = $this->utf82utf16($char);
                                $ascii .= sprintf('\u%04s', bin2hex($utf16));
                                break;

                            case 0xFC == ($ord_var_c & 0xFE):
                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                $char = pack('C*', $ord_var_c,
                                    ord($var[$c + 1]),
                                    ord($var[$c + 2]),
                                    ord($var[$c + 3]),
                                    ord($var[$c + 4]),
                                    ord($var[$c + 5]));
                                $c += 5;
                                $utf16 = $this->utf82utf16($char);
                                $ascii .= sprintf('\u%04s', bin2hex($utf16));
                                break;
                        }
                    }

                    return '"'.$ascii.'"';

                case 'array':
                    /*
                    * As per JSON spec if any array key is not an integer
                    * we must treat the the whole array as an object. We
                    * also try to catch a sparsely populated associative
                    * array with numeric keys here because some JS engines
                    * will create an array with empty indexes up to
                    * max_index which can cause memory issues and because
                    * the keys, which may be relevant, will be remapped
                    * otherwise.
                    *
                    * As per the ECMA and JSON specification an object may
                    * have any string as a property. Unfortunately due to
                    * a hole in the ECMA specification if the key is a
                    * ECMA reserved word or starts with a digit the
                    * parameter is only accessible using ECMAScript's
                    * bracket notation.
                    */

                    // treat as a JSON object
                    if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
                        $properties = array_map(array($this, 'name_value'),
                            array_keys($var),
                            array_values($var));

                        foreach ($properties as $property) {
                            if (Akeeba_Services_JSON::isError($property)) {
                                return $property;
                            }
                        }

                        return '{'.join(',', $properties).'}';
                    }

                    // treat it like a regular array
                    $elements = array_map(array($this, 'encode'), $var);

                    foreach ($elements as $element) {
                        if (Akeeba_Services_JSON::isError($element)) {
                            return $element;
                        }
                    }

                    return '['.join(',', $elements).']';

                case 'object':
                    $vars = get_object_vars($var);

                    $properties = array_map(array($this, 'name_value'),
                        array_keys($vars),
                        array_values($vars));

                    foreach ($properties as $property) {
                        if (Akeeba_Services_JSON::isError($property)) {
                            return $property;
                        }
                    }

                    return '{'.join(',', $properties).'}';

                default:
                    return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
                        ? 'null'
                        : new Akeeba_Services_JSON_Error(gettype($var).' can not be encoded as JSON string');
            }
        }

        /**
         * array-walking function for use in generating JSON-formatted name-value pairs.
         *
         * @param string $name  name of key to use
         * @param mixed  $value reference to an array element to be encoded
         *
         * @return string JSON-formatted name-value pair, like '"name":value'
         */
        public function name_value($name, $value)
        {
            $encoded_value = $this->encode($value);

            if (Akeeba_Services_JSON::isError($encoded_value)) {
                return $encoded_value;
            }

            return $this->encode(strval($name)).':'.$encoded_value;
        }

        /**
         * reduce a string by removing leading and trailing comments and whitespace.
         *
         * @param $str string      string value to strip of comments and whitespace
         *
         * @return string string value stripped of comments and whitespace
         */
        public function reduce_string($str)
        {
            $str = preg_replace(array(
                // eliminate single line comments in '// ...' form
                '#^\s*//(.+)$#m',
                // eliminate multi-line comments in '/* ... */' form, at start of string
                '#^\s*/\*(.+)\*/#Us',
                // eliminate multi-line comments in '/* ... */' form, at end of string
                '#/\*(.+)\*/\s*$#Us',
            ), '', $str);

            // eliminate extraneous space
            return trim($str);
        }

        /**
         * decodes a JSON string into appropriate variable.
         *
         * @param string $str JSON-formatted string
         *
         * @return mixed number, boolean, string, array, or object
         *               corresponding to given JSON input string.
         *               See argument 1 to Akeeba_Services_JSON() above for object-output behavior.
         *               Note that decode() always returns strings
         *               in ASCII or UTF-8 format!
         */
        public function decode($str)
        {
            $str = $this->reduce_string($str);

            switch (strtolower($str)) {
                case 'true':
                    return true;

                case 'false':
                    return false;

                case 'null':
                    return null;

                default:
                    $m = array();

                    if (is_numeric($str)) {
                        // Lookie-loo, it's a number

                        // This would work on its own, but I'm trying to be
                        // good about returning integers where appropriate:
                        // return (float)$str;

                        // Return float or int, as appropriate
                        return ((float) $str == (int) $str)
                            ? (int) $str
                            : (float) $str;
                    } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
                        // STRINGS RETURNED IN UTF-8 FORMAT
                        $delim       = substr($str, 0, 1);
                        $chrs        = substr($str, 1, -1);
                        $utf8        = '';
                        $strlen_chrs = strlen($chrs);

                        for ($c = 0; $c < $strlen_chrs; ++$c) {
                            $substr_chrs_c_2 = substr($chrs, $c, 2);
                            $ord_chrs_c      = ord($chrs[$c]);

                            switch (true) {
                                case '\b' == $substr_chrs_c_2:
                                    $utf8 .= chr(0x08);
                                    ++$c;
                                    break;
                                case '\t' == $substr_chrs_c_2:
                                    $utf8 .= chr(0x09);
                                    ++$c;
                                    break;
                                case '\n' == $substr_chrs_c_2:
                                    $utf8 .= chr(0x0A);
                                    ++$c;
                                    break;
                                case '\f' == $substr_chrs_c_2:
                                    $utf8 .= chr(0x0C);
                                    ++$c;
                                    break;
                                case '\r' == $substr_chrs_c_2:
                                    $utf8 .= chr(0x0D);
                                    ++$c;
                                    break;

                                case '\\"' == $substr_chrs_c_2:
                                case '\\\'' == $substr_chrs_c_2:
                                case '\\\\' == $substr_chrs_c_2:
                                case '\\/' == $substr_chrs_c_2:
                                    if (('"' == $delim && '\\\'' != $substr_chrs_c_2) ||
                                        ("'" == $delim && '\\"' != $substr_chrs_c_2)
                                    ) {
                                        $utf8 .= $chrs[++$c];
                                    }
                                    break;

                                case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
                                    // single, escaped unicode character
                                    $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
                                        .chr(hexdec(substr($chrs, ($c + 4), 2)));
                                    $utf8 .= $this->utf162utf8($utf16);
                                    $c += 5;
                                    break;

                                case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
                                    $utf8 .= $chrs[$c];
                                    break;

                                case 0xC0 == ($ord_chrs_c & 0xE0):
                                    // characters U-00000080 - U-000007FF, mask 110XXXXX
                                    //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                    $utf8 .= substr($chrs, $c, 2);
                                    ++$c;
                                    break;

                                case 0xE0 == ($ord_chrs_c & 0xF0):
                                    // characters U-00000800 - U-0000FFFF, mask 1110XXXX
                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                    $utf8 .= substr($chrs, $c, 3);
                                    $c += 2;
                                    break;

                                case 0xF0 == ($ord_chrs_c & 0xF8):
                                    // characters U-00010000 - U-001FFFFF, mask 11110XXX
                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                    $utf8 .= substr($chrs, $c, 4);
                                    $c += 3;
                                    break;

                                case 0xF8 == ($ord_chrs_c & 0xFC):
                                    // characters U-00200000 - U-03FFFFFF, mask 111110XX
                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                    $utf8 .= substr($chrs, $c, 5);
                                    $c += 4;
                                    break;

                                case 0xFC == ($ord_chrs_c & 0xFE):
                                    // characters U-04000000 - U-7FFFFFFF, mask 1111110X
                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
                                    $utf8 .= substr($chrs, $c, 6);
                                    $c += 5;
                                    break;
                            }
                        }

                        return $utf8;
                    } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
                        // array, or object notation

                        if ('[' == $str[0]) {
                            $stk = array(SERVICES_JSON_IN_ARR);
                            $arr = array();
                        } else {
                            if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
                                $stk = array(SERVICES_JSON_IN_OBJ);
                                $obj = array();
                            } else {
                                $stk = array(SERVICES_JSON_IN_OBJ);
                                $obj = new stdClass();
                            }
                        }

                        array_push($stk, array('what' => SERVICES_JSON_SLICE,
                            'where'                   => 0,
                            'delim'                   => false, ));

                        $chrs = substr($str, 1, -1);
                        $chrs = $this->reduce_string($chrs);

                        if ('' == $chrs) {
                            if (SERVICES_JSON_IN_ARR == reset($stk)) {
                                return $arr;
                            } else {
                                return $obj;
                            }
                        }

                        //print("\nparsing {$chrs}\n");

                        $strlen_chrs = strlen($chrs);

                        for ($c = 0; $c <= $strlen_chrs; ++$c) {
                            $top             = end($stk);
                            $substr_chrs_c_2 = substr($chrs, $c, 2);

                            if (($c == $strlen_chrs) || ((',' == $chrs[$c]) && (SERVICES_JSON_SLICE == $top['what']))) {
                                // found a comma that is not inside a string, array, etc.,
                                // OR we've reached the end of the character list
                                $slice = substr($chrs, $top['where'], ($c - $top['where']));
                                array_push($stk, array('what' => SERVICES_JSON_SLICE,
                                    'where'                   => ($c + 1),
                                    'delim'                   => false, ));
                                //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");

                                if (SERVICES_JSON_IN_ARR == reset($stk)) {
                                    // we are in an array, so just push an element onto the stack
                                    array_push($arr, $this->decode($slice));
                                } elseif (SERVICES_JSON_IN_OBJ == reset($stk)) {
                                    // we are in an object, so figure
                                    // out the property name and set an
                                    // element in an associative array,
                                    // for now
                                    $parts = array();

                                    if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
                                        // "name":value pair
                                        $key = $this->decode($parts[1]);
                                        $val = $this->decode($parts[2]);

                                        if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
                                            $obj[$key] = $val;
                                        } else {
                                            $obj->$key = $val;
                                        }
                                    } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
                                        // name:value pair, where name is unquoted
                                        $key = $parts[1];
                                        $val = $this->decode($parts[2]);

                                        if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
                                            $obj[$key] = $val;
                                        } else {
                                            $obj->$key = $val;
                                        }
                                    }
                                }
                            } elseif ((('"' == $chrs[$c]) || ("'" == $chrs[$c])) && (SERVICES_JSON_IN_STR != $top['what'])) {
                                // found a quote, and we are not inside a string
                                array_push($stk, array('what' => SERVICES_JSON_IN_STR,
                                    'where'                   => $c,
                                    'delim'                   => $chrs[$c], ));
                            //print("Found start of string at {$c}\n");
                            } elseif (($chrs[$c] == $top['delim']) &&
                                (SERVICES_JSON_IN_STR == $top['what']) &&
                                (1 != (strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2)
                            ) {
                                // found a quote, we're in a string, and it's not escaped
                                // we know that it's not escaped becase there is _not_ an
                                // odd number of backslashes at the end of the string so far
                                array_pop($stk);
                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
                            } elseif (('[' == $chrs[$c]) &&
                                in_array($top['what'], array(SERVICES_JSON_SLICE,
                                    SERVICES_JSON_IN_ARR,
                                    SERVICES_JSON_IN_OBJ, ))
                            ) {
                                // found a left-bracket, and we are in an array, object, or slice
                                array_push($stk, array('what' => SERVICES_JSON_IN_ARR,
                                    'where'                   => $c,
                                    'delim'                   => false, ));
                            //print("Found start of array at {$c}\n");
                            } elseif ((']' == $chrs[$c]) && (SERVICES_JSON_IN_ARR == $top['what'])) {
                                // found a right-bracket, and we're in an array
                                array_pop($stk);
                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
                            } elseif (('{' == $chrs[$c]) &&
                                in_array($top['what'], array(SERVICES_JSON_SLICE,
                                    SERVICES_JSON_IN_ARR,
                                    SERVICES_JSON_IN_OBJ, ))
                            ) {
                                // found a left-brace, and we are in an array, object, or slice
                                array_push($stk, array('what' => SERVICES_JSON_IN_OBJ,
                                    'where'                   => $c,
                                    'delim'                   => false, ));
                            //print("Found start of object at {$c}\n");
                            } elseif (('}' == $chrs[$c]) && (SERVICES_JSON_IN_OBJ == $top['what'])) {
                                // found a right-brace, and we're in an object
                                array_pop($stk);
                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
                            } elseif (('/*' == $substr_chrs_c_2) &&
                                in_array($top['what'], array(SERVICES_JSON_SLICE,
                                    SERVICES_JSON_IN_ARR,
                                    SERVICES_JSON_IN_OBJ, ))
                            ) {
                                // found a comment start, and we are in an array, object, or slice
                                array_push($stk, array('what' => SERVICES_JSON_IN_CMT,
                                    'where'                   => $c,
                                    'delim'                   => false, ));
                                ++$c;
                            //print("Found start of comment at {$c}\n");
                            } elseif (('*/' == $substr_chrs_c_2) && (SERVICES_JSON_IN_CMT == $top['what'])) {
                                // found a comment end, and we're in one now
                                array_pop($stk);
                                ++$c;

                                for ($i = $top['where']; $i <= $c; ++$i) {
                                    $chrs = substr_replace($chrs, ' ', $i, 1);
                                }

                                //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
                            }
                        }

                        if (SERVICES_JSON_IN_ARR == reset($stk)) {
                            return $arr;
                        } elseif (SERVICES_JSON_IN_OBJ == reset($stk)) {
                            return $obj;
                        }
                    }
            }
        }

        public function isError($data, $code = null)
        {
            if (class_exists('pear')) {
                return PEAR::isError($data, $code);
            } elseif (is_object($data) && ('services_json_error' == get_class($data) ||
                    is_subclass_of($data, 'services_json_error'))
            ) {
                return true;
            }

            return false;
        }
    }

    class Akeeba_Services_JSON_Error
    {
        public function Akeeba_Services_JSON_Error($message = 'unknown error', $code = null,
                                            $mode = null, $options = null, $userinfo = null)
        {
        }
    }
}

if (!function_exists('json_encode')) {
    function json_encode($value, $options = 0)
    {
        $flags = SERVICES_JSON_LOOSE_TYPE;
        if ($options & JSON_FORCE_OBJECT) {
            $flags = 0;
        }
        $encoder = new Akeeba_Services_JSON($flags);

        return $encoder->encode($value);
    }
}

if (!function_exists('json_decode')) {
    function json_decode($value, $assoc = false)
    {
        $flags = 0;
        if ($assoc) {
            $flags = SERVICES_JSON_LOOSE_TYPE;
        }
        $decoder = new Akeeba_Services_JSON($flags);

        return $decoder->decode($value);
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * The base class of Akeeba Engine objects. Allows for error and warnings logging
 * and propagation. Largely based on the Joomla! 1.5 JObject class.
 */
abstract class AKAbstractObject
{
    /** @var array The queue size of the $_errors array. Set to 0 for infinite size. */
    protected $_errors_queue_size = 0;
    /** @var array The queue size of the $_warnings array. Set to 0 for infinite size. */
    protected $_warnings_queue_size = 0;
    /** @var array An array of errors */
    private $_errors = array();
    /** @var array An array of warnings */
    private $_warnings = array();

    /**
     * Public constructor, makes sure we are instanciated only by the factory class.
     */
    public function __construct()
    {
    }

    /**
     * Get the most recent error message.
     *
     * @param int $i Optional error index
     *
     * @return string Error message
     */
    public function getError($i = null)
    {
        return $this->getItemFromArray($this->_errors, $i);
    }

    /**
     * Returns the last item of a LIFO string message queue, or a specific item
     * if so specified.
     *
     * @param array $array An array of strings, holding messages
     * @param int   $i     Optional message index
     *
     * @return mixed The message string, or false if the key doesn't exist
     */
    private function getItemFromArray($array, $i = null)
    {
        // Find the item
        if (null === $i) {
            // Default, return the last item
            $item = end($array);
        } elseif (!array_key_exists($i, $array)) {
            // If $i has been specified but does not exist, return false
            return false;
        } else {
            $item = $array[$i];
        }

        return $item;
    }

    /**
     * Return all errors, if any.
     *
     * @return array Array of error messages
     */
    public function getErrors()
    {
        return $this->_errors;
    }

    /**
     * Resets all error messages.
     */
    public function resetErrors()
    {
        $this->_errors = array();
    }

    /**
     * Get the most recent warning message.
     *
     * @param int $i Optional warning index
     *
     * @return string Error message
     */
    public function getWarning($i = null)
    {
        return $this->getItemFromArray($this->_warnings, $i);
    }

    /**
     * Return all warnings, if any.
     *
     * @return array Array of error messages
     */
    public function getWarnings()
    {
        return $this->_warnings;
    }

    /**
     * Resets all warning messages.
     */
    public function resetWarnings()
    {
        $this->_warnings = array();
    }

    /**
     * Propagates errors and warnings to a foreign object. The foreign object SHOULD
     * implement the setError() and/or setWarning() methods but DOESN'T HAVE TO be of
     * AKAbstractObject type. For example, this can even be used to propagate to a
     * JObject instance in Joomla!. Propagated items will be removed from ourself.
     *
     * @param object $object the object to propagate errors and warnings to
     */
    public function propagateToObject(&$object)
    {
        // Skip non-objects
        if (!is_object($object)) {
            return;
        }

        if (method_exists($object, 'setError')) {
            if (!empty($this->_errors)) {
                foreach ($this->_errors as $error) {
                    $object->setError($error);
                }
                $this->_errors = array();
            }
        }

        if (method_exists($object, 'setWarning')) {
            if (!empty($this->_warnings)) {
                foreach ($this->_warnings as $warning) {
                    $object->setWarning($warning);
                }
                $this->_warnings = array();
            }
        }
    }

    /**
     * Propagates errors and warnings from a foreign object. Each propagated list is
     * then cleared on the foreign object, as long as it implements resetErrors() and/or
     * resetWarnings() methods.
     *
     * @param object $object The object to propagate errors and warnings from
     */
    public function propagateFromObject(&$object)
    {
        if (method_exists($object, 'getErrors')) {
            $errors = $object->getErrors();
            if (!empty($errors)) {
                foreach ($errors as $error) {
                    $this->setError($error);
                }
            }
            if (method_exists($object, 'resetErrors')) {
                $object->resetErrors();
            }
        }

        if (method_exists($object, 'getWarnings')) {
            $warnings = $object->getWarnings();
            if (!empty($warnings)) {
                foreach ($warnings as $warning) {
                    $this->setWarning($warning);
                }
            }
            if (method_exists($object, 'resetWarnings')) {
                $object->resetWarnings();
            }
        }
    }

    /**
     * Add an error message.
     *
     * @param string $error Error message
     */
    public function setError($error)
    {
        if ($this->_errors_queue_size > 0) {
            if (count($this->_errors) >= $this->_errors_queue_size) {
                array_shift($this->_errors);
            }
        }
        array_push($this->_errors, $error);
    }

    /**
     * Add an error message.
     *
     * @param string $error Error message
     */
    public function setWarning($warning)
    {
        if ($this->_warnings_queue_size > 0) {
            if (count($this->_warnings) >= $this->_warnings_queue_size) {
                array_shift($this->_warnings);
            }
        }

        array_push($this->_warnings, $warning);
    }

    /**
     * Sets the size of the error queue (acts like a LIFO buffer).
     *
     * @param int $newSize The new queue size. Set to 0 for infinite length.
     */
    protected function setErrorsQueueSize($newSize = 0)
    {
        $this->_errors_queue_size = (int) $newSize;
    }

    /**
     * Sets the size of the warnings queue (acts like a LIFO buffer).
     *
     * @param int $newSize The new queue size. Set to 0 for infinite length.
     */
    protected function setWarningsQueueSize($newSize = 0)
    {
        $this->_warnings_queue_size = (int) $newSize;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * The superclass of all Akeeba Kickstart parts. The "parts" are intelligent stateful
 * classes which perform a single procedure and have preparation, running and
 * finalization phases. The transition between phases is handled automatically by
 * this superclass' tick() final public method, which should be the ONLY public API
 * exposed to the rest of the Akeeba Engine.
 */
abstract class AKAbstractPart extends AKAbstractObject
{
    /**
     * Indicates whether this part has finished its initialisation cycle.
     *
     * @var bool
     */
    protected $isPrepared = false;

    /**
     * Indicates whether this part has more work to do (it's in running state).
     *
     * @var bool
     */
    protected $isRunning = false;

    /**
     * Indicates whether this part has finished its finalization cycle.
     *
     * @var bool
     */
    protected $isFinished = false;

    /**
     * Indicates whether this part has finished its run cycle.
     *
     * @var bool
     */
    protected $hasRan = false;

    /**
     * The name of the engine part (a.k.a. Domain), used in return table
     * generation.
     *
     * @var string
     */
    protected $active_domain = '';

    /**
     * The step this engine part is in. Used verbatim in return table and
     * should be set by the code in the _run() method.
     *
     * @var string
     */
    protected $active_step = '';

    /**
     * A more detailed description of the step this engine part is in. Used
     * verbatim in return table and should be set by the code in the _run()
     * method.
     *
     * @var string
     */
    protected $active_substep = '';

    /**
     * Any configuration variables, in the form of an array.
     *
     * @var array
     */
    protected $_parametersArray = array();

    /** @var string The database root key */
    protected $databaseRoot = array();
    /** @var array An array of observers */
    protected $observers = array();
    /** @var int Last reported warnings's position in array */
    private $warnings_pointer = -1;

    /**
     * The public interface to an engine part. This method takes care for
     * calling the correct method in order to perform the initialisation -
     * run - finalisation cycle of operation and return a proper reponse array.
     *
     * @return array A Reponse Array
     */
    final public function tick()
    {
        // Call the right action method, depending on engine part state
        switch ($this->getState()) {
            case 'init':
                $this->_prepare();
                break;
            case 'prepared':
                $this->_run();
                break;
            case 'running':
                $this->_run();
                break;
            case 'postrun':
                $this->_finalize();
                break;
        }

        // Send a Return Table back to the caller
        $out = $this->_makeReturnTable();

        return $out;
    }

    /**
     * Returns the state of this engine part.
     *
     * @return string The state of this engine part. It can be one of
     *                error, init, prepared, running, postrun, finished.
     */
    final public function getState()
    {
        if ($this->getError()) {
            return 'error';
        }

        if (!($this->isPrepared)) {
            return 'init';
        }

        if (!($this->isFinished) && !($this->isRunning) && !($this->hasRun) && ($this->isPrepared)) {
            return 'prepared';
        }

        if (!($this->isFinished) && $this->isRunning && !($this->hasRun)) {
            return 'running';
        }

        if (!($this->isFinished) && !($this->isRunning) && $this->hasRun) {
            return 'postrun';
        }

        if ($this->isFinished) {
            return 'finished';
        }
    }

    /**
     * Runs the preparation for this part. Should set _isPrepared
     * to true.
     */
    abstract protected function _prepare();

    /**
     * Runs the main functionality loop for this part. Upon calling,
     * should set the _isRunning to true. When it finished, should set
     * the _hasRan to true. If an error is encountered, setError should
     * be used.
     */
    abstract protected function _run();

    /**
     * Runs the finalisation process for this part. Should set
     * _isFinished to true.
     */
    abstract protected function _finalize();

    /**
     * Constructs a Response Array based on the engine part's state.
     *
     * @return array The Response Array for the current state
     */
    final protected function _makeReturnTable()
    {
        // Get a list of warnings
        $warnings = $this->getWarnings();
        // Report only new warnings if there is no warnings queue size
        if (0 == $this->_warnings_queue_size) {
            if (($this->warnings_pointer > 0) && ($this->warnings_pointer < (count($warnings)))) {
                $warnings = array_slice($warnings, $this->warnings_pointer + 1);
                $this->warnings_pointer += count($warnings);
            } else {
                $this->warnings_pointer = count($warnings);
            }
        }

        $out = array(
            'HasRun'   => (!($this->isFinished)),
            'Domain'   => $this->active_domain,
            'Step'     => $this->active_step,
            'Substep'  => $this->active_substep,
            'Error'    => $this->getError(),
            'Warnings' => $warnings,
        );

        return $out;
    }

    /**
     * Returns a copy of the class's status array.
     *
     * @return array
     */
    public function getStatusArray()
    {
        return $this->_makeReturnTable();
    }

    /**
     * Sends any kind of setup information to the engine part. Using this,
     * we avoid passing parameters to the constructor of the class. These
     * parameters should be passed as an indexed array and should be taken
     * into account during the preparation process only. This function will
     * set the error flag if it's called after the engine part is prepared.
     *
     * @param array $parametersArray the parameters to be passed to the
     *                               engine part
     */
    final public function setup($parametersArray)
    {
        if ($this->isPrepared) {
            $this->setState('error', "Can't modify configuration after the preparation of ".$this->active_domain);
        } else {
            $this->_parametersArray = $parametersArray;
            if (array_key_exists('root', $parametersArray)) {
                $this->databaseRoot = $parametersArray['root'];
            }
        }
    }

    /**
     * Sets the engine part's internal state, in an easy to use manner.
     *
     * @param string $state        One of init, prepared, running, postrun, finished, error
     * @param string $errorMessage The reported error message, should the state be set to error
     */
    protected function setState($state = 'init', $errorMessage = 'Invalid setState argument')
    {
        switch ($state) {
            case 'init':
                $this->isPrepared = false;
                $this->isRunning  = false;
                $this->isFinished = false;
                $this->hasRun     = false;
                break;

            case 'prepared':
                $this->isPrepared = true;
                $this->isRunning  = false;
                $this->isFinished = false;
                $this->hasRun     = false;
                break;

            case 'running':
                $this->isPrepared = true;
                $this->isRunning  = true;
                $this->isFinished = false;
                $this->hasRun     = false;
                break;

            case 'postrun':
                $this->isPrepared = true;
                $this->isRunning  = false;
                $this->isFinished = false;
                $this->hasRun     = true;
                break;

            case 'finished':
                $this->isPrepared = true;
                $this->isRunning  = false;
                $this->isFinished = true;
                $this->hasRun     = false;
                break;

            case 'error':
            default:
                $this->setError($errorMessage);
                break;
        }
    }

    final public function getDomain()
    {
        return $this->active_domain;
    }

    final public function getStep()
    {
        return $this->active_step;
    }

    final public function getSubstep()
    {
        return $this->active_substep;
    }

    /**
     * Attaches an observer object.
     *
     * @param AKAbstractPartObserver $obs
     */
    public function attach(AKAbstractPartObserver $obs)
    {
        $this->observers["$obs"] = $obs;
    }

    /**
     * Dettaches an observer object.
     *
     * @param AKAbstractPartObserver $obs
     */
    public function detach(AKAbstractPartObserver $obs)
    {
        delete($this->observers["$obs"]);
    }

    /**
     * Sets the BREAKFLAG, which instructs this engine part that the current step must break immediately,
     * in fear of timing out.
     */
    protected function setBreakFlag()
    {
        AKFactory::set('volatile.breakflag', true);
    }

    final protected function setDomain($new_domain)
    {
        $this->active_domain = $new_domain;
    }

    final protected function setStep($new_step)
    {
        $this->active_step = $new_step;
    }

    final protected function setSubstep($new_substep)
    {
        $this->active_substep = $new_substep;
    }

    /**
     * Notifies observers each time something interesting happened to the part.
     *
     * @param mixed $message The event object
     */
    protected function notify($message)
    {
        foreach ($this->observers as $obs) {
            $obs->update($this, $message);
        }
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * The base class of unarchiver classes.
 */
abstract class AKAbstractUnarchiver extends AKAbstractPart
{
    /** @var array List of the names of all archive parts */
    public $archiveList = array();
    /** @var int The total size of all archive parts */
    public $totalSize = array();
    /** @var array Which files to rename */
    public $renameFiles = array();
    /** @var array Which directories to rename */
    public $renameDirs = array();
    /** @var array Which files to skip */
    public $skipFiles = array();
    /** @var string Archive filename */
    protected $filename = null;
    /** @var int Current archive part number */
    protected $currentPartNumber = -1;
    /** @var int The offset inside the current part */
    protected $currentPartOffset = 0;
    /** @var bool Should I restore permissions? */
    protected $flagRestorePermissions = false;
    /** @var AKAbstractPostproc Post processing class */
    protected $postProcEngine = null;
    /** @var string Absolute path to prepend to extracted files */
    protected $addPath = '';
    /** @var int Chunk size for processing */
    protected $chunkSize = 524288;

    /** @var resource File pointer to the current archive part file */
    protected $fp = null;

    /** @var int Run state when processing the current archive file */
    protected $runState = null;

    /** @var stdClass File header data, as read by the readFileHeader() method */
    protected $fileHeader = null;

    /** @var int How much of the uncompressed data we've read so far */
    protected $dataReadLength = 0;

    /** @var array Unwriteable files in these directories are always ignored and do not cause errors when not extracted */
    protected $ignoreDirectories = array();

    /**
     * Public constructor.
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Wakeup function, called whenever the class is unserialized.
     */
    public function __wakeup()
    {
        if ($this->currentPartNumber >= 0) {
            $this->fp = @fopen($this->archiveList[$this->currentPartNumber], 'rb');
            if ((is_resource($this->fp)) && ($this->currentPartOffset > 0)) {
                @fseek($this->fp, $this->currentPartOffset);
            }
        }
    }

    /**
     * Sleep function, called whenever the class is serialized.
     */
    public function shutdown()
    {
        if (is_resource($this->fp)) {
            $this->currentPartOffset = @ftell($this->fp);
            @fclose($this->fp);
        }
    }

    /**
     * Is this file or directory contained in a directory we've decided to ignore
     * write errors for? This is useful to let the extraction work despite write
     * errors in the log, logs and tmp directories which MIGHT be used by the system
     * on some low quality hosts and Plesk-powered hosts.
     *
     * @param string $shortFilename The relative path of the file/directory in the package
     *
     * @return bool True if it belongs in an ignored directory
     */
    public function isIgnoredDirectory($shortFilename)
    {
        return false;
        if ('/' == substr($shortFilename, -1)) {
            $check = substr($shortFilename, 0, -1);
        } else {
            $check = dirname($shortFilename);
        }

        return in_array($check, $this->ignoreDirectories);
    }

    /**
     * Implements the abstract _prepare() method.
     */
    final protected function _prepare()
    {
        parent::__construct();

        if (count($this->_parametersArray) > 0) {
            foreach ($this->_parametersArray as $key => $value) {
                switch ($key) {
                    // Archive's absolute filename
                    case 'filename':
                        $this->filename = $value;

                        // Sanity check
                        if (!empty($value)) {
                            $value = strtolower($value);

                            if (strlen($value) > 6) {
                                if (
                                    ('http://' == substr($value, 0, 7))
                                    || ('https://' == substr($value, 0, 8))
                                    || ('ftp://' == substr($value, 0, 6))
                                    || ('ssh2://' == substr($value, 0, 7))
                                    || ('ssl://' == substr($value, 0, 6))
                                ) {
                                    $this->setState('error', 'Invalid archive location');
                                }
                            }
                        }

                        break;

                    // Should I restore permissions?
                    case 'restore_permissions':
                        $this->flagRestorePermissions = $value;
                        break;

                    // Should I use FTP?
                    case 'post_proc':
                        $this->postProcEngine = AKFactory::getpostProc($value);
                        break;

                    // Path to add in the beginning
                    case 'add_path':
                        $this->addPath = $value;
                        $this->addPath = str_replace('\\', '/', $this->addPath);
                        $this->addPath = rtrim($this->addPath, '/');
                        if (!empty($this->addPath)) {
                            $this->addPath .= '/';
                        }
                        break;

                    // Which files to rename (hash array)
                    case 'rename_files':
                        $this->renameFiles = $value;
                        break;

                    // Which files to rename (hash array)
                    case 'rename_dirs':
                        $this->renameDirs = $value;
                        break;

                    // Which files to skip (indexed array)
                    case 'skip_files':
                        $this->skipFiles = $value;
                        break;

                    // Which directories to ignore when we can't write files in them (indexed array)
                    case 'ignoredirectories':
                        $this->ignoreDirectories = $value;
                        break;
                }
            }
        }

        $this->scanArchives();

        $this->readArchiveHeader();
        $errMessage = $this->getError();
        if (!empty($errMessage)) {
            $this->setState('error', $errMessage);
        } else {
            $this->runState = AK_STATE_NOFILE;
            $this->setState('prepared');
        }
    }

    /**
     * Scans for archive parts.
     */
    private function scanArchives()
    {
        if (defined('KSDEBUG')) {
            @unlink('debug.txt');
        }
        debugMsg('Preparing to scan archives');

        $privateArchiveList = array();

        // Get the components of the archive filename
        $dirname         = dirname($this->filename);
        $base_extension  = $this->getBaseExtension();
        $basename        = basename($this->filename, $base_extension);
        $this->totalSize = 0;

        // Scan for multiple parts until we don't find any more of them
        $count             = 0;
        $found             = true;
        $this->archiveList = array();
        while ($found) {
            ++$count;
            $extension = substr($base_extension, 0, 2).sprintf('%02d', $count);
            $filename  = $dirname.DIRECTORY_SEPARATOR.$basename.$extension;
            $found     = file_exists($filename);
            if ($found) {
                debugMsg('- Found archive '.$filename);
                // Add yet another part, with a numeric-appended filename
                $this->archiveList[] = $filename;

                $filesize = @filesize($filename);
                $this->totalSize += $filesize;

                $privateArchiveList[] = array($filename, $filesize);
            } else {
                debugMsg('- Found archive '.$this->filename);
                // Add the last part, with the regular extension
                $this->archiveList[] = $this->filename;

                $filename = $this->filename;
                $filesize = @filesize($filename);
                $this->totalSize += $filesize;

                $privateArchiveList[] = array($filename, $filesize);
            }
        }
        debugMsg('Total archive parts: '.$count);

        $this->currentPartNumber = -1;
        $this->currentPartOffset = 0;
        $this->runState          = AK_STATE_NOFILE;

        // Send start of file notification
        $message                     = new stdClass();
        $message->type               = 'totalsize';
        $message->content            = new stdClass();
        $message->content->totalsize = $this->totalSize;
        $message->content->filelist  = $privateArchiveList;
        $this->notify($message);
    }

    /**
     * Returns the base extension of the file, e.g. '.jpa'.
     *
     * @return string
     */
    private function getBaseExtension()
    {
        static $baseextension;

        if (empty($baseextension)) {
            $basename      = basename($this->filename);
            $lastdot       = strrpos($basename, '.');
            $baseextension = substr($basename, $lastdot);
        }

        return $baseextension;
    }

    /**
     * Concrete classes are supposed to use this method in order to read the archive's header and
     * prepare themselves to the point of being ready to extract the first file.
     */
    abstract protected function readArchiveHeader();

    protected function _run()
    {
        if ('postrun' == $this->getState()) {
            return;
        }

        $this->setState('running');

        $timer = AKFactory::getTimer();

        $status = true;
        while ($status && ($timer->getTimeLeft() > 0)) {
            switch ($this->runState) {
                case AK_STATE_NOFILE:
                    debugMsg(__CLASS__.'::_run() - Reading file header');
                    $status = $this->readFileHeader();
                    if ($status) {
                        debugMsg(__CLASS__.'::_run() - Preparing to extract '.$this->fileHeader->realFile);
                        // Send start of file notification
                        $message          = new stdClass();
                        $message->type    = 'startfile';
                        $message->content = new stdClass();
                        if (array_key_exists('realfile', get_object_vars($this->fileHeader))) {
                            $message->content->realfile = $this->fileHeader->realFile;
                        } else {
                            $message->content->realfile = $this->fileHeader->file;
                        }
                        $message->content->file = $this->fileHeader->file;
                        if (array_key_exists('compressed', get_object_vars($this->fileHeader))) {
                            $message->content->compressed = $this->fileHeader->compressed;
                        } else {
                            $message->content->compressed = 0;
                        }
                        $message->content->uncompressed = $this->fileHeader->uncompressed;
                        $this->notify($message);
                    } else {
                        debugMsg(__CLASS__.'::_run() - Could not read file header');
                    }
                    break;

                case AK_STATE_HEADER:
                case AK_STATE_DATA:
                    debugMsg(__CLASS__.'::_run() - Processing file data');
                    $status = $this->processFileData();
                    break;

                case AK_STATE_DATAREAD:
                case AK_STATE_POSTPROC:
                    debugMsg(__CLASS__.'::_run() - Calling post-processing class');
                    $this->postProcEngine->timestamp = $this->fileHeader->timestamp;
                    $status                          = $this->postProcEngine->process();
                    $this->propagateFromObject($this->postProcEngine);
                    $this->runState = AK_STATE_DONE;
                    break;

                case AK_STATE_DONE:
                default:
                    if ($status) {
                        debugMsg(__CLASS__.'::_run() - Finished extracting file');
                        // Send end of file notification
                        $message          = new stdClass();
                        $message->type    = 'endfile';
                        $message->content = new stdClass();
                        if (array_key_exists('realfile', get_object_vars($this->fileHeader))) {
                            $message->content->realfile = $this->fileHeader->realFile;
                        } else {
                            $message->content->realfile = $this->fileHeader->file;
                        }
                        $message->content->file = $this->fileHeader->file;
                        if (array_key_exists('compressed', get_object_vars($this->fileHeader))) {
                            $message->content->compressed = $this->fileHeader->compressed;
                        } else {
                            $message->content->compressed = 0;
                        }
                        $message->content->uncompressed = $this->fileHeader->uncompressed;
                        $this->notify($message);
                    }
                    $this->runState = AK_STATE_NOFILE;
                    continue;
            }
        }

        $error = $this->getError();
        if (!$status && (AK_STATE_NOFILE == $this->runState) && empty($error)) {
            debugMsg(__CLASS__.'::_run() - Just finished');
            // We just finished
            $this->setState('postrun');
        } elseif (!empty($error)) {
            debugMsg(__CLASS__.'::_run() - Halted with an error:');
            debugMsg($error);
            $this->setState('error', $error);
        }
    }

    /**
     * Concrete classes must use this method to read the file header.
     *
     * @return bool True if reading the file was successful, false if an error occured or we reached end of archive
     */
    abstract protected function readFileHeader();

    /**
     * Concrete classes must use this method to process file data. It must set $runState to AK_STATE_DATAREAD when
     * it's finished processing the file data.
     *
     * @return bool True if processing the file data was successful, false if an error occured
     */
    abstract protected function processFileData();

    protected function _finalize()
    {
        // Nothing to do
        $this->setState('finished');
    }

    /**
     * Opens the next part file for reading.
     */
    protected function nextFile()
    {
        debugMsg('Current part is '.$this->currentPartNumber.'; opening the next part');
        ++$this->currentPartNumber;

        if ($this->currentPartNumber > (count($this->archiveList) - 1)) {
            $this->setState('postrun');

            return false;
        } else {
            if (is_resource($this->fp)) {
                @fclose($this->fp);
            }
            debugMsg('Opening file '.$this->archiveList[$this->currentPartNumber]);
            $this->fp = @fopen($this->archiveList[$this->currentPartNumber], 'rb');
            if (false === $this->fp) {
                debugMsg('Could not open file - crash imminent');
            }
            fseek($this->fp, 0);
            $this->currentPartOffset = 0;

            return true;
        }
    }

    /**
     * Returns true if we have reached the end of file.
     *
     * @param $local bool True to return EOF of the local file, false (default) to return if we have reached the end of the archive set
     *
     * @return bool True if we have reached End Of File
     */
    protected function isEOF($local = false)
    {
        $eof = @feof($this->fp);

        if (!$eof) {
            // Border case: right at the part's end (eeeek!!!). For the life of me, I don't understand why
            // feof() doesn't report true. It expects the fp to be positioned *beyond* the EOF to report
            // true. Incredible! :(
            $position = @ftell($this->fp);
            $filesize = @filesize($this->archiveList[$this->currentPartNumber]);
            if ($filesize <= 0) {
                // 2Gb or more files on a 32 bit version of PHP tend to get screwed up. Meh.
                $eof = false;
            } elseif ($position >= $filesize) {
                $eof = true;
            }
        }

        if ($local) {
            return $eof;
        } else {
            return $eof && ($this->currentPartNumber >= (count($this->archiveList) - 1));
        }
    }

    /**
     * Tries to make a directory user-writable so that we can write a file to it.
     *
     * @param $path string A path to a file
     */
    protected function setCorrectPermissions($path)
    {
        static $rootDir = null;

        if (is_null($rootDir)) {
            $rootDir = rtrim(AKFactory::get('kickstart.setup.destdir', ''), '/\\');
        }

        $directory = rtrim(dirname($path), '/\\');
        if ($directory != $rootDir) {
            // Is this an unwritable directory?
            if (!is_writeable($directory)) {
                $this->postProcEngine->chmod($directory, 0755);
            }
        }
        $this->postProcEngine->chmod($path, 0644);
    }

    /**
     * Reads data from the archive and notifies the observer with the 'reading' message.
     *
     * @param $fp
     * @param $length
     */
    protected function fread($fp, $length = null)
    {
        if (is_numeric($length)) {
            if ($length > 0) {
                $data = fread($fp, $length);
            } else {
                $data = fread($fp, PHP_INT_MAX);
            }
        } else {
            $data = fread($fp, PHP_INT_MAX);
        }
        if (false === $data) {
            $data = '';
        }

        // Send start of file notification
        $message                  = new stdClass();
        $message->type            = 'reading';
        $message->content         = new stdClass();
        $message->content->length = strlen($data);
        $this->notify($message);

        return $data;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * File post processor engines base class.
 */
abstract class AKAbstractPostproc extends AKAbstractObject
{
    /** @var int The UNIX timestamp of the file's desired modification date */
    public $timestamp = 0;
    /** @var string The current (real) file path we'll have to process */
    protected $filename = null;
    /** @var int The requested permissions */
    protected $perms = 0755;
    /** @var string The temporary file path we gave to the unarchiver engine */
    protected $tempFilename = null;

    /**
     * Processes the current file, e.g. moves it from temp to final location by FTP.
     */
    abstract public function process();

    /**
     * The unarchiver tells us the path to the filename it wants to extract and we give it
     * a different path instead.
     *
     * @param string $filename The path to the real file
     * @param int    $perms    The permissions we need the file to have
     *
     * @return string The path to the temporary file
     */
    abstract public function processFilename($filename, $perms = 0755);

    /**
     * Recursively creates a directory if it doesn't exist.
     *
     * @param string $dirName The directory to create
     * @param int    $perms   The permissions to give to that directory
     */
    abstract public function createDirRecursive($dirName, $perms);

    abstract public function chmod($file, $perms);

    abstract public function unlink($file);

    abstract public function rmdir($directory);

    abstract public function rename($from, $to);
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * Descendants of this class can be used in the unarchiver's observer methods (attach, detach and notify).
 *
 * @author Nicholas
 */
abstract class AKAbstractPartObserver
{
    abstract public function update($object, $message);
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * Direct file writer.
 */
class AKPostprocDirect extends AKAbstractPostproc
{
    public function process()
    {
        $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false);
        if ($restorePerms) {
            @chmod($this->filename, $this->perms);
        } else {
            if (@is_file($this->filename)) {
                @chmod($this->filename, 0644);
            } else {
                @chmod($this->filename, 0755);
            }
        }
        if ($this->timestamp > 0) {
            @touch($this->filename, $this->timestamp);
        }

        return true;
    }

    public function processFilename($filename, $perms = 0755)
    {
        $this->perms    = $perms;
        $this->filename = $filename;

        return $filename;
    }

    public function createDirRecursive($dirName, $perms)
    {
        if (AKFactory::get('kickstart.setup.dryrun', '0')) {
            return true;
        }
        if (@mkdir($dirName, 0755, true)) {
            @chmod($dirName, 0755);

            return true;
        }

        $root = AKFactory::get('kickstart.setup.destdir');
        $root = rtrim(str_replace('\\', '/', $root), '/');
        $dir  = rtrim(str_replace('\\', '/', $dirName), '/');
        if (0 === strpos($dir, $root)) {
            $dir = ltrim(substr($dir, strlen($root)), '/');
            $root .= '/';
        } else {
            $root = '';
        }

        if (empty($dir)) {
            return true;
        }

        $dirArray = explode('/', $dir);
        $path     = '';
        foreach ($dirArray as $dir) {
            $path .= $dir.'/';
            $ret = is_dir($root.$path) ? true : @mkdir($root.$path);
            if (!$ret) {
                // Is this a file instead of a directory?
                if (is_file($root.$path)) {
                    @unlink($root.$path);
                    $ret = @mkdir($root.$path);
                }
                if (!$ret) {
                    $this->setError(AKText::sprintf('COULDNT_CREATE_DIR', $path));

                    return false;
                }
            }
            // Try to set new directory permissions to 0755
            @chmod($root.$path, $perms);
        }

        return true;
    }

    public function chmod($file, $perms)
    {
        if (AKFactory::get('kickstart.setup.dryrun', '0')) {
            return true;
        }

        return @chmod($file, $perms);
    }

    public function unlink($file)
    {
        return @unlink($file);
    }

    public function rmdir($directory)
    {
        return @rmdir($directory);
    }

    public function rename($from, $to)
    {
        return @rename($from, $to);
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * FTP file writer.
 */
class AKPostprocFTP extends AKAbstractPostproc
{
    /** @var bool Should I use FTP over implicit SSL? */
    public $useSSL = false;
    /** @var bool use Passive mode? */
    public $passive = true;
    /** @var string FTP host name */
    public $host = '';
    /** @var int FTP port */
    public $port = 21;
    /** @var string FTP user name */
    public $user = '';
    /** @var string FTP password */
    public $pass = '';
    /** @var string FTP initial directory */
    public $dir = '';
    /** @var resource The FTP handle */
    private $handle = null;
    /** @var string The temporary directory where the data will be stored */
    private $tempDir = '';

    public function __construct()
    {
        parent::__construct();

        $this->useSSL  = AKFactory::get('kickstart.ftp.ssl', false);
        $this->passive = AKFactory::get('kickstart.ftp.passive', true);
        $this->host    = AKFactory::get('kickstart.ftp.host', '');
        $this->port    = AKFactory::get('kickstart.ftp.port', 21);
        if ('' == trim($this->port)) {
            $this->port = 21;
        }
        $this->user    = AKFactory::get('kickstart.ftp.user', '');
        $this->pass    = AKFactory::get('kickstart.ftp.pass', '');
        $this->dir     = AKFactory::get('kickstart.ftp.dir', '');
        $this->tempDir = AKFactory::get('kickstart.ftp.tempdir', '');

        $connected = $this->connect();

        if ($connected) {
            if (!empty($this->tempDir)) {
                $tempDir  = rtrim($this->tempDir, '/\\').'/';
                $writable = $this->isDirWritable($tempDir);
            } else {
                $tempDir  = '';
                $writable = false;
            }

            if (!$writable) {
                // Default temporary directory is the current root
                $tempDir = KSROOTDIR;
                if (empty($tempDir)) {
                    // Oh, we have no directory reported!
                    $tempDir = '.';
                }
                $absoluteDirToHere = $tempDir;
                $tempDir           = rtrim(str_replace('\\', '/', $tempDir), '/');
                if (!empty($tempDir)) {
                    $tempDir .= '/';
                }
                $this->tempDir = $tempDir;
                // Is this directory writable?
                $writable = $this->isDirWritable($tempDir);
            }

            if (!$writable) {
                // Nope. Let's try creating a temporary directory in the site's root.
                $tempDir = $absoluteDirToHere.'/kicktemp';
                $this->createDirRecursive($tempDir, 0777);
                // Try making it writable...
                $this->fixPermissions($tempDir);
                $writable = $this->isDirWritable($tempDir);
            }

            // Was the new directory writable?
            if (!$writable) {
                // Let's see if the user has specified one
                $userdir = AKFactory::get('kickstart.ftp.tempdir', '');
                if (!empty($userdir)) {
                    // Is it an absolute or a relative directory?
                    $absolute = false;
                    $absolute = $absolute || ('/' == substr($userdir, 0, 1));
                    $absolute = $absolute || (':' == substr($userdir, 1, 1));
                    $absolute = $absolute || (':' == substr($userdir, 2, 1));
                    if (!$absolute) {
                        // Make absolute
                        $tempDir = $absoluteDirToHere.$userdir;
                    } else {
                        // it's already absolute
                        $tempDir = $userdir;
                    }
                    // Does the directory exist?
                    if (is_dir($tempDir)) {
                        // Yeah. Is it writable?
                        $writable = $this->isDirWritable($tempDir);
                    }
                }
            }
            $this->tempDir = $tempDir;

            if (!$writable) {
                // No writable directory found!!!
                $this->setError(AKText::_('FTP_TEMPDIR_NOT_WRITABLE'));
            } else {
                AKFactory::set('kickstart.ftp.tempdir', $tempDir);
                $this->tempDir = $tempDir;
            }
        }
    }

    public function connect()
    {
        // Connect to server, using SSL if so required
        if ($this->useSSL) {
            $this->handle = @ftp_ssl_connect($this->host, $this->port);
        } else {
            $this->handle = @ftp_connect($this->host, $this->port);
        }
        if (false === $this->handle) {
            $this->setError(AKText::_('WRONG_FTP_HOST'));

            return false;
        }

        // Login
        if (!@ftp_login($this->handle, $this->user, $this->pass)) {
            $this->setError(AKText::_('WRONG_FTP_USER'));
            @ftp_close($this->handle);

            return false;
        }

        // Change to initial directory
        if (!@ftp_chdir($this->handle, $this->dir)) {
            $this->setError(AKText::_('WRONG_FTP_PATH1'));
            @ftp_close($this->handle);

            return false;
        }

        // Enable passive mode if the user requested it
        if ($this->passive) {
            @ftp_pasv($this->handle, true);
        } else {
            @ftp_pasv($this->handle, false);
        }

        // Try to download ourselves
        $testFilename = defined('KSSELFNAME') ? KSSELFNAME : basename(__FILE__);
        $tempHandle   = fopen('php://temp', 'r+');
        if (false === @ftp_fget($this->handle, $tempHandle, $testFilename, FTP_ASCII, 0)) {
            $this->setError(AKText::_('WRONG_FTP_PATH2'));
            @ftp_close($this->handle);
            fclose($tempHandle);

            return false;
        }
        fclose($tempHandle);

        return true;
    }

    private function isDirWritable($dir)
    {
        $fp = @fopen($dir.'/kickstart.dat', 'wb');
        if (false === $fp) {
            return false;
        } else {
            @fclose($fp);
            unlink($dir.'/kickstart.dat');

            return true;
        }
    }

    public function createDirRecursive($dirName, $perms)
    {
        // Strip absolute filesystem path to website's root
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            // UNIXize the paths
            $removePath = str_replace('\\', '/', $removePath);
            $dirName    = str_replace('\\', '/', $dirName);
            // Make sure they both end in a slash
            $removePath = rtrim($removePath, '/\\').'/';
            $dirName    = rtrim($dirName, '/\\').'/';
            // Process the path removal
            $left = substr($dirName, 0, strlen($removePath));
            if ($left == $removePath) {
                $dirName = substr($dirName, strlen($removePath));
            }
        }
        if (empty($dirName)) {
            $dirName = '';
        } // 'cause the substr() above may return FALSE.

        $check = '/'.trim($this->dir, '/').'/'.trim($dirName, '/');
        if ($this->is_dir($check)) {
            return true;
        }

        $alldirs     = explode('/', $dirName);
        $previousDir = '/'.trim($this->dir);
        foreach ($alldirs as $curdir) {
            $check = $previousDir.'/'.$curdir;
            if (!$this->is_dir($check)) {
                // Proactively try to delete a file by the same name
                @ftp_delete($this->handle, $check);

                if (false === @ftp_mkdir($this->handle, $check)) {
                    // If we couldn't create the directory, attempt to fix the permissions in the PHP level and retry!
                    $this->fixPermissions($removePath.$check);
                    if (false === @ftp_mkdir($this->handle, $check)) {
                        // Can we fall back to pure PHP mode, sire?
                        if (!@mkdir($check)) {
                            $this->setError(AKText::sprintf('FTP_CANT_CREATE_DIR', $check));

                            return false;
                        } else {
                            // Since the directory was built by PHP, change its permissions
                            @chmod($check, '0777');

                            return true;
                        }
                    }
                }
                @ftp_chmod($this->handle, $perms, $check);
            }
            $previousDir = $check;
        }

        return true;
    }

    private function is_dir($dir)
    {
        return @ftp_chdir($this->handle, $dir);
    }

    private function fixPermissions($path)
    {
        // Turn off error reporting
        if (!defined('KSDEBUG')) {
            $oldErrorReporting = @error_reporting(E_NONE);
        }

        // Get UNIX style paths
        $relPath  = str_replace('\\', '/', $path);
        $basePath = rtrim(str_replace('\\', '/', KSROOTDIR), '/');
        $basePath = rtrim($basePath, '/');
        if (!empty($basePath)) {
            $basePath .= '/';
        }
        // Remove the leading relative root
        if (substr($relPath, 0, strlen($basePath)) == $basePath) {
            $relPath = substr($relPath, strlen($basePath));
        }
        $dirArray  = explode('/', $relPath);
        $pathBuilt = rtrim($basePath, '/');
        foreach ($dirArray as $dir) {
            if (empty($dir)) {
                continue;
            }
            $oldPath = $pathBuilt;
            $pathBuilt .= '/'.$dir;
            if (is_dir($oldPath.$dir)) {
                @chmod($oldPath.$dir, 0777);
            } else {
                if (false === @chmod($oldPath.$dir, 0777)) {
                    @unlink($oldPath.$dir);
                }
            }
        }

        // Restore error reporting
        if (!defined('KSDEBUG')) {
            @error_reporting($oldErrorReporting);
        }
    }

    public function __wakeup()
    {
        $this->connect();
    }

    public function process()
    {
        if (is_null($this->tempFilename)) {
            // If an empty filename is passed, it means that we shouldn't do any post processing, i.e.
            // the entity was a directory or symlink
            return true;
        }

        $remotePath = dirname($this->filename);
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            $removePath = ltrim($removePath, '/');
            $remotePath = ltrim($remotePath, '/');
            $left       = substr($remotePath, 0, strlen($removePath));
            if ($left == $removePath) {
                $remotePath = substr($remotePath, strlen($removePath));
            }
        }

        $absoluteFSPath  = dirname($this->filename);
        $relativeFTPPath = trim($remotePath, '/');
        $absoluteFTPPath = '/'.trim($this->dir, '/').'/'.trim($remotePath, '/');
        $onlyFilename    = basename($this->filename);

        $remoteName = $absoluteFTPPath.'/'.$onlyFilename;

        $ret = @ftp_chdir($this->handle, $absoluteFTPPath);
        if (false === $ret) {
            $ret = $this->createDirRecursive($absoluteFSPath, 0755);
            if (false === $ret) {
                $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename));

                return false;
            }
            $ret = @ftp_chdir($this->handle, $absoluteFTPPath);
            if (false === $ret) {
                $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename));

                return false;
            }
        }

        $ret = @ftp_put($this->handle, $remoteName, $this->tempFilename, FTP_BINARY);
        if (false === $ret) {
            // If we couldn't create the file, attempt to fix the permissions in the PHP level and retry!
            $this->fixPermissions($this->filename);
            $this->unlink($this->filename);

            $fp = @fopen($this->tempFilename, 'rb');
            if (false !== $fp) {
                $ret = @ftp_fput($this->handle, $remoteName, $fp, FTP_BINARY);
                @fclose($fp);
            } else {
                $ret = false;
            }
        }
        @unlink($this->tempFilename);

        if (false === $ret) {
            $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename));

            return false;
        }
        $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false);
        if ($restorePerms) {
            @ftp_chmod($this->_handle, $this->perms, $remoteName);
        } else {
            @ftp_chmod($this->_handle, 0644, $remoteName);
        }

        return true;
    }

    /*
     * Tries to fix directory/file permissions in the PHP level, so that
     * the FTP operation doesn't fail.
     * @param $path string The full path to a directory or file
     */

    public function unlink($file)
    {
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            $left = substr($file, 0, strlen($removePath));
            if ($left == $removePath) {
                $file = substr($file, strlen($removePath));
            }
        }

        $check = '/'.trim($this->dir, '/').'/'.trim($file, '/');

        return @ftp_delete($this->handle, $check);
    }

    public function processFilename($filename, $perms = 0755)
    {
        // Catch some error conditions...
        if ($this->getError()) {
            return false;
        }

        // If a null filename is passed, it means that we shouldn't do any post processing, i.e.
        // the entity was a directory or symlink
        if (is_null($filename)) {
            $this->filename     = null;
            $this->tempFilename = null;

            return null;
        }

        // Strip absolute filesystem path to website's root
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            $left = substr($filename, 0, strlen($removePath));
            if ($left == $removePath) {
                $filename = substr($filename, strlen($removePath));
            }
        }

        // Trim slash on the left
        $filename = ltrim($filename, '/');

        $this->filename     = $filename;
        $this->tempFilename = tempnam($this->tempDir, 'kickstart-');
        $this->perms        = $perms;

        if (empty($this->tempFilename)) {
            // Oops! Let's try something different
            $this->tempFilename = $this->tempDir.'/kickstart-'.time().'.dat';
        }

        return $this->tempFilename;
    }

    public function close()
    {
        @ftp_close($this->handle);
    }

    public function chmod($file, $perms)
    {
        return @ftp_chmod($this->handle, $perms, $file);
    }

    public function rmdir($directory)
    {
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            $left = substr($directory, 0, strlen($removePath));
            if ($left == $removePath) {
                $directory = substr($directory, strlen($removePath));
            }
        }

        $check = '/'.trim($this->dir, '/').'/'.trim($directory, '/');

        return @ftp_rmdir($this->handle, $check);
    }

    public function rename($from, $to)
    {
        $originalFrom = $from;
        $originalTo   = $to;

        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            $left = substr($from, 0, strlen($removePath));
            if ($left == $removePath) {
                $from = substr($from, strlen($removePath));
            }
        }
        $from = '/'.trim($this->dir, '/').'/'.trim($from, '/');

        if (!empty($removePath)) {
            $left = substr($to, 0, strlen($removePath));
            if ($left == $removePath) {
                $to = substr($to, strlen($removePath));
            }
        }
        $to = '/'.trim($this->dir, '/').'/'.trim($to, '/');

        $result = @ftp_rename($this->handle, $from, $to);
        if (true !== $result) {
            return @rename($from, $to);
        } else {
            return true;
        }
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * FTP file writer.
 */
class AKPostprocSFTP extends AKAbstractPostproc
{
    /** @var bool Should I use FTP over implicit SSL? */
    public $useSSL = false;
    /** @var bool use Passive mode? */
    public $passive = true;
    /** @var string FTP host name */
    public $host = '';
    /** @var int FTP port */
    public $port = 21;
    /** @var string FTP user name */
    public $user = '';
    /** @var string FTP password */
    public $pass = '';
    /** @var string FTP initial directory */
    public $dir = '';

    /** @var resource SFTP resource handle */
    private $handle = null;

    /** @var resource SSH2 connection resource handle */
    private $_connection = null;

    /** @var string Current remote directory, including the remote directory string */
    private $_currentdir;

    /** @var string The temporary directory where the data will be stored */
    private $tempDir = '';

    public function __construct()
    {
        parent::__construct();

        $this->host = AKFactory::get('kickstart.ftp.host', '');
        $this->port = AKFactory::get('kickstart.ftp.port', 22);

        if ('' == trim($this->port)) {
            $this->port = 22;
        }

        $this->user    = AKFactory::get('kickstart.ftp.user', '');
        $this->pass    = AKFactory::get('kickstart.ftp.pass', '');
        $this->dir     = AKFactory::get('kickstart.ftp.dir', '');
        $this->tempDir = AKFactory::get('kickstart.ftp.tempdir', '');

        $connected = $this->connect();

        if ($connected) {
            if (!empty($this->tempDir)) {
                $tempDir  = rtrim($this->tempDir, '/\\').'/';
                $writable = $this->isDirWritable($tempDir);
            } else {
                $tempDir  = '';
                $writable = false;
            }

            if (!$writable) {
                // Default temporary directory is the current root
                $tempDir = KSROOTDIR;
                if (empty($tempDir)) {
                    // Oh, we have no directory reported!
                    $tempDir = '.';
                }
                $absoluteDirToHere = $tempDir;
                $tempDir           = rtrim(str_replace('\\', '/', $tempDir), '/');
                if (!empty($tempDir)) {
                    $tempDir .= '/';
                }
                $this->tempDir = $tempDir;
                // Is this directory writable?
                $writable = $this->isDirWritable($tempDir);
            }

            if (!$writable) {
                // Nope. Let's try creating a temporary directory in the site's root.
                $tempDir = $absoluteDirToHere.'/kicktemp';
                $this->createDirRecursive($tempDir, 0777);
                // Try making it writable...
                $this->fixPermissions($tempDir);
                $writable = $this->isDirWritable($tempDir);
            }

            // Was the new directory writable?
            if (!$writable) {
                // Let's see if the user has specified one
                $userdir = AKFactory::get('kickstart.ftp.tempdir', '');
                if (!empty($userdir)) {
                    // Is it an absolute or a relative directory?
                    $absolute = false;
                    $absolute = $absolute || ('/' == substr($userdir, 0, 1));
                    $absolute = $absolute || (':' == substr($userdir, 1, 1));
                    $absolute = $absolute || (':' == substr($userdir, 2, 1));
                    if (!$absolute) {
                        // Make absolute
                        $tempDir = $absoluteDirToHere.$userdir;
                    } else {
                        // it's already absolute
                        $tempDir = $userdir;
                    }
                    // Does the directory exist?
                    if (is_dir($tempDir)) {
                        // Yeah. Is it writable?
                        $writable = $this->isDirWritable($tempDir);
                    }
                }
            }
            $this->tempDir = $tempDir;

            if (!$writable) {
                // No writable directory found!!!
                $this->setError(AKText::_('SFTP_TEMPDIR_NOT_WRITABLE'));
            } else {
                AKFactory::set('kickstart.ftp.tempdir', $tempDir);
                $this->tempDir = $tempDir;
            }
        }
    }

    public function connect()
    {
        $this->_connection = false;

        if (!function_exists('ssh2_connect')) {
            $this->setError(AKText::_('SFTP_NO_SSH2'));

            return false;
        }

        $this->_connection = @ssh2_connect($this->host, $this->port);

        if (!@ssh2_auth_password($this->_connection, $this->user, $this->pass)) {
            $this->setError(AKText::_('SFTP_WRONG_USER'));

            $this->_connection = false;

            return false;
        }

        $this->handle = @ssh2_sftp($this->_connection);

        // I must have an absolute directory
        if (!$this->dir) {
            $this->setError(AKText::_('SFTP_WRONG_STARTING_DIR'));

            return false;
        }

        // Change to initial directory
        if (!$this->sftp_chdir('/')) {
            $this->setError(AKText::_('SFTP_WRONG_STARTING_DIR'));

            unset($this->_connection);
            unset($this->handle);

            return false;
        }

        // Try to download ourselves
        $testFilename = defined('KSSELFNAME') ? KSSELFNAME : basename(__FILE__);
        $basePath     = '/'.trim($this->dir, '/');

        if (false === @fopen("ssh2.sftp://{$this->handle}$basePath/$testFilename", 'r+')) {
            $this->setError(AKText::_('SFTP_WRONG_STARTING_DIR'));

            unset($this->_connection);
            unset($this->handle);

            return false;
        }

        return true;
    }

    /**
     * Changes to the requested directory in the remote server. You give only the
     * path relative to the initial directory and it does all the rest by itself,
     * including doing nothing if the remote directory is the one we want.
     *
     * @param string $dir The (realtive) remote directory
     *
     * @return bool true if successful, false otherwise
     */
    private function sftp_chdir($dir)
    {
        // Strip absolute filesystem path to website's root
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            // UNIXize the paths
            $removePath = str_replace('\\', '/', $removePath);
            $dir        = str_replace('\\', '/', $dir);

            // Make sure they both end in a slash
            $removePath = rtrim($removePath, '/\\').'/';
            $dir        = rtrim($dir, '/\\').'/';

            // Process the path removal
            $left = substr($dir, 0, strlen($removePath));

            if ($left == $removePath) {
                $dir = substr($dir, strlen($removePath));
            }
        }

        if (empty($dir)) {
            // Because the substr() above may return FALSE.
            $dir = '';
        }

        // Calculate "real" (absolute) SFTP path
        $realdir = '/' == substr($this->dir, -1) ? substr($this->dir, 0, strlen($this->dir) - 1) : $this->dir;
        $realdir .= '/'.$dir;
        $realdir = '/' == substr($realdir, 0, 1) ? $realdir : '/'.$realdir;

        if ($this->_currentdir == $realdir) {
            // Already there, do nothing
            return true;
        }

        $result = @ssh2_sftp_stat($this->handle, $realdir);

        if (false === $result) {
            return false;
        } else {
            // Update the private "current remote directory" variable
            $this->_currentdir = $realdir;

            return true;
        }
    }

    private function isDirWritable($dir)
    {
        if (false === @fopen("ssh2.sftp://{$this->handle}$dir/kickstart.dat", 'wb')) {
            return false;
        } else {
            @ssh2_sftp_unlink($this->handle, $dir.'/kickstart.dat');

            return true;
        }
    }

    public function createDirRecursive($dirName, $perms)
    {
        // Strip absolute filesystem path to website's root
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            // UNIXize the paths
            $removePath = str_replace('\\', '/', $removePath);
            $dirName    = str_replace('\\', '/', $dirName);
            // Make sure they both end in a slash
            $removePath = rtrim($removePath, '/\\').'/';
            $dirName    = rtrim($dirName, '/\\').'/';
            // Process the path removal
            $left = substr($dirName, 0, strlen($removePath));
            if ($left == $removePath) {
                $dirName = substr($dirName, strlen($removePath));
            }
        }
        if (empty($dirName)) {
            $dirName = '';
        } // 'cause the substr() above may return FALSE.

        $check = '/'.trim($this->dir, '/ ').'/'.trim($dirName, '/');

        if ($this->is_dir($check)) {
            return true;
        }

        $alldirs     = explode('/', $dirName);
        $previousDir = '/'.trim($this->dir, '/ ');

        foreach ($alldirs as $curdir) {
            if (!$curdir) {
                continue;
            }

            $check = $previousDir.'/'.$curdir;

            if (!$this->is_dir($check)) {
                // Proactively try to delete a file by the same name
                @ssh2_sftp_unlink($this->handle, $check);

                if (false === @ssh2_sftp_mkdir($this->handle, $check)) {
                    // If we couldn't create the directory, attempt to fix the permissions in the PHP level and retry!
                    $this->fixPermissions($check);

                    if (false === @ssh2_sftp_mkdir($this->handle, $check)) {
                        // Can we fall back to pure PHP mode, sire?
                        if (!@mkdir($check)) {
                            $this->setError(AKText::sprintf('FTP_CANT_CREATE_DIR', $check));

                            return false;
                        } else {
                            // Since the directory was built by PHP, change its permissions
                            @chmod($check, '0777');

                            return true;
                        }
                    }
                }

                @ssh2_sftp_chmod($this->handle, $check, $perms);
            }

            $previousDir = $check;
        }

        return true;
    }

    private function is_dir($dir)
    {
        return $this->sftp_chdir($dir);
    }

    private function fixPermissions($path)
    {
        // Turn off error reporting
        if (!defined('KSDEBUG')) {
            $oldErrorReporting = @error_reporting(E_NONE);
        }

        // Get UNIX style paths
        $relPath  = str_replace('\\', '/', $path);
        $basePath = rtrim(str_replace('\\', '/', KSROOTDIR), '/');
        $basePath = rtrim($basePath, '/');

        if (!empty($basePath)) {
            $basePath .= '/';
        }

        // Remove the leading relative root
        if (substr($relPath, 0, strlen($basePath)) == $basePath) {
            $relPath = substr($relPath, strlen($basePath));
        }

        $dirArray  = explode('/', $relPath);
        $pathBuilt = rtrim($basePath, '/');

        foreach ($dirArray as $dir) {
            if (empty($dir)) {
                continue;
            }

            $oldPath = $pathBuilt;
            $pathBuilt .= '/'.$dir;

            if (is_dir($oldPath.'/'.$dir)) {
                @chmod($oldPath.'/'.$dir, 0777);
            } else {
                if (false === @chmod($oldPath.'/'.$dir, 0777)) {
                    @unlink($oldPath.$dir);
                }
            }
        }

        // Restore error reporting
        if (!defined('KSDEBUG')) {
            @error_reporting($oldErrorReporting);
        }
    }

    public function __wakeup()
    {
        $this->connect();
    }

    /*
     * Tries to fix directory/file permissions in the PHP level, so that
     * the FTP operation doesn't fail.
     * @param $path string The full path to a directory or file
     */

    public function process()
    {
        if (is_null($this->tempFilename)) {
            // If an empty filename is passed, it means that we shouldn't do any post processing, i.e.
            // the entity was a directory or symlink
            return true;
        }

        $remotePath      = dirname($this->filename);
        $absoluteFSPath  = dirname($this->filename);
        $absoluteFTPPath = '/'.trim($this->dir, '/').'/'.trim($remotePath, '/');
        $onlyFilename    = basename($this->filename);

        $remoteName = $absoluteFTPPath.'/'.$onlyFilename;

        $ret = $this->sftp_chdir($absoluteFTPPath);

        if (false === $ret) {
            $ret = $this->createDirRecursive($absoluteFSPath, 0755);

            if (false === $ret) {
                $this->setError(AKText::sprintf('SFTP_COULDNT_UPLOAD', $this->filename));

                return false;
            }

            $ret = $this->sftp_chdir($absoluteFTPPath);

            if (false === $ret) {
                $this->setError(AKText::sprintf('SFTP_COULDNT_UPLOAD', $this->filename));

                return false;
            }
        }

        // Create the file
        $ret = $this->write($this->tempFilename, $remoteName);

        // If I got a -1 it means that I wasn't able to open the file, so I have to stop here
        if (-1 === $ret) {
            $this->setError(AKText::sprintf('SFTP_COULDNT_UPLOAD', $this->filename));

            return false;
        }

        if (false === $ret) {
            // If we couldn't create the file, attempt to fix the permissions in the PHP level and retry!
            $this->fixPermissions($this->filename);
            $this->unlink($this->filename);

            $ret = $this->write($this->tempFilename, $remoteName);
        }

        @unlink($this->tempFilename);

        if (false === $ret) {
            $this->setError(AKText::sprintf('SFTP_COULDNT_UPLOAD', $this->filename));

            return false;
        }
        $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false);

        if ($restorePerms) {
            $this->chmod($remoteName, $this->perms);
        } else {
            $this->chmod($remoteName, 0644);
        }

        return true;
    }

    private function write($local, $remote)
    {
        $fp      = @fopen("ssh2.sftp://{$this->handle}$remote", 'w');
        $localfp = @fopen($local, 'rb');

        if (false === $fp) {
            return -1;
        }

        if (false === $localfp) {
            @fclose($fp);

            return -1;
        }

        $res = true;

        while (!feof($localfp) && (false !== $res)) {
            $buffer = @fread($localfp, 65567);
            $res    = @fwrite($fp, $buffer);
        }

        @fclose($fp);
        @fclose($localfp);

        return $res;
    }

    public function unlink($file)
    {
        $check = '/'.trim($this->dir, '/').'/'.trim($file, '/');

        return @ssh2_sftp_unlink($this->handle, $check);
    }

    public function chmod($file, $perms)
    {
        return @ssh2_sftp_chmod($this->handle, $file, $perms);
    }

    public function processFilename($filename, $perms = 0755)
    {
        // Catch some error conditions...
        if ($this->getError()) {
            return false;
        }

        // If a null filename is passed, it means that we shouldn't do any post processing, i.e.
        // the entity was a directory or symlink
        if (is_null($filename)) {
            $this->filename     = null;
            $this->tempFilename = null;

            return null;
        }

        // Strip absolute filesystem path to website's root
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        if (!empty($removePath)) {
            $left = substr($filename, 0, strlen($removePath));
            if ($left == $removePath) {
                $filename = substr($filename, strlen($removePath));
            }
        }

        // Trim slash on the left
        $filename = ltrim($filename, '/');

        $this->filename     = $filename;
        $this->tempFilename = tempnam($this->tempDir, 'kickstart-');
        $this->perms        = $perms;

        if (empty($this->tempFilename)) {
            // Oops! Let's try something different
            $this->tempFilename = $this->tempDir.'/kickstart-'.time().'.dat';
        }

        return $this->tempFilename;
    }

    public function close()
    {
        unset($this->_connection);
        unset($this->handle);
    }

    public function rmdir($directory)
    {
        $check = '/'.trim($this->dir, '/').'/'.trim($directory, '/');

        return @ssh2_sftp_rmdir($this->handle, $check);
    }

    public function rename($from, $to)
    {
        $from = '/'.trim($this->dir, '/').'/'.trim($from, '/');
        $to   = '/'.trim($this->dir, '/').'/'.trim($to, '/');

        $result = @ssh2_sftp_rename($this->handle, $from, $to);

        if (true !== $result) {
            return @rename($from, $to);
        } else {
            return true;
        }
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * Hybrid direct / FTP mode file writer.
 */
class AKPostprocHybrid extends AKAbstractPostproc
{
    /** @var bool Should I use the FTP layer? */
    public $useFTP = false;

    /** @var bool Should I use FTP over implicit SSL? */
    public $useSSL = false;

    /** @var bool use Passive mode? */
    public $passive = true;

    /** @var string FTP host name */
    public $host = '';

    /** @var int FTP port */
    public $port = 21;

    /** @var string FTP user name */
    public $user = '';

    /** @var string FTP password */
    public $pass = '';

    /** @var string FTP initial directory */
    public $dir = '';

    /** @var resource The FTP handle */
    private $handle = null;

    /** @var string The temporary directory where the data will be stored */
    private $tempDir = '';

    /** @var null The FTP connection handle */
    private $_handle = null;

    /**
     * Public constructor. Tries to connect to the FTP server.
     */
    public function __construct()
    {
        parent::__construct();

        $this->useFTP  = true;
        $this->useSSL  = AKFactory::get('kickstart.ftp.ssl', false);
        $this->passive = AKFactory::get('kickstart.ftp.passive', true);
        $this->host    = AKFactory::get('kickstart.ftp.host', '');
        $this->port    = AKFactory::get('kickstart.ftp.port', 21);
        $this->user    = AKFactory::get('kickstart.ftp.user', '');
        $this->pass    = AKFactory::get('kickstart.ftp.pass', '');
        $this->dir     = AKFactory::get('kickstart.ftp.dir', '');
        $this->tempDir = AKFactory::get('kickstart.ftp.tempdir', '');

        if ('' == trim($this->port)) {
            $this->port = 21;
        }

        // If FTP is not configured, skip it altogether
        if (empty($this->host) || empty($this->user) || empty($this->pass)) {
            $this->useFTP = false;
        }

        // Try to connect to the FTP server
        $connected = $this->connect();

        // If the connection fails, skip FTP altogether
        if (!$connected) {
            $this->useFTP = false;
        }

        if ($connected) {
            if (!empty($this->tempDir)) {
                $tempDir  = rtrim($this->tempDir, '/\\').'/';
                $writable = $this->isDirWritable($tempDir);
            } else {
                $tempDir  = '';
                $writable = false;
            }

            if (!$writable) {
                // Default temporary directory is the current root
                $tempDir = KSROOTDIR;
                if (empty($tempDir)) {
                    // Oh, we have no directory reported!
                    $tempDir = '.';
                }
                $absoluteDirToHere = $tempDir;
                $tempDir           = rtrim(str_replace('\\', '/', $tempDir), '/');
                if (!empty($tempDir)) {
                    $tempDir .= '/';
                }
                $this->tempDir = $tempDir;
                // Is this directory writable?
                $writable = $this->isDirWritable($tempDir);
            }

            if (!$writable) {
                // Nope. Let's try creating a temporary directory in the site's root.
                $tempDir = $absoluteDirToHere.'/kicktemp';
                $this->createDirRecursive($tempDir, 0777);
                // Try making it writable...
                $this->fixPermissions($tempDir);
                $writable = $this->isDirWritable($tempDir);
            }

            // Was the new directory writable?
            if (!$writable) {
                // Let's see if the user has specified one
                $userdir = AKFactory::get('kickstart.ftp.tempdir', '');
                if (!empty($userdir)) {
                    // Is it an absolute or a relative directory?
                    $absolute = false;
                    $absolute = $absolute || ('/' == substr($userdir, 0, 1));
                    $absolute = $absolute || (':' == substr($userdir, 1, 1));
                    $absolute = $absolute || (':' == substr($userdir, 2, 1));
                    if (!$absolute) {
                        // Make absolute
                        $tempDir = $absoluteDirToHere.$userdir;
                    } else {
                        // it's already absolute
                        $tempDir = $userdir;
                    }
                    // Does the directory exist?
                    if (is_dir($tempDir)) {
                        // Yeah. Is it writable?
                        $writable = $this->isDirWritable($tempDir);
                    }
                }
            }
            $this->tempDir = $tempDir;

            if (!$writable) {
                // No writable directory found!!!
                $this->setError(AKText::_('FTP_TEMPDIR_NOT_WRITABLE'));
            } else {
                AKFactory::set('kickstart.ftp.tempdir', $tempDir);
                $this->tempDir = $tempDir;
            }
        }
    }

    /**
     * Tries to connect to the FTP server.
     *
     * @return bool
     */
    public function connect()
    {
        if (!$this->useFTP) {
            return false;
        }

        // Connect to server, using SSL if so required
        if ($this->useSSL) {
            $this->handle = @ftp_ssl_connect($this->host, $this->port);
        } else {
            $this->handle = @ftp_connect($this->host, $this->port);
        }
        if (false === $this->handle) {
            $this->setError(AKText::_('WRONG_FTP_HOST'));

            return false;
        }

        // Login
        if (!@ftp_login($this->handle, $this->user, $this->pass)) {
            $this->setError(AKText::_('WRONG_FTP_USER'));
            @ftp_close($this->handle);

            return false;
        }

        // Change to initial directory
        if (!@ftp_chdir($this->handle, $this->dir)) {
            $this->setError(AKText::_('WRONG_FTP_PATH1'));
            @ftp_close($this->handle);

            return false;
        }

        // Enable passive mode if the user requested it
        if ($this->passive) {
            @ftp_pasv($this->handle, true);
        } else {
            @ftp_pasv($this->handle, false);
        }

        // Try to download ourselves
        $testFilename = defined('KSSELFNAME') ? KSSELFNAME : basename(__FILE__);
        $tempHandle   = fopen('php://temp', 'r+');

        if (false === @ftp_fget($this->handle, $tempHandle, $testFilename, FTP_ASCII, 0)) {
            $this->setError(AKText::_('WRONG_FTP_PATH2'));
            @ftp_close($this->handle);
            fclose($tempHandle);

            return false;
        }

        fclose($tempHandle);

        return true;
    }

    /**
     * Is the directory writeable?
     *
     * @param string $dir The directory ti check
     *
     * @return bool
     */
    private function isDirWritable($dir)
    {
        $fp = @fopen($dir.'/kickstart.dat', 'wb');

        if (false === $fp) {
            return false;
        }

        @fclose($fp);
        unlink($dir.'/kickstart.dat');

        return true;
    }

    /**
     * Create a directory, recursively.
     *
     * @param string $dirName The directory to create
     * @param int    $perms   The permissions to give to the directory
     *
     * @return bool
     */
    public function createDirRecursive($dirName, $perms)
    {
        // Strip absolute filesystem path to website's root
        $removePath = AKFactory::get('kickstart.setup.destdir', '');

        if (!empty($removePath)) {
            // UNIXize the paths
            $removePath = str_replace('\\', '/', $removePath);
            $dirName    = str_replace('\\', '/', $dirName);
            // Make sure they both end in a slash
            $removePath = rtrim($removePath, '/\\').'/';
            $dirName    = rtrim($dirName, '/\\').'/';
            // Process the path removal
            $left = substr($dirName, 0, strlen($removePath));

            if ($left == $removePath) {
                $dirName = substr($dirName, strlen($removePath));
            }
        }

        // 'cause the substr() above may return FALSE.
        if (empty($dirName)) {
            $dirName = '';
        }

        $check   = '/'.trim($this->dir, '/').'/'.trim($dirName, '/');
        $checkFS = $removePath.trim($dirName, '/');

        if ($this->is_dir($check)) {
            return true;
        }

        $alldirs       = explode('/', $dirName);
        $previousDir   = '/'.trim($this->dir);
        $previousDirFS = rtrim($removePath, '/\\');

        foreach ($alldirs as $curdir) {
            $check   = $previousDir.'/'.$curdir;
            $checkFS = $previousDirFS.'/'.$curdir;

            if (!is_dir($checkFS) && !$this->is_dir($check)) {
                // Proactively try to delete a file by the same name
                if (!@unlink($checkFS) && $this->useFTP) {
                    @ftp_delete($this->handle, $check);
                }

                $createdDir = @mkdir($checkFS, 0755);

                if (!$createdDir && $this->useFTP) {
                    $createdDir = @ftp_mkdir($this->handle, $check);
                }

                if (false === $createdDir) {
                    // If we couldn't create the directory, attempt to fix the permissions in the PHP level and retry!
                    $this->fixPermissions($checkFS);

                    $createdDir = @mkdir($checkFS, 0755);
                    if (!$createdDir && $this->useFTP) {
                        $createdDir = @ftp_mkdir($this->handle, $check);
                    }

                    if (false === $createdDir) {
                        $this->setError(AKText::sprintf('FTP_CANT_CREATE_DIR', $check));

                        return false;
                    }
                }

                if (!@chmod($checkFS, $perms) && $this->useFTP) {
                    @ftp_chmod($this->handle, $perms, $check);
                }
            }

            $previousDir   = $check;
            $previousDirFS = $checkFS;
        }

        return true;
    }

    private function is_dir($dir)
    {
        if ($this->useFTP) {
            return @ftp_chdir($this->handle, $dir);
        }

        return false;
    }

    /**
     * Tries to fix directory/file permissions in the PHP level, so that
     * the FTP operation doesn't fail.
     *
     * @param $path string The full path to a directory or file
     */
    private function fixPermissions($path)
    {
        // Turn off error reporting
        if (!defined('KSDEBUG')) {
            $oldErrorReporting = @error_reporting(E_NONE);
        }

        // Get UNIX style paths
        $relPath  = str_replace('\\', '/', $path);
        $basePath = rtrim(str_replace('\\', '/', KSROOTDIR), '/');
        $basePath = rtrim($basePath, '/');

        if (!empty($basePath)) {
            $basePath .= '/';
        }

        // Remove the leading relative root
        if (substr($relPath, 0, strlen($basePath)) == $basePath) {
            $relPath = substr($relPath, strlen($basePath));
        }

        $dirArray  = explode('/', $relPath);
        $pathBuilt = rtrim($basePath, '/');

        foreach ($dirArray as $dir) {
            if (empty($dir)) {
                continue;
            }

            $oldPath = $pathBuilt;
            $pathBuilt .= '/'.$dir;

            if (is_dir($oldPath.$dir)) {
                @chmod($oldPath.$dir, 0777);
            } else {
                if (false === @chmod($oldPath.$dir, 0777)) {
                    @unlink($oldPath.$dir);
                }
            }
        }

        // Restore error reporting
        if (!defined('KSDEBUG')) {
            @error_reporting($oldErrorReporting);
        }
    }

    /**
     * Called after unserialisation, tries to reconnect to FTP.
     */
    public function __wakeup()
    {
        if ($this->useFTP) {
            $this->connect();
        }
    }

    public function __destruct()
    {
        if (!$this->useFTP) {
            @ftp_close($this->handle);
        }
    }

    /**
     * Post-process an extracted file, using FTP or direct file writes to move it.
     *
     * @return bool
     */
    public function process()
    {
        if (is_null($this->tempFilename)) {
            // If an empty filename is passed, it means that we shouldn't do any post processing, i.e.
            // the entity was a directory or symlink
            return true;
        }

        $remotePath = dirname($this->filename);
        $removePath = AKFactory::get('kickstart.setup.destdir', '');
        $root       = rtrim($removePath, '/\\');

        if (!empty($removePath)) {
            $removePath = ltrim($removePath, '/');
            $remotePath = ltrim($remotePath, '/');
            $left       = substr($remotePath, 0, strlen($removePath));

            if ($left == $removePath) {
                $remotePath = substr($remotePath, strlen($removePath));
            }
        }

        $absoluteFSPath  = dirname($this->filename);
        $relativeFTPPath = trim($remotePath, '/');
        $absoluteFTPPath = '/'.trim($this->dir, '/').'/'.trim($remotePath, '/');
        $onlyFilename    = basename($this->filename);

        $remoteName = $absoluteFTPPath.'/'.$onlyFilename;

        // Does the directory exist?
        if (!is_dir($root.'/'.$absoluteFSPath)) {
            $ret = $this->createDirRecursive($absoluteFSPath, 0755);

            if ((false === $ret) && ($this->useFTP)) {
                $ret = @ftp_chdir($this->handle, $absoluteFTPPath);
            }

            if (false === $ret) {
                $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename));

                return false;
            }
        }

        if ($this->useFTP) {
            $ret = @ftp_chdir($this->handle, $absoluteFTPPath);
        }

        // Try copying directly
        $ret = @copy($this->tempFilename, $root.'/'.$this->filename);

        if (false === $ret) {
            $this->fixPermissions($this->filename);
            $this->unlink($this->filename);

            $ret = @copy($this->tempFilename, $root.'/'.$this->filename);
        }

        if ($this->useFTP && (false === $ret)) {
            $ret = @ftp_put($this->handle, $remoteName, $this->tempFilename, FTP_BINARY);

            if (false === $ret) {
                // If we couldn't create the file, attempt to fix the permissions in the PHP level and retry!
                $this->fixPermissions($this->filename);
                $this->unlink($this->filename);

                $fp = @fopen($this->tempFilename, 'rb');
                if (false !== $fp) {
                    $ret = @ftp_fput($this->handle, $remoteName, $fp, FTP_BINARY);
                    @fclose($fp);
                } else {
                    $ret = false;
                }
            }
        }

        @unlink($this->tempFilename);

        if (false === $ret) {
            $this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename));

            return false;
        }

        $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false);
        $perms        = $restorePerms ? $this->perms : 0644;

        $ret = @chmod($root.'/'.$this->filename, $perms);

        if ($this->useFTP && (false === $ret)) {
            @ftp_chmod($this->_handle, $perms, $remoteName);
        }

        return true;
    }

    public function unlink($file)
    {
        $ret = @unlink($file);

        if (!$ret && $this->useFTP) {
            $removePath = AKFactory::get('kickstart.setup.destdir', '');
            if (!empty($removePath)) {
                $left = substr($file, 0, strlen($removePath));
                if ($left == $removePath) {
                    $file = substr($file, strlen($removePath));
                }
            }

            $check = '/'.trim($this->dir, '/').'/'.trim($file, '/');

            $ret = @ftp_delete($this->handle, $check);
        }

        return $ret;
    }

    /**
     * Create a temporary filename.
     *
     * @param string $filename The original filename
     * @param int    $perms    The file permissions
     *
     * @return string
     */
    public function processFilename($filename, $perms = 0755)
    {
        // Catch some error conditions...
        if ($this->getError()) {
            return false;
        }

        // If a null filename is passed, it means that we shouldn't do any post processing, i.e.
        // the entity was a directory or symlink
        if (is_null($filename)) {
            $this->filename     = null;
            $this->tempFilename = null;

            return null;
        }

        // Strip absolute filesystem path to website's root
        $removePath = AKFactory::get('kickstart.setup.destdir', '');

        if (!empty($removePath)) {
            $left = substr($filename, 0, strlen($removePath));

            if ($left == $removePath) {
                $filename = substr($filename, strlen($removePath));
            }
        }

        // Trim slash on the left
        $filename = ltrim($filename, '/');

        $this->filename     = $filename;
        $this->tempFilename = tempnam($this->tempDir, 'kickstart-');
        $this->perms        = $perms;

        if (empty($this->tempFilename)) {
            // Oops! Let's try something different
            $this->tempFilename = $this->tempDir.'/kickstart-'.time().'.dat';
        }

        return $this->tempFilename;
    }

    /**
     * Closes the FTP connection.
     */
    public function close()
    {
        if (!$this->useFTP) {
            @ftp_close($this->handle);
        }
    }

    public function chmod($file, $perms)
    {
        if (AKFactory::get('kickstart.setup.dryrun', '0')) {
            return true;
        }

        $ret = @chmod($file, $perms);

        if (!$ret && $this->useFTP) {
            // Strip absolute filesystem path to website's root
            $removePath = AKFactory::get('kickstart.setup.destdir', '');

            if (!empty($removePath)) {
                $left = substr($file, 0, strlen($removePath));

                if ($left == $removePath) {
                    $file = substr($file, strlen($removePath));
                }
            }

            // Trim slash on the left
            $file = ltrim($file, '/');

            $ret = @ftp_chmod($this->handle, $perms, $file);
        }

        return $ret;
    }

    public function rmdir($directory)
    {
        $ret = @rmdir($directory);

        if (!$ret && $this->useFTP) {
            $removePath = AKFactory::get('kickstart.setup.destdir', '');
            if (!empty($removePath)) {
                $left = substr($directory, 0, strlen($removePath));
                if ($left == $removePath) {
                    $directory = substr($directory, strlen($removePath));
                }
            }

            $check = '/'.trim($this->dir, '/').'/'.trim($directory, '/');

            $ret = @ftp_rmdir($this->handle, $check);
        }

        return $ret;
    }

    public function rename($from, $to)
    {
        $ret = @rename($from, $to);

        if (!$ret && $this->useFTP) {
            $originalFrom = $from;
            $originalTo   = $to;

            $removePath = AKFactory::get('kickstart.setup.destdir', '');
            if (!empty($removePath)) {
                $left = substr($from, 0, strlen($removePath));
                if ($left == $removePath) {
                    $from = substr($from, strlen($removePath));
                }
            }
            $from = '/'.trim($this->dir, '/').'/'.trim($from, '/');

            if (!empty($removePath)) {
                $left = substr($to, 0, strlen($removePath));
                if ($left == $removePath) {
                    $to = substr($to, strlen($removePath));
                }
            }
            $to = '/'.trim($this->dir, '/').'/'.trim($to, '/');

            $ret = @ftp_rename($this->handle, $from, $to);
        }

        return $ret;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * JPA archive extraction class.
 */
class AKUnarchiverJPA extends AKAbstractUnarchiver
{
    protected $archiveHeaderData = array();

    protected function readArchiveHeader()
    {
        debugMsg('Preparing to read archive header');
        // Initialize header data array
        $this->archiveHeaderData = new stdClass();

        // Open the first part
        debugMsg('Opening the first part');
        $this->nextFile();

        // Fail for unreadable files
        if (false === $this->fp) {
            debugMsg('Could not open the first part');

            return false;
        }

        // Read the signature
        $sig = fread($this->fp, 3);

        if ('JPA' != $sig) {
            // Not a JPA file
            debugMsg('Invalid archive signature');
            $this->setError(AKText::_('ERR_NOT_A_JPA_FILE'));

            return false;
        }

        // Read and parse header length
        $header_length_array = unpack('v', fread($this->fp, 2));
        $header_length       = $header_length_array[1];

        // Read and parse the known portion of header data (14 bytes)
        $bin_data    = fread($this->fp, 14);
        $header_data = unpack('Cmajor/Cminor/Vcount/Vuncsize/Vcsize', $bin_data);

        // Load any remaining header data (forward compatibility)
        $rest_length = $header_length - 19;
        if ($rest_length > 0) {
            $junk = fread($this->fp, $rest_length);
        } else {
            $junk = '';
        }

        // Temporary array with all the data we read
        $temp = array(
            'signature'        => $sig,
            'length'           => $header_length,
            'major'            => $header_data['major'],
            'minor'            => $header_data['minor'],
            'filecount'        => $header_data['count'],
            'uncompressedsize' => $header_data['uncsize'],
            'compressedsize'   => $header_data['csize'],
            'unknowndata'      => $junk,
        );
        // Array-to-object conversion
        foreach ($temp as $key => $value) {
            $this->archiveHeaderData->{$key} = $value;
        }

        debugMsg('Header data:');
        debugMsg('Length              : '.$header_length);
        debugMsg('Major               : '.$header_data['major']);
        debugMsg('Minor               : '.$header_data['minor']);
        debugMsg('File count          : '.$header_data['count']);
        debugMsg('Uncompressed size   : '.$header_data['uncsize']);
        debugMsg('Compressed size	  : '.$header_data['csize']);

        $this->currentPartOffset = @ftell($this->fp);

        $this->dataReadLength = 0;

        return true;
    }

    /**
     * Concrete classes must use this method to read the file header.
     *
     * @return bool True if reading the file was successful, false if an error occured or we reached end of archive
     */
    protected function readFileHeader()
    {
        // If the current part is over, proceed to the next part please
        if ($this->isEOF(true)) {
            debugMsg('Archive part EOF; moving to next file');
            $this->nextFile();
        }

        debugMsg('Reading file signature');
        // Get and decode Entity Description Block
        $signature = fread($this->fp, 3);

        $this->fileHeader            = new stdClass();
        $this->fileHeader->timestamp = 0;

        // Check signature
        if ('JPF' != $signature) {
            if ($this->isEOF(true)) {
                // This file is finished; make sure it's the last one
                $this->nextFile();
                if (!$this->isEOF(false)) {
                    debugMsg('Invalid file signature before end of archive encountered');
                    $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset));

                    return false;
                }

                // We're just finished
                return false;
            } else {
                $screwed = true;
                if (AKFactory::get('kickstart.setup.ignoreerrors', false)) {
                    debugMsg('Invalid file block signature; launching heuristic file block signature scanner');
                    $screwed = !$this->heuristicFileHeaderLocator();
                    if (!$screwed) {
                        $signature = 'JPF';
                    } else {
                        debugMsg('Heuristics failed. Brace yourself for the imminent crash.');
                    }
                }
                if ($screwed) {
                    debugMsg('Invalid file block signature');
                    // This is not a file block! The archive is corrupt.
                    $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset));

                    return false;
                }
            }
        }
        // This a JPA Entity Block. Process the header.

        $isBannedFile = false;

        // Read length of EDB and of the Entity Path Data
        $length_array = unpack('vblocksize/vpathsize', fread($this->fp, 4));
        // Read the path data
        if ($length_array['pathsize'] > 0) {
            $file = fread($this->fp, $length_array['pathsize']);
        } else {
            $file = '';
        }

        // Handle file renaming
        $isRenamed = false;
        if (is_array($this->renameFiles) && (count($this->renameFiles) > 0)) {
            if (array_key_exists($file, $this->renameFiles)) {
                $file      = $this->renameFiles[$file];
                $isRenamed = true;
            }
        }

        // Handle directory renaming
        $isDirRenamed = false;
        if (is_array($this->renameDirs) && (count($this->renameDirs) > 0)) {
            if (array_key_exists(dirname($file), $this->renameDirs)) {
                $file         = rtrim($this->renameDirs[dirname($file)], '/').'/'.basename($file);
                $isRenamed    = true;
                $isDirRenamed = true;
            }
        }

        // Read and parse the known data portion
        $bin_data    = fread($this->fp, 14);
        $header_data = unpack('Ctype/Ccompression/Vcompsize/Vuncompsize/Vperms', $bin_data);
        // Read any unknown data
        $restBytes = $length_array['blocksize'] - (21 + $length_array['pathsize']);
        if ($restBytes > 0) {
            // Start reading the extra fields
            while ($restBytes >= 4) {
                $extra_header_data = fread($this->fp, 4);
                $extra_header      = unpack('vsignature/vlength', $extra_header_data);
                $restBytes -= 4;
                $extra_header['length'] -= 4;
                switch ($extra_header['signature']) {
                    case 256:
                        // File modified timestamp
                        if ($extra_header['length'] > 0) {
                            $bindata = fread($this->fp, $extra_header['length']);
                            $restBytes -= $extra_header['length'];
                            $timestamps                  = unpack('Vmodified', substr($bindata, 0, 4));
                            $filectime                   = $timestamps['modified'];
                            $this->fileHeader->timestamp = $filectime;
                        }
                        break;

                    default:
                        // Unknown field
                        if ($extra_header['length'] > 0) {
                            $junk = fread($this->fp, $extra_header['length']);
                            $restBytes -= $extra_header['length'];
                        }
                        break;
                }
            }
            if ($restBytes > 0) {
                $junk = fread($this->fp, $restBytes);
            }
        }

        $compressionType = $header_data['compression'];

        // Populate the return array
        $this->fileHeader->file         = $file;
        $this->fileHeader->compressed   = $header_data['compsize'];
        $this->fileHeader->uncompressed = $header_data['uncompsize'];
        switch ($header_data['type']) {
            case 0:
                $this->fileHeader->type = 'dir';
                break;

            case 1:
                $this->fileHeader->type = 'file';
                break;

            case 2:
                $this->fileHeader->type = 'link';
                break;
        }
        switch ($compressionType) {
            case 0:
                $this->fileHeader->compression = 'none';
                break;
            case 1:
                $this->fileHeader->compression = 'gzip';
                break;
            case 2:
                $this->fileHeader->compression = 'bzip2';
                break;
        }
        $this->fileHeader->permissions = $header_data['perms'];

        // Find hard-coded banned files
        if (('.' == basename($this->fileHeader->file)) || ('..' == basename($this->fileHeader->file))) {
            $isBannedFile = true;
        }

        // Also try to find banned files passed in class configuration
        if ((count($this->skipFiles) > 0) && (!$isRenamed)) {
            if (in_array($this->fileHeader->file, $this->skipFiles)) {
                $isBannedFile = true;
            }
        }

        // If we have a banned file, let's skip it
        if ($isBannedFile) {
            debugMsg('Skipping file '.$this->fileHeader->file);
            // Advance the file pointer, skipping exactly the size of the compressed data
            $seekleft = $this->fileHeader->compressed;
            while ($seekleft > 0) {
                // Ensure that we can seek past archive part boundaries
                $curSize = @filesize($this->archiveList[$this->currentPartNumber]);
                $curPos  = @ftell($this->fp);
                $canSeek = $curSize - $curPos;
                if ($canSeek > $seekleft) {
                    $canSeek = $seekleft;
                }
                @fseek($this->fp, $canSeek, SEEK_CUR);
                $seekleft -= $canSeek;
                if ($seekleft) {
                    $this->nextFile();
                }
            }

            $this->currentPartOffset = @ftell($this->fp);
            $this->runState          = AK_STATE_DONE;

            return true;
        }

        // Last chance to prepend a path to the filename
        if (!empty($this->addPath) && !$isDirRenamed) {
            $this->fileHeader->file = $this->addPath.$this->fileHeader->file;
        }

        // Get the translated path name
        $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false);
        if ('file' == $this->fileHeader->type) {
            // Regular file; ask the postproc engine to process its filename
            if ($restorePerms) {
                $this->fileHeader->realFile = $this->postProcEngine->processFilename($this->fileHeader->file, $this->fileHeader->permissions);
            } else {
                $this->fileHeader->realFile = $this->postProcEngine->processFilename($this->fileHeader->file);
            }
        } elseif ('dir' == $this->fileHeader->type) {
            $dir = $this->fileHeader->file;

            // Directory; just create it
            if ($restorePerms) {
                $this->postProcEngine->createDirRecursive($this->fileHeader->file, $this->fileHeader->permissions);
            } else {
                $this->postProcEngine->createDirRecursive($this->fileHeader->file, 0755);
            }
            $this->postProcEngine->processFilename(null);
        } else {
            // Symlink; do not post-process
            $this->postProcEngine->processFilename(null);
        }

        $this->createDirectory();

        // Header is read
        $this->runState = AK_STATE_HEADER;

        $this->dataReadLength = 0;

        return true;
    }

    protected function heuristicFileHeaderLocator()
    {
        $ret     = false;
        $fullEOF = false;

        while (!$ret && !$fullEOF) {
            $this->currentPartOffset = @ftell($this->fp);
            if ($this->isEOF(true)) {
                $this->nextFile();
            }

            if ($this->isEOF(false)) {
                $fullEOF = true;
                continue;
            }

            // Read 512Kb
            $chunk     = fread($this->fp, 524288);
            $size_read = mb_strlen($chunk, '8bit');
            //$pos = strpos($chunk, 'JPF');
            $pos = mb_strpos($chunk, 'JPF', 0, '8bit');
            if (false !== $pos) {
                // We found it!
                $this->currentPartOffset += $pos + 3;
                @fseek($this->fp, $this->currentPartOffset, SEEK_SET);
                $ret = true;
            } else {
                // Not yet found :(
                $this->currentPartOffset = @ftell($this->fp);
            }
        }

        return $ret;
    }

    /**
     * Creates the directory this file points to.
     */
    protected function createDirectory()
    {
        if (AKFactory::get('kickstart.setup.dryrun', '0')) {
            return true;
        }

        // Do we need to create a directory?
        if (empty($this->fileHeader->realFile)) {
            $this->fileHeader->realFile = $this->fileHeader->file;
        }
        $lastSlash = strrpos($this->fileHeader->realFile, '/');
        $dirName   = substr($this->fileHeader->realFile, 0, $lastSlash);
        $perms     = $this->flagRestorePermissions ? $this->fileHeader->permissions : 0755;
        $ignore    = AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($dirName);
        if ((false == $this->postProcEngine->createDirRecursive($dirName, $perms)) && (!$ignore)) {
            $this->setError(AKText::sprintf('COULDNT_CREATE_DIR', $dirName));

            return false;
        } else {
            return true;
        }
    }

    /**
     * Concrete classes must use this method to process file data. It must set $runState to AK_STATE_DATAREAD when
     * it's finished processing the file data.
     *
     * @return bool True if processing the file data was successful, false if an error occured
     */
    protected function processFileData()
    {
        switch ($this->fileHeader->type) {
            case 'dir':
                return $this->processTypeDir();
                break;

            case 'link':
                return $this->processTypeLink();
                break;

            case 'file':
                switch ($this->fileHeader->compression) {
                    case 'none':
                        return $this->processTypeFileUncompressed();
                        break;

                    case 'gzip':
                    case 'bzip2':
                        return $this->processTypeFileCompressedSimple();
                        break;
                }
                break;

            default:
                debugMsg('Unknown file type '.$this->fileHeader->type);
                break;
        }
    }

    /**
     * Process the file data of a directory entry.
     *
     * @return bool
     */
    private function processTypeDir()
    {
        // Directory entries in the JPA do not have file data, therefore we're done processing the entry
        $this->runState = AK_STATE_DATAREAD;

        return true;
    }

    /**
     * Process the file data of a link entry.
     *
     * @return bool
     */
    private function processTypeLink()
    {
        $readBytes   = 0;
        $toReadBytes = 0;
        $leftBytes   = $this->fileHeader->compressed;
        $data        = '';

        while ($leftBytes > 0) {
            $toReadBytes     = ($leftBytes > $this->chunkSize) ? $this->chunkSize : $leftBytes;
            $mydata          = $this->fread($this->fp, $toReadBytes);
            $reallyReadBytes = akstringlen($mydata);
            $data .= $mydata;
            $leftBytes -= $reallyReadBytes;
            if ($reallyReadBytes < $toReadBytes) {
                // We read less than requested! Why? Did we hit local EOF?
                if ($this->isEOF(true) && !$this->isEOF(false)) {
                    // Yeap. Let's go to the next file
                    $this->nextFile();
                } else {
                    debugMsg('End of local file before reading all data with no more parts left. The archive is corrupt or truncated.');
                    // Nope. The archive is corrupt
                    $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                    return false;
                }
            }
        }

        // Try to remove an existing file or directory by the same name
        if (file_exists($this->fileHeader->realFile)) {
            @unlink($this->fileHeader->realFile);
            @rmdir($this->fileHeader->realFile);
        }
        // Remove any trailing slash
        if ('/' == substr($this->fileHeader->realFile, -1)) {
            $this->fileHeader->realFile = substr($this->fileHeader->realFile, 0, -1);
        }
        // Create the symlink - only possible within PHP context. There's no support built in the FTP protocol, so no postproc use is possible here :(
        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            @symlink($data, $this->fileHeader->realFile);
        }

        $this->runState = AK_STATE_DATAREAD;

        return true; // No matter if the link was created!
    }

    private function processTypeFileUncompressed()
    {
        // Uncompressed files are being processed in small chunks, to avoid timeouts
        if ((0 == $this->dataReadLength) && !AKFactory::get('kickstart.setup.dryrun', '0')) {
            // Before processing file data, ensure permissions are adequate
            $this->setCorrectPermissions($this->fileHeader->file);
        }

        // Open the output file
        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);
            if (0 == $this->dataReadLength) {
                $outfp = @fopen($this->fileHeader->realFile, 'wb');
            } else {
                $outfp = @fopen($this->fileHeader->realFile, 'ab');
            }

            // Can we write to the file?
            if ((false === $outfp) && (!$ignore)) {
                // An error occured
                debugMsg('Could not write to output file');
                $this->setError(AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile));

                return false;
            }
        }

        // Does the file have any data, at all?
        if (0 == $this->fileHeader->compressed) {
            // No file data!
            if (!AKFactory::get('kickstart.setup.dryrun', '0') && is_resource($outfp)) {
                @fclose($outfp);
            }
            $this->runState = AK_STATE_DATAREAD;

            return true;
        }

        // Reference to the global timer
        $timer = AKFactory::getTimer();

        $toReadBytes = 0;
        $leftBytes   = $this->fileHeader->compressed - $this->dataReadLength;

        // Loop while there's data to read and enough time to do it
        while (($leftBytes > 0) && ($timer->getTimeLeft() > 0)) {
            $toReadBytes     = ($leftBytes > $this->chunkSize) ? $this->chunkSize : $leftBytes;
            $data            = $this->fread($this->fp, $toReadBytes);
            $reallyReadBytes = akstringlen($data);
            $leftBytes -= $reallyReadBytes;
            $this->dataReadLength += $reallyReadBytes;
            if ($reallyReadBytes < $toReadBytes) {
                // We read less than requested! Why? Did we hit local EOF?
                if ($this->isEOF(true) && !$this->isEOF(false)) {
                    // Yeap. Let's go to the next file
                    $this->nextFile();
                } else {
                    // Nope. The archive is corrupt
                    debugMsg('Not enough data in file. The archive is truncated or corrupt.');
                    $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                    return false;
                }
            }
            if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
                if (is_resource($outfp)) {
                    @fwrite($outfp, $data);
                }
            }
        }

        // Close the file pointer
        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            if (is_resource($outfp)) {
                @fclose($outfp);
            }
        }

        // Was this a pre-timeout bail out?
        if ($leftBytes > 0) {
            $this->runState = AK_STATE_DATA;
        } else {
            // Oh! We just finished!
            $this->runState       = AK_STATE_DATAREAD;
            $this->dataReadLength = 0;
        }

        return true;
    }

    private function processTypeFileCompressedSimple()
    {
        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            // Before processing file data, ensure permissions are adequate
            $this->setCorrectPermissions($this->fileHeader->file);

            // Open the output file
            $outfp = @fopen($this->fileHeader->realFile, 'wb');

            // Can we write to the file?
            $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);
            if ((false === $outfp) && (!$ignore)) {
                // An error occured
                debugMsg('Could not write to output file');
                $this->setError(AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile));

                return false;
            }
        }

        // Does the file have any data, at all?
        if (0 == $this->fileHeader->compressed) {
            // No file data!
            if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
                if (is_resource($outfp)) {
                    @fclose($outfp);
                }
            }
            $this->runState = AK_STATE_DATAREAD;

            return true;
        }

        // Simple compressed files are processed as a whole; we can't do chunk processing
        $zipData = $this->fread($this->fp, $this->fileHeader->compressed);
        while (akstringlen($zipData) < $this->fileHeader->compressed) {
            // End of local file before reading all data, but have more archive parts?
            if ($this->isEOF(true) && !$this->isEOF(false)) {
                // Yeap. Read from the next file
                $this->nextFile();
                $bytes_left = $this->fileHeader->compressed - akstringlen($zipData);
                $zipData .= $this->fread($this->fp, $bytes_left);
            } else {
                debugMsg('End of local file before reading all data with no more parts left. The archive is corrupt or truncated.');
                $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                return false;
            }
        }

        if ('gzip' == $this->fileHeader->compression) {
            $unzipData = gzinflate($zipData);
        } elseif ('bzip2' == $this->fileHeader->compression) {
            $unzipData = bzdecompress($zipData);
        }
        unset($zipData);

        // Write to the file.
        if (!AKFactory::get('kickstart.setup.dryrun', '0') && is_resource($outfp)) {
            @fwrite($outfp, $unzipData, $this->fileHeader->uncompressed);
            @fclose($outfp);
        }
        unset($unzipData);

        $this->runState = AK_STATE_DATAREAD;

        return true;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * ZIP archive extraction class.
 *
 * Since the file data portion of ZIP and JPA are similarly structured (it's empty for dirs,
 * linked node name for symlinks, dumped binary data for no compressions and dumped gzipped
 * binary data for gzip compression) we just have to subclass AKUnarchiverJPA and change the
 * header reading bits. Reusable code ;)
 */
class AKUnarchiverZIP extends AKUnarchiverJPA
{
    public $expectDataDescriptor = false;

    protected function readArchiveHeader()
    {
        debugMsg('Preparing to read archive header');
        // Initialize header data array
        $this->archiveHeaderData = new stdClass();

        // Open the first part
        debugMsg('Opening the first part');
        $this->nextFile();

        // Fail for unreadable files
        if (false === $this->fp) {
            debugMsg('The first part is not readable');

            return false;
        }

        // Read a possible multipart signature
        $sigBinary  = fread($this->fp, 4);
        $headerData = unpack('Vsig', $sigBinary);

        // Roll back if it's not a multipart archive
        if (0x04034b50 == $headerData['sig']) {
            debugMsg('The archive is not multipart');
            fseek($this->fp, -4, SEEK_CUR);
        } else {
            debugMsg('The archive is multipart');
        }

        $multiPartSigs = array(
            0x08074b50,        // Multi-part ZIP
            0x30304b50,        // Multi-part ZIP (alternate)
            0x04034b50,        // Single file
        );
        if (!in_array($headerData['sig'], $multiPartSigs)) {
            debugMsg('Invalid header signature '.dechex($headerData['sig']));
            $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

            return false;
        }

        $this->currentPartOffset = @ftell($this->fp);
        debugMsg('Current part offset after reading header: '.$this->currentPartOffset);

        $this->dataReadLength = 0;

        return true;
    }

    /**
     * Concrete classes must use this method to read the file header.
     *
     * @return bool True if reading the file was successful, false if an error occured or we reached end of archive
     */
    protected function readFileHeader()
    {
        // If the current part is over, proceed to the next part please
        if ($this->isEOF(true)) {
            debugMsg('Opening next archive part');
            $this->nextFile();
        }

        if ($this->expectDataDescriptor) {
            // The last file had bit 3 of the general purpose bit flag set. This means that we have a
            // 12 byte data descriptor we need to skip. To make things worse, there might also be a 4
            // byte optional data descriptor header (0x08074b50).
            $junk = @fread($this->fp, 4);
            $junk = unpack('Vsig', $junk);
            if (0x08074b50 == $junk['sig']) {
                // Yes, there was a signature
                $junk = @fread($this->fp, 12);
                debugMsg('Data descriptor (w/ header) skipped at '.(ftell($this->fp) - 12));
            } else {
                // No, there was no signature, just read another 8 bytes
                $junk = @fread($this->fp, 8);
                debugMsg('Data descriptor (w/out header) skipped at '.(ftell($this->fp) - 8));
            }

            // And check for EOF, too
            if ($this->isEOF(true)) {
                debugMsg('EOF before reading header');

                $this->nextFile();
            }
        }

        // Get and decode Local File Header
        $headerBinary = fread($this->fp, 30);
        $headerData   = unpack('Vsig/C2ver/vbitflag/vcompmethod/vlastmodtime/vlastmoddate/Vcrc/Vcompsize/Vuncomp/vfnamelen/veflen', $headerBinary);

        // Check signature
        if (!(0x04034b50 == $headerData['sig'])) {
            debugMsg('Not a file signature at '.(ftell($this->fp) - 4));

            // The signature is not the one used for files. Is this a central directory record (i.e. we're done)?
            if (0x02014b50 == $headerData['sig']) {
                debugMsg('EOCD signature at '.(ftell($this->fp) - 4));
                // End of ZIP file detected. We'll just skip to the end of file...
                while ($this->nextFile()) {
                }
                @fseek($this->fp, 0, SEEK_END); // Go to EOF
                return false;
            } else {
                debugMsg('Invalid signature '.dechex($headerData['sig']).' at '.ftell($this->fp));
                $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                return false;
            }
        }

        // If bit 3 of the bitflag is set, expectDataDescriptor is true
        $this->expectDataDescriptor = ($headerData['bitflag'] & 4) == 4;

        $this->fileHeader            = new stdClass();
        $this->fileHeader->timestamp = 0;

        // Read the last modified data and time
        $lastmodtime = $headerData['lastmodtime'];
        $lastmoddate = $headerData['lastmoddate'];

        if ($lastmoddate && $lastmodtime) {
            // ----- Extract time
            $v_hour    = ($lastmodtime & 0xF800) >> 11;
            $v_minute  = ($lastmodtime & 0x07E0) >> 5;
            $v_seconde = ($lastmodtime & 0x001F) * 2;

            // ----- Extract date
            $v_year  = (($lastmoddate & 0xFE00) >> 9) + 1980;
            $v_month = ($lastmoddate & 0x01E0) >> 5;
            $v_day   = $lastmoddate & 0x001F;

            // ----- Get UNIX date format
            $this->fileHeader->timestamp = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
        }

        $isBannedFile = false;

        $this->fileHeader->compressed   = $headerData['compsize'];
        $this->fileHeader->uncompressed = $headerData['uncomp'];
        $nameFieldLength                = $headerData['fnamelen'];
        $extraFieldLength               = $headerData['eflen'];

        // Read filename field
        $this->fileHeader->file = fread($this->fp, $nameFieldLength);

        // Handle file renaming
        $isRenamed = false;
        if (is_array($this->renameFiles) && (count($this->renameFiles) > 0)) {
            if (array_key_exists($this->fileHeader->file, $this->renameFiles)) {
                $this->fileHeader->file = $this->renameFiles[$this->fileHeader->file];
                $isRenamed              = true;
            }
        }

        // Handle directory renaming
        $isDirRenamed = false;
        if (is_array($this->renameDirs) && (count($this->renameDirs) > 0)) {
            if (array_key_exists(dirname($this->fileHeader->file), $this->renameDirs)) {
                $file         = rtrim($this->renameDirs[dirname($this->fileHeader->file)], '/').'/'.basename($this->fileHeader->file);
                $isRenamed    = true;
                $isDirRenamed = true;
            }
        }

        // Read extra field if present
        if ($extraFieldLength > 0) {
            $extrafield = fread($this->fp, $extraFieldLength);
        }

        debugMsg('*'.ftell($this->fp).' IS START OF '.$this->fileHeader->file.' ('.$this->fileHeader->compressed.' bytes)');

        // Decide filetype -- Check for directories
        $this->fileHeader->type = 'file';
        if (strrpos($this->fileHeader->file, '/') == strlen($this->fileHeader->file) - 1) {
            $this->fileHeader->type = 'dir';
        }
        // Decide filetype -- Check for symbolic links
        if ((10 == $headerData['ver1']) && (3 == $headerData['ver2'])) {
            $this->fileHeader->type = 'link';
        }

        switch ($headerData['compmethod']) {
            case 0:
                $this->fileHeader->compression = 'none';
                break;
            case 8:
                $this->fileHeader->compression = 'gzip';
                break;
        }

        // Find hard-coded banned files
        if (('.' == basename($this->fileHeader->file)) || ('..' == basename($this->fileHeader->file))) {
            $isBannedFile = true;
        }

        // Also try to find banned files passed in class configuration
        if ((count($this->skipFiles) > 0) && (!$isRenamed)) {
            if (in_array($this->fileHeader->file, $this->skipFiles)) {
                $isBannedFile = true;
            }
        }

        // If we have a banned file, let's skip it
        if ($isBannedFile) {
            // Advance the file pointer, skipping exactly the size of the compressed data
            $seekleft = $this->fileHeader->compressed;
            while ($seekleft > 0) {
                // Ensure that we can seek past archive part boundaries
                $curSize = @filesize($this->archiveList[$this->currentPartNumber]);
                $curPos  = @ftell($this->fp);
                $canSeek = $curSize - $curPos;
                if ($canSeek > $seekleft) {
                    $canSeek = $seekleft;
                }
                @fseek($this->fp, $canSeek, SEEK_CUR);
                $seekleft -= $canSeek;
                if ($seekleft) {
                    $this->nextFile();
                }
            }

            $this->currentPartOffset = @ftell($this->fp);
            $this->runState          = AK_STATE_DONE;

            return true;
        }

        // Last chance to prepend a path to the filename
        if (!empty($this->addPath) && !$isDirRenamed) {
            $this->fileHeader->file = $this->addPath.$this->fileHeader->file;
        }

        // Get the translated path name
        if ('file' == $this->fileHeader->type) {
            $this->fileHeader->realFile = $this->postProcEngine->processFilename($this->fileHeader->file);
        } elseif ('dir' == $this->fileHeader->type) {
            $this->fileHeader->timestamp = 0;

            $dir = $this->fileHeader->file;

            $this->postProcEngine->createDirRecursive($this->fileHeader->file, 0755);
            $this->postProcEngine->processFilename(null);
        } else {
            // Symlink; do not post-process
            $this->fileHeader->timestamp = 0;
            $this->postProcEngine->processFilename(null);
        }

        $this->createDirectory();

        // Header is read
        $this->runState = AK_STATE_HEADER;

        return true;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * JPS archive extraction class.
 */
class AKUnarchiverJPS extends AKUnarchiverJPA
{
    protected $archiveHeaderData = array();

    protected $password = '';

    public function __construct()
    {
        parent::__construct();

        $this->password = AKFactory::get('kickstart.jps.password', '');
    }

    protected function readArchiveHeader()
    {
        // Initialize header data array
        $this->archiveHeaderData = new stdClass();

        // Open the first part
        $this->nextFile();

        // Fail for unreadable files
        if (false === $this->fp) {
            return false;
        }

        // Read the signature
        $sig = fread($this->fp, 3);

        if ('JPS' != $sig) {
            // Not a JPA file
            $this->setError(AKText::_('ERR_NOT_A_JPS_FILE'));

            return false;
        }

        // Read and parse the known portion of header data (5 bytes)
        $bin_data    = fread($this->fp, 5);
        $header_data = unpack('Cmajor/Cminor/cspanned/vextra', $bin_data);

        // Load any remaining header data (forward compatibility)
        $rest_length = $header_data['extra'];
        if ($rest_length > 0) {
            $junk = fread($this->fp, $rest_length);
        } else {
            $junk = '';
        }

        // Temporary array with all the data we read
        $temp = array(
            'signature' => $sig,
            'major'     => $header_data['major'],
            'minor'     => $header_data['minor'],
            'spanned'   => $header_data['spanned'],
        );
        // Array-to-object conversion
        foreach ($temp as $key => $value) {
            $this->archiveHeaderData->{$key} = $value;
        }

        $this->currentPartOffset = @ftell($this->fp);

        $this->dataReadLength = 0;

        return true;
    }

    /**
     * Concrete classes must use this method to read the file header.
     *
     * @return bool True if reading the file was successful, false if an error occured or we reached end of archive
     */
    protected function readFileHeader()
    {
        // If the current part is over, proceed to the next part please
        if ($this->isEOF(true)) {
            $this->nextFile();
        }

        // Get and decode Entity Description Block
        $signature = fread($this->fp, 3);

        // Check for end-of-archive siganture
        if ('JPE' == $signature) {
            $this->setState('postrun');

            return true;
        }

        $this->fileHeader            = new stdClass();
        $this->fileHeader->timestamp = 0;

        // Check signature
        if ('JPF' != $signature) {
            if ($this->isEOF(true)) {
                // This file is finished; make sure it's the last one
                $this->nextFile();
                if (!$this->isEOF(false)) {
                    $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset));

                    return false;
                }

                // We're just finished
                return false;
            } else {
                fseek($this->fp, -6, SEEK_CUR);
                $signature = fread($this->fp, 3);
                if ('JPE' == $signature) {
                    return false;
                }

                $this->setError(AKText::sprintf('INVALID_FILE_HEADER', $this->currentPartNumber, $this->currentPartOffset));

                return false;
            }
        }
        // This a JPA Entity Block. Process the header.

        $isBannedFile = false;

        // Read and decrypt the header
        $edbhData = fread($this->fp, 4);
        $edbh     = unpack('vencsize/vdecsize', $edbhData);
        $bin_data = fread($this->fp, $edbh['encsize']);

        // Decrypt and truncate
        $bin_data = AKEncryptionAES::AESDecryptCBC($bin_data, $this->password, 128);
        $bin_data = substr($bin_data, 0, $edbh['decsize']);

        // Read length of EDB and of the Entity Path Data
        $length_array = unpack('vpathsize', substr($bin_data, 0, 2));
        // Read the path data
        $file = substr($bin_data, 2, $length_array['pathsize']);

        // Handle file renaming
        $isRenamed = false;
        if (is_array($this->renameFiles) && (count($this->renameFiles) > 0)) {
            if (array_key_exists($file, $this->renameFiles)) {
                $file      = $this->renameFiles[$file];
                $isRenamed = true;
            }
        }

        // Handle directory renaming
        $isDirRenamed = false;
        if (is_array($this->renameDirs) && (count($this->renameDirs) > 0)) {
            if (array_key_exists(dirname($file), $this->renameDirs)) {
                $file         = rtrim($this->renameDirs[dirname($file)], '/').'/'.basename($file);
                $isRenamed    = true;
                $isDirRenamed = true;
            }
        }

        // Read and parse the known data portion
        $bin_data    = substr($bin_data, 2 + $length_array['pathsize']);
        $header_data = unpack('Ctype/Ccompression/Vuncompsize/Vperms/Vfilectime', $bin_data);

        $this->fileHeader->timestamp = $header_data['filectime'];
        $compressionType             = $header_data['compression'];

        // Populate the return array
        $this->fileHeader->file         = $file;
        $this->fileHeader->uncompressed = $header_data['uncompsize'];
        switch ($header_data['type']) {
            case 0:
                $this->fileHeader->type = 'dir';
                break;

            case 1:
                $this->fileHeader->type = 'file';
                break;

            case 2:
                $this->fileHeader->type = 'link';
                break;
        }
        switch ($compressionType) {
            case 0:
                $this->fileHeader->compression = 'none';
                break;
            case 1:
                $this->fileHeader->compression = 'gzip';
                break;
            case 2:
                $this->fileHeader->compression = 'bzip2';
                break;
        }
        $this->fileHeader->permissions = $header_data['perms'];

        // Find hard-coded banned files
        if (('.' == basename($this->fileHeader->file)) || ('..' == basename($this->fileHeader->file))) {
            $isBannedFile = true;
        }

        // Also try to find banned files passed in class configuration
        if ((count($this->skipFiles) > 0) && (!$isRenamed)) {
            if (in_array($this->fileHeader->file, $this->skipFiles)) {
                $isBannedFile = true;
            }
        }

        // If we have a banned file, let's skip it
        if ($isBannedFile) {
            $done = false;
            while (!$done) {
                // Read the Data Chunk Block header
                $binMiniHead = fread($this->fp, 8);
                if (in_array(substr($binMiniHead, 0, 3), array('JPF', 'JPE'))) {
                    // Not a Data Chunk Block header, I am done skipping the file
                    @fseek($this->fp, -8, SEEK_CUR); // Roll back the file pointer
                    $done = true; // Mark as done
                    continue; // Exit loop
                } else {
                    // Skip forward by the amount of compressed data
                    $miniHead = unpack('Vencsize/Vdecsize', $binMiniHead);
                    @fseek($this->fp, $miniHead['encsize'], SEEK_CUR);
                }
            }

            $this->currentPartOffset = @ftell($this->fp);
            $this->runState          = AK_STATE_DONE;

            return true;
        }

        // Last chance to prepend a path to the filename
        if (!empty($this->addPath) && !$isDirRenamed) {
            $this->fileHeader->file = $this->addPath.$this->fileHeader->file;
        }

        // Get the translated path name
        $restorePerms = AKFactory::get('kickstart.setup.restoreperms', false);
        if ('file' == $this->fileHeader->type) {
            // Regular file; ask the postproc engine to process its filename
            if ($restorePerms) {
                $this->fileHeader->realFile = $this->postProcEngine->processFilename($this->fileHeader->file, $this->fileHeader->permissions);
            } else {
                $this->fileHeader->realFile = $this->postProcEngine->processFilename($this->fileHeader->file);
            }
        } elseif ('dir' == $this->fileHeader->type) {
            $dir                        = $this->fileHeader->file;
            $this->fileHeader->realFile = $dir;

            // Directory; just create it
            if ($restorePerms) {
                $this->postProcEngine->createDirRecursive($this->fileHeader->file, $this->fileHeader->permissions);
            } else {
                $this->postProcEngine->createDirRecursive($this->fileHeader->file, 0755);
            }
            $this->postProcEngine->processFilename(null);
        } else {
            // Symlink; do not post-process
            $this->postProcEngine->processFilename(null);
        }

        $this->createDirectory();

        // Header is read
        $this->runState = AK_STATE_HEADER;

        $this->dataReadLength = 0;

        return true;
    }

    /**
     * Creates the directory this file points to.
     */
    protected function createDirectory()
    {
        if (AKFactory::get('kickstart.setup.dryrun', '0')) {
            return true;
        }

        // Do we need to create a directory?
        $lastSlash = strrpos($this->fileHeader->realFile, '/');
        $dirName   = substr($this->fileHeader->realFile, 0, $lastSlash);
        $perms     = $this->flagRestorePermissions ? $retArray['permissions'] : 0755;
        $ignore    = AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($dirName);
        if ((false == $this->postProcEngine->createDirRecursive($dirName, $perms)) && (!$ignore)) {
            $this->setError(AKText::sprintf('COULDNT_CREATE_DIR', $dirName));

            return false;
        } else {
            return true;
        }
    }

    /**
     * Concrete classes must use this method to process file data. It must set $runState to AK_STATE_DATAREAD when
     * it's finished processing the file data.
     *
     * @return bool True if processing the file data was successful, false if an error occured
     */
    protected function processFileData()
    {
        switch ($this->fileHeader->type) {
            case 'dir':
                return $this->processTypeDir();
                break;

            case 'link':
                return $this->processTypeLink();
                break;

            case 'file':
                switch ($this->fileHeader->compression) {
                    case 'none':
                        return $this->processTypeFileUncompressed();
                        break;

                    case 'gzip':
                    case 'bzip2':
                        return $this->processTypeFileCompressedSimple();
                        break;
                }
                break;
        }
    }

    /**
     * Process the file data of a directory entry.
     *
     * @return bool
     */
    private function processTypeDir()
    {
        // Directory entries in the JPA do not have file data, therefore we're done processing the entry
        $this->runState = AK_STATE_DATAREAD;

        return true;
    }

    /**
     * Process the file data of a link entry.
     *
     * @return bool
     */
    private function processTypeLink()
    {
        // Does the file have any data, at all?
        if (0 == $this->fileHeader->uncompressed) {
            // No file data!
            $this->runState = AK_STATE_DATAREAD;

            return true;
        }

        // Read the mini header
        $binMiniHeader   = fread($this->fp, 8);
        $reallyReadBytes = akstringlen($binMiniHeader);
        if ($reallyReadBytes < 8) {
            // We read less than requested! Why? Did we hit local EOF?
            if ($this->isEOF(true) && !$this->isEOF(false)) {
                // Yeap. Let's go to the next file
                $this->nextFile();
                // Retry reading the header
                $binMiniHeader   = fread($this->fp, 8);
                $reallyReadBytes = akstringlen($binMiniHeader);
                // Still not enough data? If so, the archive is corrupt or missing parts.
                if ($reallyReadBytes < 8) {
                    $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                    return false;
                }
            } else {
                // Nope. The archive is corrupt
                $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                return false;
            }
        }

        // Read the encrypted data
        $miniHeader      = unpack('Vencsize/Vdecsize', $binMiniHeader);
        $toReadBytes     = $miniHeader['encsize'];
        $data            = $this->fread($this->fp, $toReadBytes);
        $reallyReadBytes = akstringlen($data);
        if ($reallyReadBytes < $toReadBytes) {
            // We read less than requested! Why? Did we hit local EOF?
            if ($this->isEOF(true) && !$this->isEOF(false)) {
                // Yeap. Let's go to the next file
                $this->nextFile();
                // Read the rest of the data
                $toReadBytes -= $reallyReadBytes;
                $restData        = $this->fread($this->fp, $toReadBytes);
                $reallyReadBytes = akstringlen($data);
                if ($reallyReadBytes < $toReadBytes) {
                    $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                    return false;
                }
                $data .= $restData;
            } else {
                // Nope. The archive is corrupt
                $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                return false;
            }
        }

        // Decrypt the data
        $data = AKEncryptionAES::AESDecryptCBC($data, $this->password, 128);

        // Is the length of the decrypted data less than expected?
        $data_length = akstringlen($data);
        if ($data_length < $miniHeader['decsize']) {
            $this->setError(AKText::_('ERR_INVALID_JPS_PASSWORD'));

            return false;
        }

        // Trim the data
        $data = substr($data, 0, $miniHeader['decsize']);

        // Try to remove an existing file or directory by the same name
        if (file_exists($this->fileHeader->file)) {
            @unlink($this->fileHeader->file);
            @rmdir($this->fileHeader->file);
        }
        // Remove any trailing slash
        if ('/' == substr($this->fileHeader->file, -1)) {
            $this->fileHeader->file = substr($this->fileHeader->file, 0, -1);
        }
        // Create the symlink - only possible within PHP context. There's no support built in the FTP protocol, so no postproc use is possible here :(

        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            @symlink($data, $this->fileHeader->file);
        }

        $this->runState = AK_STATE_DATAREAD;

        return true; // No matter if the link was created!
    }

    private function processTypeFileUncompressed()
    {
        // Uncompressed files are being processed in small chunks, to avoid timeouts
        if ((0 == $this->dataReadLength) && !AKFactory::get('kickstart.setup.dryrun', '0')) {
            // Before processing file data, ensure permissions are adequate
            $this->setCorrectPermissions($this->fileHeader->file);
        }

        // Open the output file
        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);
            if (0 == $this->dataReadLength) {
                $outfp = @fopen($this->fileHeader->realFile, 'wb');
            } else {
                $outfp = @fopen($this->fileHeader->realFile, 'ab');
            }

            // Can we write to the file?
            if ((false === $outfp) && (!$ignore)) {
                // An error occured
                $this->setError(AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile));

                return false;
            }
        }

        // Does the file have any data, at all?
        if (0 == $this->fileHeader->uncompressed) {
            // No file data!
            if (!AKFactory::get('kickstart.setup.dryrun', '0') && is_resource($outfp)) {
                @fclose($outfp);
            }
            $this->runState = AK_STATE_DATAREAD;

            return true;
        } else {
            $this->setError('An uncompressed file was detected; this is not supported by this archive extraction utility');

            return false;
        }

        return true;
    }

    private function processTypeFileCompressedSimple()
    {
        $timer = AKFactory::getTimer();

        // Files are being processed in small chunks, to avoid timeouts
        if ((0 == $this->dataReadLength) && !AKFactory::get('kickstart.setup.dryrun', '0')) {
            // Before processing file data, ensure permissions are adequate
            $this->setCorrectPermissions($this->fileHeader->file);
        }

        // Open the output file
        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            // Open the output file
            $outfp = @fopen($this->fileHeader->realFile, 'wb');

            // Can we write to the file?
            $ignore = AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);
            if ((false === $outfp) && (!$ignore)) {
                // An error occured
                $this->setError(AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile));

                return false;
            }
        }

        // Does the file have any data, at all?
        if (0 == $this->fileHeader->uncompressed) {
            // No file data!
            if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
                if (is_resource($outfp)) {
                    @fclose($outfp);
                }
            }
            $this->runState = AK_STATE_DATAREAD;

            return true;
        }

        $leftBytes = $this->fileHeader->uncompressed - $this->dataReadLength;

        // Loop while there's data to write and enough time to do it
        while (($leftBytes > 0) && ($timer->getTimeLeft() > 0)) {
            // Read the mini header
            $binMiniHeader   = fread($this->fp, 8);
            $reallyReadBytes = akstringlen($binMiniHeader);
            if ($reallyReadBytes < 8) {
                // We read less than requested! Why? Did we hit local EOF?
                if ($this->isEOF(true) && !$this->isEOF(false)) {
                    // Yeap. Let's go to the next file
                    $this->nextFile();
                    // Retry reading the header
                    $binMiniHeader   = fread($this->fp, 8);
                    $reallyReadBytes = akstringlen($binMiniHeader);
                    // Still not enough data? If so, the archive is corrupt or missing parts.
                    if ($reallyReadBytes < 8) {
                        $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                        return false;
                    }
                } else {
                    // Nope. The archive is corrupt
                    $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                    return false;
                }
            }

            // Read the encrypted data
            $miniHeader      = unpack('Vencsize/Vdecsize', $binMiniHeader);
            $toReadBytes     = $miniHeader['encsize'];
            $data            = $this->fread($this->fp, $toReadBytes);
            $reallyReadBytes = akstringlen($data);
            if ($reallyReadBytes < $toReadBytes) {
                // We read less than requested! Why? Did we hit local EOF?
                if ($this->isEOF(true) && !$this->isEOF(false)) {
                    // Yeap. Let's go to the next file
                    $this->nextFile();
                    // Read the rest of the data
                    $toReadBytes -= $reallyReadBytes;
                    $restData        = $this->fread($this->fp, $toReadBytes);
                    $reallyReadBytes = akstringlen($restData);
                    if ($reallyReadBytes < $toReadBytes) {
                        $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                        return false;
                    }
                    if (0 == akstringlen($data)) {
                        $data = $restData;
                    } else {
                        $data .= $restData;
                    }
                } else {
                    // Nope. The archive is corrupt
                    $this->setError(AKText::_('ERR_CORRUPT_ARCHIVE'));

                    return false;
                }
            }

            // Decrypt the data
            $data = AKEncryptionAES::AESDecryptCBC($data, $this->password, 128);

            // Is the length of the decrypted data less than expected?
            $data_length = akstringlen($data);
            if ($data_length < $miniHeader['decsize']) {
                $this->setError(AKText::_('ERR_INVALID_JPS_PASSWORD'));

                return false;
            }

            // Trim the data
            $data = substr($data, 0, $miniHeader['decsize']);

            // Decompress
            $data    = gzinflate($data);
            $unc_len = akstringlen($data);

            // Write the decrypted data
            if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
                if (is_resource($outfp)) {
                    @fwrite($outfp, $data, akstringlen($data));
                }
            }

            // Update the read length
            $this->dataReadLength += $unc_len;
            $leftBytes = $this->fileHeader->uncompressed - $this->dataReadLength;
        }

        // Close the file pointer
        if (!AKFactory::get('kickstart.setup.dryrun', '0')) {
            if (is_resource($outfp)) {
                @fclose($outfp);
            }
        }

        // Was this a pre-timeout bail out?
        if ($leftBytes > 0) {
            $this->runState = AK_STATE_DATA;
        } else {
            // Oh! We just finished!
            $this->runState       = AK_STATE_DATAREAD;
            $this->dataReadLength = 0;
        }

        return true;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * Timer class.
 */
class AKCoreTimer extends AKAbstractObject
{
    /** @var int Maximum execution time allowance per step */
    private $max_exec_time = null;

    /** @var int Timestamp of execution start */
    private $start_time = null;

    /**
     * Public constructor, creates the timer object and calculates the execution time limits.
     *
     * @return AECoreTimer
     */
    public function __construct()
    {
        parent::__construct();

        // Initialize start time
        $this->start_time = $this->microtime_float();

        // Get configured max time per step and bias
        $config_max_exec_time = AKFactory::get('kickstart.tuning.max_exec_time', 14);
        $bias                 = AKFactory::get('kickstart.tuning.run_time_bias', 75) / 100;

        // Get PHP's maximum execution time (our upper limit)
        if (@function_exists('ini_get')) {
            $php_max_exec_time = @ini_get('maximum_execution_time');
            if ((!is_numeric($php_max_exec_time)) || (0 == $php_max_exec_time)) {
                // If we have no time limit, set a hard limit of about 10 seconds
                // (safe for Apache and IIS timeouts, verbose enough for users)
                $php_max_exec_time = 14;
            }
        } else {
            // If ini_get is not available, use a rough default
            $php_max_exec_time = 14;
        }

        // Apply an arbitrary correction to counter CMS load time
        --$php_max_exec_time;

        // Apply bias
        $php_max_exec_time    = $php_max_exec_time * $bias;
        $config_max_exec_time = $config_max_exec_time * $bias;

        // Use the most appropriate time limit value
        if ($config_max_exec_time > $php_max_exec_time) {
            $this->max_exec_time = $php_max_exec_time;
        } else {
            $this->max_exec_time = $config_max_exec_time;
        }
    }

    /**
     * Returns the current timestampt in decimal seconds.
     */
    private function microtime_float()
    {
        list($usec, $sec) = explode(' ', microtime());

        return (float) $usec + (float) $sec;
    }

    /**
     * Wake-up function to reset internal timer when we get unserialized.
     */
    public function __wakeup()
    {
        // Re-initialize start time on wake-up
        $this->start_time = $this->microtime_float();
    }

    /**
     * Gets the number of seconds left, before we hit the "must break" threshold.
     *
     * @return float
     */
    public function getTimeLeft()
    {
        return $this->max_exec_time - $this->getRunningTime();
    }

    /**
     * Gets the time elapsed since object creation/unserialization, effectively how
     * long Akeeba Engine has been processing data.
     *
     * @return float
     */
    public function getRunningTime()
    {
        return $this->microtime_float() - $this->start_time;
    }

    /**
     * Enforce the minimum execution time.
     */
    public function enforce_min_exec_time()
    {
        // Try to get a sane value for PHP's maximum_execution_time INI parameter
        if (@function_exists('ini_get')) {
            $php_max_exec = @ini_get('maximum_execution_time');
        } else {
            $php_max_exec = 10;
        }
        if (('' == $php_max_exec) || (0 == $php_max_exec)) {
            $php_max_exec = 10;
        }
        // Decrease $php_max_exec time by 500 msec we need (approx.) to tear down
        // the application, as well as another 500msec added for rounding
        // error purposes. Also make sure this is never gonna be less than 0.
        $php_max_exec = max($php_max_exec * 1000 - 1000, 0);

        // Get the "minimum execution time per step" Akeeba Backup configuration variable
        $minexectime = AKFactory::get('kickstart.tuning.min_exec_time', 0);
        if (!is_numeric($minexectime)) {
            $minexectime = 0;
        }

        // Make sure we are not over PHP's time limit!
        if ($minexectime > $php_max_exec) {
            $minexectime = $php_max_exec;
        }

        // Get current running time
        $elapsed_time = $this->getRunningTime() * 1000;

        // Only run a sleep delay if we haven't reached the minexectime execution time
        if (($minexectime > $elapsed_time) && ($elapsed_time > 0)) {
            $sleep_msec = $minexectime - $elapsed_time;
            if (function_exists('usleep')) {
                usleep(1000 * $sleep_msec);
            } elseif (function_exists('time_nanosleep')) {
                $sleep_sec  = floor($sleep_msec / 1000);
                $sleep_nsec = 1000000 * ($sleep_msec - ($sleep_sec * 1000));
                time_nanosleep($sleep_sec, $sleep_nsec);
            } elseif (function_exists('time_sleep_until')) {
                $until_timestamp = time() + $sleep_msec / 1000;
                time_sleep_until($until_timestamp);
            } elseif (function_exists('sleep')) {
                $sleep_sec = ceil($sleep_msec / 1000);
                sleep($sleep_sec);
            }
        } elseif ($elapsed_time > 0) {
            // No sleep required, even if user configured us to be able to do so.
        }
    }

    /**
     * Reset the timer. It should only be used in CLI mode!
     */
    public function resetTime()
    {
        $this->start_time = $this->microtime_float();
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * A filesystem scanner which uses opendir().
 */
class AKUtilsLister extends AKAbstractObject
{
    public function &getFiles($folder, $pattern = '*')
    {
        // Initialize variables
        $arr   = array();
        $false = false;

        if (!is_dir($folder)) {
            return $false;
        }

        $handle = @opendir($folder);
        // If directory is not accessible, just return FALSE
        if (false === $handle) {
            $this->setWarning('Unreadable directory '.$folder);

            return $false;
        }

        while (false !== ($file = @readdir($handle))) {
            if (!fnmatch($pattern, $file)) {
                continue;
            }

            if (('.' != $file) && ('..' != $file)) {
                $ds    = ('' == $folder) || ('/' == $folder) || ('/' == @substr($folder, -1)) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) ? '' : DIRECTORY_SEPARATOR;
                $dir   = $folder.$ds.$file;
                $isDir = is_dir($dir);
                if (!$isDir) {
                    $arr[] = $dir;
                }
            }
        }
        @closedir($handle);

        return $arr;
    }

    public function &getFolders($folder, $pattern = '*')
    {
        // Initialize variables
        $arr   = array();
        $false = false;

        if (!is_dir($folder)) {
            return $false;
        }

        $handle = @opendir($folder);
        // If directory is not accessible, just return FALSE
        if (false === $handle) {
            $this->setWarning('Unreadable directory '.$folder);

            return $false;
        }

        while (false !== ($file = @readdir($handle))) {
            if (!fnmatch($pattern, $file)) {
                continue;
            }

            if (('.' != $file) && ('..' != $file)) {
                $ds    = ('' == $folder) || ('/' == $folder) || ('/' == @substr($folder, -1)) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) ? '' : DIRECTORY_SEPARATOR;
                $dir   = $folder.$ds.$file;
                $isDir = is_dir($dir);
                if ($isDir) {
                    $arr[] = $dir;
                }
            }
        }
        @closedir($handle);

        return $arr;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * A simple INI-based i18n engine.
 */
class AKText extends AKAbstractObject
{
    /**
     * The default (en_GB) translation used when no other translation is available.
     *
     * @var array
     */
    private $default_translation = array(
        'AUTOMODEON'                     => 'Auto-mode enabled',
        'ERR_NOT_A_JPA_FILE'             => 'The file is not a JPA archive',
        'ERR_CORRUPT_ARCHIVE'            => 'The archive file is corrupt, truncated or archive parts are missing',
        'ERR_INVALID_LOGIN'              => 'Invalid login',
        'COULDNT_CREATE_DIR'             => 'Could not create %s folder',
        'COULDNT_WRITE_FILE'             => 'Could not open %s for writing.',
        'WRONG_FTP_HOST'                 => 'Wrong FTP host or port',
        'WRONG_FTP_USER'                 => 'Wrong FTP username or password',
        'WRONG_FTP_PATH1'                => 'Wrong FTP initial directory - the directory doesn\'t exist',
        'FTP_CANT_CREATE_DIR'            => 'Could not create directory %s',
        'FTP_TEMPDIR_NOT_WRITABLE'       => 'Could not find or create a writable temporary directory',
        'SFTP_TEMPDIR_NOT_WRITABLE'      => 'Could not find or create a writable temporary directory',
        'FTP_COULDNT_UPLOAD'             => 'Could not upload %s',
        'THINGS_HEADER'                  => 'Things you should know about Akeeba Kickstart',
        'THINGS_01'                      => 'Kickstart is not an installer. It is an archive extraction tool. The actual installer was put inside the archive file at backup time.',
        'THINGS_02'                      => 'Kickstart is not the only way to extract the backup archive. You can use Akeeba eXtract Wizard and upload the extracted files using FTP instead.',
        'THINGS_03'                      => 'Kickstart is bound by your server\'s configuration. As such, it may not work at all.',
        'THINGS_04'                      => 'You should download and upload your archive files using FTP in Binary transfer mode. Any other method could lead to a corrupt backup archive and restoration failure.',
        'THINGS_05'                      => 'Post-restoration site load errors are usually caused by .htaccess or php.ini directives. You should understand that blank pages, 404 and 500 errors can usually be worked around by editing the aforementioned files. It is not our job to mess with your configuration files, because this could be dangerous for your site.',
        'THINGS_06'                      => 'Kickstart overwrites files without a warning. If you are not sure that you are OK with that do not continue.',
        'THINGS_07'                      => 'Trying to restore to the temporary URL of a cPanel host (e.g. http://1.2.3.4/~username) will lead to restoration failure and your site will appear to be not working. This is normal and it\'s just how your server and CMS software work.',
        'THINGS_08'                      => 'You are supposed to read the documentation before using this software. Most issues can be avoided, or easily worked around, by understanding how this software works.',
        'THINGS_09'                      => 'This text does not imply that there is a problem detected. It is standard text displayed every time you launch Kickstart.',
        'CLOSE_LIGHTBOX'                 => 'Click here or press ESC to close this message',
        'SELECT_ARCHIVE'                 => 'Select a backup archive',
        'ARCHIVE_FILE'                   => 'Archive file:',
        'SELECT_EXTRACTION'              => 'Select an extraction method',
        'WRITE_TO_FILES'                 => 'Write to files:',
        'WRITE_HYBRID'                   => 'Hybrid (use FTP only if needed)',
        'WRITE_DIRECTLY'                 => 'Directly',
        'WRITE_FTP'                      => 'Use FTP for all files',
        'WRITE_SFTP'                     => 'Use SFTP for all files',
        'FTP_HOST'                       => '(S)FTP host name:',
        'FTP_PORT'                       => '(S)FTP port:',
        'FTP_FTPS'                       => 'Use FTP over SSL (FTPS)',
        'FTP_PASSIVE'                    => 'Use FTP Passive Mode',
        'FTP_USER'                       => '(S)FTP user name:',
        'FTP_PASS'                       => '(S)FTP password:',
        'FTP_DIR'                        => '(S)FTP directory:',
        'FTP_TEMPDIR'                    => 'Temporary directory:',
        'FTP_CONNECTION_OK'              => 'FTP Connection Established',
        'SFTP_CONNECTION_OK'             => 'SFTP Connection Established',
        'FTP_CONNECTION_FAILURE'         => 'The FTP Connection Failed',
        'SFTP_CONNECTION_FAILURE'        => 'The SFTP Connection Failed',
        'FTP_TEMPDIR_WRITABLE'           => 'The temporary directory is writable.',
        'FTP_TEMPDIR_UNWRITABLE'         => 'The temporary directory is not writable. Please check the permissions.',
        'FTPBROWSER_ERROR_HOSTNAME'      => 'Invalid FTP host or port',
        'FTPBROWSER_ERROR_USERPASS'      => 'Invalid FTP username or password',
        'FTPBROWSER_ERROR_NOACCESS'      => "Directory doesn't exist or you don't have enough permissions to access it",
        'FTPBROWSER_ERROR_UNSUPPORTED'   => "Sorry, your FTP server doesn't support our FTP directory browser.",
        'FTPBROWSER_LBL_GOPARENT'        => '&lt;up one level&gt;',
        'FTPBROWSER_LBL_INSTRUCTIONS'    => 'Click on a directory to navigate into it. Click on OK to select that directory, Cancel to abort the procedure.',
        'FTPBROWSER_LBL_ERROR'           => 'An error occurred',
        'SFTP_NO_SSH2'                   => 'Your web server does not have the SSH2 PHP module, therefore can not connect to SFTP servers.',
        'SFTP_NO_FTP_SUPPORT'            => 'Your SSH server does not allow SFTP connections',
        'SFTP_WRONG_USER'                => 'Wrong SFTP username or password',
        'SFTP_WRONG_STARTING_DIR'        => 'You must supply a valid absolute path',
        'SFTPBROWSER_ERROR_NOACCESS'     => "Directory doesn't exist or you don't have enough permissions to access it",
        'SFTP_COULDNT_UPLOAD'            => 'Could not upload %s',
        'SFTP_CANT_CREATE_DIR'           => 'Could not create directory %s',
        'UI-ROOT'                        => '&lt;root&gt;',
        'CONFIG_UI_FTPBROWSER_TITLE'     => 'FTP Directory Browser',
        'FTP_BROWSE'                     => 'Browse',
        'BTN_CHECK'                      => 'Check',
        'BTN_RESET'                      => 'Reset',
        'BTN_TESTFTPCON'                 => 'Test FTP connection',
        'BTN_TESTSFTPCON'                => 'Test SFTP connection',
        'BTN_GOTOSTART'                  => 'Start over',
        'FINE_TUNE'                      => 'Fine tune',
        'MIN_EXEC_TIME'                  => 'Minimum execution time:',
        'MAX_EXEC_TIME'                  => 'Maximum execution time:',
        'SECONDS_PER_STEP'               => 'seconds per step',
        'EXTRACT_FILES'                  => 'Extract files',
        'BTN_START'                      => 'Start',
        'EXTRACTING'                     => 'Extracting',
        'DO_NOT_CLOSE_EXTRACT'           => 'Do not close this window while the extraction is in progress',
        'RESTACLEANUP'                   => 'Restoration and Clean Up',
        'BTN_RUNINSTALLER'               => 'Run the Installer',
        'BTN_CLEANUP'                    => 'Clean Up',
        'BTN_SITEFE'                     => 'Visit your site\'s front-end',
        'BTN_SITEBE'                     => 'Visit your site\'s back-end',
        'WARNINGS'                       => 'Extraction Warnings',
        'ERROR_OCCURED'                  => 'An error occurred',
        'STEALTH_MODE'                   => 'Stealth mode',
        'STEALTH_URL'                    => 'HTML file to show to web visitors',
        'ERR_NOT_A_JPS_FILE'             => 'The file is not a JPA archive',
        'ERR_INVALID_JPS_PASSWORD'       => 'The password you gave is wrong or the archive is corrupt',
        'JPS_PASSWORD'                   => 'Archive Password (for JPS files)',
        'INVALID_FILE_HEADER'            => 'Invalid header in archive file, part %s, offset %s',
        'NEEDSOMEHELPKS'                 => 'Want some help to use this tool? Read this first:',
        'QUICKSTART'                     => 'Quick Start Guide',
        'CANTGETITTOWORK'                => 'Can\'t get it to work? Click me!',
        'NOARCHIVESCLICKHERE'            => 'No archives detected. Click here for troubleshooting instructions.',
        'POSTRESTORATIONTROUBLESHOOTING' => 'Something not working after the restoration? Click here for troubleshooting instructions.',
        'UPDATE_HEADER'                  => 'An updated version of Akeeba Kickstart (<span id="update-version">unknown</span>) is available!',
        'UPDATE_NOTICE'                  => 'You are advised to always use the latest version of Akeeba Kickstart available. Older versions may be subject to bugs and will not be supported.',
        'UPDATE_DLNOW'                   => 'Download now',
        'UPDATE_MOREINFO'                => 'More information',
        'IGNORE_MOST_ERRORS'             => 'Ignore most errors',
        'WRONG_FTP_PATH2'                => 'Wrong FTP initial directory - the directory doesn\'t correspond to your site\'s web root',
        'ARCHIVE_DIRECTORY'              => 'Archive directory:',
        'RELOAD_ARCHIVES'                => 'Reload',
        'CONFIG_UI_SFTPBROWSER_TITLE'    => 'SFTP Directory Browser',
    );

    /**
     * The array holding the translation keys.
     *
     * @var array
     */
    private $strings;

    /**
     * The currently detected language (ISO code).
     *
     * @var string
     */
    private $language;

    /*
     * Initializes the translation engine
     * @return AKText
     */
    public function __construct()
    {
        // Start with the default translation
        $this->strings = $this->default_translation;
        // Try loading the translation file in English, if it exists
        $this->loadTranslation('en-GB');
        // Try loading the translation file in the browser's preferred language, if it exists
        $this->getBrowserLanguage();
        if (!is_null($this->language)) {
            $this->loadTranslation();
        }
    }

    private function loadTranslation($lang = null)
    {
        if (defined('KSLANGDIR')) {
            $dirname = KSLANGDIR;
        } else {
            $dirname = KSROOTDIR;
        }
        $basename = basename(__FILE__, '.php').'.ini';
        if (empty($lang)) {
            $lang = $this->language;
        }

        $translationFilename = $dirname.DIRECTORY_SEPARATOR.$lang.'.'.$basename;
        if (!@file_exists($translationFilename) && ('kickstart.ini' != $basename)) {
            $basename            = 'kickstart.ini';
            $translationFilename = $dirname.DIRECTORY_SEPARATOR.$lang.'.'.$basename;
        }
        if (!@file_exists($translationFilename)) {
            return;
        }
        $temp = self::parse_ini_file($translationFilename, false);

        if (!is_array($this->strings)) {
            $this->strings = array();
        }
        if (empty($temp)) {
            $this->strings = array_merge($this->default_translation, $this->strings);
        } else {
            $this->strings = array_merge($this->strings, $temp);
        }
    }

    /**
     * A PHP based INI file parser.
     *
     * Thanks to asohn ~at~ aircanopy ~dot~ net for posting this handy function on
     * the parse_ini_file page on http://gr.php.net/parse_ini_file
     *
     * @param string $file             Filename to process
     * @param bool   $process_sections True to also process INI sections
     *
     * @return array An associative array of sections, keys and values
     */
    public static function parse_ini_file($file, $process_sections = false, $raw_data = false)
    {
        $process_sections = (true !== $process_sections) ? false : true;

        if (!$raw_data) {
            $ini = @file($file);
        } else {
            $ini = $file;
        }
        if (0 == count($ini)) {
            return array();
        }

        $sections = array();
        $values   = array();
        $result   = array();
        $globals  = array();
        $i        = 0;
        if (!empty($ini)) {
            foreach ($ini as $line) {
                $line = trim($line);
                $line = str_replace("\t", ' ', $line);

                // Comments
                if (!preg_match('/^[a-zA-Z0-9[]/', $line)) {
                    continue;
                }

                // Sections
                if ('[' == $line[0]) {
                    $tmp        = explode(']', $line);
                    $sections[] = trim(substr($tmp[0], 1));
                    ++$i;
                    continue;
                }

                // Key-value pair
                list($key, $value) = explode('=', $line, 2);
                $key               = trim($key);
                $value             = trim($value);
                if (strstr($value, ';')) {
                    $tmp = explode(';', $value);
                    if (2 == count($tmp)) {
                        if ((('"' != $value[0]) && ("'" != $value[0])) ||
                        preg_match('/^".*"\s*;/', $value) || preg_match('/^".*;[^"]*$/', $value) ||
                        preg_match("/^'.*'\s*;/", $value) || preg_match("/^'.*;[^']*$/", $value)
                    ) {
                            $value = $tmp[0];
                        }
                    } else {
                        if ('"' == $value[0]) {
                            $value = preg_replace('/^"(.*)".*/', '$1', $value);
                        } elseif ("'" == $value[0]) {
                            $value = preg_replace("/^'(.*)'.*/", '$1', $value);
                        } else {
                            $value = $tmp[0];
                        }
                    }
                }
                $value = trim($value);
                $value = trim($value, "'\"");

                if (0 == $i) {
                    if ('[]' == substr($line, -1, 2)) {
                        $globals[$key][] = $value;
                    } else {
                        $globals[$key] = $value;
                    }
                } else {
                    if ('[]' == substr($line, -1, 2)) {
                        $values[$i - 1][$key][] = $value;
                    } else {
                        $values[$i - 1][$key] = $value;
                    }
                }
            }
        }

        for ($j = 0; $j < $i; ++$j) {
            if (true === $process_sections) {
                $result[$sections[$j]] = $values[$j];
            } else {
                $result[] = $values[$j];
            }
        }

        return $result + $globals;
    }

    public function getBrowserLanguage()
    {
        // Detection code from Full Operating system language detection, by Harald Hope
        // Retrieved from http://techpatterns.com/downloads/php_language_detection.php
        $user_languages = array();
        //check to see if language is set
        if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
            $languages = strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']);
            // $languages = ' fr-ch;q=0.3, da, en-us;q=0.8, en;q=0.5, fr;q=0.3';
            // need to remove spaces from strings to avoid error
            $languages = str_replace(' ', '', $languages);
            $languages = explode(',', $languages);

            foreach ($languages as $language_list) {
                // pull out the language, place languages into array of full and primary
                // string structure:
                $temp_array = array();
                // slice out the part before ; on first step, the part before - on second, place into array
                $temp_array[0] = substr($language_list, 0, strcspn($language_list, ';')); //full language
                $temp_array[1] = substr($language_list, 0, 2); // cut out primary language
                if ((5 == strlen($temp_array[0])) && (('-' == substr($temp_array[0], 2, 1)) || ('_' == substr($temp_array[0], 2, 1)))) {
                    $langLocation  = strtoupper(substr($temp_array[0], 3, 2));
                    $temp_array[0] = $temp_array[1].'-'.$langLocation;
                }
                //place this array into main $user_languages language array
                $user_languages[] = $temp_array;
            }
        } else {// if no languages found
            $user_languages[0] = array('', ''); //return blank array.
        }

        $this->language = null;
        $basename       = basename(__FILE__, '.php').'.ini';

        // Try to match main language part of the filename, irrespective of the location, e.g. de_DE will do if de_CH doesn't exist.
        if (class_exists('AKUtilsLister')) {
            $fs       = new AKUtilsLister();
            $iniFiles = $fs->getFiles(KSROOTDIR, '*.'.$basename);
            if (empty($iniFiles) && ('kickstart.ini' != $basename)) {
                $basename = 'kickstart.ini';
                $iniFiles = $fs->getFiles(KSROOTDIR, '*.'.$basename);
            }
        } else {
            $iniFiles = null;
        }

        if (is_array($iniFiles)) {
            foreach ($user_languages as $languageStruct) {
                if (is_null($this->language)) {
                    // Get files matching the main lang part
                    $iniFiles = $fs->getFiles(KSROOTDIR, $languageStruct[1].'-??.'.$basename);
                    if (count($iniFiles) > 0) {
                        $filename       = $iniFiles[0];
                        $filename       = substr($filename, strlen(KSROOTDIR) + 1);
                        $this->language = substr($filename, 0, 5);
                    } else {
                        $this->language = null;
                    }
                }
            }
        }

        if (is_null($this->language)) {
            // Try to find a full language match
            foreach ($user_languages as $languageStruct) {
                if (@file_exists($languageStruct[0].'.'.$basename) && is_null($this->language)) {
                    $this->language = $languageStruct[0];
                } else {
                }
            }
        } else {
            // Do we have an exact match?
            foreach ($user_languages as $languageStruct) {
                if (substr($this->language, 0, strlen($languageStruct[1])) == $languageStruct[1]) {
                    if (file_exists($languageStruct[0].'.'.$basename)) {
                        $this->language = $languageStruct[0];
                    }
                }
            }
        }

        // Now, scan for full language based on the partial match
    }

    public static function sprintf($key)
    {
        $text = self::getInstance();
        $args = func_get_args();
        if (count($args) > 0) {
            $args[0] = $text->_($args[0]);

            return @call_user_func_array('sprintf', $args);
        }

        return '';
    }

    /**
     * Singleton pattern for Language.
     *
     * @return AKText The global AKText instance
     */
    public static function &getInstance()
    {
        static $instance;

        if (!is_object($instance)) {
            $instance = new AKText();
        }

        return $instance;
    }

    public static function _($string)
    {
        $text = self::getInstance();

        $key = strtoupper($string);
        $key = '_' == substr($key, 0, 1) ? substr($key, 1) : $key;

        if (isset($text->strings[$key])) {
            $string = $text->strings[$key];
        } else {
            if (defined($string)) {
                $string = constant($string);
            }
        }

        return $string;
    }

    public function dumpLanguage()
    {
        $out = '';
        foreach ($this->strings as $key => $value) {
            $out .= "$key=$value\n";
        }

        return $out;
    }

    public function asJavascript()
    {
        $out = '';
        foreach ($this->strings as $key => $value) {
            $key   = addcslashes($key, '\\\'"');
            $value = addcslashes($value, '\\\'"');
            if (!empty($out)) {
                $out .= ",\n";
            }
            $out .= "'$key':\t'$value'";
        }

        return $out;
    }

    public function resetTranslation()
    {
        $this->strings = $this->default_translation;
    }

    public function addDefaultLanguageStrings($stringList = array())
    {
        if (!is_array($stringList)) {
            return;
        }
        if (empty($stringList)) {
            return;
        }

        $this->strings = array_merge($stringList, $this->strings);
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * The Akeeba Kickstart Factory class
 * This class is reponssible for instanciating all Akeeba Kicsktart classes.
 */
class AKFactory
{
    /** @var array A list of instanciated objects */
    private $objectlist = array();

    /** @var array Simple hash data storage */
    private $varlist = array();

    /** Private constructor makes sure we can't directly instanciate the class */
    private function __construct()
    {
    }

    /**
     * Gets a serialized snapshot of the Factory for safekeeping (hibernate).
     *
     * @return string The serialized snapshot of the Factory
     */
    public static function serialize()
    {
        $engine = self::getUnarchiver();
        $engine->shutdown();
        $serialized = serialize(self::getInstance());

        if (function_exists('base64_encode') && function_exists('base64_decode')) {
            $serialized = base64_encode($serialized);
        }

        return $serialized;
    }

    /**
     * Gets the unarchiver engine.
     */
    public static function &getUnarchiver($configOverride = null)
    {
        static $class_name;

        if (!empty($configOverride)) {
            if ($configOverride['reset']) {
                $class_name = null;
            }
        }

        if (empty($class_name)) {
            $filetype = self::get('kickstart.setup.filetype', null);

            if (empty($filetype)) {
                $filename      = self::get('kickstart.setup.sourcefile', null);
                $basename      = basename($filename);
                $baseextension = strtoupper(substr($basename, -3));
                switch ($baseextension) {
                    case 'JPA':
                        $filetype = 'JPA';
                        break;

                    case 'JPS':
                        $filetype = 'JPS';
                        break;

                    case 'ZIP':
                        $filetype = 'ZIP';
                        break;

                    default:
                        die('Invalid archive type or extension in file '.$filename);
                        break;
                }
            }

            $class_name = 'AKUnarchiver'.ucfirst($filetype);
        }

        $destdir = self::get('kickstart.setup.destdir', null);
        if (empty($destdir)) {
            $destdir = KSROOTDIR;
        }

        $object = self::getClassInstance($class_name);
        if ('init' == $object->getState()) {
            $sourcePath = self::get('kickstart.setup.sourcepath', '');
            $sourceFile = self::get('kickstart.setup.sourcefile', '');

            if (!empty($sourcePath)) {
                $sourceFile = rtrim($sourcePath, '/\\').'/'.$sourceFile;
            }

            // Initialize the object
            $config = array(
                'filename'            => $sourceFile,
                'restore_permissions' => self::get('kickstart.setup.restoreperms', 0),
                'post_proc'           => self::get('kickstart.procengine', 'direct'),
                'add_path'            => self::get('kickstart.setup.targetpath', $destdir),
                'rename_files'        => array('.htaccess' => 'htaccess.bak',
                    'php.ini'                              => 'php.ini.bak',
                    'web.config'                           => 'web.config.bak', ),
                'skip_files' => array(basename(__FILE__),
                    'kickstart.php',
                    'abiautomation.ini',
                    'htaccess.bak',
                    'php.ini.bak',
                    'cacert.pem', ),
                'ignoredirectories' => array('tmp', 'log', 'logs'),
            );

            if (!defined('KICKSTART')) {
                // In restore.php mode we have to exclude some more files
                $config['skip_files'][] = 'administrator/components/com_akeeba/restore.php';
                $config['skip_files'][] = 'administrator/components/com_akeeba/restoration.php';
            }

            if (!empty($configOverride)) {
                foreach ($configOverride as $key => $value) {
                    $config[$key] = $value;
                }
            }

            $object->setup($config);
        }

        return $object;
    }

    // ========================================================================
    // Public factory interface
    // ========================================================================

    public static function get($key, $default = null)
    {
        $self = self::getInstance();
        if (array_key_exists($key, $self->varlist)) {
            return $self->varlist[$key];
        } else {
            return $default;
        }
    }

    /**
     * Gets a single, internally used instance of the Factory.
     *
     * @param string $serialized_data [optional] Serialized data to spawn the instance from
     *
     * @return AKFactory A reference to the unique Factory object instance
     */
    protected static function &getInstance($serialized_data = null)
    {
        static $myInstance;
        if (!is_object($myInstance) || !is_null($serialized_data)) {
            if (!is_null($serialized_data)) {
                $myInstance = unserialize($serialized_data);
            } else {
                $myInstance = new self();
            }
        }

        return $myInstance;
    }

    /**
     * Internal function which instanciates a class named $class_name.
     * The autoloader.
     *
     * @param object $class_name
     *
     * @return
     */
    protected static function &getClassInstance($class_name)
    {
        $self = self::getInstance();
        if (!isset($self->objectlist[$class_name])) {
            $self->objectlist[$class_name] = new $class_name();
        }

        return $self->objectlist[$class_name];
    }

    // ========================================================================
    // Public hash data storage interface
    // ========================================================================

    /**
     * Regenerates the full Factory state from a serialized snapshot (resume).
     *
     * @param string $serialized_data The serialized snapshot to resume from
     */
    public static function unserialize($serialized_data)
    {
        if (function_exists('base64_encode') && function_exists('base64_decode')) {
            $serialized_data = base64_decode($serialized_data);
        }
        self::getInstance($serialized_data);
    }

    /**
     * Reset the internal factory state, freeing all previously created objects.
     */
    public static function nuke()
    {
        $self = self::getInstance();
        foreach ($self->objectlist as $key => $object) {
            $self->objectlist[$key] = null;
        }
        $self->objectlist = array();
    }

    // ========================================================================
    // Akeeba Kickstart classes
    // ========================================================================

    public static function set($key, $value)
    {
        $self                = self::getInstance();
        $self->varlist[$key] = $value;
    }

    /**
     * Gets the post processing engine.
     *
     * @param string $proc_engine
     */
    public static function &getPostProc($proc_engine = null)
    {
        static $class_name;
        if (empty($class_name)) {
            if (empty($proc_engine)) {
                $proc_engine = self::get('kickstart.procengine', 'direct');
            }
            $class_name = 'AKPostproc'.ucfirst($proc_engine);
        }

        return self::getClassInstance($class_name);
    }

    /**
     * Get the a reference to the Akeeba Engine's timer.
     *
     * @return AKCoreTimer
     */
    public static function &getTimer()
    {
        return self::getClassInstance('AKCoreTimer');
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * AES implementation in PHP (c) Chris Veness 2005-2013.
 * Right to use and adapt is granted for under a simple creative commons attribution
 * licence. No warranty of any form is offered.
 *
 * Modified for Akeeba Backup by Nicholas K. Dionysopoulos
 */
class AKEncryptionAES
{
    // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [�5.1.1]
    protected static $Sbox =
        array(0x63,
            0x7c,
            0x77,
            0x7b,
            0xf2,
            0x6b,
            0x6f,
            0xc5,
            0x30,
            0x01,
            0x67,
            0x2b,
            0xfe,
            0xd7,
            0xab,
            0x76,
            0xca,
            0x82,
            0xc9,
            0x7d,
            0xfa,
            0x59,
            0x47,
            0xf0,
            0xad,
            0xd4,
            0xa2,
            0xaf,
            0x9c,
            0xa4,
            0x72,
            0xc0,
            0xb7,
            0xfd,
            0x93,
            0x26,
            0x36,
            0x3f,
            0xf7,
            0xcc,
            0x34,
            0xa5,
            0xe5,
            0xf1,
            0x71,
            0xd8,
            0x31,
            0x15,
            0x04,
            0xc7,
            0x23,
            0xc3,
            0x18,
            0x96,
            0x05,
            0x9a,
            0x07,
            0x12,
            0x80,
            0xe2,
            0xeb,
            0x27,
            0xb2,
            0x75,
            0x09,
            0x83,
            0x2c,
            0x1a,
            0x1b,
            0x6e,
            0x5a,
            0xa0,
            0x52,
            0x3b,
            0xd6,
            0xb3,
            0x29,
            0xe3,
            0x2f,
            0x84,
            0x53,
            0xd1,
            0x00,
            0xed,
            0x20,
            0xfc,
            0xb1,
            0x5b,
            0x6a,
            0xcb,
            0xbe,
            0x39,
            0x4a,
            0x4c,
            0x58,
            0xcf,
            0xd0,
            0xef,
            0xaa,
            0xfb,
            0x43,
            0x4d,
            0x33,
            0x85,
            0x45,
            0xf9,
            0x02,
            0x7f,
            0x50,
            0x3c,
            0x9f,
            0xa8,
            0x51,
            0xa3,
            0x40,
            0x8f,
            0x92,
            0x9d,
            0x38,
            0xf5,
            0xbc,
            0xb6,
            0xda,
            0x21,
            0x10,
            0xff,
            0xf3,
            0xd2,
            0xcd,
            0x0c,
            0x13,
            0xec,
            0x5f,
            0x97,
            0x44,
            0x17,
            0xc4,
            0xa7,
            0x7e,
            0x3d,
            0x64,
            0x5d,
            0x19,
            0x73,
            0x60,
            0x81,
            0x4f,
            0xdc,
            0x22,
            0x2a,
            0x90,
            0x88,
            0x46,
            0xee,
            0xb8,
            0x14,
            0xde,
            0x5e,
            0x0b,
            0xdb,
            0xe0,
            0x32,
            0x3a,
            0x0a,
            0x49,
            0x06,
            0x24,
            0x5c,
            0xc2,
            0xd3,
            0xac,
            0x62,
            0x91,
            0x95,
            0xe4,
            0x79,
            0xe7,
            0xc8,
            0x37,
            0x6d,
            0x8d,
            0xd5,
            0x4e,
            0xa9,
            0x6c,
            0x56,
            0xf4,
            0xea,
            0x65,
            0x7a,
            0xae,
            0x08,
            0xba,
            0x78,
            0x25,
            0x2e,
            0x1c,
            0xa6,
            0xb4,
            0xc6,
            0xe8,
            0xdd,
            0x74,
            0x1f,
            0x4b,
            0xbd,
            0x8b,
            0x8a,
            0x70,
            0x3e,
            0xb5,
            0x66,
            0x48,
            0x03,
            0xf6,
            0x0e,
            0x61,
            0x35,
            0x57,
            0xb9,
            0x86,
            0xc1,
            0x1d,
            0x9e,
            0xe1,
            0xf8,
            0x98,
            0x11,
            0x69,
            0xd9,
            0x8e,
            0x94,
            0x9b,
            0x1e,
            0x87,
            0xe9,
            0xce,
            0x55,
            0x28,
            0xdf,
            0x8c,
            0xa1,
            0x89,
            0x0d,
            0xbf,
            0xe6,
            0x42,
            0x68,
            0x41,
            0x99,
            0x2d,
            0x0f,
            0xb0,
            0x54,
            0xbb,
            0x16, );

    // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [�5.2]
    protected static $Rcon = array(
        array(0x00, 0x00, 0x00, 0x00),
        array(0x01, 0x00, 0x00, 0x00),
        array(0x02, 0x00, 0x00, 0x00),
        array(0x04, 0x00, 0x00, 0x00),
        array(0x08, 0x00, 0x00, 0x00),
        array(0x10, 0x00, 0x00, 0x00),
        array(0x20, 0x00, 0x00, 0x00),
        array(0x40, 0x00, 0x00, 0x00),
        array(0x80, 0x00, 0x00, 0x00),
        array(0x1b, 0x00, 0x00, 0x00),
        array(0x36, 0x00, 0x00, 0x00), );

    protected static $passwords = array();

    /**
     * Encrypt a text using AES encryption in Counter mode of operation
     *  - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf.
     *
     * Unicode multi-byte character safe
     *
     * @param plaintext source text to be encrypted
     * @param password  the password to use to generate a key
     * @param nBits     number of bits to be used in the key (128, 192, or 256)
     *
     * @return encrypted text
     */
    public static function AESEncryptCtr($plaintext, $password, $nBits)
    {
        $blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
        if (!(128 == $nBits || 192 == $nBits || 256 == $nBits)) {
            return '';
        }  // standard allows 128/192/256 bit keys
        // note PHP (5) gives us plaintext and password in UTF8 encoding!

        // use AES itself to encrypt password to get cipher key (using plain password as source for
        // key expansion) - gives us well encrypted key
        $nBytes  = $nBits / 8;  // no bytes in key
        $pwBytes = array();
        for ($i = 0; $i < $nBytes; ++$i) {
            $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
        }
        $key = self::Cipher($pwBytes, self::KeyExpansion($pwBytes));
        $key = array_merge($key, array_slice($key, 0, $nBytes - 16));  // expand key to 16/24/32 bytes long

        // initialise counter block (NIST SP800-38A �B.2): millisecond time-stamp for nonce in
        // 1st 8 bytes, block counter in 2nd 8 bytes
        $counterBlock = array();
        $nonce        = floor(microtime(true) * 1000);   // timestamp: milliseconds since 1-Jan-1970
        $nonceSec     = floor($nonce / 1000);
        $nonceMs      = $nonce % 1000;
        // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
        for ($i = 0; $i < 4; ++$i) {
            $counterBlock[$i] = self::urs($nonceSec, $i * 8) & 0xff;
        }
        for ($i = 0; $i < 4; ++$i) {
            $counterBlock[$i + 4] = $nonceMs & 0xff;
        }
        // and convert it to a string to go on the front of the ciphertext
        $ctrTxt = '';
        for ($i = 0; $i < 8; ++$i) {
            $ctrTxt .= chr($counterBlock[$i]);
        }

        // generate key schedule - an expansion of the key into distinct Key Rounds for each round
        $keySchedule = self::KeyExpansion($key);

        $blockCount = ceil(strlen($plaintext) / $blockSize);
        $ciphertxt  = array();  // ciphertext as array of strings

        for ($b = 0; $b < $blockCount; ++$b) {
            // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
            // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
            for ($c = 0; $c < 4; ++$c) {
                $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
            }
            for ($c = 0; $c < 4; ++$c) {
                $counterBlock[15 - $c - 4] = self::urs($b / 0x100000000, $c * 8);
            }

            $cipherCntr = self::Cipher($counterBlock, $keySchedule);  // -- encrypt counter block --

            // block size is reduced on final block
            $blockLength = $b < $blockCount - 1 ? $blockSize : (strlen($plaintext) - 1) % $blockSize + 1;
            $cipherByte  = array();

            for ($i = 0; $i < $blockLength; ++$i) {  // -- xor plaintext with ciphered counter byte-by-byte --
                $cipherByte[$i] = $cipherCntr[$i] ^ ord(substr($plaintext, $b * $blockSize + $i, 1));
                $cipherByte[$i] = chr($cipherByte[$i]);
            }
            $ciphertxt[$b] = implode('', $cipherByte);  // escape troublesome characters in ciphertext
        }

        // implode is more efficient than repeated string concatenation
        $ciphertext = $ctrTxt.implode('', $ciphertxt);
        $ciphertext = base64_encode($ciphertext);

        return $ciphertext;
    }

    /**
     * AES Cipher function: encrypt 'input' with Rijndael algorithm.
     *
     * @param input message as byte-array (16 bytes)
     * @param w     key schedule as 2D byte-array (Nr+1 x Nb bytes) -
     *              generated from the cipher key by KeyExpansion()
     *
     * @return ciphertext as byte-array (16 bytes)
     */
    protected static function Cipher($input, $w)
    {    // main Cipher function [�5.1]
        $Nb = 4;                 // block size (in words): no of columns in state (fixed at 4 for AES)
        $Nr = count($w) / $Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys

        $state = array();  // initialise 4xNb byte-array 'state' with input [�3.4]
        for ($i = 0; $i < 4 * $Nb; ++$i) {
            $state[$i % 4][floor($i / 4)] = $input[$i];
        }

        $state = self::AddRoundKey($state, $w, 0, $Nb);

        for ($round = 1; $round < $Nr; ++$round) {  // apply Nr rounds
            $state = self::SubBytes($state, $Nb);
            $state = self::ShiftRows($state, $Nb);
            $state = self::MixColumns($state, $Nb);
            $state = self::AddRoundKey($state, $w, $round, $Nb);
        }

        $state = self::SubBytes($state, $Nb);
        $state = self::ShiftRows($state, $Nb);
        $state = self::AddRoundKey($state, $w, $Nr, $Nb);

        $output = array(4 * $Nb);  // convert state to 1-d array before returning [�3.4]
        for ($i = 0; $i < 4 * $Nb; ++$i) {
            $output[$i] = $state[$i % 4][floor($i / 4)];
        }

        return $output;
    }

    protected static function AddRoundKey($state, $w, $rnd, $Nb)
    {  // xor Round Key into state S [�5.1.4]
        for ($r = 0; $r < 4; ++$r) {
            for ($c = 0; $c < $Nb; ++$c) {
                $state[$r][$c] ^= $w[$rnd * 4 + $c][$r];
            }
        }

        return $state;
    }

    protected static function SubBytes($s, $Nb)
    {    // apply SBox to state S [�5.1.1]
        for ($r = 0; $r < 4; ++$r) {
            for ($c = 0; $c < $Nb; ++$c) {
                $s[$r][$c] = self::$Sbox[$s[$r][$c]];
            }
        }

        return $s;
    }

    protected static function ShiftRows($s, $Nb)
    {    // shift row r of state S left by r bytes [�5.1.2]
        $t = array(4);
        for ($r = 1; $r < 4; ++$r) {
            for ($c = 0; $c < 4; ++$c) {
                $t[$c] = $s[$r][($c + $r) % $Nb];
            }  // shift into temp copy
            for ($c = 0; $c < 4; ++$c) {
                $s[$r][$c] = $t[$c];
            }         // and copy back
        }          // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
        return $s;  // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
    }

    protected static function MixColumns($s, $Nb)
    {   // combine bytes of each col of state S [�5.1.3]
        for ($c = 0; $c < 4; ++$c) {
            $a = array(4);  // 'a' is a copy of the current column from 's'
            $b = array(4);  // 'b' is a�{02} in GF(2^8)
            for ($i = 0; $i < 4; ++$i) {
                $a[$i] = $s[$i][$c];
                $b[$i] = $s[$i][$c] & 0x80 ? $s[$i][$c] << 1 ^ 0x011b : $s[$i][$c] << 1;
            }
            // a[n] ^ b[n] is a�{03} in GF(2^8)
            $s[0][$c] = $b[0] ^ $a[1] ^ $b[1] ^ $a[2] ^ $a[3]; // 2*a0 + 3*a1 + a2 + a3
            $s[1][$c] = $a[0] ^ $b[1] ^ $a[2] ^ $b[2] ^ $a[3]; // a0 * 2*a1 + 3*a2 + a3
            $s[2][$c] = $a[0] ^ $a[1] ^ $b[2] ^ $a[3] ^ $b[3]; // a0 + a1 + 2*a2 + 3*a3
            $s[3][$c] = $a[0] ^ $b[0] ^ $a[1] ^ $a[2] ^ $b[3]; // 3*a0 + a1 + a2 + 2*a3
        }

        return $s;
    }

    /**
     * Key expansion for Rijndael Cipher(): performs key expansion on cipher key
     * to generate a key schedule.
     *
     * @param key cipher key byte-array (16 bytes)
     *
     * @return key schedule as 2D byte-array (Nr+1 x Nb bytes)
     */
    protected static function KeyExpansion($key)
    {  // generate Key Schedule from Cipher Key [�5.2]
        $Nb = 4;              // block size (in words): no of columns in state (fixed at 4 for AES)
        $Nk = count($key) / 4;  // key length (in words): 4/6/8 for 128/192/256-bit keys
        $Nr = $Nk + 6;        // no of rounds: 10/12/14 for 128/192/256-bit keys

        $w    = array();
        $temp = array();

        for ($i = 0; $i < $Nk; ++$i) {
            $r     = array($key[4 * $i], $key[4 * $i + 1], $key[4 * $i + 2], $key[4 * $i + 3]);
            $w[$i] = $r;
        }

        for ($i = $Nk; $i < ($Nb * ($Nr + 1)); ++$i) {
            $w[$i] = array();
            for ($t = 0; $t < 4; ++$t) {
                $temp[$t] = $w[$i - 1][$t];
            }
            if (0 == $i % $Nk) {
                $temp = self::SubWord(self::RotWord($temp));
                for ($t = 0; $t < 4; ++$t) {
                    $temp[$t] ^= self::$Rcon[$i / $Nk][$t];
                }
            } elseif ($Nk > 6 && 4 == $i % $Nk) {
                $temp = self::SubWord($temp);
            }
            for ($t = 0; $t < 4; ++$t) {
                $w[$i][$t] = $w[$i - $Nk][$t] ^ $temp[$t];
            }
        }

        return $w;
    }

    protected static function SubWord($w)
    {    // apply SBox to 4-byte word w
        for ($i = 0; $i < 4; ++$i) {
            $w[$i] = self::$Sbox[$w[$i]];
        }

        return $w;
    }

    /*
     * Unsigned right shift function, since PHP has neither >>> operator nor unsigned ints
     *
     * @param a  number to be shifted (32-bit integer)
     * @param b  number of bits to shift a to the right (0..31)
     * @return   a right-shifted and zero-filled by b bits
     */

    protected static function RotWord($w)
    {    // rotate 4-byte word w left by one byte
        $tmp = $w[0];
        for ($i = 0; $i < 3; ++$i) {
            $w[$i] = $w[$i + 1];
        }
        $w[3] = $tmp;

        return $w;
    }

    protected static function urs($a, $b)
    {
        $a &= 0xffffffff;
        $b &= 0x1f;  // (bounds check)
        if ($a & 0x80000000 && $b > 0) {   // if left-most bit set
            $a = ($a >> 1) & 0x7fffffff;   //   right-shift one bit & clear left-most bit
            $a = $a >> ($b - 1);           //   remaining right-shifts
        } else {                       // otherwise
            $a = ($a >> $b);               //   use normal right-shift
        }

        return $a;
    }

    /**
     * Decrypt a text encrypted by AES in counter mode of operation.
     *
     * @param ciphertext source text to be decrypted
     * @param password   the password to use to generate a key
     * @param nBits      number of bits to be used in the key (128, 192, or 256)
     *
     * @return decrypted text
     */
    public static function AESDecryptCtr($ciphertext, $password, $nBits)
    {
        $blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
        if (!(128 == $nBits || 192 == $nBits || 256 == $nBits)) {
            return '';
        }  // standard allows 128/192/256 bit keys
        $ciphertext = base64_decode($ciphertext);

        // use AES to encrypt password (mirroring encrypt routine)
        $nBytes  = $nBits / 8;  // no bytes in key
        $pwBytes = array();
        for ($i = 0; $i < $nBytes; ++$i) {
            $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
        }
        $key = self::Cipher($pwBytes, self::KeyExpansion($pwBytes));
        $key = array_merge($key, array_slice($key, 0, $nBytes - 16));  // expand key to 16/24/32 bytes long

        // recover nonce from 1st element of ciphertext
        $counterBlock = array();
        $ctrTxt       = substr($ciphertext, 0, 8);
        for ($i = 0; $i < 8; ++$i) {
            $counterBlock[$i] = ord(substr($ctrTxt, $i, 1));
        }

        // generate key schedule
        $keySchedule = self::KeyExpansion($key);

        // separate ciphertext into blocks (skipping past initial 8 bytes)
        $nBlocks = ceil((strlen($ciphertext) - 8) / $blockSize);
        $ct      = array();
        for ($b = 0; $b < $nBlocks; ++$b) {
            $ct[$b] = substr($ciphertext, 8 + $b * $blockSize, 16);
        }
        $ciphertext = $ct;  // ciphertext is now array of block-length strings

        // plaintext will get generated block-by-block into array of block-length strings
        $plaintxt = array();

        for ($b = 0; $b < $nBlocks; ++$b) {
            // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
            for ($c = 0; $c < 4; ++$c) {
                $counterBlock[15 - $c] = self::urs($b, $c * 8) & 0xff;
            }
            for ($c = 0; $c < 4; ++$c) {
                $counterBlock[15 - $c - 4] = self::urs(($b + 1) / 0x100000000 - 1, $c * 8) & 0xff;
            }

            $cipherCntr = self::Cipher($counterBlock, $keySchedule);  // encrypt counter block

            $plaintxtByte = array();
            for ($i = 0; $i < strlen($ciphertext[$b]); ++$i) {
                // -- xor plaintext with ciphered counter byte-by-byte --
                $plaintxtByte[$i] = $cipherCntr[$i] ^ ord(substr($ciphertext[$b], $i, 1));
                $plaintxtByte[$i] = chr($plaintxtByte[$i]);
            }
            $plaintxt[$b] = implode('', $plaintxtByte);
        }

        // join array of blocks into single plaintext string
        $plaintext = implode('', $plaintxt);

        return $plaintext;
    }

    /**
     * AES decryption in CBC mode. This is the standard mode (the CTR methods
     * actually use Rijndael-128 in CTR mode, which - technically - isn't AES).
     *
     * Supports AES-128, AES-192 and AES-256. It supposes that the last 4 bytes
     * contained a little-endian unsigned long integer representing the unpadded
     * data length.
     *
     * @since  3.0.1
     *
     * @author Nicholas K. Dionysopoulos
     *
     * @param string $ciphertext The data to encrypt
     * @param string $password   Encryption password
     * @param int    $nBits      Encryption key size. Can be 128, 192 or 256
     *
     * @return string The plaintext
     */
    public static function AESDecryptCBC($ciphertext, $password, $nBits = 128)
    {
        if (!(128 == $nBits || 192 == $nBits || 256 == $nBits)) {
            return false;
        }  // standard allows 128/192/256 bit keys
        if (!function_exists('mcrypt_module_open')) {
            return false;
        }

        // Try to fetch cached key/iv or create them if they do not exist
        $lookupKey = $password.'-'.$nBits;
        if (array_key_exists($lookupKey, self::$passwords)) {
            $key = self::$passwords[$lookupKey]['key'];
            $iv  = self::$passwords[$lookupKey]['iv'];
        } else {
            // use AES itself to encrypt password to get cipher key (using plain password as source for
            // key expansion) - gives us well encrypted key
            $nBytes  = $nBits / 8;  // no bytes in key
            $pwBytes = array();
            for ($i = 0; $i < $nBytes; ++$i) {
                $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
            }
            $key    = self::Cipher($pwBytes, self::KeyExpansion($pwBytes));
            $key    = array_merge($key, array_slice($key, 0, $nBytes - 16));  // expand key to 16/24/32 bytes long
            $newKey = '';
            foreach ($key as $int) {
                $newKey .= chr($int);
            }
            $key = $newKey;

            // Create an Initialization Vector (IV) based on the password, using the same technique as for the key
            $nBytes  = 16;  // AES uses a 128 -bit (16 byte) block size, hence the IV size is always 16 bytes
            $pwBytes = array();
            for ($i = 0; $i < $nBytes; ++$i) {
                $pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
            }
            $iv    = self::Cipher($pwBytes, self::KeyExpansion($pwBytes));
            $newIV = '';
            foreach ($iv as $int) {
                $newIV .= chr($int);
            }
            $iv = $newIV;

            self::$passwords[$lookupKey]['key'] = $key;
            self::$passwords[$lookupKey]['iv']  = $iv;
        }

        // Read the data size
        $data_size = unpack('V', substr($ciphertext, -4));

        // Decrypt
        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
        mcrypt_generic_init($td, $key, $iv);
        $plaintext = mdecrypt_generic($td, substr($ciphertext, 0, -4));
        mcrypt_generic_deinit($td);

        // Trim padding, if necessary
        if (strlen($plaintext) > $data_size) {
            $plaintext = substr($plaintext, 0, $data_size);
        }

        return $plaintext;
    }
}

/**
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library.
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 */

/**
 * The Master Setup will read the configuration parameters from restoration.php or
 * the JSON-encoded "configuration" input variable and return the status.
 *
 * @return bool True if the master configuration was applied to the Factory object
 */
function masterSetup()
{
    // ------------------------------------------------------------
    // 1. Import basic setup parameters
    // ------------------------------------------------------------

    $ini_data = null;

    // In restore.php mode, require restoration.php or fail
    if (!defined('KICKSTART')) {
        // This is the standalone mode, used by Akeeba Backup Professional. It looks for a restoration.php
        // file to perform its magic. If the file is not there, we will abort.
        $setupFile = 'tmp/restoration.php';

        if (!file_exists($setupFile)) {
            AKFactory::set('kickstart.enabled', false);

            return false;
        }

        // Load restoration.php. It creates a global variable named $restoration_setup
        require_once $setupFile;

        $ini_data = $restoration_setup;

        if (empty($ini_data)) {
            // No parameters fetched. Darn, how am I supposed to work like that?!
            AKFactory::set('kickstart.enabled', false);

            return false;
        }

        AKFactory::set('kickstart.enabled', true);
    } else {
        // Maybe we have $restoration_setup defined in the head of kickstart.php
        global $restoration_setup;

        if (!empty($restoration_setup) && !is_array($restoration_setup)) {
            $ini_data = AKText::parse_ini_file($restoration_setup, false, true);
        } elseif (is_array($restoration_setup)) {
            $ini_data = $restoration_setup;
        }
    }

    // Import any data from $restoration_setup
    if (!empty($ini_data)) {
        foreach ($ini_data as $key => $value) {
            AKFactory::set($key, $value);
        }
        AKFactory::set('kickstart.enabled', true);
    }

    // Reinitialize $ini_data
    $ini_data = null;

    // ------------------------------------------------------------
    // 2. Explode JSON parameters into $_REQUEST scope
    // ------------------------------------------------------------

    // Detect a JSON string in the request variable and store it.
    $json = getQueryParam('json', null);

    // Remove everything from the request, post and get arrays
    if (!empty($_REQUEST)) {
        foreach ($_REQUEST as $key => $value) {
            unset($_REQUEST[$key]);
        }
    }

    if (!empty($_POST)) {
        foreach ($_POST as $key => $value) {
            unset($_POST[$key]);
        }
    }

    if (!empty($_GET)) {
        foreach ($_GET as $key => $value) {
            unset($_GET[$key]);
        }
    }

    // Decrypt a possibly encrypted JSON string
    $password = AKFactory::get('kickstart.security.password', null);

    if (!empty($json)) {
        if (!empty($password)) {
            $json = AKEncryptionAES::AESDecryptCtr($json, $password, 128);

            if (empty($json)) {
                die('###{"status":false,"message":"Invalid login"}###');
            }
        }

        // Get the raw data
        $raw = json_decode($json, true);

        if (!empty($password) && (empty($raw))) {
            die('###{"status":false,"message":"Invalid login"}###');
        }

        // Pass all JSON data to the request array
        if (!empty($raw)) {
            foreach ($raw as $key => $value) {
                $_REQUEST[$key] = $value;
            }
        }
    } elseif (!empty($password)) {
        die('###{"status":false,"message":"Invalid login"}###');
    }

    // ------------------------------------------------------------
    // 3. Try the "factory" variable
    // ------------------------------------------------------------
    // A "factory" variable will override all other settings.
    $serialized = getQueryParam('factory', null);

    if (!is_null($serialized)) {
        // Get the serialized factory
        AKFactory::unserialize($serialized);
        AKFactory::set('kickstart.enabled', true);

        return true;
    }

    // ------------------------------------------------------------
    // 4. Try the configuration variable for Kickstart
    // ------------------------------------------------------------
    if (defined('KICKSTART')) {
        $configuration = getQueryParam('configuration');

        if (!is_null($configuration)) {
            // Let's decode the configuration from JSON to array
            $ini_data = json_decode($configuration, true);
        } else {
            // Neither exists. Enable Kickstart's interface anyway.
            $ini_data = array('kickstart.enabled' => true);
        }

        // Import any INI data we might have from other sources
        if (!empty($ini_data)) {
            foreach ($ini_data as $key => $value) {
                AKFactory::set($key, $value);
            }

            AKFactory::set('kickstart.enabled', true);

            return true;
        }
    }
}

/*
 * Akeeba Restore
 * A JSON-powered JPA, JPS and ZIP archive extraction library
 *
 * @copyright   2010-2014 Nicholas K. Dionysopoulos / Akeeba Ltd.
 * @license     GNU GPL v2 or - at your option - any later version
 * @package     akeebabackup
 * @subpackage  kickstart
 */

// Mini-controller for restore.php
if (!defined('KICKSTART')) {
    // The observer class, used to report number of files and bytes processed
    class RestorationObserver extends AKAbstractPartObserver
    {
        public $compressedTotal   = 0;
        public $uncompressedTotal = 0;
        public $filesProcessed    = 0;

        public function update($object, $message)
        {
            if (!is_object($message)) {
                return;
            }

            if (!array_key_exists('type', get_object_vars($message))) {
                return;
            }

            if ('startfile' == $message->type) {
                ++$this->filesProcessed;
                $this->compressedTotal += $message->content->compressed;
                $this->uncompressedTotal += $message->content->uncompressed;
            }
        }

        public function __toString()
        {
            return __CLASS__;
        }
    }

    // Import configuration
    masterSetup();

    $retArray = array(
        'status'  => true,
        'message' => null,
    );

    $enabled = AKFactory::get('kickstart.enabled', false);

    if ($enabled) {
        $task = getQueryParam('task');

        switch ($task) {
            case 'ping':
                // ping task - realy does nothing!
                $timer = AKFactory::getTimer();
                $timer->enforce_min_exec_time();
                break;

            case 'startRestore':
                AKFactory::nuke(); // Reset the factory

            // Let the control flow to the next step (the rest of the code is common!!)

            // no break
            case 'stepRestore':
                $engine   = AKFactory::getUnarchiver(); // Get the engine
                $observer = new RestorationObserver(); // Create a new observer
                $engine->attach($observer); // Attach the observer
                $engine->tick();
                $ret = $engine->getStatusArray();

                if ('' != $ret['Error']) {
                    $retArray['status']  = false;
                    $retArray['done']    = true;
                    $retArray['message'] = $ret['Error'];
                } elseif (!$ret['HasRun']) {
                    $retArray['files']    = $observer->filesProcessed;
                    $retArray['bytesIn']  = $observer->compressedTotal;
                    $retArray['bytesOut'] = $observer->uncompressedTotal;
                    $retArray['status']   = true;
                    $retArray['done']     = true;
                } else {
                    $retArray['files']    = $observer->filesProcessed;
                    $retArray['bytesIn']  = $observer->compressedTotal;
                    $retArray['bytesOut'] = $observer->uncompressedTotal;
                    $retArray['status']   = true;
                    $retArray['done']     = false;
                    $retArray['factory']  = AKFactory::serialize();
                }
                break;

            case 'finalizeRestore':
                $root = AKFactory::get('kickstart.setup.destdir');
                // Remove the installation directory
                recursive_remove_directory($root.'/installation');

                $postproc = AKFactory::getPostProc();

                // Rename htaccess.bak to .htaccess
                if (file_exists($root.'/htaccess.bak')) {
                    if (file_exists($root.'/.htaccess')) {
                        $postproc->unlink($root.'/.htaccess');
                    }
                    $postproc->rename($root.'/htaccess.bak', $root.'/.htaccess');
                }

                // Rename htaccess.bak to .htaccess
                if (file_exists($root.'/web.config.bak')) {
                    if (file_exists($root.'/web.config')) {
                        $postproc->unlink($root.'/web.config');
                    }
                    $postproc->rename($root.'/web.config.bak', $root.'/web.config');
                }

                // Remove restoration.php
                $basepath = KSROOTDIR;
                $basepath = rtrim(str_replace('\\', '/', $basepath), '/');
                if (!empty($basepath)) {
                    $basepath .= '/';
                }
                $postproc->unlink($basepath.'restoration.php');

                // Import a custom finalisation file
                if (file_exists(dirname(__FILE__).'/restore_finalisation.php')) {
                    include_once dirname(__FILE__).'/restore_finalisation.php';
                }

                // Run a custom finalisation script
                if (function_exists('finalizeRestore')) {
                    finalizeRestore($root, $basepath);
                }
                break;

            default:
                // Invalid task!
                $enabled = false;
                break;
        }
    }

    // Maybe we weren't authorized or the task was invalid?
    if (!$enabled) {
        // Maybe the user failed to enter any information
        $retArray['status']  = false;
        $retArray['message'] = AKText::_('ERR_INVALID_LOGIN');
    }

    // JSON encode the message
    $json = json_encode($retArray);
    // Do I have to encrypt?
    $password = AKFactory::get('kickstart.security.password', null);
    if (!empty($password)) {
        $json = AKEncryptionAES::AESEncryptCtr($json, $password, 128);
    }

    // Return the message
    echo "###$json###";
}

// ------------ lixlpixel recursive PHP functions -------------
// recursive_remove_directory( directory to delete, empty )
// expects path to directory and optional TRUE / FALSE to empty
// of course PHP has to have the rights to delete the directory
// you specify and all files and folders inside the directory
// ------------------------------------------------------------
function recursive_remove_directory($directory)
{
    // if the path has a slash at the end we remove it here
    if ('/' == substr($directory, -1)) {
        $directory = substr($directory, 0, -1);
    }
    // if the path is not valid or is not a directory ...
    if (!file_exists($directory) || !is_dir($directory)) {
        // ... we return false and exit the function
        return false;
    // ... if the path is not readable
    } elseif (!is_readable($directory)) {
        // ... we return false and exit the function
        return false;
    // ... else if the path is readable
    } else {
        // we open the directory
        $handle   = opendir($directory);
        $postproc = AKFactory::getPostProc();
        // and scan through the items inside
        while (false !== ($item = readdir($handle))) {
            // if the filepointer is not the current directory
            // or the parent directory
            if ('.' != $item && '..' != $item) {
                // we build the new path to delete
                $path = $directory.'/'.$item;
                // if the new path is a directory
                if (is_dir($path)) {
                    // we call this function with the new path
                    recursive_remove_directory($path);
                // if the new path is a file
                } else {
                    // we remove the file
                    $postproc->unlink($path);
                }
            }
        }
        // close the directory
        closedir($handle);
        // try to delete the now empty directory
        if (!$postproc->rmdir($directory)) {
            // return false if not possible
            return false;
        }

        // return success
        return true;
    }
}
PK��#]l>��+�+)system/bfnetwork/bfnetwork/Crypt/Base.phpnu�[���<?php

/**
 * Base Class for all Crypt_* cipher classes.
 *
 * PHP versions 4 and 5
 *
 * Internally for phpseclib developers:
 *  If you plan to add a new cipher class, please note following rules:
 *
 *  - The new Crypt_* cipher class should extend Crypt_Base
 *
 *  - Following methods are then required to be overridden/overloaded:
 *
 *    - _encryptBlock()
 *
 *    - _decryptBlock()
 *
 *    - _setupKey()
 *
 *  - All other methods are optional to be overridden/overloaded
 *
 *  - Look at the source code of the current ciphers how they extend Crypt_Base
 *    and take one of them as a start up for the new cipher class.
 *
 *  - Please read all the other comments/notes/hints here also for each class var/method
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category  Crypt
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 * @see      http://phpseclib.sourceforge.net
 */

/**#@+
 * @access public
 * @see Crypt_Base::encrypt()
 * @see Crypt_Base::decrypt()
 */
/**
 * Encrypt / decrypt using the Counter mode.
 *
 * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
 *
 * @see http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
 */
define('CRYPT_MODE_CTR', -1);
/*
 * Encrypt / decrypt using the Electronic Code Book mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
 */
define('CRYPT_MODE_ECB', 1);
/*
 * Encrypt / decrypt using the Code Book Chaining mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
 */
define('CRYPT_MODE_CBC', 2);
/*
 * Encrypt / decrypt using the Cipher Feedback mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
 */
define('CRYPT_MODE_CFB', 3);
/*
 * Encrypt / decrypt using the Output Feedback mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
 */
define('CRYPT_MODE_OFB', 4);
/*
 * Encrypt / decrypt using streaming mode.
 *
 */
define('CRYPT_MODE_STREAM', 5);
/**#@-*/

/**#@+
 * @access private
 * @see Crypt_Base::Crypt_Base()
 */
/*
 * Base value for the internal implementation $engine switch
 */
define('CRYPT_MODE_INTERNAL', 1);
/*
 * Base value for the mcrypt implementation $engine switch
 */
define('CRYPT_MODE_MCRYPT', 2);
/**#@-*/

/**
 * Base Class for all Crypt_* cipher classes.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
 */
class Crypt_Base
{
    /**
     * The Encryption Mode.
     *
     * @see Crypt_Base::Crypt_Base()
     *
     * @var int
     */
    public $mode;

    /**
     * The Block Length of the block cipher.
     *
     * @var int
     */
    public $block_size = 16;

    /**
     * The Key.
     *
     * @see Crypt_Base::setKey()
     *
     * @var string
     */
    public $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

    /**
     * The Initialization Vector.
     *
     * @see Crypt_Base::setIV()
     *
     * @var string
     */
    public $iv;

    /**
     * A "sliding" Initialization Vector.
     *
     * @see Crypt_Base::enableContinuousBuffer()
     * @see Crypt_Base::_clearBuffers()
     *
     * @var string
     */
    public $encryptIV;

    /**
     * A "sliding" Initialization Vector.
     *
     * @see Crypt_Base::enableContinuousBuffer()
     * @see Crypt_Base::_clearBuffers()
     *
     * @var string
     */
    public $decryptIV;

    /**
     * Continuous Buffer status.
     *
     * @see Crypt_Base::enableContinuousBuffer()
     *
     * @var bool
     */
    public $continuousBuffer = false;

    /**
     * Encryption buffer for CTR, OFB and CFB modes.
     *
     * @see Crypt_Base::encrypt()
     * @see Crypt_Base::_clearBuffers()
     *
     * @var array
     */
    public $enbuffer;

    /**
     * Decryption buffer for CTR, OFB and CFB modes.
     *
     * @see Crypt_Base::decrypt()
     * @see Crypt_Base::_clearBuffers()
     *
     * @var array
     */
    public $debuffer;

    /**
     * mcrypt resource for encryption.
     *
     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
     *
     * @see Crypt_Base::encrypt()
     *
     * @var resource
     */
    public $enmcrypt;

    /**
     * mcrypt resource for decryption.
     *
     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
     *
     * @see Crypt_Base::decrypt()
     *
     * @var resource
     */
    public $demcrypt;

    /**
     * Does the enmcrypt resource need to be (re)initialized?
     *
     * @see Crypt_Twofish::setKey()
     * @see Crypt_Twofish::setIV()
     *
     * @var bool
     */
    public $enchanged = true;

    /**
     * Does the demcrypt resource need to be (re)initialized?
     *
     * @see Crypt_Twofish::setKey()
     * @see Crypt_Twofish::setIV()
     *
     * @var bool
     */
    public $dechanged = true;

    /**
     * mcrypt resource for CFB mode.
     *
     * mcrypt's CFB mode, in (and only in) buffered context,
     * is broken, so phpseclib implements the CFB mode by it self,
     * even when the mcrypt php extension is available.
     *
     * In order to do the CFB-mode work (fast) phpseclib
     * use a separate ECB-mode mcrypt resource.
     *
     * @see http://phpseclib.sourceforge.net/cfb-demo.phps
     * @see Crypt_Base::encrypt()
     * @see Crypt_Base::decrypt()
     * @see Crypt_Base::_setupMcrypt()
     *
     * @var resource
     */
    public $ecb;

    /**
     * Optimizing value while CFB-encrypting.
     *
     * Only relevant if $continuousBuffer enabled
     * and $engine == CRYPT_MODE_MCRYPT
     *
     * It's faster to re-init $enmcrypt if
     * $buffer bytes > $cfb_init_len than
     * using the $ecb resource furthermore.
     *
     * This value depends of the chosen cipher
     * and the time it would be needed for it's
     * initialization [by mcrypt_generic_init()]
     * which, typically, depends on the complexity
     * on its internaly Key-expanding algorithm.
     *
     * @see Crypt_Base::encrypt()
     *
     * @var int
     */
    public $cfb_init_len = 600;

    /**
     * Does internal cipher state need to be (re)initialized?
     *
     * @see setKey()
     * @see setIV()
     * @see disableContinuousBuffer()
     *
     * @var bool
     */
    public $changed = true;

    /**
     * Padding status.
     *
     * @see Crypt_Base::enablePadding()
     *
     * @var bool
     */
    public $padding = true;

    /**
     * Is the mode one that is paddable?
     *
     * @see Crypt_Base::Crypt_Base()
     *
     * @var bool
     */
    public $paddable = false;

    /**
     * Holds which crypt engine internaly should be use,
     * which will be determined automatically on __construct().
     *
     * Currently available $engines are:
     * - CRYPT_MODE_MCRYPT   (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
     * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required)
     *
     * In the pipeline... maybe. But currently not available:
     * - CRYPT_MODE_OPENSSL  (very fast, php-extension: openssl, extension_loaded('openssl') required)
     *
     * If possible, CRYPT_MODE_MCRYPT will be used for each cipher.
     * Otherwise CRYPT_MODE_INTERNAL
     *
     * @see Crypt_Base::encrypt()
     * @see Crypt_Base::decrypt()
     *
     * @var int
     */
    public $engine;

    /**
     * The mcrypt specific name of the cipher.
     *
     * Only used if $engine == CRYPT_MODE_MCRYPT
     *
     * @see http://www.php.net/mcrypt_module_open
     * @see http://www.php.net/mcrypt_list_algorithms
     * @see Crypt_Base::_setupMcrypt()
     *
     * @var string
     */
    public $cipher_name_mcrypt;

    /**
     * The default password key_size used by setPassword().
     *
     * @see Crypt_Base::setPassword()
     *
     * @var int
     */
    public $password_key_size = 32;

    /**
     * The default salt used by setPassword().
     *
     * @see Crypt_Base::setPassword()
     *
     * @var string
     */
    public $password_default_salt = 'phpseclib/salt';

    /**
     * The namespace used by the cipher for its constants.
     *
     * ie: AES.php is using CRYPT_AES_MODE_* for its constants
     *     so $const_namespace is AES
     *
     *     DES.php is using CRYPT_DES_MODE_* for its constants
     *     so $const_namespace is DES... and so on
     *
     * All CRYPT_<$const_namespace>_MODE_* are aliases of
     * the generic CRYPT_MODE_* constants, so both could be used
     * for each cipher.
     *
     * Example:
     * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
     * $aes = new Crypt_AES(CRYPT_MODE_CFB);     // identical
     *
     * @see Crypt_Base::Crypt_Base()
     *
     * @var string
     */
    public $const_namespace;

    /**
     * The name of the performance-optimized callback function.
     *
     * Used by encrypt() / decrypt()
     * only if $engine == CRYPT_MODE_INTERNAL
     *
     * @see Crypt_Base::encrypt()
     * @see Crypt_Base::decrypt()
     * @see Crypt_Base::_setupInlineCrypt()
     * @see Crypt_Base::$use_inline_crypt
     *
     * @var callable
     */
    public $inline_crypt;

    /**
     * Holds whether performance-optimized $inline_crypt() can/should be used.
     *
     * @see Crypt_Base::encrypt()
     * @see Crypt_Base::decrypt()
     * @see Crypt_Base::inline_crypt
     *
     * @var mixed
     */
    public $use_inline_crypt;

    /**
     * Default Constructor.
     *
     * Determines whether or not the mcrypt extension should be used.
     *
     * $mode could be:
     *
     * - CRYPT_MODE_ECB
     *
     * - CRYPT_MODE_CBC
     *
     * - CRYPT_MODE_CTR
     *
     * - CRYPT_MODE_CFB
     *
     * - CRYPT_MODE_OFB
     *
     * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
     *
     * If not explicitly set, CRYPT_MODE_CBC will be used.
     *
     * @param optional Integer $mode
     */
    public function __construct($mode = CRYPT_MODE_CBC)
    {
        $const_crypt_mode = 'CRYPT_'.$this->const_namespace.'_MODE';

        // Determining the availibility of mcrypt support for the cipher
        if (!defined($const_crypt_mode)) {
            switch (true) {
                case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()):
                    define($const_crypt_mode, CRYPT_MODE_MCRYPT);
                    break;
                default:
                    define($const_crypt_mode, CRYPT_MODE_INTERNAL);
            }
        }

        // Determining which internal $engine should be used.
        // The fastes possible first.
        switch (true) {
            case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL
                $this->engine = CRYPT_MODE_INTERNAL;
                break;
            case CRYPT_MODE_MCRYPT == constant($const_crypt_mode):
                $this->engine = CRYPT_MODE_MCRYPT;
                break;
            default:
                $this->engine = CRYPT_MODE_INTERNAL;
        }

        // $mode dependent settings
        switch ($mode) {
            case CRYPT_MODE_ECB:
                $this->paddable = true;
                $this->mode     = $mode;
                break;
            case CRYPT_MODE_CTR:
            case CRYPT_MODE_CFB:
            case CRYPT_MODE_OFB:
            case CRYPT_MODE_STREAM:
                $this->mode = $mode;
                break;
            case CRYPT_MODE_CBC:
            default:
                $this->paddable = true;
                $this->mode     = CRYPT_MODE_CBC;
        }

        // Determining whether inline crypting can be used by the cipher
        if (false !== $this->use_inline_crypt && function_exists('create_function')) {
            $this->use_inline_crypt = true;
        }
    }

    /**
     * Sets the password.
     *
     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
     *         $hash, $salt, $count, $dkLen
     *
     *         Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @see Crypt/Hash.php
     *
     * @param string          $password
     * @param optional String $method
     *
     * @return bool
     */
    public function setPassword($password, $method = 'pbkdf2')
    {
        $key = '';

        switch ($method) {
            default: // 'pbkdf2' or 'pbkdf1'
                $func_args = func_get_args();

                // Hash function
                $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';

                // WPA and WPA2 use the SSID as the salt
                $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;

                // RFC2898#section-4.2 uses 1,000 iterations by default
                // WPA and WPA2 use 4,096.
                $count = isset($func_args[4]) ? $func_args[4] : 1000;

                // Keylength
                if (isset($func_args[5])) {
                    $dkLen = $func_args[5];
                } else {
                    $dkLen = 'pbkdf1' == $method ? 2 * $this->password_key_size : $this->password_key_size;
                }

                switch (true) {
                    case 'pbkdf1' == $method:
                        if (!class_exists('Crypt_Hash')) {
                            include_once 'Crypt/Hash.php';
                        }
                        $hashObj = new Crypt_Hash();
                        $hashObj->setHash($hash);
                        if ($dkLen > $hashObj->getLength()) {
                            user_error('Derived key too long');

                            return false;
                        }
                        $t = $password.$salt;
                        for ($i = 0; $i < $count; ++$i) {
                            $t = $hashObj->hash($t);
                        }
                        $key = substr($t, 0, $dkLen);

                        $this->setKey(substr($key, 0, $dkLen >> 1));
                        $this->setIV(substr($key, $dkLen >> 1));

                        return true;
                    // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
                    case !function_exists('hash_pbkdf2'):
                    case !function_exists('hash_algos'):
                    case !in_array($hash, hash_algos()):
                        if (!class_exists('Crypt_Hash')) {
                            include_once 'Crypt/Hash.php';
                        }
                        $i = 1;
                        while (strlen($key) < $dkLen) {
                            $hmac = new Crypt_Hash();
                            $hmac->setHash($hash);
                            $hmac->setKey($password);
                            $f = $u = $hmac->hash($salt.pack('N', $i++));
                            for ($j = 2; $j <= $count; ++$j) {
                                $u = $hmac->hash($u);
                                $f ^= $u;
                            }
                            $key .= $f;
                        }
                        $key = substr($key, 0, $dkLen);
                        break;
                    default:
                        $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
                }
        }

        $this->setKey($key);

        return true;
    }

    /**
     * Sets the key.
     *
     * The min/max length(s) of the key depends on the cipher which is used.
     * If the key not fits the length(s) of the cipher it will paded with null bytes
     * up to the closest valid key length.  If the key is more than max length,
     * we trim the excess bits.
     *
     * If the key is not explicitly set, it'll be assumed to be all null bytes.
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @param string $key
     */
    public function setKey($key)
    {
        $this->key     = $key;
        $this->changed = true;
    }

    /**
     * Sets the initialization vector. (optional).
     *
     * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used.  If not explicitly set, it'll be assumed
     * to be all zero's.
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @param string $iv
     */
    public function setIV($iv)
    {
        if (CRYPT_MODE_ECB == $this->mode) {
            return;
        }

        $this->iv      = $iv;
        $this->changed = true;
    }

    /**
     * Encrypts a message.
     *
     * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
     * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
     * necessary are discussed in the following
     * URL:
     *
     * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
     *
     * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
     * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
     * length.
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @see Crypt_Base::decrypt()
     *
     * @param string $plaintext
     *
     * @return string $cipertext
     */
    public function encrypt($plaintext)
    {
        if (CRYPT_MODE_MCRYPT == $this->engine) {
            if ($this->changed) {
                $this->_setupMcrypt();
                $this->changed = false;
            }
            if ($this->enchanged) {
                mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
                $this->enchanged = false;
            }

            // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
            // using mcrypt's default handing of CFB the above would output two different things.  using phpseclib's
            // rewritten CFB implementation the above outputs the same thing twice.
            if (CRYPT_MODE_CFB == $this->mode && $this->continuousBuffer) {
                $block_size = $this->block_size;
                $iv         = &$this->encryptIV;
                $pos        = &$this->enbuffer['pos'];
                $len        = strlen($plaintext);
                $ciphertext = '';
                $i          = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max      = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    $ciphertext                      = substr($iv, $orig_pos) ^ $plaintext;
                    $iv                              = substr_replace($iv, $ciphertext, $orig_pos, $i);
                    $this->enbuffer['enmcrypt_init'] = true;
                }
                if ($len >= $block_size) {
                    if (false === $this->enbuffer['enmcrypt_init'] || $len > $this->cfb_init_len) {
                        if (true === $this->enbuffer['enmcrypt_init']) {
                            mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
                            $this->enbuffer['enmcrypt_init'] = false;
                        }
                        $ciphertext .= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
                        $iv = substr($ciphertext, -$block_size);
                        $len %= $block_size;
                    } else {
                        while ($len >= $block_size) {
                            $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
                            $ciphertext .= $iv;
                            $len -= $block_size;
                            $i += $block_size;
                        }
                    }
                }

                if ($len) {
                    $iv    = mcrypt_generic($this->ecb, $iv);
                    $block = $iv ^ substr($plaintext, -$len);
                    $iv    = substr_replace($iv, $block, 0, $len);
                    $ciphertext .= $block;
                    $pos = $len;
                }

                return $ciphertext;
            }

            if ($this->paddable) {
                $plaintext = $this->_pad($plaintext);
            }

            $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);

            if (!$this->continuousBuffer) {
                mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
            }

            return $ciphertext;
        }

        if ($this->changed) {
            $this->_setup();
            $this->changed = false;
        }
        if ($this->use_inline_crypt) {
            $inline = $this->inline_crypt;

            return $inline('encrypt', $this, $plaintext);
        }
        if ($this->paddable) {
            $plaintext = $this->_pad($plaintext);
        }

        $buffer     = &$this->enbuffer;
        $block_size = $this->block_size;
        $ciphertext = '';
        switch ($this->mode) {
            case CRYPT_MODE_ECB:
                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                    $ciphertext .= $this->_encryptBlock(substr($plaintext, $i, $block_size));
                }
                break;
            case CRYPT_MODE_CBC:
                $xor = $this->encryptIV;
                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                    $block = substr($plaintext, $i, $block_size);
                    $block = $this->_encryptBlock($block ^ $xor);
                    $xor   = $block;
                    $ciphertext .= $block;
                }
                if ($this->continuousBuffer) {
                    $this->encryptIV = $xor;
                }
                break;
            case CRYPT_MODE_CTR:
                $xor = $this->encryptIV;
                if (strlen($buffer['encrypted'])) {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $block = substr($plaintext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['encrypted'])) {
                            $buffer['encrypted'] .= $this->_encryptBlock($this->_generateXor($xor, $block_size));
                        }
                        $key = $this->_stringShift($buffer['encrypted'], $block_size);
                        $ciphertext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $block = substr($plaintext, $i, $block_size);
                        $key   = $this->_encryptBlock($this->_generateXor($xor, $block_size));
                        $ciphertext .= $block ^ $key;
                    }
                }
                if ($this->continuousBuffer) {
                    $this->encryptIV = $xor;
                    if ($start = strlen($plaintext) % $block_size) {
                        $buffer['encrypted'] = substr($key, $start).$buffer['encrypted'];
                    }
                }
                break;
            case CRYPT_MODE_CFB:
                // cfb loosely routines inspired by openssl's:
                // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
                if ($this->continuousBuffer) {
                    $iv  = &$this->encryptIV;
                    $pos = &$buffer['pos'];
                } else {
                    $iv  = $this->encryptIV;
                    $pos = 0;
                }
                $len = strlen($plaintext);
                $i   = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max      = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
                    $iv         = substr_replace($iv, $ciphertext, $orig_pos, $i);
                }
                while ($len >= $block_size) {
                    $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
                    $ciphertext .= $iv;
                    $len -= $block_size;
                    $i += $block_size;
                }
                if ($len) {
                    $iv    = $this->_encryptBlock($iv);
                    $block = $iv ^ substr($plaintext, $i);
                    $iv    = substr_replace($iv, $block, 0, $len);
                    $ciphertext .= $block;
                    $pos = $len;
                }
                break;
            case CRYPT_MODE_OFB:
                $xor = $this->encryptIV;
                if (strlen($buffer['xor'])) {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $block = substr($plaintext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['xor'])) {
                            $xor = $this->_encryptBlock($xor);
                            $buffer['xor'] .= $xor;
                        }
                        $key = $this->_stringShift($buffer['xor'], $block_size);
                        $ciphertext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $xor = $this->_encryptBlock($xor);
                        $ciphertext .= substr($plaintext, $i, $block_size) ^ $xor;
                    }
                    $key = $xor;
                }
                if ($this->continuousBuffer) {
                    $this->encryptIV = $xor;
                    if ($start = strlen($plaintext) % $block_size) {
                        $buffer['xor'] = substr($key, $start).$buffer['xor'];
                    }
                }
                break;
            case CRYPT_MODE_STREAM:
                $ciphertext = $this->_encryptBlock($plaintext);
                break;
        }

        return $ciphertext;
    }

    /**
     * Setup the CRYPT_MODE_MCRYPT $engine.
     *
     * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
     * Used (only) if $engine = CRYPT_MODE_MCRYPT
     *
     * _setupMcrypt() will be called each time if $changed === true
     * typically this happens when using one or more of following public methods:
     *
     * - setKey()
     *
     * - setIV()
     *
     * - disableContinuousBuffer()
     *
     * - First run of encrypt() / decrypt()
     *
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @see setKey()
     * @see setIV()
     * @see disableContinuousBuffer()
     */
    public function _setupMcrypt()
    {
        $this->_clearBuffers();
        $this->enchanged = $this->dechanged = true;

        if (!isset($this->enmcrypt)) {
            static $mcrypt_modes = array(
                CRYPT_MODE_CTR    => 'ctr',
                CRYPT_MODE_ECB    => MCRYPT_MODE_ECB,
                CRYPT_MODE_CBC    => MCRYPT_MODE_CBC,
                CRYPT_MODE_CFB    => 'ncfb',
                CRYPT_MODE_OFB    => MCRYPT_MODE_NOFB,
                CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
            );

            $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
            $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');

            // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
            // to workaround mcrypt's broken ncfb implementation in buffered mode
            // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
            if (CRYPT_MODE_CFB == $this->mode) {
                $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
            }
        } // else should mcrypt_generic_deinit be called?

        if (CRYPT_MODE_CFB == $this->mode) {
            mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
        }
    }

    /**
     * Clears internal buffers.
     *
     * Clearing/resetting the internal buffers is done everytime
     * after disableContinuousBuffer() or on cipher $engine (re)init
     * ie after setKey() or setIV()
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     */
    public function _clearBuffers()
    {
        $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
        $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);

        // mcrypt's handling of invalid's $iv:
        // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
        $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
    }

    /**
     * Pads a string.
     *
     * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
     * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
     * chr($this->block_size - (strlen($text) % $this->block_size)
     *
     * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
     * and padding will, hence forth, be enabled.
     *
     * @see Crypt_Base::_unpad()
     *
     * @param string $text
     *
     * @return string
     */
    public function _pad($text)
    {
        $length = strlen($text);

        if (!$this->padding) {
            if (0 == $length % $this->block_size) {
                return $text;
            } else {
                user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
                $this->padding = true;
            }
        }

        $pad = $this->block_size - ($length % $this->block_size);

        return str_pad($text, $length + $pad, chr($pad));
    }

    /**
     * Setup the CRYPT_MODE_INTERNAL $engine.
     *
     * (re)init, if necessary, the internal cipher $engine and flush all $buffers
     * Used (only) if $engine == CRYPT_MODE_INTERNAL
     *
     * _setup() will be called each time if $changed === true
     * typically this happens when using one or more of following public methods:
     *
     * - setKey()
     *
     * - setIV()
     *
     * - disableContinuousBuffer()
     *
     * - First run of encrypt() / decrypt() with no init-settings
     *
     * Internally: _setup() is called always before(!) en/decryption.
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @see setKey()
     * @see setIV()
     * @see disableContinuousBuffer()
     */
    public function _setup()
    {
        $this->_clearBuffers();
        $this->_setupKey();

        if ($this->use_inline_crypt) {
            $this->_setupInlineCrypt();
        }
    }

    /**
     * Setup the key (expansion).
     *
     * Only used if $engine == CRYPT_MODE_INTERNAL
     *
     * Note: Must extend by the child Crypt_* class
     *
     * @see Crypt_Base::_setup()
     */
    public function _setupKey()
    {
        user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__).'() must extend by class '.get_class($this), E_USER_ERROR);
    }

    /**
     * Setup the performance-optimized function for de/encrypt().
     *
     * Stores the created (or existing) callback function-name
     * in $this->inline_crypt
     *
     * Internally for phpseclib developers:
     *
     *     _setupInlineCrypt() would be called only if:
     *
     *     - $engine == CRYPT_MODE_INTERNAL and
     *
     *     - $use_inline_crypt === true
     *
     *     - each time on _setup(), after(!) _setupKey()
     *
     *
     *     This ensures that _setupInlineCrypt() has always a
     *     full ready2go initializated internal cipher $engine state
     *     where, for example, the keys allready expanded,
     *     keys/block_size calculated and such.
     *
     *     It is, each time if called, the responsibility of _setupInlineCrypt():
     *
     *     - to set $this->inline_crypt to a valid and fully working callback function
     *       as a (faster) replacement for encrypt() / decrypt()
     *
     *     - NOT to create unlimited callback functions (for memory reasons!)
     *       no matter how often _setupInlineCrypt() would be called. At some
     *       point of amount they must be generic re-useable.
     *
     *     - the code of _setupInlineCrypt() it self,
     *       and the generated callback code,
     *       must be, in following order:
     *       - 100% safe
     *       - 100% compatible to encrypt()/decrypt()
     *       - using only php5+ features/lang-constructs/php-extensions if
     *         compatibility (down to php4) or fallback is provided
     *       - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
     *       - >= 10% faster than encrypt()/decrypt() [which is, by the way,
     *         the reason for the existence of _setupInlineCrypt() :-)]
     *       - memory-nice
     *       - short (as good as possible)
     *
     * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
     *       - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
     *       - The following variable names are reserved:
     *         - $_*  (all variable names prefixed with an underscore)
     *         - $self (object reference to it self. Do not use $this, but $self instead)
     *         - $in (the content of $in has to en/decrypt by the generated code)
     *       - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
     *
     *
     * @see Crypt_Base::_setup()
     * @see Crypt_Base::_createInlineCryptFunction()
     * @see Crypt_Base::encrypt()
     * @see Crypt_Base::decrypt()
     */
    public function _setupInlineCrypt()
    {
        // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()

        // If, for any reason, an extending Crypt_Base() Crypt_* class
        // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
        // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
        // in the constructor at object instance-time
        // or, if it's runtime-specific, at runtime

        $this->use_inline_crypt = false;
    }

    /**
     * Encrypts a block.
     *
     * Note: Must extend by the child Crypt_* class
     *
     * @param string $in
     *
     * @return string
     */
    public function _encryptBlock($in)
    {
        user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__).'() must extend by class '.get_class($this), E_USER_ERROR);
    }

    /**
     * Generate CTR XOR encryption key.
     *
     * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
     * plaintext / ciphertext in CTR mode.
     *
     * @see Crypt_Base::decrypt()
     * @see Crypt_Base::encrypt()
     *
     * @param string $iv
     * @param int    $length
     *
     * @return string $xor
     */
    public function _generateXor(&$iv, $length)
    {
        $xor        = '';
        $block_size = $this->block_size;
        $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
        for ($i = 0; $i < $num_blocks; ++$i) {
            $xor .= $iv;
            for ($j = 4; $j <= $block_size; $j += 4) {
                $temp = substr($iv, -$j, 4);
                switch ($temp) {
                    case "\xFF\xFF\xFF\xFF":
                        $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
                        break;
                    case "\x7F\xFF\xFF\xFF":
                        $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
                        break 2;
                    default:
                        extract(unpack('Ncount', $temp));
                        $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
                        break 2;
                }
            }
        }

        return $xor;
    }

    /**
     * String Shift.
     *
     * Inspired by array_shift
     *
     * @param string           $string
     * @param optional Integer $index
     *
     * @return string
     */
    public function _stringShift(&$string, $index = 1)
    {
        $substr = substr($string, 0, $index);
        $string = substr($string, $index);

        return $substr;
    }

    /**
     * Decrypts a message.
     *
     * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
     * it is.
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @see Crypt_Base::encrypt()
     *
     * @param string $ciphertext
     *
     * @return string $plaintext
     */
    public function decrypt($ciphertext)
    {
        if (CRYPT_MODE_MCRYPT == $this->engine) {
            $block_size = $this->block_size;
            if ($this->changed) {
                $this->_setupMcrypt();
                $this->changed = false;
            }
            if ($this->dechanged) {
                mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
                $this->dechanged = false;
            }

            if (CRYPT_MODE_CFB == $this->mode && $this->continuousBuffer) {
                $iv        = &$this->decryptIV;
                $pos       = &$this->debuffer['pos'];
                $len       = strlen($ciphertext);
                $plaintext = '';
                $i         = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max      = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
                    $iv        = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
                }
                if ($len >= $block_size) {
                    $cb = substr($ciphertext, $i, $len - $len % $block_size);
                    $plaintext .= mcrypt_generic($this->ecb, $iv.$cb) ^ $cb;
                    $iv = substr($cb, -$block_size);
                    $len %= $block_size;
                }
                if ($len) {
                    $iv = mcrypt_generic($this->ecb, $iv);
                    $plaintext .= $iv ^ substr($ciphertext, -$len);
                    $iv  = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
                    $pos = $len;
                }

                return $plaintext;
            }

            if ($this->paddable) {
                // we pad with chr(0) since that's what mcrypt_generic does.  to quote from {@link http://www.php.net/function.mcrypt-generic}:
                // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
                $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0));
            }

            $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);

            if (!$this->continuousBuffer) {
                mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
            }

            return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
        }

        if ($this->changed) {
            $this->_setup();
            $this->changed = false;
        }
        if ($this->use_inline_crypt) {
            $inline = $this->inline_crypt;

            return $inline('decrypt', $this, $ciphertext);
        }

        $block_size = $this->block_size;
        if ($this->paddable) {
            // we pad with chr(0) since that's what mcrypt_generic does [...]
            $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0));
        }

        $buffer    = &$this->debuffer;
        $plaintext = '';
        switch ($this->mode) {
            case CRYPT_MODE_ECB:
                for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                    $plaintext .= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
                }
                break;
            case CRYPT_MODE_CBC:
                $xor = $this->decryptIV;
                for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                    $block = substr($ciphertext, $i, $block_size);
                    $plaintext .= $this->_decryptBlock($block) ^ $xor;
                    $xor = $block;
                }
                if ($this->continuousBuffer) {
                    $this->decryptIV = $xor;
                }
                break;
            case CRYPT_MODE_CTR:
                $xor = $this->decryptIV;
                if (strlen($buffer['ciphertext'])) {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $block = substr($ciphertext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['ciphertext'])) {
                            $buffer['ciphertext'] .= $this->_encryptBlock($this->_generateXor($xor, $block_size));
                        }
                        $key = $this->_stringShift($buffer['ciphertext'], $block_size);
                        $plaintext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $block = substr($ciphertext, $i, $block_size);
                        $key   = $this->_encryptBlock($this->_generateXor($xor, $block_size));
                        $plaintext .= $block ^ $key;
                    }
                }
                if ($this->continuousBuffer) {
                    $this->decryptIV = $xor;
                    if ($start = strlen($ciphertext) % $block_size) {
                        $buffer['ciphertext'] = substr($key, $start).$buffer['ciphertext'];
                    }
                }
                break;
            case CRYPT_MODE_CFB:
                if ($this->continuousBuffer) {
                    $iv  = &$this->decryptIV;
                    $pos = &$buffer['pos'];
                } else {
                    $iv  = $this->decryptIV;
                    $pos = 0;
                }
                $len = strlen($ciphertext);
                $i   = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max      = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
                    $iv        = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
                }
                while ($len >= $block_size) {
                    $iv = $this->_encryptBlock($iv);
                    $cb = substr($ciphertext, $i, $block_size);
                    $plaintext .= $iv ^ $cb;
                    $iv = $cb;
                    $len -= $block_size;
                    $i += $block_size;
                }
                if ($len) {
                    $iv = $this->_encryptBlock($iv);
                    $plaintext .= $iv ^ substr($ciphertext, $i);
                    $iv  = substr_replace($iv, substr($ciphertext, $i), 0, $len);
                    $pos = $len;
                }
                break;
            case CRYPT_MODE_OFB:
                $xor = $this->decryptIV;
                if (strlen($buffer['xor'])) {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $block = substr($ciphertext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['xor'])) {
                            $xor = $this->_encryptBlock($xor);
                            $buffer['xor'] .= $xor;
                        }
                        $key = $this->_stringShift($buffer['xor'], $block_size);
                        $plaintext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $xor = $this->_encryptBlock($xor);
                        $plaintext .= substr($ciphertext, $i, $block_size) ^ $xor;
                    }
                    $key = $xor;
                }
                if ($this->continuousBuffer) {
                    $this->decryptIV = $xor;
                    if ($start = strlen($ciphertext) % $block_size) {
                        $buffer['xor'] = substr($key, $start).$buffer['xor'];
                    }
                }
                break;
            case CRYPT_MODE_STREAM:
                $plaintext = $this->_decryptBlock($ciphertext);
                break;
        }

        return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
    }

    /**
     * Unpads a string.
     *
     * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
     * and false will be returned.
     *
     * @see Crypt_Base::_pad()
     *
     * @param string $text
     *
     * @return string
     */
    public function _unpad($text)
    {
        if (!$this->padding) {
            return $text;
        }

        $length = ord($text[strlen($text) - 1]);

        if (!$length || $length > $this->block_size) {
            return false;
        }

        return substr($text, 0, -$length);
    }

    /**
     * Decrypts a block.
     *
     * Note: Must extend by the child Crypt_* class
     *
     * @param string $in
     *
     * @return string
     */
    public function _decryptBlock($in)
    {
        user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__).'() must extend by class '.get_class($this), E_USER_ERROR);
    }

    /**
     * Pad "packets".
     *
     * Block ciphers working by encrypting between their specified [$this->]block_size at a time
     * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
     * pad the input so that it is of the proper length.
     *
     * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH,
     * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
     * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
     * transmitted separately)
     *
     * @see Crypt_Base::disablePadding()
     */
    public function enablePadding()
    {
        $this->padding = true;
    }

    /**
     * Do not pad packets.
     *
     * @see Crypt_Base::enablePadding()
     */
    public function disablePadding()
    {
        $this->padding = false;
    }

    /**
     * Treat consecutive "packets" as if they are a continuous buffer.
     *
     * Say you have a 32-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
     * will yield different outputs:
     *
     * <code>
     *    echo $rijndael->encrypt(substr($plaintext,  0, 16));
     *    echo $rijndael->encrypt(substr($plaintext, 16, 16));
     * </code>
     * <code>
     *    echo $rijndael->encrypt($plaintext);
     * </code>
     *
     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
     * another, as demonstrated with the following:
     *
     * <code>
     *    $rijndael->encrypt(substr($plaintext, 0, 16));
     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
     * </code>
     * <code>
     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
     * </code>
     *
     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
     *
     * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
     * however, they are also less intuitive and more likely to cause you problems.
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @see Crypt_Base::disableContinuousBuffer()
     */
    public function enableContinuousBuffer()
    {
        if (CRYPT_MODE_ECB == $this->mode) {
            return;
        }

        $this->continuousBuffer = true;
    }

    /**
     * Treat consecutive packets as if they are a discontinuous buffer.
     *
     * The default behavior.
     *
     * Note: Could, but not must, extend by the child Crypt_* class
     *
     * @see Crypt_Base::enableContinuousBuffer()
     */
    public function disableContinuousBuffer()
    {
        if (CRYPT_MODE_ECB == $this->mode) {
            return;
        }
        if (!$this->continuousBuffer) {
            return;
        }

        $this->continuousBuffer = false;
        $this->changed          = true;
    }

    /**
     * Creates the performance-optimized function for en/decrypt().
     *
     * Internally for phpseclib developers:
     *
     *    _createInlineCryptFunction():
     *
     *    - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
     *      with the current [$this->]mode of operation code
     *
     *    - create the $inline function, which called by encrypt() / decrypt()
     *      as its replacement to speed up the en/decryption operations.
     *
     *    - return the name of the created $inline callback function
     *
     *    - used to speed up en/decryption
     *
     *
     *
     *    The main reason why can speed up things [up to 50%] this way are:
     *
     *    - using variables more effective then regular.
     *      (ie no use of expensive arrays but integers $k_0, $k_1 ...
     *      or even, for example, the pure $key[] values hardcoded)
     *
     *    - avoiding 1000's of function calls of ie _encryptBlock()
     *      but inlining the crypt operations.
     *      in the mode of operation for() loop.
     *
     *    - full loop unroll the (sometimes key-dependent) rounds
     *      avoiding this way ++$i counters and runtime-if's etc...
     *
     *    The basic code architectur of the generated $inline en/decrypt()
     *    lambda function, in pseudo php, is:
     *
     *    <code>
     *    +----------------------------------------------------------------------------------------------+
     *    | callback $inline = create_function:                                                          |
     *    | lambda_function_0001_crypt_ECB($action, $text)                                               |
     *    | {                                                                                            |
     *    |     INSERT PHP CODE OF:                                                                      |
     *    |     $cipher_code['init_crypt'];                  // general init code.                       |
     *    |                                                  // ie: $sbox'es declarations used for       |
     *    |                                                  //     encrypt and decrypt'ing.             |
     *    |                                                                                              |
     *    |     switch ($action) {                                                                       |
     *    |         case 'encrypt':                                                                      |
     *    |             INSERT PHP CODE OF:                                                              |
     *    |             $cipher_code['init_encrypt'];       // encrypt sepcific init code.               |
     *    |                                                    ie: specified $key or $box                |
     *    |                                                        declarations for encrypt'ing.         |
     *    |                                                                                              |
     *    |             foreach ($ciphertext) {                                                          |
     *    |                 $in = $block_size of $ciphertext;                                            |
     *    |                                                                                              |
     *    |                 INSERT PHP CODE OF:                                                          |
     *    |                 $cipher_code['encrypt_block'];  // encrypt's (string) $in, which is always:  |
     *    |                                                 // strlen($in) == $this->block_size          |
     *    |                                                 // here comes the cipher algorithm in action |
     *    |                                                 // for encryption.                           |
     *    |                                                 // $cipher_code['encrypt_block'] has to      |
     *    |                                                 // encrypt the content of the $in variable   |
     *    |                                                                                              |
     *    |                 $plaintext .= $in;                                                           |
     *    |             }                                                                                |
     *    |             return $plaintext;                                                               |
     *    |                                                                                              |
     *    |         case 'decrypt':                                                                      |
     *    |             INSERT PHP CODE OF:                                                              |
     *    |             $cipher_code['init_decrypt'];       // decrypt sepcific init code                |
     *    |                                                    ie: specified $key or $box                |
     *    |                                                        declarations for decrypt'ing.         |
     *    |             foreach ($plaintext) {                                                           |
     *    |                 $in = $block_size of $plaintext;                                             |
     *    |                                                                                              |
     *    |                 INSERT PHP CODE OF:                                                          |
     *    |                 $cipher_code['decrypt_block'];  // decrypt's (string) $in, which is always   |
     *    |                                                 // strlen($in) == $this->block_size          |
     *    |                                                 // here comes the cipher algorithm in action |
     *    |                                                 // for decryption.                           |
     *    |                                                 // $cipher_code['decrypt_block'] has to      |
     *    |                                                 // decrypt the content of the $in variable   |
     *    |                 $ciphertext .= $in;                                                          |
     *    |             }                                                                                |
     *    |             return $ciphertext;                                                              |
     *    |     }                                                                                        |
     *    | }                                                                                            |
     *    +----------------------------------------------------------------------------------------------+
     *    </code>
     *
     *    See also the Crypt_*::_setupInlineCrypt()'s for
     *    productive inline $cipher_code's how they works.
     *
     *    Structure of:
     *    <code>
     *    $cipher_code = array(
     *        'init_crypt'    => (string) '', // optional
     *        'init_encrypt'  => (string) '', // optional
     *        'init_decrypt'  => (string) '', // optional
     *        'encrypt_block' => (string) '', // required
     *        'decrypt_block' => (string) ''  // required
     *    );
     *    </code>
     *
     * @see Crypt_Base::_setupInlineCrypt()
     * @see Crypt_Base::encrypt()
     * @see Crypt_Base::decrypt()
     *
     * @param array $cipher_code
     *
     * @return string (the name of the created callback function)
     */
    public function _createInlineCryptFunction($cipher_code)
    {
        $block_size = $this->block_size;

        // optional
        $init_crypt   = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
        $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
        $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
        // required
        $encrypt_block = $cipher_code['encrypt_block'];
        $decrypt_block = $cipher_code['decrypt_block'];

        // Generating mode of operation inline code,
        // merged with the $cipher_code algorithm
        // for encrypt- and decryption.
        switch ($this->mode) {
            case CRYPT_MODE_ECB:
                $encrypt = $init_encrypt.'
                    $_ciphertext = "";
                    $_text = $self->_pad($_text);
                    $_plaintext_len = strlen($_text);

                    for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                        $in = substr($_text, $_i, '.$block_size.');
                        '.$encrypt_block.'
                        $_ciphertext.= $in;
                    }

                    return $_ciphertext;
                    ';

                $decrypt = $init_decrypt.'
                    $_plaintext = "";
                    $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
                    $_ciphertext_len = strlen($_text);

                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                        $in = substr($_text, $_i, '.$block_size.');
                        '.$decrypt_block.'
                        $_plaintext.= $in;
                    }

                    return $self->_unpad($_plaintext);
                    ';
                break;
            case CRYPT_MODE_CTR:
                $encrypt = $init_encrypt.'
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);
                    $_xor = $self->encryptIV;
                    $_buffer = &$self->enbuffer;

                    if (strlen($_buffer["encrypted"])) {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["encrypted"])) {
                                $in = $self->_generateXor($_xor, '.$block_size.');
                                '.$encrypt_block.'
                                $_buffer["encrypted"].= $in;
                            }
                            $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.');
                            $_ciphertext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            $in = $self->_generateXor($_xor, '.$block_size.');
                            '.$encrypt_block.'
                            $_key = $in;
                            $_ciphertext.= $_block ^ $_key;
                        }
                    }
                    if ($self->continuousBuffer) {
                        $self->encryptIV = $_xor;
                        if ($_start = $_plaintext_len % '.$block_size.') {
                            $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"];
                        }
                    }

                    return $_ciphertext;
                ';

                $decrypt = $init_encrypt.'
                    $_plaintext = "";
                    $_ciphertext_len = strlen($_text);
                    $_xor = $self->decryptIV;
                    $_buffer = &$self->debuffer;

                    if (strlen($_buffer["ciphertext"])) {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
                                $in = $self->_generateXor($_xor, '.$block_size.');
                                '.$encrypt_block.'
                                $_buffer["ciphertext"].= $in;
                            }
                            $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.');
                            $_plaintext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            $in = $self->_generateXor($_xor, '.$block_size.');
                            '.$encrypt_block.'
                            $_key = $in;
                            $_plaintext.= $_block ^ $_key;
                        }
                    }
                    if ($self->continuousBuffer) {
                        $self->decryptIV = $_xor;
                        if ($_start = $_ciphertext_len % '.$block_size.') {
                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
                        }
                    }

                    return $_plaintext;
                    ';
                break;
            case CRYPT_MODE_CFB:
                $encrypt = $init_encrypt.'
                    $_ciphertext = "";
                    $_buffer = &$self->enbuffer;

                    if ($self->continuousBuffer) {
                        $_iv = &$self->encryptIV;
                        $_pos = &$_buffer["pos"];
                    } else {
                        $_iv = $self->encryptIV;
                        $_pos = 0;
                    }
                    $_len = strlen($_text);
                    $_i = 0;
                    if ($_pos) {
                        $_orig_pos = $_pos;
                        $_max = '.$block_size.' - $_pos;
                        if ($_len >= $_max) {
                            $_i = $_max;
                            $_len-= $_max;
                            $_pos = 0;
                        } else {
                            $_i = $_len;
                            $_pos+= $_len;
                            $_len = 0;
                        }
                        $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
                        $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
                    }
                    while ($_len >= '.$block_size.') {
                        $in = $_iv;
                        '.$encrypt_block.';
                        $_iv = $in ^ substr($_text, $_i, '.$block_size.');
                        $_ciphertext.= $_iv;
                        $_len-= '.$block_size.';
                        $_i+= '.$block_size.';
                    }
                    if ($_len) {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_iv = $in;
                        $_block = $_iv ^ substr($_text, $_i);
                        $_iv = substr_replace($_iv, $_block, 0, $_len);
                        $_ciphertext.= $_block;
                        $_pos = $_len;
                    }
                    return $_ciphertext;
                ';

                $decrypt = $init_encrypt.'
                    $_plaintext = "";
                    $_buffer = &$self->debuffer;

                    if ($self->continuousBuffer) {
                        $_iv = &$self->decryptIV;
                        $_pos = &$_buffer["pos"];
                    } else {
                        $_iv = $self->decryptIV;
                        $_pos = 0;
                    }
                    $_len = strlen($_text);
                    $_i = 0;
                    if ($_pos) {
                        $_orig_pos = $_pos;
                        $_max = '.$block_size.' - $_pos;
                        if ($_len >= $_max) {
                            $_i = $_max;
                            $_len-= $_max;
                            $_pos = 0;
                        } else {
                            $_i = $_len;
                            $_pos+= $_len;
                            $_len = 0;
                        }
                        $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
                        $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
                    }
                    while ($_len >= '.$block_size.') {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_iv = $in;
                        $cb = substr($_text, $_i, '.$block_size.');
                        $_plaintext.= $_iv ^ $cb;
                        $_iv = $cb;
                        $_len-= '.$block_size.';
                        $_i+= '.$block_size.';
                    }
                    if ($_len) {
                        $in = $_iv;
                        '.$encrypt_block.'
                        $_iv = $in;
                        $_plaintext.= $_iv ^ substr($_text, $_i);
                        $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
                        $_pos = $_len;
                    }

                    return $_plaintext;
                    ';
                break;
            case CRYPT_MODE_OFB:
                $encrypt = $init_encrypt.'
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);
                    $_xor = $self->encryptIV;
                    $_buffer = &$self->enbuffer;

                    if (strlen($_buffer["xor"])) {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["xor"])) {
                                $in = $_xor;
                                '.$encrypt_block.'
                                $_xor = $in;
                                $_buffer["xor"].= $_xor;
                            }
                            $_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
                            $_ciphertext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                            $in = $_xor;
                            '.$encrypt_block.'
                            $_xor = $in;
                            $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
                        }
                        $_key = $_xor;
                    }
                    if ($self->continuousBuffer) {
                        $self->encryptIV = $_xor;
                        if ($_start = $_plaintext_len % '.$block_size.') {
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
                        }
                    }
                    return $_ciphertext;
                    ';

                $decrypt = $init_encrypt.'
                    $_plaintext = "";
                    $_ciphertext_len = strlen($_text);
                    $_xor = $self->decryptIV;
                    $_buffer = &$self->debuffer;

                    if (strlen($_buffer["xor"])) {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $_block = substr($_text, $_i, '.$block_size.');
                            if (strlen($_block) > strlen($_buffer["xor"])) {
                                $in = $_xor;
                                '.$encrypt_block.'
                                $_xor = $in;
                                $_buffer["xor"].= $_xor;
                            }
                            $_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
                            $_plaintext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                            $in = $_xor;
                            '.$encrypt_block.'
                            $_xor = $in;
                            $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
                        }
                        $_key = $_xor;
                    }
                    if ($self->continuousBuffer) {
                        $self->decryptIV = $_xor;
                        if ($_start = $_ciphertext_len % '.$block_size.') {
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
                        }
                    }
                    return $_plaintext;
                    ';
                break;
            case CRYPT_MODE_STREAM:
                $encrypt = $init_encrypt.'
                    $_ciphertext = "";
                    '.$encrypt_block.'
                    return $_ciphertext;
                    ';
                $decrypt = $init_decrypt.'
                    $_plaintext = "";
                    '.$decrypt_block.'
                    return $_plaintext;
                    ';
                break;
            // case CRYPT_MODE_CBC:
            default:
                $encrypt = $init_encrypt.'
                    $_ciphertext = "";
                    $_text = $self->_pad($_text);
                    $_plaintext_len = strlen($_text);

                    $in = $self->encryptIV;

                    for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
                        $in = substr($_text, $_i, '.$block_size.') ^ $in;
                        '.$encrypt_block.'
                        $_ciphertext.= $in;
                    }

                    if ($self->continuousBuffer) {
                        $self->encryptIV = $in;
                    }

                    return $_ciphertext;
                    ';

                $decrypt = $init_decrypt.'
                    $_plaintext = "";
                    $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
                    $_ciphertext_len = strlen($_text);

                    $_iv = $self->decryptIV;

                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
                        $in = $_block = substr($_text, $_i, '.$block_size.');
                        '.$decrypt_block.'
                        $_plaintext.= $in ^ $_iv;
                        $_iv = $_block;
                    }

                    if ($self->continuousBuffer) {
                        $self->decryptIV = $_iv;
                    }

                    return $self->_unpad($_plaintext);
                    ';
                break;
        }

        // Create the $inline function and return its name as string. Ready to run!
        return create_function('$_action, &$self, $_text', $init_crypt.'if ($_action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }');
    }

    /**
     * Holds the lambda_functions table (classwide).
     *
     * Each name of the lambda function, created from
     * _setupInlineCrypt() && _createInlineCryptFunction()
     * is stored, classwide (!), here for reusing.
     *
     * The string-based index of $function is a classwide
     * uniqe value representing, at least, the $mode of
     * operation (or more... depends of the optimizing level)
     * for which $mode the lambda function was created.
     *
     * @return &Array
     */
    public function &_getLambdaFunctions()
    {
        static $functions = array();

        return $functions;
    }
}
PK��#]%��A�"�"(system/bfnetwork/bfnetwork/Crypt/RC4.phpnu�[���<?php

/**
 * Pure-PHP implementation of RC4.
 *
 * Uses mcrypt, if available, and an internal implementation, otherwise.
 *
 * PHP versions 4 and 5
 *
 * Useful resources are as follows:
 *
 *  - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
 *  - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
 *
 * RC4 is also known as ARCFOUR or ARC4.  The reason is elaborated upon at Wikipedia.  This class is named RC4 and not
 * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'Crypt/RC4.php';
 *
 *    $rc4 = new Crypt_RC4();
 *
 *    $rc4->setKey('abcdefgh');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $rc4->decrypt($rc4->encrypt($plaintext));
 * ?>
 * </code>
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category  Crypt
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 * @see      http://phpseclib.sourceforge.net
 */

/**
 * Include Crypt_Base.
 *
 * Base cipher class
 */
if (!class_exists('Crypt_Base')) {
    include_once 'Base.php';
}

/**#@+
 * @access private
 * @see Crypt_RC4::Crypt_RC4()
 */
/*
 * Toggles the internal implementation
 */
define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/*
 * Toggles the mcrypt implementation
 */
define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/

/**#@+
 * @access private
 * @see Crypt_RC4::_crypt()
 */
define('CRYPT_RC4_ENCRYPT', 0);
define('CRYPT_RC4_DECRYPT', 1);
/**#@-*/

/**
 * Pure-PHP implementation of RC4.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Crypt_RC4 extends Crypt_Base
{
    /**
     * Block Length of the cipher.
     *
     * RC4 is a stream cipher
     * so we the block_size to 0
     *
     * @see Crypt_Base::block_size
     *
     * @var int
     */
    public $block_size = 0;

    /**
     * The default password key_size used by setPassword().
     *
     * @see Crypt_Base::password_key_size
     * @see Crypt_Base::setPassword()
     *
     * @var int
     */
    public $password_key_size = 128; // = 1024 bits

    /**
     * The namespace used by the cipher for its constants.
     *
     * @see Crypt_Base::const_namespace
     *
     * @var string
     */
    public $const_namespace = 'RC4';

    /**
     * The mcrypt specific name of the cipher.
     *
     * @see Crypt_Base::cipher_name_mcrypt
     *
     * @var string
     */
    public $cipher_name_mcrypt = 'arcfour';

    /**
     * Holds whether performance-optimized $inline_crypt() can/should be used.
     *
     * @see Crypt_Base::inline_crypt
     *
     * @var mixed
     */
    public $use_inline_crypt = false; // currently not available

    /**
     * The Key.
     *
     * @see Crypt_RC4::setKey()
     *
     * @var string
     */
    public $key = "\0";

    /**
     * The Key Stream for decryption and encryption.
     *
     * @see Crypt_RC4::setKey()
     *
     * @var array
     */
    public $stream;

    /**
     * Default Constructor.
     *
     * Determines whether or not the mcrypt extension should be used.
     *
     * @see Crypt_Base::Crypt_Base()
     *
     * @return Crypt_RC4
     */
    public function __construct()
    {
        parent::__construct(CRYPT_MODE_STREAM);
    }

    /**
     * Dummy function.
     *
     * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
     * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
     * calling setKey().
     *
     * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way.  Since, in that protocol,
     * the IV's are relatively easy to predict, an attack described by
     * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
     * can be used to quickly guess at the rest of the key.  The following links elaborate:
     *
     * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
     * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
     *
     * @param string $iv
     *
     * @see Crypt_RC4::setKey()
     */
    public function setIV($iv)
    {
    }

    /**
     * Sets the key.
     *
     * Keys can be between 1 and 256 bytes long.  If they are longer then 256 bytes, the first 256 bytes will
     * be used.  If no key is explicitly set, it'll be assumed to be a single null byte.
     *
     * @see Crypt_Base::setKey()
     *
     * @param string $key
     */
    public function setKey($key)
    {
        parent::setKey(substr($key, 0, 256));
    }

    /**
     * Encrypts a message.
     *
     * @see Crypt_Base::decrypt()
     * @see Crypt_RC4::_crypt()
     *
     * @param string $plaintext
     *
     * @return string $ciphertext
     */
    public function encrypt($plaintext)
    {
        if (CRYPT_MODE_MCRYPT == $this->engine) {
            return parent::encrypt($plaintext);
        }

        return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
    }

    /**
     * Encrypts or decrypts a message.
     *
     * @see Crypt_RC4::encrypt()
     * @see Crypt_RC4::decrypt()
     *
     * @param string $text
     * @param int    $mode
     *
     * @return string $text
     */
    public function _crypt($text, $mode)
    {
        if ($this->changed) {
            $this->_setup();
            $this->changed = false;
        }

        $stream = &$this->stream[$mode];
        if ($this->continuousBuffer) {
            $i         = &$stream[0];
            $j         = &$stream[1];
            $keyStream = &$stream[2];
        } else {
            $i         = $stream[0];
            $j         = $stream[1];
            $keyStream = $stream[2];
        }

        $len = strlen($text);
        for ($k = 0; $k < $len; ++$k) {
            $i   = ($i + 1) & 255;
            $ksi = $keyStream[$i];
            $j   = ($j + $ksi) & 255;
            $ksj = $keyStream[$j];

            $keyStream[$i] = $ksj;
            $keyStream[$j] = $ksi;
            $text[$k]      = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
        }

        return $text;
    }

    /**
     * Decrypts a message.
     *
     * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
     * At least if the continuous buffer is disabled.
     *
     * @see Crypt_Base::encrypt()
     * @see Crypt_RC4::_crypt()
     *
     * @param string $ciphertext
     *
     * @return string $plaintext
     */
    public function decrypt($ciphertext)
    {
        if (CRYPT_MODE_MCRYPT == $this->engine) {
            return parent::decrypt($ciphertext);
        }

        return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
    }

    /**
     * Setup the key (expansion).
     *
     * @see Crypt_Base::_setupKey()
     */
    public function _setupKey()
    {
        $key       = $this->key;
        $keyLength = strlen($key);
        $keyStream = range(0, 255);
        $j         = 0;
        for ($i = 0; $i < 256; ++$i) {
            $j             = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
            $temp          = $keyStream[$i];
            $keyStream[$i] = $keyStream[$j];
            $keyStream[$j] = $temp;
        }

        $this->stream                    = array();
        $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
            0, // index $i
            0, // index $j
            $keyStream,
        );
    }
}
PK��#]�IVB/n/n)system/bfnetwork/bfnetwork/Crypt/Hash.phpnu�[���<?php

/**
 * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
 *
 * Uses hash() or mhash() if available and an internal implementation, otherwise.  Currently supports the following:
 *
 * md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
 *
 * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
 * the hash.  If no valid algorithm is provided, sha1 will be used.
 *
 * PHP versions 4 and 5
 *
 * {@internal The variable names are the same as those in
 * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'Crypt/Hash.php';
 *
 *    $hash = new Crypt_Hash('sha1');
 *
 *    $hash->setKey('abcdefg');
 *
 *    echo base64_encode($hash->hash('abcdefg'));
 * ?>
 * </code>
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category  Crypt
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 * @see      http://phpseclib.sourceforge.net
 */

/**#@+
 * @access private
 * @see Crypt_Hash::Crypt_Hash()
 */
/**
 * Toggles the internal implementation.
 */
define('CRYPT_HASH_MODE_INTERNAL', 1);
/*
 * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
 */
define('CRYPT_HASH_MODE_MHASH', 2);
/*
 * Toggles the hash() implementation, which works on PHP 5.1.2+.
 */
define('CRYPT_HASH_MODE_HASH', 3);
/**#@-*/

/**
 * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Crypt_Hash
{
    /**
     * Hash Parameter.
     *
     * @see Crypt_Hash::setHash()
     *
     * @var int
     */
    public $hashParam;

    /**
     * Byte-length of compression blocks / key (Internal HMAC).
     *
     * @see Crypt_Hash::setAlgorithm()
     *
     * @var int
     */
    public $b;

    /**
     * Byte-length of hash output (Internal HMAC).
     *
     * @see Crypt_Hash::setHash()
     *
     * @var int
     */
    public $l = false;

    /**
     * Hash Algorithm.
     *
     * @see Crypt_Hash::setHash()
     *
     * @var string
     */
    public $hash;

    /**
     * Key.
     *
     * @see Crypt_Hash::setKey()
     *
     * @var string
     */
    public $key = false;

    /**
     * Outer XOR (Internal HMAC).
     *
     * @see Crypt_Hash::setKey()
     *
     * @var string
     */
    public $opad;

    /**
     * Inner XOR (Internal HMAC).
     *
     * @see Crypt_Hash::setKey()
     *
     * @var string
     */
    public $ipad;

    /**
     * Default Constructor.
     *
     * @param optional String $hash
     *
     * @return Crypt_Hash
     */
    public function __construct($hash = 'sha1')
    {
        if (!defined('CRYPT_HASH_MODE')) {
            switch (true) {
                case extension_loaded('hash'):
                    define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
                    break;
                case extension_loaded('mhash'):
                    define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
                    break;
                default:
                    define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
            }
        }

        $this->setHash($hash);
    }

    /**
     * Sets the key for HMACs.
     *
     * Keys can be of any length.
     *
     * @param optional String $key
     */
    public function setKey($key = false)
    {
        $this->key = $key;
    }

    /**
     * Gets the hash function.
     *
     * As set by the constructor or by the setHash() method.
     *
     * @return string
     */
    public function getHash()
    {
        return $this->hashParam;
    }

    /**
     * Sets the hash function.
     *
     * @param string $hash
     */
    public function setHash($hash)
    {
        $this->hashParam = $hash = strtolower($hash);
        switch ($hash) {
            case 'md5-96':
            case 'sha1-96':
            case 'sha256-96':
            case 'sha512-96':
                $hash    = substr($hash, 0, -3);
                $this->l = 12; // 96 / 8 = 12
                break;
            case 'md2':
            case 'md5':
                $this->l = 16;
                break;
            case 'sha1':
                $this->l = 20;
                break;
            case 'sha256':
                $this->l = 32;
                break;
            case 'sha384':
                $this->l = 48;
                break;
            case 'sha512':
                $this->l = 64;
        }

        switch ($hash) {
            case 'md2':
                $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
                    CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
                break;
            case 'sha384':
            case 'sha512':
                $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
                break;
            default:
                $mode = CRYPT_HASH_MODE;
        }

        switch ($mode) {
            case CRYPT_HASH_MODE_MHASH:
                switch ($hash) {
                    case 'md5':
                        $this->hash = MHASH_MD5;
                        break;
                    case 'sha256':
                        $this->hash = MHASH_SHA256;
                        break;
                    case 'sha1':
                    default:
                        $this->hash = MHASH_SHA1;
                }

                return;
            case CRYPT_HASH_MODE_HASH:
                switch ($hash) {
                    case 'md5':
                        $this->hash = 'md5';

                        return;
                    case 'md2':
                    case 'sha256':
                    case 'sha384':
                    case 'sha512':
                        $this->hash = $hash;

                        return;
                    case 'sha1':
                    default:
                        $this->hash = 'sha1';
                }

                return;
        }

        switch ($hash) {
            case 'md2':
                $this->b    = 16;
                $this->hash = array($this, '_md2');
                break;
            case 'md5':
                $this->b    = 64;
                $this->hash = array($this, '_md5');
                break;
            case 'sha256':
                $this->b    = 64;
                $this->hash = array($this, '_sha256');
                break;
            case 'sha384':
            case 'sha512':
                $this->b    = 128;
                $this->hash = array($this, '_sha512');
                break;
            case 'sha1':
            default:
                $this->b    = 64;
                $this->hash = array($this, '_sha1');
        }

        $this->ipad = str_repeat(chr(0x36), $this->b);
        $this->opad = str_repeat(chr(0x5C), $this->b);
    }

    /**
     * Compute the HMAC.
     *
     * @param string $text
     *
     * @return string
     */
    public function hash($text)
    {
        $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;

        if (!empty($this->key) || is_string($this->key)) {
            switch ($mode) {
                case CRYPT_HASH_MODE_MHASH:
                    $output = mhash($this->hash, $text, $this->key);
                    break;
                case CRYPT_HASH_MODE_HASH:
                    $output = hash_hmac($this->hash, $text, $this->key, true);
                    break;
                case CRYPT_HASH_MODE_INTERNAL:
                    /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
                        resultant L byte string as the actual key to HMAC."

                        -- http://tools.ietf.org/html/rfc2104#section-2 */
                    $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;

                    $key  = str_pad($key, $this->b, chr(0));      // step 1
                    $temp = $this->ipad ^ $key;                   // step 2
                    $temp .= $text;                                // step 3
                    $temp   = call_user_func($this->hash, $temp);   // step 4
                    $output = $this->opad ^ $key;                   // step 5
                    $output .= $temp;                                // step 6
                    $output = call_user_func($this->hash, $output); // step 7
            }
        } else {
            switch ($mode) {
                case CRYPT_HASH_MODE_MHASH:
                    $output = mhash($this->hash, $text);
                    break;
                case CRYPT_HASH_MODE_HASH:
                    $output = hash($this->hash, $text, true);
                    break;
                case CRYPT_HASH_MODE_INTERNAL:
                    $output = call_user_func($this->hash, $text);
            }
        }

        return substr($output, 0, $this->l);
    }

    /**
     * Returns the hash length (in bytes).
     *
     * @return int
     */
    public function getLength()
    {
        return $this->l;
    }

    /**
     * Wrapper for MD5.
     *
     * @param string $m
     */
    public function _md5($m)
    {
        return pack('H*', md5($m));
    }

    /**
     * Wrapper for SHA1.
     *
     * @param string $m
     */
    public function _sha1($m)
    {
        return pack('H*', sha1($m));
    }

    /**
     * Pure-PHP implementation of MD2.
     *
     * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
     *
     * @param string $m
     */
    public function _md2($m)
    {
        static $s = array(
            41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
            19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
            76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
            138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
            245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
            148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
            39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
            181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
            150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
            112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
            96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
            85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
            234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
            129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
            8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
            203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
            166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
            31, 26, 219, 153, 141, 51, 159, 17, 131, 20,
        );

        // Step 1. Append Padding Bytes
        $pad = 16 - (strlen($m) & 0xF);
        $m .= str_repeat(chr($pad), $pad);

        $length = strlen($m);

        // Step 2. Append Checksum
        $c = str_repeat(chr(0), 16);
        $l = chr(0);
        for ($i = 0; $i < $length; $i += 16) {
            for ($j = 0; $j < 16; ++$j) {
                // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
                //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
                // per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
                $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
                $l     = $c[$j];
            }
        }
        $m .= $c;

        $length += 16;

        // Step 3. Initialize MD Buffer
        $x = str_repeat(chr(0), 48);

        // Step 4. Process Message in 16-Byte Blocks
        for ($i = 0; $i < $length; $i += 16) {
            for ($j = 0; $j < 16; ++$j) {
                $x[$j + 16] = $m[$i + $j];
                $x[$j + 32] = $x[$j + 16] ^ $x[$j];
            }
            $t = chr(0);
            for ($j = 0; $j < 18; ++$j) {
                for ($k = 0; $k < 48; ++$k) {
                    $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
                    //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
                }
                $t = chr(ord($t) + $j);
            }
        }

        // Step 5. Output
        return substr($x, 0, 16);
    }

    /**
     * Pure-PHP implementation of SHA256.
     *
     * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
     *
     * @param string $m
     */
    public function _sha256($m)
    {
        if (extension_loaded('suhosin')) {
            return pack('H*', sha256($m));
        }

        // Initialize variables
        $hash = array(
            0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
        );
        // Initialize table of round constants
        // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
        static $k = array(
            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
        );

        // Pre-processing
        $length = strlen($m);
        // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
        $m .= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
        $m[$length] = chr(0x80);
        // we don't support hashing strings 512MB long
        $m .= pack('N2', 0, $length << 3);

        // Process the message in successive 512-bit chunks
        $chunks = str_split($m, 64);
        foreach ($chunks as $chunk) {
            $w = array();
            for ($i = 0; $i < 16; ++$i) {
                extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
                $w[] = $temp;
            }

            // Extend the sixteen 32-bit words into sixty-four 32-bit words
            for ($i = 16; $i < 64; ++$i) {
                $s0 = $this->_rightRotate($w[$i - 15], 7) ^
                    $this->_rightRotate($w[$i - 15], 18) ^
                    $this->_rightShift($w[$i - 15], 3);
                $s1 = $this->_rightRotate($w[$i - 2], 17) ^
                    $this->_rightRotate($w[$i - 2], 19) ^
                    $this->_rightShift($w[$i - 2], 10);
                $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
            }

            // Initialize hash value for this chunk
            list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;

            // Main loop
            for ($i = 0; $i < 64; ++$i) {
                $s0 = $this->_rightRotate($a, 2) ^
                    $this->_rightRotate($a, 13) ^
                    $this->_rightRotate($a, 22);
                $maj = ($a & $b) ^
                    ($a & $c) ^
                    ($b & $c);
                $t2 = $this->_add($s0, $maj);

                $s1 = $this->_rightRotate($e, 6) ^
                    $this->_rightRotate($e, 11) ^
                    $this->_rightRotate($e, 25);
                $ch = ($e & $f) ^
                    ($this->_not($e) & $g);
                $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);

                $h = $g;
                $g = $f;
                $f = $e;
                $e = $this->_add($d, $t1);
                $d = $c;
                $c = $b;
                $b = $a;
                $a = $this->_add($t1, $t2);
            }

            // Add this chunk's hash to result so far
            $hash = array(
                $this->_add($hash[0], $a),
                $this->_add($hash[1], $b),
                $this->_add($hash[2], $c),
                $this->_add($hash[3], $d),
                $this->_add($hash[4], $e),
                $this->_add($hash[5], $f),
                $this->_add($hash[6], $g),
                $this->_add($hash[7], $h),
            );
        }

        // Produce the final hash value (big-endian)
        return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
    }

    /**
     * String Shift.
     *
     * Inspired by array_shift
     *
     * @param string           $string
     * @param optional Integer $index
     *
     * @return string
     */
    public function _string_shift(&$string, $index = 1)
    {
        $substr = substr($string, 0, $index);
        $string = substr($string, $index);

        return $substr;
    }

    /**
     * Right Rotate.
     *
     * @param int $int
     * @param int $amt
     *
     * @see _sha256()
     *
     * @return int
     */
    public function _rightRotate($int, $amt)
    {
        $invamt = 32 - $amt;
        $mask   = (1 << $invamt) - 1;

        return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
    }

    /**
     * Right Shift.
     *
     * @param int $int
     * @param int $amt
     *
     * @see _sha256()
     *
     * @return int
     */
    public function _rightShift($int, $amt)
    {
        $mask = (1 << (32 - $amt)) - 1;

        return ($int >> $amt) & $mask;
    }

    /**
     * Add.
     *
     * _sha256() adds multiple unsigned 32-bit integers.  Since PHP doesn't support unsigned integers and since the
     * possibility of overflow exists, care has to be taken.  Math_BigInteger() could be used but this should be faster.
     *
     * @param int $...
     *
     * @return int
     *
     * @see _sha256()
     */
    public function _add()
    {
        static $mod;
        if (!isset($mod)) {
            $mod = pow(2, 32);
        }

        $result    = 0;
        $arguments = func_get_args();
        foreach ($arguments as $argument) {
            $result += $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
        }

        return fmod($result, $mod);
    }

    /**
     * Not.
     *
     * @param int $int
     *
     * @see _sha256()
     *
     * @return int
     */
    public function _not($int)
    {
        return ~$int & 0xFFFFFFFF;
    }

    /**
     * Pure-PHP implementation of SHA384 and SHA512.
     *
     * @param string $m
     */
    public function _sha512($m)
    {
        if (!class_exists('Math_BigInteger')) {
            include_once 'Math/BigInteger.php';
        }

        static $init384, $init512, $k;

        if (!isset($k)) {
            // Initialize variables
            $init384 = array( // initial values for SHA384
                'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
                '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4',
            );
            $init512 = array( // initial values for SHA512
                '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
                '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179',
            );

            for ($i = 0; $i < 8; ++$i) {
                $init384[$i] = new Math_BigInteger($init384[$i], 16);
                $init384[$i]->setPrecision(64);
                $init512[$i] = new Math_BigInteger($init512[$i], 16);
                $init512[$i]->setPrecision(64);
            }

            // Initialize table of round constants
            // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
            $k = array(
                '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
                '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
                'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
                '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
                'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
                '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
                '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
                'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
                '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
                '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
                'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
                'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
                '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
                '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
                '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
                '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
                'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
                '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
                '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
                '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817',
            );

            for ($i = 0; $i < 80; ++$i) {
                $k[$i] = new Math_BigInteger($k[$i], 16);
            }
        }

        $hash = 48 == $this->l ? $init384 : $init512;

        // Pre-processing
        $length = strlen($m);
        // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
        $m .= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
        $m[$length] = chr(0x80);
        // we don't support hashing strings 512MB long
        $m .= pack('N4', 0, 0, 0, $length << 3);

        // Process the message in successive 1024-bit chunks
        $chunks = str_split($m, 128);
        foreach ($chunks as $chunk) {
            $w = array();
            for ($i = 0; $i < 16; ++$i) {
                $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
                $temp->setPrecision(64);
                $w[] = $temp;
            }

            // Extend the sixteen 32-bit words into eighty 32-bit words
            for ($i = 16; $i < 80; ++$i) {
                $temp = array(
                    $w[$i - 15]->bitwise_rightRotate(1),
                    $w[$i - 15]->bitwise_rightRotate(8),
                    $w[$i - 15]->bitwise_rightShift(7),
                );
                $s0   = $temp[0]->bitwise_xor($temp[1]);
                $s0   = $s0->bitwise_xor($temp[2]);
                $temp = array(
                    $w[$i - 2]->bitwise_rightRotate(19),
                    $w[$i - 2]->bitwise_rightRotate(61),
                    $w[$i - 2]->bitwise_rightShift(6),
                );
                $s1    = $temp[0]->bitwise_xor($temp[1]);
                $s1    = $s1->bitwise_xor($temp[2]);
                $w[$i] = $w[$i - 16]->copy();
                $w[$i] = $w[$i]->add($s0);
                $w[$i] = $w[$i]->add($w[$i - 7]);
                $w[$i] = $w[$i]->add($s1);
            }

            // Initialize hash value for this chunk
            $a = $hash[0]->copy();
            $b = $hash[1]->copy();
            $c = $hash[2]->copy();
            $d = $hash[3]->copy();
            $e = $hash[4]->copy();
            $f = $hash[5]->copy();
            $g = $hash[6]->copy();
            $h = $hash[7]->copy();

            // Main loop
            for ($i = 0; $i < 80; ++$i) {
                $temp = array(
                    $a->bitwise_rightRotate(28),
                    $a->bitwise_rightRotate(34),
                    $a->bitwise_rightRotate(39),
                );
                $s0   = $temp[0]->bitwise_xor($temp[1]);
                $s0   = $s0->bitwise_xor($temp[2]);
                $temp = array(
                    $a->bitwise_and($b),
                    $a->bitwise_and($c),
                    $b->bitwise_and($c),
                );
                $maj = $temp[0]->bitwise_xor($temp[1]);
                $maj = $maj->bitwise_xor($temp[2]);
                $t2  = $s0->add($maj);

                $temp = array(
                    $e->bitwise_rightRotate(14),
                    $e->bitwise_rightRotate(18),
                    $e->bitwise_rightRotate(41),
                );
                $s1   = $temp[0]->bitwise_xor($temp[1]);
                $s1   = $s1->bitwise_xor($temp[2]);
                $temp = array(
                    $e->bitwise_and($f),
                    $g->bitwise_and($e->bitwise_not()),
                );
                $ch = $temp[0]->bitwise_xor($temp[1]);
                $t1 = $h->add($s1);
                $t1 = $t1->add($ch);
                $t1 = $t1->add($k[$i]);
                $t1 = $t1->add($w[$i]);

                $h = $g->copy();
                $g = $f->copy();
                $f = $e->copy();
                $e = $d->add($t1);
                $d = $c->copy();
                $c = $b->copy();
                $b = $a->copy();
                $a = $t1->add($t2);
            }

            // Add this chunk's hash to result so far
            $hash = array(
                $hash[0]->add($a),
                $hash[1]->add($b),
                $hash[2]->add($c),
                $hash[3]->add($d),
                $hash[4]->add($e),
                $hash[5]->add($f),
                $hash[6]->add($g),
                $hash[7]->add($h),
            );
        }

        // Produce the final hash value (big-endian)
        // (Crypt_Hash::hash() trims the output for hashes but not for HMACs.  as such, we trim the output here)
        $temp = $hash[0]->toBytes().$hash[1]->toBytes().$hash[2]->toBytes().$hash[3]->toBytes().
            $hash[4]->toBytes().$hash[5]->toBytes();
        if (48 != $this->l) {
            $temp .= $hash[6]->toBytes().$hash[7]->toBytes();
        }

        return $temp;
    }
}
PK��#]}���(system/bfnetwork/bfnetwork/Crypt/RSA.phpnu�[���<?php

/**
 * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
 *
 * PHP versions 4 and 5
 *
 * Here's an example of how to encrypt and decrypt text with this library:
 * <code>
 * <?php
 *    include 'Crypt/RSA.php';
 *
 *    $rsa = new Crypt_RSA();
 *    extract($rsa->createKey());
 *
 *    $plaintext = 'terrafrost';
 *
 *    $rsa->loadKey($privatekey);
 *    $ciphertext = $rsa->encrypt($plaintext);
 *
 *    $rsa->loadKey($publickey);
 *    echo $rsa->decrypt($ciphertext);
 * ?>
 * </code>
 *
 * Here's an example of how to create signatures and verify signatures with this library:
 * <code>
 * <?php
 *    include 'Crypt/RSA.php';
 *
 *    $rsa = new Crypt_RSA();
 *    extract($rsa->createKey());
 *
 *    $plaintext = 'terrafrost';
 *
 *    $rsa->loadKey($privatekey);
 *    $signature = $rsa->sign($plaintext);
 *
 *    $rsa->loadKey($publickey);
 *    echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
 * ?>
 * </code>
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category  Crypt
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 * @see      http://phpseclib.sourceforge.net
 */

/**
 * Include Crypt_Random.
 */
// the class_exists() will only be called if the crypt_random_string function hasn't been defined and
// will trigger a call to __autoload() if you're wanting to auto-load classes
// call function_exists() a second time to stop the include_once from being called outside
// of the auto loader
if (!function_exists('crypt_random_string')) {
    include_once 'Random.php';
}

/*
 * Include Crypt_Hash
 */
if (!class_exists('Crypt_Hash')) {
    include_once 'Hash.php';
}

/**#@+
 * @access public
 * @see Crypt_RSA::encrypt()
 * @see Crypt_RSA::decrypt()
 */
/*
 * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
 * (OAEP) for encryption / decryption.
 *
 * Uses sha1 by default.
 *
 * @see Crypt_RSA::setHash()
 * @see Crypt_RSA::setMGFHash()
 */
define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
/*
 * Use PKCS#1 padding.
 *
 * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
 * compatibility with protocols (like SSH-1) written before OAEP's introduction.
 */
define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
/**#@-*/

/**#@+
 * @access public
 * @see Crypt_RSA::sign()
 * @see Crypt_RSA::verify()
 * @see Crypt_RSA::setHash()
 */
/*
 * Use the Probabilistic Signature Scheme for signing
 *
 * Uses sha1 by default.
 *
 * @see Crypt_RSA::setSaltLength()
 * @see Crypt_RSA::setMGFHash()
 */
define('CRYPT_RSA_SIGNATURE_PSS', 1);
/*
 * Use the PKCS#1 scheme by default.
 *
 * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
 * compatibility with protocols (like SSH-2) written before PSS's introduction.
 */
define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
/**#@-*/

/**#@+
 * @access private
 * @see Crypt_RSA::createKey()
 */
/*
 * ASN1 Integer
 */
define('CRYPT_RSA_ASN1_INTEGER', 2);
/*
 * ASN1 Bit String
 */
define('CRYPT_RSA_ASN1_BITSTRING', 3);
/*
 * ASN1 Octet String
 */
define('CRYPT_RSA_ASN1_OCTETSTRING', 4);
/*
 * ASN1 Object Identifier
 */
define('CRYPT_RSA_ASN1_OBJECT', 6);
/*
 * ASN1 Sequence (with the constucted bit set)
 */
define('CRYPT_RSA_ASN1_SEQUENCE', 48);
/**#@-*/

/**#@+
 * @access private
 * @see Crypt_RSA::Crypt_RSA()
 */
/*
 * To use the pure-PHP implementation
 */
define('CRYPT_RSA_MODE_INTERNAL', 1);
/*
 * To use the OpenSSL library
 *
 * (if enabled; otherwise, the internal implementation will be used)
 */
define('CRYPT_RSA_MODE_OPENSSL', 2);
/**#@-*/

/*
 * Default openSSL configuration file.
 */
define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__).'/../openssl.cnf');

/**#@+
 * @access public
 * @see Crypt_RSA::createKey()
 * @see Crypt_RSA::setPrivateKeyFormat()
 */
/*
 * PKCS#1 formatted private key
 *
 * Used by OpenSSH
 */
define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
/*
 * PuTTY formatted private key
 */
define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
/*
 * XML formatted private key
 */
define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
/*
 * PKCS#8 formatted private key
 */
define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 3);
/**#@-*/

/**#@+
 * @access public
 * @see Crypt_RSA::createKey()
 * @see Crypt_RSA::setPublicKeyFormat()
 */
/*
 * Raw public key
 *
 * An array containing two Math_BigInteger objects.
 *
 * The exponent can be indexed with any of the following:
 *
 * 0, e, exponent, publicExponent
 *
 * The modulus can be indexed with any of the following:
 *
 * 1, n, modulo, modulus
 */
define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
/*
 * PKCS#1 formatted public key (raw)
 *
 * Used by File/X509.php
 *
 * Has the following header:
 *
 * -----BEGIN RSA PUBLIC KEY-----
 *
 * Analogous to ssh-keygen's pem format (as specified by -m)
 */
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
/*
 * XML formatted public key
 */
define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
/*
 * OpenSSH formatted public key
 *
 * Place in $HOME/.ssh/authorized_keys
 */
define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
/*
 * PKCS#1 formatted public key (encapsulated)
 *
 * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
 *
 * Has the following header:
 *
 * -----BEGIN PUBLIC KEY-----
 *
 * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
 * is specific to private keys it's basically creating a DER-encoded wrapper
 * for keys. This just extends that same concept to public keys (much like ssh-keygen)
 */
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7);
/**#@-*/

/**
 * Pure-PHP PKCS#1 compliant implementation of RSA.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Crypt_RSA
{
    /**
     * Precomputed Zero.
     *
     * @var array
     */
    public $zero;

    /**
     * Precomputed One.
     *
     * @var array
     */
    public $one;

    /**
     * Private Key Format.
     *
     * @var int
     */
    public $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;

    /**
     * Public Key Format.
     *
     * @var int
     */
    public $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8;

    /**
     * Modulus (ie. n).
     *
     * @var Math_BigInteger
     */
    public $modulus;

    /**
     * Modulus length.
     *
     * @var Math_BigInteger
     */
    public $k;

    /**
     * Exponent (ie. e or d).
     *
     * @var Math_BigInteger
     */
    public $exponent;

    /**
     * Primes for Chinese Remainder Theorem (ie. p and q).
     *
     * @var array
     */
    public $primes;

    /**
     * Exponents for Chinese Remainder Theorem (ie. dP and dQ).
     *
     * @var array
     */
    public $exponents;

    /**
     * Coefficients for Chinese Remainder Theorem (ie. qInv).
     *
     * @var array
     */
    public $coefficients;

    /**
     * Hash name.
     *
     * @var string
     */
    public $hashName;

    /**
     * Hash function.
     *
     * @var Crypt_Hash
     */
    public $hash;

    /**
     * Length of hash function output.
     *
     * @var int
     */
    public $hLen;

    /**
     * Length of salt.
     *
     * @var int
     */
    public $sLen;

    /**
     * Hash function for the Mask Generation Function.
     *
     * @var Crypt_Hash
     */
    public $mgfHash;

    /**
     * Length of MGF hash function output.
     *
     * @var int
     */
    public $mgfHLen;

    /**
     * Encryption mode.
     *
     * @var int
     */
    public $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;

    /**
     * Signature mode.
     *
     * @var int
     */
    public $signatureMode = CRYPT_RSA_SIGNATURE_PSS;

    /**
     * Public Exponent.
     *
     * @var mixed
     */
    public $publicExponent = false;

    /**
     * Password.
     *
     * @var string
     */
    public $password = false;

    /**
     * Components.
     *
     * For use with parsing XML formatted keys.  PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
     * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
     *
     * @see Crypt_RSA::_start_element_handler()
     *
     * @var array
     */
    public $components = array();

    /**
     * Current String.
     *
     * For use with parsing XML formatted keys.
     *
     * @see Crypt_RSA::_character_handler()
     * @see Crypt_RSA::_stop_element_handler()
     *
     * @var mixed
     */
    public $current;

    /**
     * OpenSSL configuration file name.
     *
     * Set to null to use system configuration file.
     *
     * @see Crypt_RSA::createKey()
     *
     * @var mixed
     * @Access public
     */
    public $configFile;

    /**
     * Public key comment field.
     *
     * @var string
     */
    public $comment = 'phpseclib-generated-key';

    /**
     * The constructor.
     *
     * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself.  The reason
     * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully.  openssl_pkey_new(), in particular, requires
     * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
     *
     * @return Crypt_RSA
     */
    public function __construct()
    {
        if (!class_exists('Math_BigInteger')) {
            include_once 'Math/BigInteger.php';
        }

        $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;

        if (!defined('CRYPT_RSA_MODE')) {
            switch (true) {
                // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
                // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
                // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
                case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
                    define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
                    break;
                // openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0
                case !function_exists('openssl_pkey_get_details'):
                    define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
                    break;
                case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
                    // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
                    ob_start();
                    @phpinfo();
                    $content = ob_get_contents();
                    ob_end_clean();

                    preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);

                    $versions = array();
                    if (!empty($matches[1])) {
                        for ($i = 0; $i < count($matches[1]); ++$i) {
                            $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));

                            // Remove letter part in OpenSSL version
                            if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
                                $versions[$matches[1][$i]] = $fullVersion;
                            } else {
                                $versions[$matches[1][$i]] = $m[0];
                            }
                        }
                    }

                    // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
                    switch (true) {
                        case !isset($versions['Header']):
                        case !isset($versions['Library']):
                        case $versions['Header'] == $versions['Library']:
                            define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
                            break;
                        default:
                            define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
                            define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
                    }
                    break;
                default:
                    define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
            }
        }

        $this->zero = new Math_BigInteger();
        $this->one  = new Math_BigInteger(1);

        $this->hash     = new Crypt_Hash('sha1');
        $this->hLen     = $this->hash->getLength();
        $this->hashName = 'sha1';
        $this->mgfHash  = new Crypt_Hash('sha1');
        $this->mgfHLen  = $this->mgfHash->getLength();
    }

    /**
     * Create public / private key pair.
     *
     * Returns an array with the following three elements:
     *  - 'privatekey': The private key.
     *  - 'publickey':  The public key.
     *  - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
     *                  Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
     *
     * @param optional Integer         $bits
     * @param optional Integer         $timeout
     * @param optional Math_BigInteger $p
     */
    public function createKey($bits = 1024, $timeout = false, $partial = array())
    {
        if (!defined('CRYPT_RSA_EXPONENT')) {
            // http://en.wikipedia.org/wiki/65537_%28number%29
            define('CRYPT_RSA_EXPONENT', '65537');
        }
        // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
        // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
        // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
        // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
        // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
        // generation when there's a chance neither gmp nor OpenSSL are installed)
        if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
            define('CRYPT_RSA_SMALLEST_PRIME', 4096);
        }

        // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
        if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
            $config = array();
            if (isset($this->configFile)) {
                $config['config'] = $this->configFile;
            }
            $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
            openssl_pkey_export($rsa, $privatekey, null, $config);
            $publickey = openssl_pkey_get_details($rsa);
            $publickey = $publickey['key'];

            $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
            $publickey  = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));

            // clear the buffer of error strings stemming from a minimalistic openssl.cnf
            while (false !== openssl_error_string());

            return array(
                'privatekey' => $privatekey,
                'publickey'  => $publickey,
                'partialkey' => false,
            );
        }

        static $e;
        if (!isset($e)) {
            $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
        }

        extract($this->_generateMinMax($bits));
        $absoluteMin = $min;
        $temp        = $bits >> 1; // divide by two to see how many bits P and Q would be
        if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
            $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
            $temp       = CRYPT_RSA_SMALLEST_PRIME;
        } else {
            $num_primes = 2;
        }
        extract($this->_generateMinMax($temp + $bits % $temp));
        $finalMax = $max;
        extract($this->_generateMinMax($temp));

        $generator = new Math_BigInteger();

        $n = $this->one->copy();
        if (!empty($partial)) {
            extract(unserialize($partial));
        } else {
            $exponents = $coefficients = $primes = array();
            $lcm       = array(
                'top'    => $this->one->copy(),
                'bottom' => false,
            );
        }

        $start = time();
        $i0    = count($primes) + 1;

        do {
            for ($i = $i0; $i <= $num_primes; ++$i) {
                if (false !== $timeout) {
                    $timeout -= time() - $start;
                    $start = time();
                    if ($timeout <= 0) {
                        return array(
                            'privatekey' => '',
                            'publickey'  => '',
                            'partialkey' => serialize(array(
                                'primes'       => $primes,
                                'coefficients' => $coefficients,
                                'lcm'          => $lcm,
                                'exponents'    => $exponents,
                            )),
                        );
                    }
                }

                if ($i == $num_primes) {
                    list($min, $temp) = $absoluteMin->divide($n);
                    if (!$temp->equals($this->zero)) {
                        $min = $min->add($this->one); // ie. ceil()
                    }
                    $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
                } else {
                    $primes[$i] = $generator->randomPrime($min, $max, $timeout);
                }

                if (false === $primes[$i]) { // if we've reached the timeout
                    if (count($primes) > 1) {
                        $partialkey = '';
                    } else {
                        array_pop($primes);
                        $partialkey = serialize(array(
                            'primes'       => $primes,
                            'coefficients' => $coefficients,
                            'lcm'          => $lcm,
                            'exponents'    => $exponents,
                        ));
                    }

                    return array(
                        'privatekey' => '',
                        'publickey'  => '',
                        'partialkey' => $partialkey,
                    );
                }

                // the first coefficient is calculated differently from the rest
                // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
                if ($i > 2) {
                    $coefficients[$i] = $n->modInverse($primes[$i]);
                }

                $n = $n->multiply($primes[$i]);

                $temp = $primes[$i]->subtract($this->one);

                // textbook RSA implementations use Euler's totient function instead of the least common multiple.
                // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
                $lcm['top']    = $lcm['top']->multiply($temp);
                $lcm['bottom'] = false === $lcm['bottom'] ? $temp : $lcm['bottom']->gcd($temp);

                $exponents[$i] = $e->modInverse($temp);
            }

            list($temp) = $lcm['top']->divide($lcm['bottom']);
            $gcd        = $temp->gcd($e);
            $i0         = 1;
        } while (!$gcd->equals($this->one));

        $d = $e->modInverse($temp);

        $coefficients[2] = $primes[2]->modInverse($primes[1]);

        // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
        // RSAPrivateKey ::= SEQUENCE {
        //     version           Version,
        //     modulus           INTEGER,  -- n
        //     publicExponent    INTEGER,  -- e
        //     privateExponent   INTEGER,  -- d
        //     prime1            INTEGER,  -- p
        //     prime2            INTEGER,  -- q
        //     exponent1         INTEGER,  -- d mod (p-1)
        //     exponent2         INTEGER,  -- d mod (q-1)
        //     coefficient       INTEGER,  -- (inverse of q) mod p
        //     otherPrimeInfos   OtherPrimeInfos OPTIONAL
        // }

        return array(
            'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
            'publickey'  => $this->_convertPublicKey($n, $e),
            'partialkey' => false,
        );
    }

    /**
     * Break a public or private key down into its constituant components.
     *
     * @see _convertPublicKey()
     * @see _convertPrivateKey()
     *
     * @param string $key
     * @param int    $type
     *
     * @return array
     */
    public function _parseKey($key, $type)
    {
        if (CRYPT_RSA_PUBLIC_FORMAT_RAW != $type && !is_string($key)) {
            return false;
        }

        switch ($type) {
            case CRYPT_RSA_PUBLIC_FORMAT_RAW:
                if (!is_array($key)) {
                    return false;
                }
                $components = array();
                switch (true) {
                    case isset($key['e']):
                        $components['publicExponent'] = $key['e']->copy();
                        break;
                    case isset($key['exponent']):
                        $components['publicExponent'] = $key['exponent']->copy();
                        break;
                    case isset($key['publicExponent']):
                        $components['publicExponent'] = $key['publicExponent']->copy();
                        break;
                    case isset($key[0]):
                        $components['publicExponent'] = $key[0]->copy();
                }
                switch (true) {
                    case isset($key['n']):
                        $components['modulus'] = $key['n']->copy();
                        break;
                    case isset($key['modulo']):
                        $components['modulus'] = $key['modulo']->copy();
                        break;
                    case isset($key['modulus']):
                        $components['modulus'] = $key['modulus']->copy();
                        break;
                    case isset($key[1]):
                        $components['modulus'] = $key[1]->copy();
                }

                return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
            case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
            case CRYPT_RSA_PRIVATE_FORMAT_PKCS8:
            case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
                /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
                   "outside the scope" of PKCS#1.  PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
                   protect private keys, however, that's not what OpenSSL* does.  OpenSSL protects private keys by adding
                   two new "fields" to the key - DEK-Info and Proc-Type.  These fields are discussed here:

                   http://tools.ietf.org/html/rfc1421#section-4.6.1.1
                   http://tools.ietf.org/html/rfc1421#section-4.6.1.3

                   DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
                   DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
                   function.  As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
                   own implementation.  ie. the implementation *is* the standard and any bugs that may exist in that
                   implementation are part of the standard, as well.

                   * OpenSSL is the de facto standard.  It's utilized by OpenSSH and other projects */
                if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
                    $iv     = pack('H*', trim($matches[2]));
                    $symkey = pack('H*', md5($this->password.substr($iv, 0, 8))); // symkey is short for symmetric key
                    $symkey .= pack('H*', md5($symkey.$this->password.substr($iv, 0, 8)));
                    // remove the Proc-Type / DEK-Info sections as they're no longer needed
                    $key        = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
                    $ciphertext = $this->_extractBER($key);
                    if (false === $ciphertext) {
                        $ciphertext = $key;
                    }
                    switch ($matches[1]) {
                        case 'AES-256-CBC':
                            if (!class_exists('Crypt_AES')) {
                                include_once 'Crypt/AES.php';
                            }
                            $crypto = new Crypt_AES();
                            break;
                        case 'AES-128-CBC':
                            if (!class_exists('Crypt_AES')) {
                                include_once 'Crypt/AES.php';
                            }
                            $symkey = substr($symkey, 0, 16);
                            $crypto = new Crypt_AES();
                            break;
                        case 'DES-EDE3-CFB':
                            if (!class_exists('Crypt_TripleDES')) {
                                include_once 'Crypt/TripleDES.php';
                            }
                            $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
                            break;
                        case 'DES-EDE3-CBC':
                            if (!class_exists('Crypt_TripleDES')) {
                                include_once 'Crypt/TripleDES.php';
                            }
                            $symkey = substr($symkey, 0, 24);
                            $crypto = new Crypt_TripleDES();
                            break;
                        case 'DES-CBC':
                            if (!class_exists('Crypt_DES')) {
                                include_once 'Crypt/DES.php';
                            }
                            $crypto = new Crypt_DES();
                            break;
                        default:
                            return false;
                    }
                    $crypto->setKey($symkey);
                    $crypto->setIV($iv);
                    $decoded = $crypto->decrypt($ciphertext);
                } else {
                    $decoded = $this->_extractBER($key);
                }

                if (false !== $decoded) {
                    $key = $decoded;
                }

                $components = array();

                if (CRYPT_RSA_ASN1_SEQUENCE != ord($this->_string_shift($key))) {
                    return false;
                }
                if ($this->_decodeLength($key) != strlen($key)) {
                    return false;
                }

                $tag = ord($this->_string_shift($key));
                /* intended for keys for which OpenSSL's asn1parse returns the following:

                    0:d=0  hl=4 l= 631 cons: SEQUENCE
                    4:d=1  hl=2 l=   1 prim:  INTEGER           :00
                    7:d=1  hl=2 l=  13 cons:  SEQUENCE
                    9:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
                   20:d=2  hl=2 l=   0 prim:   NULL
                   22:d=1  hl=4 l= 609 prim:  OCTET STRING

                   ie. PKCS8 keys*/

                if (CRYPT_RSA_ASN1_INTEGER == $tag && "\x01\x00\x30" == substr($key, 0, 3)) {
                    $this->_string_shift($key, 3);
                    $tag = CRYPT_RSA_ASN1_SEQUENCE;
                }

                if (CRYPT_RSA_ASN1_SEQUENCE == $tag) {
                    $temp = $this->_string_shift($key, $this->_decodeLength($key));
                    if (CRYPT_RSA_ASN1_OBJECT != ord($this->_string_shift($temp))) {
                        return false;
                    }
                    $length = $this->_decodeLength($temp);
                    switch ($this->_string_shift($temp, $length)) {
                        case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
                            break;
                        case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
                            /*
                               PBEParameter ::= SEQUENCE {
                                   salt OCTET STRING (SIZE(8)),
                                   iterationCount INTEGER }
                            */
                            if (CRYPT_RSA_ASN1_SEQUENCE != ord($this->_string_shift($temp))) {
                                return false;
                            }
                            if ($this->_decodeLength($temp) != strlen($temp)) {
                                return false;
                            }
                            $this->_string_shift($temp); // assume it's an octet string
                            $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
                            if (CRYPT_RSA_ASN1_INTEGER != ord($this->_string_shift($temp))) {
                                return false;
                            }
                            $this->_decodeLength($temp);
                            list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
                            $this->_string_shift($key); // assume it's an octet string
                            $length = $this->_decodeLength($key);
                            if (strlen($key) != $length) {
                                return false;
                            }

                            if (!class_exists('Crypt_DES')) {
                                include_once 'Crypt/DES.php';
                            }
                            $crypto = new Crypt_DES();
                            $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
                            $key = $crypto->decrypt($key);
                            if (false === $key) {
                                return false;
                            }

                            return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
                        default:
                            return false;
                    }
                    /* intended for keys for which OpenSSL's asn1parse returns the following:

                        0:d=0  hl=4 l= 290 cons: SEQUENCE
                        4:d=1  hl=2 l=  13 cons:  SEQUENCE
                        6:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
                       17:d=2  hl=2 l=   0 prim:   NULL
                       19:d=1  hl=4 l= 271 prim:  BIT STRING */
                    $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
                    $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
                    // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
                    //  unused bits in the final subsequent octet. The number shall be in the range zero to seven."
                    //  -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
                    if (CRYPT_RSA_ASN1_BITSTRING == $tag) {
                        $this->_string_shift($key);
                    }
                    if (CRYPT_RSA_ASN1_SEQUENCE != ord($this->_string_shift($key))) {
                        return false;
                    }
                    if ($this->_decodeLength($key) != strlen($key)) {
                        return false;
                    }
                    $tag = ord($this->_string_shift($key));
                }
                if (CRYPT_RSA_ASN1_INTEGER != $tag) {
                    return false;
                }

                $length = $this->_decodeLength($key);
                $temp   = $this->_string_shift($key, $length);
                if (1 != strlen($temp) || ord($temp) > 2) {
                    $components['modulus'] = new Math_BigInteger($temp, 256);
                    $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
                    $length                                                                                    = $this->_decodeLength($key);
                    $components[CRYPT_RSA_PUBLIC_FORMAT_PKCS1 == $type ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);

                    return $components;
                }
                if (CRYPT_RSA_ASN1_INTEGER != ord($this->_string_shift($key))) {
                    return false;
                }
                $length                = $this->_decodeLength($key);
                $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                $this->_string_shift($key);
                $length                       = $this->_decodeLength($key);
                $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                $this->_string_shift($key);
                $length                        = $this->_decodeLength($key);
                $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                $this->_string_shift($key);
                $length               = $this->_decodeLength($key);
                $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
                $this->_string_shift($key);
                $length                 = $this->_decodeLength($key);
                $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                $this->_string_shift($key);
                $length                  = $this->_decodeLength($key);
                $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
                $this->_string_shift($key);
                $length                    = $this->_decodeLength($key);
                $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                $this->_string_shift($key);
                $length                     = $this->_decodeLength($key);
                $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));

                if (!empty($key)) {
                    if (CRYPT_RSA_ASN1_SEQUENCE != ord($this->_string_shift($key))) {
                        return false;
                    }
                    $this->_decodeLength($key);
                    while (!empty($key)) {
                        if (CRYPT_RSA_ASN1_SEQUENCE != ord($this->_string_shift($key))) {
                            return false;
                        }
                        $this->_decodeLength($key);
                        $key                    = substr($key, 1);
                        $length                 = $this->_decodeLength($key);
                        $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                        $this->_string_shift($key);
                        $length                    = $this->_decodeLength($key);
                        $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                        $this->_string_shift($key);
                        $length                       = $this->_decodeLength($key);
                        $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
                    }
                }

                return $components;
            case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
                $parts = explode(' ', $key, 3);

                $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
                if (false === $key) {
                    return false;
                }

                $comment = isset($parts[2]) ? $parts[2] : false;

                $cleanup = "\0\0\0\7ssh-rsa" == substr($key, 0, 11);

                if (strlen($key) <= 4) {
                    return false;
                }
                extract(unpack('Nlength', $this->_string_shift($key, 4)));
                $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
                if (strlen($key) <= 4) {
                    return false;
                }
                extract(unpack('Nlength', $this->_string_shift($key, 4)));
                $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);

                if ($cleanup && strlen($key)) {
                    if (strlen($key) <= 4) {
                        return false;
                    }
                    extract(unpack('Nlength', $this->_string_shift($key, 4)));
                    $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);

                    return strlen($key) ? false : array(
                        'modulus'        => $realModulus,
                        'publicExponent' => $modulus,
                        'comment'        => $comment,
                    );
                } else {
                    return strlen($key) ? false : array(
                        'modulus'        => $modulus,
                        'publicExponent' => $publicExponent,
                        'comment'        => $comment,
                    );
                }
            // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
            // http://en.wikipedia.org/wiki/XML_Signature
            // no break
            case CRYPT_RSA_PRIVATE_FORMAT_XML:
            case CRYPT_RSA_PUBLIC_FORMAT_XML:
                $this->components = array();

                $xml = xml_parser_create('UTF-8');
                xml_set_object($xml, $this);
                xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
                xml_set_character_data_handler($xml, '_data_handler');
                // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
                if (!xml_parse($xml, '<xml>'.$key.'</xml>')) {
                    return false;
                }

                return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
            // from PuTTY's SSHPUBK.C
            case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
                $components = array();
                $key        = preg_split('#\r\n|\r|\n#', $key);
                $type       = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
                if ('ssh-rsa' != $type) {
                    return false;
                }
                $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
                $comment    = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));

                $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
                $public       = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
                $public       = substr($public, 11);
                extract(unpack('Nlength', $this->_string_shift($public, 4)));
                $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
                extract(unpack('Nlength', $this->_string_shift($public, 4)));
                $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);

                $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
                $private       = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));

                switch ($encryption) {
                    case 'aes256-cbc':
                        if (!class_exists('Crypt_AES')) {
                            include_once 'Crypt/AES.php';
                        }
                        $symkey   = '';
                        $sequence = 0;
                        while (strlen($symkey) < 32) {
                            $temp = pack('Na*', $sequence++, $this->password);
                            $symkey .= pack('H*', sha1($temp));
                        }
                        $symkey = substr($symkey, 0, 32);
                        $crypto = new Crypt_AES();
                }

                if ('none' != $encryption) {
                    $crypto->setKey($symkey);
                    $crypto->disablePadding();
                    $private = $crypto->decrypt($private);
                    if (false === $private) {
                        return false;
                    }
                }

                extract(unpack('Nlength', $this->_string_shift($private, 4)));
                if (strlen($private) < $length) {
                    return false;
                }
                $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
                if (strlen($private) < $length) {
                    return false;
                }
                $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
                extract(unpack('Nlength', $this->_string_shift($private, 4)));
                if (strlen($private) < $length) {
                    return false;
                }
                $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);

                $temp                      = $components['primes'][1]->subtract($this->one);
                $components['exponents']   = array(1 => $components['publicExponent']->modInverse($temp));
                $temp                      = $components['primes'][2]->subtract($this->one);
                $components['exponents'][] = $components['publicExponent']->modInverse($temp);

                extract(unpack('Nlength', $this->_string_shift($private, 4)));
                if (strlen($private) < $length) {
                    return false;
                }
                $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));

                return $components;
        }
    }

    /**
     * Extract raw BER from Base64 encoding.
     *
     * @param string $str
     *
     * @return string
     */
    public function _extractBER($str)
    {
        /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
         * above and beyond the ceritificate.
         * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
         *
         * Bag Attributes
         *     localKeyID: 01 00 00 00
         * subject=/O=organization/OU=org unit/CN=common name
         * issuer=/O=organization/CN=common name
         */
        $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1);
        // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
        $temp = preg_replace('#-+[^-]+-+#', '', $temp);
        // remove new lines
        $temp = str_replace(array("\r", "\n", ' '), '', $temp);
        $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;

        return false != $temp ? $temp : $str;
    }

    /**
     * String Shift.
     *
     * Inspired by array_shift
     *
     * @param string           $string
     * @param optional Integer $index
     *
     * @return string
     */
    public function _string_shift(&$string, $index = 1)
    {
        $substr = substr($string, 0, $index);
        $string = substr($string, $index);

        return $substr;
    }

    /**
     * DER-decode the length.
     *
     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
     *
     * @param string $string
     *
     * @return int
     */
    public function _decodeLength(&$string)
    {
        $length = ord($this->_string_shift($string));
        if ($length & 0x80) { // definite length, long form
            $length &= 0x7F;
            $temp           = $this->_string_shift($string, $length);
            list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
        }

        return $length;
    }

    /**
     * Generates the smallest and largest numbers requiring $bits bits.
     *
     * @param int $bits
     *
     * @return array
     */
    public function _generateMinMax($bits)
    {
        $bytes = $bits >> 3;
        $min   = str_repeat(chr(0), $bytes);
        $max   = str_repeat(chr(0xFF), $bytes);
        $msb   = $bits & 7;
        if ($msb) {
            $min = chr(1 << ($msb - 1)).$min;
            $max = chr((1 << $msb) - 1).$max;
        } else {
            $min[0] = chr(0x80);
        }

        return array(
            'min' => new Math_BigInteger($min, 256),
            'max' => new Math_BigInteger($max, 256),
        );
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @see setPrivateKeyFormat()
     *
     * @param string $RSAPrivateKey
     *
     * @return string
     */
    public function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
    {
        $signed     = CRYPT_RSA_PRIVATE_FORMAT_XML != $this->privateKeyFormat;
        $num_primes = count($primes);
        $raw        = array(
            'version'         => 2 == $num_primes ? chr(0) : chr(1), // two-prime vs. multi
            'modulus'         => $n->toBytes($signed),
            'publicExponent'  => $e->toBytes($signed),
            'privateExponent' => $d->toBytes($signed),
            'prime1'          => $primes[1]->toBytes($signed),
            'prime2'          => $primes[2]->toBytes($signed),
            'exponent1'       => $exponents[1]->toBytes($signed),
            'exponent2'       => $exponents[2]->toBytes($signed),
            'coefficient'     => $coefficients[2]->toBytes($signed),
        );

        // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
        // call _convertPublicKey() instead.
        switch ($this->privateKeyFormat) {
            case CRYPT_RSA_PRIVATE_FORMAT_XML:
                if (2 != $num_primes) {
                    return false;
                }

                return "<RSAKeyValue>\r\n".
                '  <Modulus>'.base64_encode($raw['modulus'])."</Modulus>\r\n".
                '  <Exponent>'.base64_encode($raw['publicExponent'])."</Exponent>\r\n".
                '  <P>'.base64_encode($raw['prime1'])."</P>\r\n".
                '  <Q>'.base64_encode($raw['prime2'])."</Q>\r\n".
                '  <DP>'.base64_encode($raw['exponent1'])."</DP>\r\n".
                '  <DQ>'.base64_encode($raw['exponent2'])."</DQ>\r\n".
                '  <InverseQ>'.base64_encode($raw['coefficient'])."</InverseQ>\r\n".
                '  <D>'.base64_encode($raw['privateExponent'])."</D>\r\n".
                '</RSAKeyValue>';
                break;
            case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
                if (2 != $num_primes) {
                    return false;
                }
                $key        = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
                $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
                $key .= $encryption;
                $key .= "\r\nComment: ".$this->comment."\r\n";
                $public = pack('Na*Na*Na*',
                    strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
                );
                $source = pack('Na*Na*Na*Na*',
                    strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
                    strlen($this->comment), $this->comment, strlen($public), $public
                );
                $public = base64_encode($public);
                $key .= 'Public-Lines: '.((strlen($public) + 63) >> 6)."\r\n";
                $key .= chunk_split($public, 64);
                $private = pack('Na*Na*Na*Na*',
                    strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
                    strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
                );
                if (empty($this->password) && !is_string($this->password)) {
                    $source .= pack('Na*', strlen($private), $private);
                    $hashkey = 'putty-private-key-file-mac-key';
                } else {
                    $private .= crypt_random_string(16 - (strlen($private) & 15));
                    $source .= pack('Na*', strlen($private), $private);
                    if (!class_exists('Crypt_AES')) {
                        include_once 'Crypt/AES.php';
                    }
                    $sequence = 0;
                    $symkey   = '';
                    while (strlen($symkey) < 32) {
                        $temp = pack('Na*', $sequence++, $this->password);
                        $symkey .= pack('H*', sha1($temp));
                    }
                    $symkey = substr($symkey, 0, 32);
                    $crypto = new Crypt_AES();

                    $crypto->setKey($symkey);
                    $crypto->disablePadding();
                    $private = $crypto->encrypt($private);
                    $hashkey = 'putty-private-key-file-mac-key'.$this->password;
                }

                $private = base64_encode($private);
                $key .= 'Private-Lines: '.((strlen($private) + 63) >> 6)."\r\n";
                $key .= chunk_split($private, 64);
                if (!class_exists('Crypt_Hash')) {
                    include_once 'Crypt/Hash.php';
                }
                $hash = new Crypt_Hash('sha1');
                $hash->setKey(pack('H*', sha1($hashkey)));
                $key .= 'Private-MAC: '.bin2hex($hash->hash($source))."\r\n";

                return $key;
            default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
                $components = array();
                foreach ($raw as $name => $value) {
                    $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
                }

                $RSAPrivateKey = implode('', $components);

                if ($num_primes > 2) {
                    $OtherPrimeInfos = '';
                    for ($i = 3; $i <= $num_primes; ++$i) {
                        // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
                        //
                        // OtherPrimeInfo ::= SEQUENCE {
                        //     prime             INTEGER,  -- ri
                        //     exponent          INTEGER,  -- di
                        //     coefficient       INTEGER   -- ti
                        // }
                        $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
                        $OtherPrimeInfo .= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
                        $OtherPrimeInfo .= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
                        $OtherPrimeInfos .= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
                    }
                    $RSAPrivateKey .= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
                }

                $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);

                if (CRYPT_RSA_PRIVATE_FORMAT_PKCS8 == $this->privateKeyFormat) {
                    $rsaOID        = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
                    $RSAPrivateKey = pack('Ca*a*Ca*a*',
                        CRYPT_RSA_ASN1_INTEGER, "\01\00", $rsaOID, 4, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey
                    );
                    $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
                    if (!empty($this->password) || is_string($this->password)) {
                        $salt           = crypt_random_string(8);
                        $iterationCount = 2048;

                        if (!class_exists('Crypt_DES')) {
                            include_once 'Crypt/DES.php';
                        }
                        $crypto = new Crypt_DES();
                        $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
                        $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);

                        $parameters = pack('Ca*a*Ca*N',
                            CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($salt)), $salt,
                            CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(4), $iterationCount
                        );
                        $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";

                        $encryptionAlgorithm = pack('Ca*a*Ca*a*',
                            CRYPT_RSA_ASN1_OBJECT, $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), $pbeWithMD5AndDES_CBC,
                            CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($parameters)), $parameters
                        );

                        $RSAPrivateKey = pack('Ca*a*Ca*a*',
                            CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($encryptionAlgorithm)), $encryptionAlgorithm,
                            CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey
                        );

                        $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);

                        $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n".
                            chunk_split(base64_encode($RSAPrivateKey), 64).
                            '-----END ENCRYPTED PRIVATE KEY-----';
                    } else {
                        $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n".
                            chunk_split(base64_encode($RSAPrivateKey), 64).
                            '-----END PRIVATE KEY-----';
                    }

                    return $RSAPrivateKey;
                }

                if (!empty($this->password) || is_string($this->password)) {
                    $iv     = crypt_random_string(8);
                    $symkey = pack('H*', md5($this->password.$iv)); // symkey is short for symmetric key
                    $symkey .= substr(pack('H*', md5($symkey.$this->password.$iv)), 0, 8);
                    if (!class_exists('Crypt_TripleDES')) {
                        include_once 'Crypt/TripleDES.php';
                    }
                    $des = new Crypt_TripleDES();
                    $des->setKey($symkey);
                    $des->setIV($iv);
                    $iv            = strtoupper(bin2hex($iv));
                    $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n".
                        "Proc-Type: 4,ENCRYPTED\r\n".
                        "DEK-Info: DES-EDE3-CBC,$iv\r\n".
                        "\r\n".
                        chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64).
                        '-----END RSA PRIVATE KEY-----';
                } else {
                    $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n".
                        chunk_split(base64_encode($RSAPrivateKey), 64).
                        '-----END RSA PRIVATE KEY-----';
                }

                return $RSAPrivateKey;
        }
    }

    /**
     * DER-encode the length.
     *
     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
     *
     * @param int $length
     *
     * @return string
     */
    public function _encodeLength($length)
    {
        if ($length <= 0x7F) {
            return chr($length);
        }

        $temp = ltrim(pack('N', $length), chr(0));

        return pack('Ca*', 0x80 | strlen($temp), $temp);
    }

    /**
     * Convert a public key to the appropriate format.
     *
     * @see setPublicKeyFormat()
     *
     * @param string $RSAPrivateKey
     *
     * @return string
     */
    public function _convertPublicKey($n, $e)
    {
        $signed = CRYPT_RSA_PUBLIC_FORMAT_XML != $this->publicKeyFormat;

        $modulus        = $n->toBytes($signed);
        $publicExponent = $e->toBytes($signed);

        switch ($this->publicKeyFormat) {
            case CRYPT_RSA_PUBLIC_FORMAT_RAW:
                return array('e' => $e->copy(), 'n' => $n->copy());
            case CRYPT_RSA_PUBLIC_FORMAT_XML:
                return "<RSAKeyValue>\r\n".
                '  <Modulus>'.base64_encode($modulus)."</Modulus>\r\n".
                '  <Exponent>'.base64_encode($publicExponent)."</Exponent>\r\n".
                '</RSAKeyValue>';
                break;
            case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
                // from <http://tools.ietf.org/html/rfc4253#page-15>:
                // string    "ssh-rsa"
                // mpint     e
                // mpint     n
                $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
                $RSAPublicKey = 'ssh-rsa '.base64_encode($RSAPublicKey).' '.$this->comment;

                return $RSAPublicKey;
            default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
                // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
                // RSAPublicKey ::= SEQUENCE {
                //     modulus           INTEGER,  -- n
                //     publicExponent    INTEGER   -- e
                // }
                $components = array(
                    'modulus'        => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
                    'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent),
                );

                $RSAPublicKey = pack('Ca*a*a*',
                    CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
                    $components['modulus'], $components['publicExponent']
                );

                if (CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW == $this->publicKeyFormat) {
                    $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n".
                        chunk_split(base64_encode($RSAPublicKey), 64).
                        '-----END RSA PUBLIC KEY-----';
                } else {
                    // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
                    $rsaOID       = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
                    $RSAPublicKey = chr(0).$RSAPublicKey;
                    $RSAPublicKey = chr(3).$this->_encodeLength(strlen($RSAPublicKey)).$RSAPublicKey;

                    $RSAPublicKey = pack('Ca*a*',
                        CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID.$RSAPublicKey)), $rsaOID.$RSAPublicKey
                    );

                    $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n".
                        chunk_split(base64_encode($RSAPublicKey), 64).
                        '-----END PUBLIC KEY-----';
                }

                return $RSAPublicKey;
        }
    }

    /**
     * Returns the key size.
     *
     * More specifically, this returns the size of the modulo in bits.
     *
     * @return int
     */
    public function getSize()
    {
        return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
    }

    /**
     * Start Element Handler.
     *
     * Called by xml_set_element_handler()
     *
     * @param resource $parser
     * @param string   $name
     * @param array    $attribs
     */
    public function _start_element_handler($parser, $name, $attribs)
    {
        //$name = strtoupper($name);
        switch ($name) {
            case 'MODULUS':
                $this->current = &$this->components['modulus'];
                break;
            case 'EXPONENT':
                $this->current = &$this->components['publicExponent'];
                break;
            case 'P':
                $this->current = &$this->components['primes'][1];
                break;
            case 'Q':
                $this->current = &$this->components['primes'][2];
                break;
            case 'DP':
                $this->current = &$this->components['exponents'][1];
                break;
            case 'DQ':
                $this->current = &$this->components['exponents'][2];
                break;
            case 'INVERSEQ':
                $this->current = &$this->components['coefficients'][2];
                break;
            case 'D':
                $this->current = &$this->components['privateExponent'];
        }
        $this->current = '';
    }

    /**
     * Stop Element Handler.
     *
     * Called by xml_set_element_handler()
     *
     * @param resource $parser
     * @param string   $name
     */
    public function _stop_element_handler($parser, $name)
    {
        if (isset($this->current)) {
            $this->current = new Math_BigInteger(base64_decode($this->current), 256);
            unset($this->current);
        }
    }

    /**
     * Data Handler.
     *
     * Called by xml_set_character_data_handler()
     *
     * @param resource $parser
     * @param string   $data
     */
    public function _data_handler($parser, $data)
    {
        if (!isset($this->current) || is_object($this->current)) {
            return;
        }
        $this->current .= trim($data);
    }

    /**
     * Sets the password.
     *
     * Private keys can be encrypted with a password.  To unset the password, pass in the empty string or false.
     * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
     *
     * @see createKey()
     * @see loadKey()
     *
     * @param string $password
     */
    public function setPassword($password = false)
    {
        $this->password = $password;
    }

    /**
     * Defines the private key.
     *
     * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
     * phpseclib to treat the key as a private key. This function will do that.
     *
     * Do note that when a new key is loaded the index will be cleared.
     *
     * Returns true on success, false on failure
     *
     * @see getPublicKey()
     *
     * @param string $key  optional
     * @param int    $type optional
     *
     * @return bool
     */
    public function setPrivateKey($key = false, $type = false)
    {
        if (false === $key && !empty($this->publicExponent)) {
            unset($this->publicExponent);

            return true;
        }

        $rsa = new Crypt_RSA();
        if (!$rsa->loadKey($key, $type)) {
            return false;
        }
        unset($rsa->publicExponent);

        // don't overwrite the old key if the new key is invalid
        $this->loadKey($rsa);

        return true;
    }

    /**
     * Loads a public or private key.
     *
     * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
     *
     * @param string $key
     * @param int    $type optional
     */
    public function loadKey($key, $type = false)
    {
        if (is_object($key) && 'crypt_rsa' == strtolower(get_class($key))) {
            $this->privateKeyFormat = $key->privateKeyFormat;
            $this->publicKeyFormat  = $key->publicKeyFormat;
            $this->k                = $key->k;
            $this->hLen             = $key->hLen;
            $this->sLen             = $key->sLen;
            $this->mgfHLen          = $key->mgfHLen;
            $this->encryptionMode   = $key->encryptionMode;
            $this->signatureMode    = $key->signatureMode;
            $this->password         = $key->password;
            $this->configFile       = $key->configFile;
            $this->comment          = $key->comment;

            if (is_object($key->hash)) {
                $this->hash = new Crypt_Hash($key->hash->getHash());
            }
            if (is_object($key->mgfHash)) {
                $this->mgfHash = new Crypt_Hash($key->mgfHash->getHash());
            }

            if (is_object($key->modulus)) {
                $this->modulus = $key->modulus->copy();
            }
            if (is_object($key->exponent)) {
                $this->exponent = $key->exponent->copy();
            }
            if (is_object($key->publicExponent)) {
                $this->publicExponent = $key->publicExponent->copy();
            }

            $this->primes       = array();
            $this->exponents    = array();
            $this->coefficients = array();

            foreach ($this->primes as $prime) {
                $this->primes[] = $prime->copy();
            }
            foreach ($this->exponents as $exponent) {
                $this->exponents[] = $exponent->copy();
            }
            foreach ($this->coefficients as $coefficient) {
                $this->coefficients[] = $coefficient->copy();
            }

            return true;
        }

        if (false === $type) {
            $types = array(
                CRYPT_RSA_PUBLIC_FORMAT_RAW,
                CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
                CRYPT_RSA_PRIVATE_FORMAT_XML,
                CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
                CRYPT_RSA_PUBLIC_FORMAT_OPENSSH,
            );
            foreach ($types as $type) {
                $components = $this->_parseKey($key, $type);
                if (false !== $components) {
                    break;
                }
            }
        } else {
            $components = $this->_parseKey($key, $type);
        }

        if (false === $components) {
            return false;
        }

        if (isset($components['comment']) && false !== $components['comment']) {
            $this->comment = $components['comment'];
        }
        $this->modulus  = $components['modulus'];
        $this->k        = strlen($this->modulus->toBytes());
        $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
        if (isset($components['primes'])) {
            $this->primes         = $components['primes'];
            $this->exponents      = $components['exponents'];
            $this->coefficients   = $components['coefficients'];
            $this->publicExponent = $components['publicExponent'];
        } else {
            $this->primes         = array();
            $this->exponents      = array();
            $this->coefficients   = array();
            $this->publicExponent = false;
        }

        switch ($type) {
            case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
            case CRYPT_RSA_PUBLIC_FORMAT_RAW:
                $this->setPublicKey();
                break;
            case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
                switch (true) {
                    case false !== strpos($key, '-BEGIN PUBLIC KEY-'):
                    case false !== strpos($key, '-BEGIN RSA PUBLIC KEY-'):
                        $this->setPublicKey();
                }
        }

        return true;
    }

    /**
     * Defines the public key.
     *
     * Some private key formats define the public exponent and some don't.  Those that don't define it are problematic when
     * used in certain contexts.  For example, in SSH-2, RSA authentication works by sending the public key along with a
     * message signed by the private key to the server.  The SSH-2 server looks the public key up in an index of public keys
     * and if it's present then proceeds to verify the signature.  Problem is, if your private key doesn't include the public
     * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
     * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
     * public.
     *
     * Do note that when a new key is loaded the index will be cleared.
     *
     * Returns true on success, false on failure
     *
     * @see getPublicKey()
     *
     * @param string $key  optional
     * @param int    $type optional
     *
     * @return bool
     */
    public function setPublicKey($key = false, $type = false)
    {
        // if a public key has already been loaded return false
        if (!empty($this->publicExponent)) {
            return false;
        }

        if (false === $key && !empty($this->modulus)) {
            $this->publicExponent = $this->exponent;

            return true;
        }

        if (false === $type) {
            $types = array(
                CRYPT_RSA_PUBLIC_FORMAT_RAW,
                CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
                CRYPT_RSA_PUBLIC_FORMAT_XML,
                CRYPT_RSA_PUBLIC_FORMAT_OPENSSH,
            );
            foreach ($types as $type) {
                $components = $this->_parseKey($key, $type);
                if (false !== $components) {
                    break;
                }
            }
        } else {
            $components = $this->_parseKey($key, $type);
        }

        if (false === $components) {
            return false;
        }

        if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
            $this->modulus  = $components['modulus'];
            $this->exponent = $this->publicExponent = $components['publicExponent'];

            return true;
        }

        $this->publicExponent = $components['publicExponent'];

        return true;
    }

    /**
     * Returns the public key.
     *
     * The public key is only returned under two circumstances - if the private key had the public key embedded within it
     * or if the public key was set via setPublicKey().  If the currently loaded key is supposed to be the public key this
     * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
     *
     * @see getPublicKey()
     *
     * @param string $key
     * @param int    $type optional
     */
    public function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
    {
        if (empty($this->modulus) || empty($this->publicExponent)) {
            return false;
        }

        $oldFormat             = $this->publicKeyFormat;
        $this->publicKeyFormat = $type;
        $temp                  = $this->_convertPublicKey($this->modulus, $this->publicExponent);
        $this->publicKeyFormat = $oldFormat;

        return $temp;
    }

    /**
     *  __toString() magic method.
     */
    public function __toString()
    {
        $key = $this->getPrivateKey($this->privateKeyFormat);
        if (false !== $key) {
            return $key;
        }
        $key = $this->_getPrivatePublicKey($this->publicKeyFormat);

        return false !== $key ? $key : '';
    }

    /**
     * Returns the private key.
     *
     * The private key is only returned if the currently loaded key contains the constituent prime numbers.
     *
     * @see getPublicKey()
     *
     * @param string $key
     * @param int    $type optional
     */
    public function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
    {
        if (empty($this->primes)) {
            return false;
        }

        $oldFormat              = $this->privateKeyFormat;
        $this->privateKeyFormat = $type;
        $temp                   = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
        $this->privateKeyFormat = $oldFormat;

        return $temp;
    }

    /**
     * Returns a minimalistic private key.
     *
     * Returns the private key without the prime number constituants.  Structurally identical to a public key that
     * hasn't been set as the public key
     *
     * @see getPrivateKey()
     *
     * @param string $key
     * @param int    $type optional
     */
    public function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
    {
        if (empty($this->modulus) || empty($this->exponent)) {
            return false;
        }

        $oldFormat             = $this->publicKeyFormat;
        $this->publicKeyFormat = $mode;
        $temp                  = $this->_convertPublicKey($this->modulus, $this->exponent);
        $this->publicKeyFormat = $oldFormat;

        return $temp;
    }

    /**
     *  __clone() magic method.
     */
    public function __clone()
    {
        $key = new Crypt_RSA();
        $key->loadKey($this);

        return $key;
    }

    /**
     * Determines the private key format.
     *
     * @see createKey()
     *
     * @param int $format
     */
    public function setPrivateKeyFormat($format)
    {
        $this->privateKeyFormat = $format;
    }

    /**
     * Determines the public key format.
     *
     * @see createKey()
     *
     * @param int $format
     */
    public function setPublicKeyFormat($format)
    {
        $this->publicKeyFormat = $format;
    }

    /**
     * Determines which hashing function should be used.
     *
     * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
     * decryption.  If $hash isn't supported, sha1 is used.
     *
     * @param string $hash
     */
    public function setHash($hash)
    {
        // Crypt_Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
        switch ($hash) {
            case 'md2':
            case 'md5':
            case 'sha1':
            case 'sha256':
            case 'sha384':
            case 'sha512':
                $this->hash     = new Crypt_Hash($hash);
                $this->hashName = $hash;
                break;
            default:
                $this->hash     = new Crypt_Hash('sha1');
                $this->hashName = 'sha1';
        }
        $this->hLen = $this->hash->getLength();
    }

    /**
     * Determines which hashing function should be used for the mask generation function.
     *
     * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
     * best if Hash and MGFHash are set to the same thing this is not a requirement.
     *
     * @param string $hash
     */
    public function setMGFHash($hash)
    {
        // Crypt_Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
        switch ($hash) {
            case 'md2':
            case 'md5':
            case 'sha1':
            case 'sha256':
            case 'sha384':
            case 'sha512':
                $this->mgfHash = new Crypt_Hash($hash);
                break;
            default:
                $this->mgfHash = new Crypt_Hash('sha1');
        }
        $this->mgfHLen = $this->mgfHash->getLength();
    }

    /**
     * Determines the salt length.
     *
     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
     *
     *    Typical salt lengths in octets are hLen (the length of the output
     *    of the hash function Hash) and 0.
     *
     * @param int $format
     */
    public function setSaltLength($sLen)
    {
        $this->sLen = $sLen;
    }

    /**
     * RSAES-OAEP-DECRYPT.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}.  The fact that the error
     * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
     *
     *    Note.  Care must be taken to ensure that an opponent cannot
     *    distinguish the different error conditions in Step 3.g, whether by
     *    error message or timing, or, more generally, learn partial
     *    information about the encoded message EM.  Otherwise an opponent may
     *    be able to obtain useful information about the decryption of the
     *    ciphertext C, leading to a chosen-ciphertext attack such as the one
     *    observed by Manger [36].
     *
     * As for $l...  to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
     *
     *    Both the encryption and the decryption operations of RSAES-OAEP take
     *    the value of a label L as input.  In this version of PKCS #1, L is
     *    the empty string; other uses of the label are outside the scope of
     *    this document.
     *
     * @param string $c
     * @param string $l
     *
     * @return string
     */
    public function _rsaes_oaep_decrypt($c, $l = '')
    {
        // Length checking

        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
            user_error('Decryption error');

            return false;
        }

        // RSA decryption

        $c = $this->_os2ip($c);
        $m = $this->_rsadp($c);
        if (false === $m) {
            user_error('Decryption error');

            return false;
        }
        $em = $this->_i2osp($m, $this->k);

        // EME-OAEP decoding

        $lHash      = $this->hash->hash($l);
        $y          = ord($em[0]);
        $maskedSeed = substr($em, 1, $this->hLen);
        $maskedDB   = substr($em, $this->hLen + 1);
        $seedMask   = $this->_mgf1($maskedDB, $this->hLen);
        $seed       = $maskedSeed ^ $seedMask;
        $dbMask     = $this->_mgf1($seed, $this->k - $this->hLen - 1);
        $db         = $maskedDB ^ $dbMask;
        $lHash2     = substr($db, 0, $this->hLen);
        $m          = substr($db, $this->hLen);
        if ($lHash != $lHash2) {
            user_error('Decryption error');

            return false;
        }
        $m = ltrim($m, chr(0));
        if (1 != ord($m[0])) {
            user_error('Decryption error');

            return false;
        }

        // Output the message M

        return substr($m, 1);
    }

    /**
     * Octet-String-to-Integer primitive.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
     *
     * @param string $x
     *
     * @return Math_BigInteger
     */
    public function _os2ip($x)
    {
        return new Math_BigInteger($x, 256);
    }

    /**
     * RSADP.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
     *
     * @param Math_BigInteger $c
     *
     * @return Math_BigInteger
     */
    public function _rsadp($c)
    {
        if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
            user_error('Ciphertext representative out of range');

            return false;
        }

        return $this->_exponentiate($c);
    }

    /**
     * Exponentiate with or without Chinese Remainder Theorem.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
     *
     * @param Math_BigInteger $x
     *
     * @return Math_BigInteger
     */
    public function _exponentiate($x)
    {
        if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
            return $x->modPow($this->exponent, $this->modulus);
        }

        $num_primes = count($this->primes);

        if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
            $m_i = array(
                1 => $x->modPow($this->exponents[1], $this->primes[1]),
                2 => $x->modPow($this->exponents[2], $this->primes[2]),
            );
            $h         = $m_i[1]->subtract($m_i[2]);
            $h         = $h->multiply($this->coefficients[2]);
            list(, $h) = $h->divide($this->primes[1]);
            $m         = $m_i[2]->add($h->multiply($this->primes[2]));

            $r = $this->primes[1];
            for ($i = 3; $i <= $num_primes; ++$i) {
                $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);

                $r = $r->multiply($this->primes[$i - 1]);

                $h         = $m_i->subtract($m);
                $h         = $h->multiply($this->coefficients[$i]);
                list(, $h) = $h->divide($this->primes[$i]);

                $m = $m->add($r->multiply($h));
            }
        } else {
            $smallest = $this->primes[1];
            for ($i = 2; $i <= $num_primes; ++$i) {
                if ($smallest->compare($this->primes[$i]) > 0) {
                    $smallest = $this->primes[$i];
                }
            }

            $one = new Math_BigInteger(1);

            $r = $one->random($one, $smallest->subtract($one));

            $m_i = array(
                1 => $this->_blind($x, $r, 1),
                2 => $this->_blind($x, $r, 2),
            );
            $h         = $m_i[1]->subtract($m_i[2]);
            $h         = $h->multiply($this->coefficients[2]);
            list(, $h) = $h->divide($this->primes[1]);
            $m         = $m_i[2]->add($h->multiply($this->primes[2]));

            $r = $this->primes[1];
            for ($i = 3; $i <= $num_primes; ++$i) {
                $m_i = $this->_blind($x, $r, $i);

                $r = $r->multiply($this->primes[$i - 1]);

                $h         = $m_i->subtract($m);
                $h         = $h->multiply($this->coefficients[$i]);
                list(, $h) = $h->divide($this->primes[$i]);

                $m = $m->add($r->multiply($h));
            }
        }

        return $m;
    }

    /**
     * Performs RSA Blinding.
     *
     * Protects against timing attacks by employing RSA Blinding.
     * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
     *
     * @param Math_BigInteger $x
     * @param Math_BigInteger $r
     * @param int             $i
     *
     * @return Math_BigInteger
     */
    public function _blind($x, $r, $i)
    {
        $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
        $x = $x->modPow($this->exponents[$i], $this->primes[$i]);

        $r         = $r->modInverse($this->primes[$i]);
        $x         = $x->multiply($r);
        list(, $x) = $x->divide($this->primes[$i]);

        return $x;
    }

    /**
     * Integer-to-Octet-String primitive.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
     *
     * @param Math_BigInteger $x
     * @param int             $xLen
     *
     * @return string
     */
    public function _i2osp($x, $xLen)
    {
        $x = $x->toBytes();
        if (strlen($x) > $xLen) {
            user_error('Integer too large');

            return false;
        }

        return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
    }

    /**
     * MGF1.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
     *
     * @param string $mgfSeed
     * @param int    $mgfLen
     *
     * @return string
     */
    public function _mgf1($mgfSeed, $maskLen)
    {
        // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.

        $t     = '';
        $count = ceil($maskLen / $this->mgfHLen);
        for ($i = 0; $i < $count; ++$i) {
            $c = pack('N', $i);
            $t .= $this->mgfHash->hash($mgfSeed.$c);
        }

        return substr($t, 0, $maskLen);
    }

    /**
     * RSAES-PKCS1-V1_5-DECRYPT.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
     *
     * For compatibility purposes, this function departs slightly from the description given in RFC3447.
     * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
     * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
     * public key should have the second byte set to 2.  In RFC3447 (PKCS#1 v2.1), the second byte is supposed
     * to be 2 regardless of which key is used.  For compatibility purposes, we'll just check to make sure the
     * second byte is 2 or less.  If it is, we'll accept the decrypted string as valid.
     *
     * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
     * with a strictly PKCS#1 v1.5 compliant RSA implementation.  Public key encrypted ciphertext's should but
     * not private key encrypted ciphertext's.
     *
     * @param string $c
     *
     * @return string
     */
    public function _rsaes_pkcs1_v1_5_decrypt($c)
    {
        // Length checking

        if (strlen($c) != $this->k) { // or if k < 11
            user_error('Decryption error');

            return false;
        }

        // RSA decryption

        $c = $this->_os2ip($c);
        $m = $this->_rsadp($c);

        if (false === $m) {
            user_error('Decryption error');

            return false;
        }
        $em = $this->_i2osp($m, $this->k);

        // EME-PKCS1-v1_5 decoding

        if (0 != ord($em[0]) || ord($em[1]) > 2) {
            user_error('Decryption error');

            return false;
        }

        $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
        $m  = substr($em, strlen($ps) + 3);

        if (strlen($ps) < 8) {
            user_error('Decryption error');

            return false;
        }

        // Output M

        return $m;
    }

    /**
     * Set Encryption Mode.
     *
     * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
     *
     * @param int $mode
     */
    public function setEncryptionMode($mode)
    {
        $this->encryptionMode = $mode;
    }

    /**
     * Set Signature Mode.
     *
     * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
     *
     * @param int $mode
     */
    public function setSignatureMode($mode)
    {
        $this->signatureMode = $mode;
    }

    /**
     * Get public key comment.
     *
     * @return string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * Set public key comment.
     *
     * @param string $comment
     */
    public function setComment($comment)
    {
        $this->comment = $comment;
    }

    /**
     * Encryption.
     *
     * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
     * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
     * be concatenated together.
     *
     * @see decrypt()
     *
     * @param string $plaintext
     *
     * @return string
     */
    public function encrypt($plaintext)
    {
        switch ($this->encryptionMode) {
            case CRYPT_RSA_ENCRYPTION_PKCS1:
                $length = $this->k - 11;
                if ($length <= 0) {
                    return false;
                }

                $plaintext  = str_split($plaintext, $length);
                $ciphertext = '';
                foreach ($plaintext as $m) {
                    $ciphertext .= $this->_rsaes_pkcs1_v1_5_encrypt($m);
                }

                return $ciphertext;
            //case CRYPT_RSA_ENCRYPTION_OAEP:
            default:
                $length = $this->k - 2 * $this->hLen - 2;
                if ($length <= 0) {
                    return false;
                }

                $plaintext  = str_split($plaintext, $length);
                $ciphertext = '';
                foreach ($plaintext as $m) {
                    $ciphertext .= $this->_rsaes_oaep_encrypt($m);
                }

                return $ciphertext;
        }
    }

    /**
     * RSAES-PKCS1-V1_5-ENCRYPT.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
     *
     * @param string $m
     *
     * @return string
     */
    public function _rsaes_pkcs1_v1_5_encrypt($m)
    {
        $mLen = strlen($m);

        // Length checking

        if ($mLen > $this->k - 11) {
            user_error('Message too long');

            return false;
        }

        // EME-PKCS1-v1_5 encoding

        $psLen = $this->k - $mLen - 3;
        $ps    = '';
        while (strlen($ps) != $psLen) {
            $temp = crypt_random_string($psLen - strlen($ps));
            $temp = str_replace("\x00", '', $temp);
            $ps .= $temp;
        }
        $type = 2;
        // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
        if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
            $type = 1;
            // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
            $ps = str_repeat("\xFF", $psLen);
        }
        $em = chr(0).chr($type).$ps.chr(0).$m;

        // RSA encryption
        $m = $this->_os2ip($em);
        $c = $this->_rsaep($m);
        $c = $this->_i2osp($c, $this->k);

        // Output the ciphertext C

        return $c;
    }

    /**
     * RSAEP.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
     *
     * @param Math_BigInteger $m
     *
     * @return Math_BigInteger
     */
    public function _rsaep($m)
    {
        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
            user_error('Message representative out of range');

            return false;
        }

        return $this->_exponentiate($m);
    }

    /**
     * RSAES-OAEP-ENCRYPT.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
     * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
     *
     * @param string $m
     * @param string $l
     *
     * @return string
     */
    public function _rsaes_oaep_encrypt($m, $l = '')
    {
        $mLen = strlen($m);

        // Length checking

        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        if ($mLen > $this->k - 2 * $this->hLen - 2) {
            user_error('Message too long');

            return false;
        }

        // EME-OAEP encoding

        $lHash      = $this->hash->hash($l);
        $ps         = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
        $db         = $lHash.$ps.chr(1).$m;
        $seed       = crypt_random_string($this->hLen);
        $dbMask     = $this->_mgf1($seed, $this->k - $this->hLen - 1);
        $maskedDB   = $db ^ $dbMask;
        $seedMask   = $this->_mgf1($maskedDB, $this->hLen);
        $maskedSeed = $seed ^ $seedMask;
        $em         = chr(0).$maskedSeed.$maskedDB;

        // RSA encryption

        $m = $this->_os2ip($em);
        $c = $this->_rsaep($m);
        $c = $this->_i2osp($c, $this->k);

        // Output the ciphertext C

        return $c;
    }

    /**
     * Decryption.
     *
     * @see encrypt()
     *
     * @param string $plaintext
     *
     * @return string
     */
    public function decrypt($ciphertext)
    {
        if ($this->k <= 0) {
            return false;
        }

        $ciphertext                         = str_split($ciphertext, $this->k);
        $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);

        $plaintext = '';

        switch ($this->encryptionMode) {
            case CRYPT_RSA_ENCRYPTION_PKCS1:
                $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
                break;
            //case CRYPT_RSA_ENCRYPTION_OAEP:
            default:
                $decrypt = '_rsaes_oaep_decrypt';
        }

        foreach ($ciphertext as $c) {
            $temp = $this->$decrypt($c);
            if (false === $temp) {
                return false;
            }
            $plaintext .= $temp;
        }

        return $plaintext;
    }

    /**
     * Create a signature.
     *
     * @see verify()
     *
     * @param string $message
     *
     * @return string
     */
    public function sign($message)
    {
        if (empty($this->modulus) || empty($this->exponent)) {
            return false;
        }

        switch ($this->signatureMode) {
            case CRYPT_RSA_SIGNATURE_PKCS1:
                return $this->_rsassa_pkcs1_v1_5_sign($message);
            //case CRYPT_RSA_SIGNATURE_PSS:
            default:
                return $this->_rsassa_pss_sign($message);
        }
    }

    /**
     * RSASSA-PKCS1-V1_5-SIGN.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
     *
     * @param string $m
     *
     * @return string
     */
    public function _rsassa_pkcs1_v1_5_sign($m)
    {
        // EMSA-PKCS1-v1_5 encoding

        $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
        if (false === $em) {
            user_error('RSA modulus too short');

            return false;
        }

        // RSA signature

        $m = $this->_os2ip($em);
        $s = $this->_rsasp1($m);
        $s = $this->_i2osp($s, $this->k);

        // Output the signature S

        return $s;
    }

    /**
     * EMSA-PKCS1-V1_5-ENCODE.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
     *
     * @param string $m
     * @param int    $emLen
     *
     * @return string
     */
    public function _emsa_pkcs1_v1_5_encode($m, $emLen)
    {
        $h = $this->hash->hash($m);
        if (false === $h) {
            return false;
        }

        // see http://tools.ietf.org/html/rfc3447#page-43
        switch ($this->hashName) {
            case 'md2':
                $t = pack('H*', '3020300c06082a864886f70d020205000410');
                break;
            case 'md5':
                $t = pack('H*', '3020300c06082a864886f70d020505000410');
                break;
            case 'sha1':
                $t = pack('H*', '3021300906052b0e03021a05000414');
                break;
            case 'sha256':
                $t = pack('H*', '3031300d060960864801650304020105000420');
                break;
            case 'sha384':
                $t = pack('H*', '3041300d060960864801650304020205000430');
                break;
            case 'sha512':
                $t = pack('H*', '3051300d060960864801650304020305000440');
        }
        $t .= $h;
        $tLen = strlen($t);

        if ($emLen < $tLen + 11) {
            user_error('Intended encoded message length too short');

            return false;
        }

        $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);

        $em = "\0\1$ps\0$t";

        return $em;
    }

    /**
     * RSASP1.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
     *
     * @param Math_BigInteger $m
     *
     * @return Math_BigInteger
     */
    public function _rsasp1($m)
    {
        if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
            user_error('Message representative out of range');

            return false;
        }

        return $this->_exponentiate($m);
    }

    /**
     * RSASSA-PSS-SIGN.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
     *
     * @param string $m
     *
     * @return string
     */
    public function _rsassa_pss_sign($m)
    {
        // EMSA-PSS encoding

        $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);

        // RSA signature

        $m = $this->_os2ip($em);
        $s = $this->_rsasp1($m);
        $s = $this->_i2osp($s, $this->k);

        // Output the signature S

        return $s;
    }

    /**
     * EMSA-PSS-ENCODE.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
     *
     * @param string $m
     * @param int    $emBits
     */
    public function _emsa_pss_encode($m, $emBits)
    {
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
        $sLen  = false == $this->sLen ? $this->hLen : $this->sLen;

        $mHash = $this->hash->hash($m);
        if ($emLen < $this->hLen + $sLen + 2) {
            user_error('Encoding error');

            return false;
        }

        $salt        = crypt_random_string($sLen);
        $m2          = "\0\0\0\0\0\0\0\0".$mHash.$salt;
        $h           = $this->hash->hash($m2);
        $ps          = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
        $db          = $ps.chr(1).$salt;
        $dbMask      = $this->_mgf1($h, $emLen - $this->hLen - 1);
        $maskedDB    = $db ^ $dbMask;
        $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
        $em          = $maskedDB.$h.chr(0xBC);

        return $em;
    }

    /**
     * Verifies a signature.
     *
     * @see sign()
     *
     * @param string $message
     * @param string $signature
     *
     * @return bool
     */
    public function verify($message, $signature)
    {
        if (empty($this->modulus) || empty($this->exponent)) {
            return false;
        }

        switch ($this->signatureMode) {
            case CRYPT_RSA_SIGNATURE_PKCS1:
                return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
            //case CRYPT_RSA_SIGNATURE_PSS:
            default:
                return $this->_rsassa_pss_verify($message, $signature);
        }
    }

    /**
     * RSASSA-PKCS1-V1_5-VERIFY.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
     *
     * @param string $m
     *
     * @return string
     */
    public function _rsassa_pkcs1_v1_5_verify($m, $s)
    {
        // Length checking

        if (strlen($s) != $this->k) {
            user_error('Invalid signature');

            return false;
        }

        // RSA verification

        $s  = $this->_os2ip($s);
        $m2 = $this->_rsavp1($s);
        if (false === $m2) {
            user_error('Invalid signature');

            return false;
        }
        $em = $this->_i2osp($m2, $this->k);
        if (false === $em) {
            user_error('Invalid signature');

            return false;
        }

        // EMSA-PKCS1-v1_5 encoding

        $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
        if (false === $em2) {
            user_error('RSA modulus too short');

            return false;
        }

        // Compare
        return $this->_equals($em, $em2);
    }

    /**
     * RSAVP1.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
     *
     * @param Math_BigInteger $s
     *
     * @return Math_BigInteger
     */
    public function _rsavp1($s)
    {
        if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
            user_error('Signature representative out of range');

            return false;
        }

        return $this->_exponentiate($s);
    }

    /**
     * Performs blinded RSA equality testing.
     *
     * Protects against a particular type of timing attack described.
     *
     * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
     *
     * Thanks for the heads up singpolyma!
     *
     * @param string $x
     * @param string $y
     *
     * @return bool
     */
    public function _equals($x, $y)
    {
        if (strlen($x) != strlen($y)) {
            return false;
        }

        $result = 0;
        for ($i = 0; $i < strlen($x); ++$i) {
            $result |= ord($x[$i]) ^ ord($y[$i]);
        }

        return 0 == $result;
    }

    /**
     * RSASSA-PSS-VERIFY.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
     *
     * @param string $m
     * @param string $s
     *
     * @return string
     */
    public function _rsassa_pss_verify($m, $s)
    {
        // Length checking

        if (strlen($s) != $this->k) {
            user_error('Invalid signature');

            return false;
        }

        // RSA verification

        $modBits = 8 * $this->k;

        $s2 = $this->_os2ip($s);
        $m2 = $this->_rsavp1($s2);
        if (false === $m2) {
            user_error('Invalid signature');

            return false;
        }
        $em = $this->_i2osp($m2, $modBits >> 3);
        if (false === $em) {
            user_error('Invalid signature');

            return false;
        }

        // EMSA-PSS verification

        return $this->_emsa_pss_verify($m, $em, $modBits - 1);
    }

    /**
     * EMSA-PSS-VERIFY.
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
     *
     * @param string $m
     * @param string $em
     * @param int    $emBits
     *
     * @return string
     */
    public function _emsa_pss_verify($m, $em, $emBits)
    {
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
        $sLen  = false == $this->sLen ? $this->hLen : $this->sLen;

        $mHash = $this->hash->hash($m);
        if ($emLen < $this->hLen + $sLen + 2) {
            return false;
        }

        if ($em[strlen($em) - 1] != chr(0xBC)) {
            return false;
        }

        $maskedDB = substr($em, 0, -$this->hLen - 1);
        $h        = substr($em, -$this->hLen - 1, $this->hLen);
        $temp     = chr(0xFF << ($emBits & 7));
        if ((~$maskedDB[0] & $temp) != $temp) {
            return false;
        }
        $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
        $db     = $maskedDB ^ $dbMask;
        $db[0]  = ~chr(0xFF << ($emBits & 7)) & $db[0];
        $temp   = $emLen - $this->hLen - $sLen - 2;
        if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || 1 != ord($db[$temp])) {
            return false;
        }
        $salt = substr($db, $temp + 1); // should be $sLen long
        $m2   = "\0\0\0\0\0\0\0\0".$mHash.$salt;
        $h2   = $this->hash->hash($m2);

        return $this->_equals($h, $h2);
    }
}
PK��#]5��8DD*system/bfnetwork/bfnetwork/Crypt/.htaccessnu�[���<Files ~ "^.*$">
Order deny,allow
Deny from all
Satisfy all
</Files>PK��#]]ni){6{6+system/bfnetwork/bfnetwork/Crypt/Random.phpnu�[���<?php

/**
 * Random Number Generator.
 *
 * The idea behind this function is that it can be easily replaced with your own crypt_random_string()
 * function. eg. maybe you have a better source of entropy for creating the initial states or whatever.
 *
 * PHP versions 4 and 5
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'Crypt/Random.php';
 *
 *    echo bin2hex(crypt_random_string(8));
 * ?>
 * </code>
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category  Crypt
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 * @see      http://phpseclib.sourceforge.net
 */

// laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
// have phpseclib as a requirement as well. if you're developing such a program you may encounter
// a "Cannot redeclare crypt_random_string()" error.
if (!function_exists('crypt_random_string')) {
    /*
     * "Is Windows" test
     *
     * @access private
     */
    define('CRYPT_RANDOM_IS_WINDOWS', 'WIN' === strtoupper(substr(PHP_OS, 0, 3)));

    /**
     * Generate a random string.
     *
     * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
     * microoptimizations because this function has the potential of being called a huge number of times.
     * eg. for RSA key generation.
     *
     * @param int $length
     *
     * @return string
     */
    function crypt_random_string($length)
    {
        if (CRYPT_RANDOM_IS_WINDOWS) {
            // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
            // ie. class_alias is a function that was introduced in PHP 5.3
            if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
                return mcrypt_create_iv($length);
            }
            // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
            // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
            // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
            // call php_win32_get_random_bytes():
            //
            // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
            // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
            //
            // php_win32_get_random_bytes() is defined thusly:
            //
            // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
            //
            // we're calling it, all the same, in the off chance that the mcrypt extension is not available
            if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
                return openssl_random_pseudo_bytes($length);
            }
        } else {
            // method 1. the fastest
            if (function_exists('openssl_random_pseudo_bytes')) {
                return openssl_random_pseudo_bytes($length);
            }
            // method 2
            static $fp = true;
            if (true === $fp) {
                // warning's will be output unles the error suppression operator is used. errors such as
                // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
                $fp = @fopen('/dev/urandom', 'rb');
            }
            if (true !== $fp && false !== $fp) { // surprisingly faster than !is_bool() or is_resource()
                return fread($fp, $length);
            }
            // method 3. pretty much does the same thing as method 2 per the following url:
            // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
            // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
            // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
            // restrictions or some such
            if (function_exists('mcrypt_create_iv')) {
                return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
            }
        }
        // at this point we have no choice but to use a pure-PHP CSPRNG

        // cascade entropy across multiple PHP instances by fixing the session and collecting all
        // environmental variables, including the previous session data and the current session
        // data.
        //
        // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
        // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
        // PHP isn't low level to be able to use those as sources and on a web server there's not likely
        // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
        // however, a ton of people visiting the website. obviously you don't want to base your seeding
        // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
        // by the user and (2) this isn't just looking at the data sent by the current user - it's based
        // on the data sent by all users. one user requests the page and a hash of their info is saved.
        // another user visits the page and the serialization of their data is utilized along with the
        // server envirnment stuff and a hash of the previous http request data (which itself utilizes
        // a hash of the session data before that). certainly an attacker should be assumed to have
        // full control over his own http requests. he, however, is not going to have control over
        // everyone's http requests.
        static $crypto = false, $v;
        if (false === $crypto) {
            // save old session data
            $old_session_id            = session_id();
            $old_use_cookies           = ini_get('session.use_cookies');
            $old_session_cache_limiter = session_cache_limiter();
            $_OLD_SESSION              = isset($_SESSION) ? $_SESSION : false;
            if ('' != $old_session_id) {
                session_write_close();
            }

            session_id(1);
            ini_set('session.use_cookies', 0);
            session_cache_limiter('');
            session_start();

            $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
                serialize($_SERVER).
                serialize($_POST).
                serialize($_GET).
                serialize($_COOKIE).
                serialize($GLOBALS).
                serialize($_SESSION).
                serialize($_OLD_SESSION)
            ));
            if (!isset($_SESSION['count'])) {
                $_SESSION['count'] = 0;
            }
            ++$_SESSION['count'];

            session_write_close();

            // restore old session data
            if ('' != $old_session_id) {
                session_id($old_session_id);
                session_start();
                ini_set('session.use_cookies', $old_use_cookies);
                session_cache_limiter($old_session_cache_limiter);
            } else {
                if (false !== $_OLD_SESSION) {
                    $_SESSION = $_OLD_SESSION;
                    unset($_OLD_SESSION);
                } else {
                    unset($_SESSION);
                }
            }

            // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
            // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
            // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
            // original hash and the current hash. we'll be emulating that. for more info see the following URL:
            //
            // http://tools.ietf.org/html/rfc4253#section-7.2
            //
            // see the is_string($crypto) part for an example of how to expand the keys
            $key = pack('H*', sha1($seed.'A'));
            $iv  = pack('H*', sha1($seed.'C'));

            // ciphers are used as per the nist.gov link below. also, see this link:
            //
            // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
            switch (true) {
                case phpseclib_resolve_include_path('Crypt/AES.php'):
                    if (!class_exists('Crypt_AES')) {
                        include_once 'AES.php';
                    }
                    $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
                    break;
                case phpseclib_resolve_include_path('Crypt/Twofish.php'):
                    if (!class_exists('Crypt_Twofish')) {
                        include_once 'Twofish.php';
                    }
                    $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
                    break;
                case phpseclib_resolve_include_path('Crypt/Blowfish.php'):
                    if (!class_exists('Crypt_Blowfish')) {
                        include_once 'Blowfish.php';
                    }
                    $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
                    break;
                case phpseclib_resolve_include_path('Crypt/TripleDES.php'):
                    if (!class_exists('Crypt_TripleDES')) {
                        include_once 'TripleDES.php';
                    }
                    $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
                    break;
                case phpseclib_resolve_include_path('Crypt/DES.php'):
                    if (!class_exists('Crypt_DES')) {
                        include_once 'DES.php';
                    }
                    $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
                    break;
                case phpseclib_resolve_include_path('Crypt/RC4.php'):
                    if (!class_exists('Crypt_RC4')) {
                        include_once 'RC4.php';
                    }
                    $crypto = new Crypt_RC4();
                    break;
                default:
                    user_error('crypt_random_string requires at least one symmetric cipher be loaded');

                    return false;
            }

            $crypto->setKey($key);
            $crypto->setIV($iv);
            $crypto->enableContinuousBuffer();
        }

        //return $crypto->encrypt(str_repeat("\0", $length));

        // the following is based off of ANSI X9.31:
        //
        // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
        //
        // OpenSSL uses that same standard for it's random numbers:
        //
        // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
        // (do a search for "ANS X9.31 A.2.4")
        $result = '';
        while (strlen($result) < $length) {
            $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
            $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
            $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
            $result .= $r;
        }

        return substr($result, 0, $length);
    }
}

if (!function_exists('phpseclib_resolve_include_path')) {
    /**
     * Resolve filename against the include path.
     *
     * Wrapper around stream_resolve_include_path() (which was introduced in
     * PHP 5.3.2) with fallback implementation for earlier PHP versions.
     *
     * @param string $filename
     *
     * @return mixed filename (string) on success, false otherwise
     */
    function phpseclib_resolve_include_path($filename)
    {
        if (function_exists('stream_resolve_include_path')) {
            return stream_resolve_include_path($filename);
        }

        // handle non-relative paths
        if (file_exists($filename)) {
            return realpath($filename);
        }

        $paths = PATH_SEPARATOR == ':' ?
            preg_split('#(?<!phar):#', get_include_path()) :
            explode(PATH_SEPARATOR, get_include_path());
        foreach ($paths as $prefix) {
            // path's specified in include_path don't always end in /
            $ds   = DIRECTORY_SEPARATOR == substr($prefix, -1) ? '' : DIRECTORY_SEPARATOR;
            $file = $prefix.$ds.$filename;
            if (file_exists($file)) {
                return realpath($file);
            }
        }

        return false;
    }
}
PK��#]:

&system/bfnetwork/bfnetwork/bfError.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

// Taken from http://php.net/manual/en/function.set-error-handler.php

if (class_exists('bfLog')) {
    class bfError
    {
        /**
         * CATCHABLE ERRORS.
         *
         * @param $number
         * @param $message
         * @param $file
         * @param $line
         */
        public static function captureNormal($number, $message, $file, $line)
        {
            if (2048 == $number) {
                return;
            } // E_ALL
            if (8192 == $number) {
                return;
            } // deprecated
            if ('syntax error, unexpected \'(\' in Unknown on line 13' == $message) {
                return;
            } // Crappy Virtuemart Language Issues

            bfLog::log('!!!!!! ERROR !!!!!! = '.$message.' in file '.$file.' line: '.$line);
        }

        /**
         * EXTENSIONS.
         *
         * @param $exception
         */
        public static function captureException($exception)
        {
            /*
             * Ignore these
             * 09:07:51UTC !!!!!! ERROR !!!!!! = fopen(/dev/urandom) [function.fopen]: failed to open stream: Operation not permitted
             * 09:07:51UTC !!!!!! ERROR !!!!!! = fopen() [function.fopen]: open_basedir restriction in effect. File(/dev/urandom) is not within the allowed path(s): (/usr/local/php/lib/php/:/home/www/:/usr/bin/:/tmp:/usr/local/php52/lib/php/)
             */
            if (preg_match('/dev\/urandom/', $exception->getMessage())) {
                return;
            }

            bfLog::log('!!!!!! EXCEPTION !!!!!! ='.$exception->getMessage().$exception->getFile().':'.$exception->getLine());
        }

        /**
         *UNCATCHABLE ERRORS.
         */
        public static function captureShutdown()
        {
            if (defined('_BF_LAST_BREATH')) {
                bfLog::log('Tock with dying breath said:  '._BF_LAST_BREATH);
            } else {
                bfLog::log('Tock');
            }
        }
    }

    set_error_handler(array('bfError', 'captureNormal'));
    set_exception_handler(array('bfError', 'captureException'));
    register_shutdown_function(array('bfError', 'captureShutdown'));
}
PK��#]�Џ�E�E�(system/bfnetwork/bfnetwork/bfAuditor.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

/**
 * Class bfAudit.
 */
final class bfAudit
{
    /**
     * @var bfTimer Our timer class
     */
    public $_timer;
    /**
     * @var JDatabaseMysql The database Connector
     */
    private $db;
    /**
     * @var array
     */
    private $_encryptedAndSuspectIds = array();

    /**
     * @var array
     */
    private $_encryptedIds = array();

    /**
     * @var array
     */
    private $_suspectIds = array();

    /**
     * @var array
     */
    private $_uploaderIds = array();

    /**
     * @var array
     */
    private $_hackedIds = array();

    /**
     * @var array
     */
    private $_mailerIds = array();

    /**
     * @var array
     */
    private $_notencryptedAndSuspectIds = array();

    /**
     * @var
     */
    private $alreadyAddedRootDirs = false;

    /**
     * @var
     */
    private $foundDirs;
    /**
     * @var
     */
    private $foundFiles;
    /**
     * @var
     */
    private $suspectfiles;
    /**
     * @var bool
     */
    private $noMoreFoldersToScan = false;
    /**
     * @var bool
     */
    private $noMoreFilesToScan = false;
    /**
     * @var bool
     */
    private $deepscancomplete = false;
    /**
     * @var int
     */
    private $tickOver = 0;
    /**
     * @var
     */
    private $startTime;
    /**
     * @var
     */
    private $endTime;
    /**
     * @var
     */
    private $version;
    /**
     * @var
     */
    private $platform;
    /**
     * @var
     */
    private $scancomplete;
    /**
     * @var
     */
    private $foundRecentlyModifiedFilesTotal;
    /**
     * @var
     */
    private $hashfailedcount;
    /**
     * @var int
     */
    private $step;
    /**
     * @var
     */
    private $connectorversion;
    /**
     * @var
     */
    private $files_777;
    /**
     * @var
     */
    private $hacked;
    /**
     * @var
     */
    private $zerobytes;
    /**
     * @var
     */
    private $folders_777;
    /**
     * @var
     */
    private $hidden_folders;
    /**
     * @var
     */
    private $hidden_files;
    /**
     * @var
     */
    private $renamedtohidefiles;
    /**
     * @var
     */
    private $nestedinstalls;
    /**
     * @var
     */
    private $error_logs_seen;
    /**
     * @var
     */
    private $encrypted_files;
    /**
     * @var
     */
    private $large_files;
    /**
     * @var
     */
    private $has_robots_modified;
    /**
     * @var
     */
    private $user_hasdefaultuserids;
    /**
     * @var
     */
    private $archive_files;
    /**
     * @var
     */
    private $htaccess_files;
    /**
     * @var
     */
    private $phpiniseen;
    /**
     * @var
     */
    private $uploader;
    /**
     * @var
     */
    private $mailer;
    /**
     * @var
     */
    private $max_allowed_packet;
    /**
     * @var
     */
    private $phpinwrongplace;
    /**
     * @var
     */
    private $notcorefiles;
    /**
     * @var
     */
    private $missingcorefiles;
    /**
     * @var
     */
    private $modifiedfilessincelastaudit;

    /**
     * @var
     */
    private $tmp_install_folders;

    /**
     * @var
     */
    private $sqlfilesseen;

    /**
     * @var
     */
    private $admintoolbreaches;

    /**
     * @var
     */
    private $dotunderscorefilesseen;

    /**
     * Set up the audit, reading from cached state if needed
     * Also handles the uploading of the scanner config.
     *
     * @param stdClass $request The decrypted request
     */
    public function __construct($request)
    {
        $this->_cleanUpStuff();

        bfLog::log(_BF_SPEED);

        if (_BF_API_DEBUG === true) {
            error_reporting(E_ALL);
            ini_set('display_errors', 1);
        }

        // Check that the permissions are set correctly before proceeding
        $this->_checkOurPerms();

        // Connect to the database
        $this->initDb();

        // init Joomla
        require 'bfInitJoomla.php';

        /*
         * Should we abandon/clear the current audit and restart
         *
         * If this is the first time we are running then also reset
         */
        if ((property_exists($request, 'forceRestart') && @$request->forceRestart) || (file_exists('./FIRSTRUN') && true === _BF_CONFIG_RESET_STATE_ON_UPGRADE)) {
            // reset the state
            $this->resetState();
        }

        // remove the trigger for the first run
        if (file_exists('./FIRSTRUN')) {
            @unlink('./FIRSTRUN');
        }

        // If there is a non encrypted md5's file then import it to the db
        if (property_exists($request, 'NOTENCRYPTED') && array_key_exists('md5s', $request->NOTENCRYPTED)) {
            // clean up first
            $this->db->setQuery('TRUNCATE bf_core_hashes');
            $this->db->query();

            $url = base64_decode($request->NOTENCRYPTED['md5s']);

            $options = array(
                'http' => array(
                    'method' => 'GET',
                    'header' => "Accept-language: en\r\n".
                        'User-Agent: '.$_SERVER['HTTP_HOST']."\r\n",
                ),
            );

            $context = stream_context_create($options);

            // get the data from the request
            // @ error supressor to hid errors when https:// wrapper is disabled in the server configuration by allow_url_fopen=0 in php.ini
            $data = @file_get_contents($url, false, $context);

            // F.M.L - I hate crap servers!
            if (!$data) {
                $ch = curl_init();

                // Set up bare minimum CURL Options needed for myJoomla.com
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
                curl_setopt($ch, CURLOPT_HEADER, false);
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_HOST']);

                // Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to TRUE
                $data = curl_exec($ch);

                // Did we succeed in getting something?????
                if (!$data) {
                    /*
                     * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
                     *
                     * Ok try without validation of the SSL (gulp) but this is needed on some servers without a pem file
                     * and we need to be compatible as possible - even on crappy webhosts when they need us most ;-(
                     */
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

                    //  Second Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to FALSE (gulp)
                    $data = curl_exec($ch);
                }

                curl_close($ch);
            }

            if (!$data) {
                bfEncrypt::reply(bfReply::ERROR, 'We could not download a required file from the CDN (Nothing downloaded!) - seek assistance from phil@phil-taylor.com');
            }

            if (!function_exists('gzinflate')) {
                bfEncrypt::reply(bfReply::ERROR, 'Your server doesnt meet the minimum requirements of Joomla - it has no gzinflate function in PHP!');
            }

            if (!gzinflate($data)) {
                bfEncrypt::reply(bfReply::ERROR, 'We could not download and inflate a required file from the CDN (Something wrong with the downloaded data or gzinflate of that data) - seek assistance from phil@phil-taylor.com');
            }

            $dataLines = explode("\n", gzinflate($data));

            // Import the md5s to the database - easier to query a db than a
            // single file
            $sql    = 'INSERT INTO bf_core_hashes (filewithpath, hash) VALUES ';
            $values = array();
            foreach ($dataLines as $line) {
                $parts = explode("\t", $line);

                // Do it this way for speed, 1 query instead of 4000+ queries!
                $values[] = sprintf('("/%s", "%s")', $parts[0], $parts[1]);
            }

            // import now!
            $this->db->setQuery($sql.implode(' , ', $values));
            $this->db->query();

            // memory cleanup
            unset($parts);
            unset($dataLines);
            unset($data);
        }

        // get the base bfnetwork folder
        $base = dirname(__FILE__);

        // Save our patterns to a file
        if (property_exists($request, 'NOTENCRYPTED') && array_key_exists('pattern', $request->NOTENCRYPTED)) {
            bfLog::log('Saving audit pattern config');

            $url = base64_decode($request->NOTENCRYPTED['pattern']);

            $options = array(
                'http' => array(
                    'method' => 'GET',
                    'header' => "Accept-language: en\r\n".
                        'User-Agent: '.$_SERVER['HTTP_HOST']."\r\n",
                ),
            );

            $context = stream_context_create($options);

            // get the data from the request
            // @ error supressor to hid errors when https:// wrapper is disabled in the server configuration by allow_url_fopen=0 in php.ini
            $patterns = @file_get_contents($url, false, $context);

            // F.M.L - I hate crap servers!
            if (!$patterns) {
                $ch = curl_init();

                // Set up bare minimum CURL Options needed for myJoomla.com
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
                curl_setopt($ch, CURLOPT_HEADER, false);
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_HOST']);

                // Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to TRUE
                $patterns = curl_exec($ch);

                // Did we succeed in getting something?????
                if (!$patterns) {
                    /*
                     * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
                     *
                     * Ok try without validation of the SSL (gulp) but this is needed on some servers without a pem file
                     * and we need to be compatible as possible - even on crappy webhosts when they need us most ;-(
                     */
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

                    //  Second Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to FALSE (gulp)
                    $patterns = curl_exec($ch);
                }

                curl_close($ch);
            }

            if (!$patterns) {
                bfEncrypt::reply(bfReply::ERROR, 'We could not download a required file from the CDN (Nothing downloaded!) - seek assistance from phil@phil-taylor.com');
            }

            if (false === file_put_contents($base.'/tmp/tmp.pattern', $patterns)) {
                bfEncrypt::reply(bfReply::ERROR, 'Could not save audit patterns to '.$base.'/tmp/tmp.pattern');
            }

            // finally as a last ditch attempt - ensure its worth running an audit!
            if (!filesize($base.'/tmp/tmp.pattern')) {
                bfEncrypt::reply(bfReply::ERROR, 'We have no audit config to run with - this is fatal - seek assistance!');
            }
        }

        if (property_exists($request, 'NOTENCRYPTED') && array_key_exists('config', $request->NOTENCRYPTED)) {
            // just in case
            if (!is_writable($base.'/bfConfig.php')) {
                // @ error supressor to hid errors when crappy servers dont allow chmod from php
                @chmod($base.'/bfConfig.php', 0777);
            }

            // write config to file
            file_put_contents($base.'/bfConfig.php', gzinflate(base64_decode($request->NOTENCRYPTED['config'])));

            // reset permissions to be more secure
            // @ error supressor to hid errors when crappy servers dont allow chmod from php
            @chmod($base.'/bfConfig.php', 0644);
        }

        // reset permissions - just to be sure!
        // @ error supressor to hid errors when crappy servers dont allow chmod from php
        @chmod($base.'/tmp/', 0755);

        // remove all the request
        unset($request);

        bfLog::log('Waking the lab rats from their sleep...');

        // Get the current status from the database
        $this->wakeUp();

        // init the timer
        bfLog::log('Priming the lab rats with a timer...');
        $this->_timer = bfTimer::getInstance();

        // init the steps
        bfLog::log('Teaching the lab rats to dance...');
        $this->_steps = new STEP($this->step);

        // belt and braces - check we have a step
        if (!$this->step) {
            $this->step = STEP::TESTCONNECTION;
        }
    }

    /**
     * Remove all the fluff that we need to,
     * Including old crap that we used to have installed and we dont need any longer.
     */
    private function _cleanUpStuff()
    {
    }

    /**
     * Checks and sets permissions on files/folders as tight as we can be
     * depending on the environment this script is running in
     * - I dont want 0777 but sometimes its required on some stupid environments
     * :-(.
     */
    private function _checkOurPerms()
    {
        // attempt to ensure our tmp folder is writable
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            @chmod(dirname(__FILE__).'/tmp', 0755);
        }

        // Argh!
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            @chmod(dirname(__FILE__).'/tmp', 0777);
        }

        // Give Up!
        if (!is_writeable(dirname(__FILE__).'/tmp')) {
            bfEncrypt::reply(bfReply::ERROR, 'Our '.dirname(__FILE__).'/tmp folder on your site is not writable!');
        }

        // attempt to ensure our folder is writable
        if (!is_writeable(dirname(__FILE__))) {
            @chmod(dirname(__FILE__), 0755);
        }

        // Argh!
        if (!is_writeable(dirname(__FILE__))) {
            @chmod(dirname(__FILE__), 0777);
        }

        // Give Up!
        if (!is_writeable(dirname(__FILE__))) {
            bfEncrypt::reply(bfReply::ERROR, dirname(__FILE__).'/ folder not writeable');
        }
    }

    /**
     * Init the Joomla db connection.
     *
     * @todo Rip this out and use our own database connection
     */
    private function initDb()
    {
        bfLog::log('init database connection...');

        // require all we need to access Joomla API
        require 'bfInitJoomla.php';

        $this->db = JFactory::getDBO();

        // ok then, while were are here lets look up
        // the Joomla version we are in
        $VERSION       = new JVersion();
        $this->version = $VERSION->getShortVersion();
    }

    /**
     * Reset the state of our audit, cleaning files and database.
     */
    private function resetState()
    {
        bfLog::log('Creating our database tables');

        $this->db->setQuery('SHOW TABLES LIKE "bf_files_last"');
        if ($this->db->loadResult()) {
            $this->db->setQuery('DROP TABLE IF EXISTS `bf_files_last`');
            $this->db->query();
        }

        $this->db->setQuery('SHOW TABLES LIKE "bf_files"');
        if ($this->db->loadResult()) {
            $this->db->setQuery('RENAME TABLE `bf_files` TO `bf_files_last`');
            $this->db->query();
        }

        // Drop and recreate our database tables
        $sql  = file_get_contents('./db/blank.sql');
        $sqls = explode(';', $sql);
        foreach ($sqls as $sql) {
            if ('' != trim($sql)) {
                $this->db->setQuery($sql);
                if (!$this->db->query()) {
                    bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
                }
            }
        }

        // remove any tmp files we might have created
        @unlink(dirname(__FILE__).'/tmp/tmp.md5s');
        @unlink(dirname(__FILE__).'/tmp/tmp.pattern');
        @unlink(dirname(__FILE__).'/tmp/tmp.pattern.unenc');
        @unlink(dirname(__FILE__).'/tmp/tmp.false');
        @unlink(dirname(__FILE__).'/tmp/tmp.log');
        @unlink(dirname(__FILE__).'/tmp/tmp.ob');
        @unlink(dirname(__FILE__).'/tmp/large.sql');
        @unlink(dirname(__FILE__).'/tmp/large1.sql');
        @unlink(dirname(__FILE__).'/tmp/large2.sql');
        @unlink(dirname(__FILE__).'/tmp/large3.sql');
        @unlink(dirname(__FILE__).'/tmp/large4.sql');
        @unlink(dirname(__FILE__).'/tmp/large5.sql');
        @unlink(dirname(__FILE__).'/tmp/large6.sql');
        @unlink(dirname(__FILE__).'/tmp/speedup.sql');
        @unlink(dirname(__FILE__).'/tmp/STATE');
        @unlink(dirname(__FILE__).'/tmp/STATE.php');
        @unlink(dirname(__FILE__).'/tmp/Folders');
        @unlink(dirname(__FILE__).'/tmp/Files');

        bfLog::truncate();
    }

    /**
     * Wake up the audit from the state files.
     */
    public function wakeUp()
    {
        if (!file_exists('tmp/STATE.php')) {
            return false;
        }

        // load state
        $result = unserialize(str_replace(array('<?php die();?>',
            '<? die();?>', ), '', file_get_contents('tmp/STATE.php')));

        // Doh!
        if (!$result) {
            return;
        }

        // populate state into worker
        foreach ($result as $k => $v) {
            $this->$k = $v;
        }
    }

    /**
     * Tick over.
     */
    public function tick()
    {
        if (1 != $this->scancomplete) {
            // init the start of the timer to prevent max time overruns
            if (!$this->startTime) {
                $this->startTime = time();
            }

            // increment the ticker, just shows how many ticks we have had
            ++$this->tickOver;

            // Run the correct stepAction method
            $function = $this->_steps->getStepFunction($this->step);
            bfLog::log('Running method '.$function);
            $this->$function();

            // sleep and die
            bfLog::log('Sleeping in tick');
            $this->saveState(false, __LINE__);
        } else {
            // Scan is already complete!
            bfLog::log('Sleeping as scan already complete');
            $this->saveState(true, __LINE__);
        }
    }

    /**
     * ZZZzzz......
     * Sleep state to the database to provide session persistance
     * We need a few seconds to run this :-(.
     *
     * @param bool $alreadyComplete
     */
    public function saveState($alreadyComplete = false, $line = 0)
    {
        // bfLog::log('Sleeping audit status to persistent db store');

        // When did we complete this step/audit
        $this->endTime = time();

        // make sure we cache the connectorversion
        $this->connectorversion = file_get_contents('./VERSION');

        // Inject the state to the database
        $obj = new stdClass();
        foreach ($this as $k => $v) {
            // Dont save private/system objects
            if ('db' == $k || '_steps' == $k || '_timer' == $k || '_' == substr($k, 0, 1)) {
                continue;
            }

            // convert objects and arrays to strings
            if (is_object($v) || is_array($v)) {
                $v = json_encode($v);
            }

            // inject to the object we will return
            $obj->$k = $v;
        }

        // Save state
        file_put_contents('tmp/STATE.php', '<?php die();?>'.serialize($obj));

        // save the step we are on
        $obj->step = (string) $this->_steps;

        // report back to service with json object;
        $obj->maxPHPMemoryUsed = round((memory_get_peak_usage(true) / 1048576), 2);

        $obj->queuecount = $this->_getQueueCount('files');

        // legacy
        $obj->filestoscan = $obj->queuecount;

        $obj->logtail = bfLog::getTail();

        // close db
        unset($this->db);
        unset($this->_timer);
        unset($this->_steps);

        // go to sleep, but first tell the service we are dreaming...
        bfEncrypt::reply(bfReply::SUCCESS, $obj);
    }

    /**
     * See whats left in the queue.
     *
     * @return int The number of rows
     */
    private function _getQueueCount($tbl)
    {
        $this->dbPing();
        $this->db->setQuery('SELECT count(*) FROM bf_'.$tbl.' WHERE queued = 1');

        return $this->db->loadResult();
    }

    private function dbPing()
    {
        bfLog::log('   == 1 pinging to the db with class ');
        if (null === $this->db) {
            $this->db = JFactory::getDbo();
        }

        if (!$this->db->connected()) {
            if (method_exists($this->db, 'getConnection')) {
                switch (get_class($this->db->getConnection())) {
                    case 'mysql':
                        @mysql_ping($this->db->getConnection());
                        break;
                    case 'mysqli':
                        mysqli_ping($this->db->getConnection());
                        break;
                }
            } else {
                // Joomla 1.freaking.5
                switch (get_class($this->db->name)) {
                    case 'mysql':
                        @mysql_ping($this->db->_resource);
                        break;
                    case 'mysqli':
                        mysqli_ping($this->db->_resource);
                        break;
                }
            }
        }
    }

    /**
     * This simply adds the JPATH_BASE / folders to the scan queue.
     */
    public function scanningrootdirsAction()
    {
        // Add the root folder to the scan quque
        $this->addDirToScanQueue($this->getFolders(JPATH_BASE));

        // mark scan
        $this->alreadyAddedRootDirs = true;

        // move to the next scan step
        $this->nextStepPlease();
    }

    /**
     * Add a folder to the scan queue.
     *
     * @param array $arr    Array of folders to add to the queue
     * @param int   $queued
     *
     * @return array
     */
    private function addDirToScanQueue($arr, $queued = 1)
    {
        if (!count($arr)) {
            return array();
        }
        // Update stats
        $this->foundDirs = $this->foundDirs + count($arr);

        bfLog::log('Adding '.count($arr).' folders To the audit queue');

        // skip if no folders in the array
        if (false === $arr) {
            return;
        }

        $parts = array();
        foreach ($arr as $folder) {
            // clean up
            $folder = $this->_cleanupFileFolderName($folder);
//            $folder = trim(str_replace('\\', '/', $folder));
//            $folder = str_replace('////', '/', $folder);

            // Dont allow duplicates - ffs
            $this->db->setQuery(sprintf('SELECT count(*) from bf_folders where folderwithpath = "%s"', $folder));
            if ($this->db->loadResult()) {
                bfLog::log(sprintf('WARNING: Skipping adding %s to db as its already there', $folder));
                continue;
            }

            // Dont allow blank or invalid folders
            if (!is_dir($this->_cleanupFileFolderName(JPATH_BASE.DIRECTORY_SEPARATOR.$folder))
                && !is_dir($this->_cleanupFileFolderName(JPATH_BASE.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR))
                || is_link($this->_cleanupFileFolderName(JPATH_BASE.DIRECTORY_SEPARATOR.$folder.DIRECTORY_SEPARATOR))
                || is_link($this->_cleanupFileFolderName(JPATH_BASE.DIRECTORY_SEPARATOR.$folder)) || !$folder
            ) {
                continue;
            }

            $perms = $this->_getFolderPerms($folder);

            $insertFolderToDb[] = " ( '".addslashes($folder)."', '".$perms."', ".$queued.')';
        }

        if (count($insertFolderToDb)) {
            $sqlprefix = 'INSERT INTO bf_folders ( folderwithpath, folderinfo, queued) VALUES ';
            $sqlToRun  = $sqlprefix.implode(', ', $insertFolderToDb);

            if (strlen($sqlToRun) > 1048576) {
                $insertFolderToDb = $this->array_split($insertFolderToDb, 4);

                $sqlToRun1 = $sqlprefix.implode(', ', $insertFolderToDb[0]);
                bfLog::log('sql size 1= '.strlen($sqlToRun1));
                $this->db->setQuery($sqlToRun1);
                $this->db->query();

                $sqlToRun2 = $sqlprefix.implode(', ', $insertFolderToDb[1]);
                bfLog::log('sql size 2= '.strlen($sqlToRun2));
                $this->db->setQuery($sqlToRun2);
                $this->db->query();

                $sqlToRun3 = $sqlprefix.implode(', ', $insertFolderToDb[2]);
                bfLog::log('sql size 3= '.strlen($sqlToRun3));
                $this->db->setQuery($sqlToRun3);
                $this->db->query();

                $sqlToRun4 = $sqlprefix.implode(', ', $insertFolderToDb[3]);
                bfLog::log('sql size 4= '.strlen($sqlToRun4));
                $this->db->setQuery($sqlToRun4);
                $this->db->query();
            } else {
                $this->db->setQuery($sqlToRun);
                $this->db->query();
            }
        }

        return array();
    }

    /**
     * THANK YOU WORDPRESS !!! I love you xxx.
     *
     * @param $path
     *
     * @return mixed|string|string[]|null
     */
    private function wp_normalize_path($path)
    {
        $path = str_replace('\\', '/', $path);
        $path = preg_replace('|(?<=.)/+|', '/', $path);
        if (':' === substr($path, 1, 1)) {
            $path = ucfirst($path);
        }

        // Mine, removes // from the start of a path
        if ('/' === substr($path, 0, 1) && '/' === substr($path, 1, 1)) {
            $path = substr($path, 1, strlen($path) - 1);
        }

        return $path;
    }

    /**
     * Clean up a string, a path name.
     * Wrapper to wp_normalize_path which does a better job than we did.
     *
     * @param string $str
     *
     * @return string
     */
    private function _cleanupFileFolderName($str)
    {
        return $this->wp_normalize_path($str);
    }

    /**
     * Clean up the folder name and then get the right perms.
     *
     * @param $folder
     *
     * @return string
     */
    private function _getFolderPerms($folder)
    {
        $folder = $this->ensureRooted($this->_cleanupFileFolderName($folder));
        $perms  = substr(decoct(fileperms($folder)), 2);

        return $perms;
    }

    /**
     * Ensure that we are rooted to the JPATH_BASE.
     *
     * @param string $folder
     *                       A filewithpath
     *
     * @return string
     */
    private function ensureRooted($folder)
    {
        if (JPATH_BASE === '/' && '/' === substr($folder, 0, 1)) {
            return $folder;
        }

        $str = $this->wp_normalize_path(JPATH_BASE.str_replace($this->wp_normalize_path(JPATH_BASE), '', $this->wp_normalize_path($this->_cleanupFileFolderName($folder))));

        return $str;
    }

    private function removeJPATHBASE($str)
    {
        if (JPATH_BASE === '/' && '/' === substr($str, 0, 1)) {
            return $str;
        }

        return str_replace($this->wp_normalize_path(JPATH_BASE), '', $this->wp_normalize_path($this->ensureRooted($str)));
    }

    /**
     * Spilt an array.
     *
     * @param     $array
     * @param int $pieces
     *
     * @return array
     */
    private function array_split($array, $pieces = 2)
    {
        if ($pieces < 2) {
            return array($array);
        }
        $newCount = ceil(count($array) / $pieces);
        $a        = array_slice($array, 0, $newCount);
        $b        = $this->array_split(array_slice($array, $newCount), $pieces - 1);

        return array_merge(array($a), $b);
    }

    /**
     * Function taken from Akeeba filesystem.php.
     *
     * @copyright Copyright (c)2009 Nicholas K. Dionysopoulos
     * @license   GNU GPL version 3 or, at your option, any later version
     *
     * @version   Id: scanner.php 158 2010-06-10 08:46:49Z nikosdion
     */
    private function getFolders($folder)
    {
        // Initialize variables
        $arr   = array();
        $false = false;

        $folder = trim($folder);

        if (!is_dir($folder) && !is_dir($folder.DIRECTORY_SEPARATOR) || is_link($folder.DIRECTORY_SEPARATOR) || is_link($folder) || !$folder) {
            return $false;
        }

        if (@file_exists($folder.DIRECTORY_SEPARATOR.'.myjoomla.ignore.folder')) {
            return array();
        }

        $handle = @opendir($folder);
        if (false === $handle) {
            $handle = @opendir($folder.DIRECTORY_SEPARATOR);
        }
        // If directory is not accessible, just return FALSE
        if (false === $handle) {
            return $false;
        }

        while ((false !== ($file = @readdir($handle)))) {
            if (('.' != $file) && ('..' != $file) && (null != trim($file))) {
                $ds    = ('' == $folder) || (DIRECTORY_SEPARATOR == $folder) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) ? '' : DIRECTORY_SEPARATOR;
                $dir   = trim($folder.$ds.$file);
                $isDir = @is_dir($dir);
                if ($isDir) {
                    $arr[] = $this->removeJPATHBASE($folder.DIRECTORY_SEPARATOR.$file);
                }
            }
        }
        @closedir($handle);

        return $arr;
    }

    /**
     * Set pointer to the next step.
     */
    private function nextStepPlease($alsoSleep = false)
    {
        bfLog::log('Ticking over to the next step');
        $this->step = $this->_steps->nextStepPlease();
        if (true === $alsoSleep) {
            $this->saveState(false, __LINE__);
        }
    }

    /**
     * @see http://davidwalsh.name/php-file-extension
     *
     * @param $file_name
     *
     * @return string
     */
    public function get_file_extension($file_name)
    {
        return substr(strrchr($file_name, '.'), 1);
    }

    /**
     * dummy method.
     */
    private function requestscannerconfigAction()
    {
        $this->nextStepPlease();
    }

    /**
     * I never get here unless all is done :).
     */
    private function completeAction()
    {
        // Mark the audit as complete
        $this->scancomplete = 1;

        // cleanup
        @unlink('tmp/tmp.md5s');
        @unlink('tmp/tmp.pattern');
        @unlink('tmp/tmp.false');
        @unlink('tmp/Folders');
        @unlink('tmp/Files');

        bfLog::log('===== AUDIT COMPLETE =====');
    }

    /**
     * @deprecated
     *
     * Get information about the datbaase
     */
    private function dbinfoAction()
    {
        // move onto the next step
        $this->nextStepPlease();
    }

    /**
     * Do we have any backup tables.
     *
     * @return string
     */
    private function _hasBakTables()
    {
        $config = JFactory::getApplication('site');
        $dbname = $config->getCfg('db', '');
        $this->db->setQuery("SHOW TABLES WHERE `Tables_in_{$dbname}` like 'bak_%'");

        return $this->db->loadResult() ? 'TRUE' : 'FALSE';
    }

    private function testconnectionAction()
    {
        // Ask Joomla API for some settings
        $config = JFactory::getApplication('site');

        try {
            // Send an email to see if we received it... Tests if the Joomla Global Config mailer settings are correct.
            $mailer = JFactory::getMailer();
            $sender = array(
                $config->getCfg('mailfrom'),
                $config->getCfg('fromname'), );

            $mailer->setSender($sender);
            $mailer->addRecipient('AuditMailerTest@myjoomla.io'); // This is not a real mailbox, its a service that reads the body of the email, and lets the myJoomla.com service know the domain name.
            $mailer->setSubject('Audit Mailer Test');

            $s        = empty($_SERVER['HTTPS']) ? '' : ('on' == $_SERVER['HTTPS']) ? 's' : '';
            $protocol = substr(strtolower($_SERVER['SERVER_PROTOCOL']), 0, strpos(strtolower($_SERVER['SERVER_PROTOCOL']), '/')).$s;
            $port     = ('80' == $_SERVER['SERVER_PORT']) ? '' : (':'.$_SERVER['SERVER_PORT']);
            $uri      = $protocol.'://'.$_SERVER['SERVER_NAME'].$port.$_SERVER['REQUEST_URI'];
            $segments = explode('?', $uri, 2);
            $url      = $segments[0];
            $url      = str_replace(array('plugins/system/bfnetwork/bfAudit.php',
                'plugins/system/bfnetwork/bfnetwork/bfAudit.php', ), '', $url);
            $mailer->setBody($url); // ONLY THE URL OF THE SITE IS SENT - NO OTHER DATA
            $mailer->Send();
        } catch (Exception $e) {
        }

        // move onto the next step
        $this->nextStepPlease();
    }

    /**
     * @deprecated to snapshot
     */
    private function compileextensionsAction()
    {
        $this->nextStepPlease();
    }

    private function verifyextensionsAction()
    {
        require 'bfExtensions.php';
        $ext                  = new bfExtensions();
        $this->extensionsjson = $ext->getExtensions();
        $this->nextStepPlease();
    }

    /**
     * Report on the last 3 days worth of modified files, excluding ours.
     */
    private function lookingupmodifiedfilesAction()
    {
        $time = strtotime('-3 days', time());
        $sql  = "SELECT COUNT(*) FROM bf_files WHERE filemtime > '%s'
                AND filewithpath NOT LIKE '/plugins/system/bfnetwork%%'";
        $this->db->setQuery(sprintf($sql, $time));
        $this->foundRecentlyModifiedFilesTotal = $this->db->LoadResult();

        // move onto the next step
        $this->nextStepPlease();
    }

    /**
     * Scan folders and save the files that we find in the database
     * If we have saved large sql files that contain queries then run those and tick over.
     */
    private function initialscanningfilesAction()
    {
        if (file_exists('tmp/large.sql')) {
            bfLog::log('Running a cached LARGE SQL insert');
            $sql = file_get_contents('tmp/large.sql');
            if (trim($sql)) {
                $this->db->setQuery($sql);
                $this->db->query();
            }
            unlink('tmp/large.sql');
            $this->saveState(false, __LINE__);
        }
        if (file_exists('tmp/large1.sql')) {
            bfLog::log('Running a cached LARGE1 SQL insert');
            $sql = file_get_contents('tmp/large1.sql');
            if (trim($sql)) {
                $this->db->setQuery($sql);
                $this->db->query();
            }
            unlink('tmp/large1.sql');
            $this->saveState(false, __LINE__);
        }
        if (file_exists('tmp/large2.sql')) {
            bfLog::log('Running a cached LARGE2 SQL insert');
            $sql = file_get_contents('tmp/large2.sql');
            if (trim($sql)) {
                $this->db->setQuery($sql);
                $this->db->query();
            }
            unlink('tmp/large2.sql');
            $this->saveState(false, __LINE__);
        }
        if (file_exists('tmp/large3.sql')) {
            bfLog::log('Running a cached LARGE3 SQL insert');
            $sql = file_get_contents('tmp/large3.sql');
            if (trim($sql)) {
                $this->db->setQuery($sql);
                $this->db->query();
            }
            unlink('tmp/large3.sql');
            $this->saveState(false, __LINE__);
        }
        if (file_exists('tmp/large4.sql')) {
            bfLog::log('Running a cached LARGE4 SQL insert');
            $sql = file_get_contents('tmp/large4.sql');
            if (trim($sql)) {
                $this->db->setQuery($sql);
                $this->db->query();
            }
            unlink('tmp/large4.sql');
            $this->saveState(false, __LINE__);
        }
        if (file_exists('tmp/large5.sql')) {
            bfLog::log('Running a cached LARGE5 SQL insert');
            $sql = file_get_contents('tmp/large5.sql');
            if (trim($sql)) {
                $this->db->setQuery($sql);
                $this->db->query();
            }
            unlink('tmp/large5.sql');
            $this->saveState(false, __LINE__);
        }
        if (file_exists('tmp/large6.sql')) {
            bfLog::log('Running a cached LARGE6 SQL insert');
            $sql = file_get_contents('tmp/large6.sql');
            if (trim($sql)) {
                $this->db->setQuery($sql);
                $this->db->query();
            }
            unlink('tmp/large6.sql');
            $this->saveState(false, __LINE__);
        }

        // See how much is left
        $this->db->setQuery('SELECT COUNT(*) FROM bf_folders WHERE queued = 1');
        $totalLeft = $this->db->loadResult();

        // re-set the sql because mysqlpdo in Joomla borks when trying to run loadResult twice, with 0 - 00000, , :-(
        // Time wasted: days and days and days...
        $this->db->setQuery('SELECT COUNT(*)  FROM bf_folders WHERE queued = 1');

        // Nothing left so die
        if (!$totalLeft) {
            // Get all the files with core hash changes :-(
            $sql = 'SELECT f.id FROM bf_files AS f
            LEFT JOIN bf_core_hashes AS ch ON ch.filewithpath = f.filewithpath
             WHERE ch.hash != f.currenthash';

            $this->db->setQuery($sql);

            if (method_exists($this->db, 'loadColumn')) {
                $ids = $this->db->loadColumn();
            } else {
                $ids = $this->db->loadResultArray();
            }

            if (count($ids)) {
                bfLog::log('Found '.count($ids).' Core file hashes failed');
                $sql = 'UPDATE bf_files SET hashfailed = 1 WHERE id IN ('.implode(', ', $ids).')';
                file_put_contents('tmp/hashfailed.sql', $sql);
            }

            // set all the core file flags
            $sql = 'SELECT f.id FROM bf_files AS f
                    WHERE filewithpath IN(
                      SELECT filewithpath FROM bf_core_hashes
                    )';

            $this->db->setQuery($sql);
            if (method_exists($this->db, 'loadColumn')) {
                $ids = $this->db->loadColumn();
            } else {
                $ids = $this->db->loadResultArray();
            }

            if (count($ids)) {
                bfLog::log('Matched '.count($ids).' Core files');
                $sql = 'UPDATE bf_files SET iscorefile = 1 WHERE id IN ('.implode(', ', $ids).')';
                file_put_contents('tmp/corefiles.sql', $sql);
            }

            $this->noMoreFilesToScan = true;
            $this->nextStepPlease(true);
        }

        $removeFoldersFromQueueIds = array();

        // yes run the query again, allows for the while loop nicely, also only
        // loop while we have time
        while ($this->db->loadResult() > 0 && $this->_timer->getTimeLeft() > _BF_CONFIG_FILES_TIMER_ONE) {
            // ok so we have a load of folders...
            if (count($removeFoldersFromQueueIds)) {
                $this->db->setQuery('SELECT id, folderwithpath FROM bf_folders WHERE queued = 1 AND id NOT IN ('.implode(', ', $removeFoldersFromQueueIds).') ORDER BY id ASC LIMIT '._BF_CONFIG_FILES_COUNT_ONE);
            } else {
                $this->db->setQuery('SELECT id, folderwithpath FROM bf_folders WHERE queued = 1 ORDER BY id ASC LIMIT '._BF_CONFIG_FILES_COUNT_ONE);
            }
            $dirs_to_scan = $this->db->loadObjectList();

            while (count($dirs_to_scan) && $this->_timer->getTimeLeft() > _BF_CONFIG_FILES_TIMER_ONE) {
                // sql values to imploe to the insert
                $sqlvalues = array();

                // get a diretory object to scan
                $dirToScanObj = array_pop($dirs_to_scan);

                // extract the folder
                $dirToScan = $dirToScanObj->folderwithpath;

                $dirToScan = str_replace('////', '/', $dirToScan);

                // remove this current dir form the scan queue - quickly incase we get into indefinite loop;
                //$this->removeFromQueue('folders', array($dirToScanObj->id));
                $removeFoldersFromQueueIds[] = $dirToScanObj->id;

                // Make sure we have a absolute path to the folder
                $dirToScanWithPath = $this->ensureRooted($dirToScan);
//                $dirToScanWithPath = JPATH_BASE.DIRECTORY_SEPARATOR.str_replace(JPATH_BASE, '', $dirToScan);

                $filesInThisFolder = $this->getFiles($dirToScanWithPath);
                bfLog::log('Found '.count($filesInThisFolder).' files in '.$this->removeJPATHBASE($dirToScan));

                // If there are any files, and we have time left
                if (count($filesInThisFolder) && $this->_timer->getTimeLeft() > _BF_CONFIG_FILES_TIMER_TWO) {
                    // for each file then get the info
                    foreach ($filesInThisFolder as $file) {
                        // ok are we getting short of time yet?
                        if ($this->_timer->getTimeLeft() <= _BF_CONFIG_FILES_TIMER_TWO) {
                            $this->db->setQuery('/*6*/ INSERT    INTO    bf_files
                                (filewithpath, fileperms, filemtime, currenthash, size) VALUES '
                                .implode(', ', $sqlvalues));
                            if (!$this->db->query()) {
                                bfLog::log($this->db->getErrorMsg());
                            }
                            $this->removeFromQueue('folders', $removeFoldersFromQueueIds);
                            $this->saveState(false, __LINE__);
                        }

                        // with full path
                        $fileBase = $this->_cleanupFileFolderName($this->ensureRooted($dirToScanWithPath).DIRECTORY_SEPARATOR.$file);

                        // Get the file Info...
                        $fileInfo = $this->_getFileInfo($fileBase);

                        // with no JPATH_BASE
                        $fileBase = $this->removeJPATHBASE($fileBase);

                        // create the insert
                        $sqlinsert = ' ("%s", "%s", "%s", "%s", "%s") ';

                        // cache the insert so that we can insert many rows for performance
                        $sqlvalues[] = sprintf($sqlinsert, $fileBase, $fileInfo['perms'], $fileInfo['mtime'], $fileInfo['currenthash'], $fileInfo['size']);

                        // count
                        ++$this->foundFiles;
                    }

                    if (count($filesInThisFolder) > 200) {
                        bfLog::log('Sleeping as we had more than 200 files in this folder... we are saving:  '.count($filesInThisFolder));

                        $sqlvaluesParts = $this->array_split($sqlvalues, 6);

                        file_put_contents('tmp/large1.sql', '/*1*/ INSERT INTO bf_files (filewithpath, fileperms, filemtime, currenthash, size)
                        VALUES '.implode(', ', $sqlvaluesParts[0]));
                        file_put_contents('tmp/large2.sql', '/*2*/ INSERT INTO bf_files (filewithpath, fileperms, filemtime, currenthash, size)
                        VALUES '.implode(', ', $sqlvaluesParts[1]));
                        file_put_contents('tmp/large3.sql', '/*3*/ INSERT INTO bf_files (filewithpath, fileperms, filemtime, currenthash, size)
                        VALUES '.implode(', ', $sqlvaluesParts[2]));
                        file_put_contents('tmp/large4.sql', '/*4*/ INSERT INTO bf_files (filewithpath, fileperms, filemtime, currenthash, size)
                        VALUES '.implode(', ', $sqlvaluesParts[3]));
                        file_put_contents('tmp/large5.sql', '/*5*/ INSERT INTO bf_files (filewithpath, fileperms, filemtime, currenthash, size)
                        VALUES '.implode(', ', $sqlvaluesParts[4]));
                        file_put_contents('tmp/large6.sql', '/*6*/ INSERT INTO bf_files (filewithpath, fileperms, filemtime, currenthash, size)
                        VALUES '.implode(', ', $sqlvaluesParts[5]));

                        bfLog::log('Large SQL files stored for processing...');

                        $this->removeFromQueue('folders', $removeFoldersFromQueueIds);
                        $this->saveState(false, __LINE__);
                    }

                    // Save to the database when we get short of time
                    if ($this->_timer->getTimeLeft() <= _BF_CONFIG_FILES_TIMER_TWO) {
                        $this->db->setQuery('/*5*/INSERT INTO bf_files
                         (filewithpath, fileperms, filemtime, currenthash, size) VALUES '
                            .implode(', ', $sqlvalues));
                        if (!$this->db->query()) {
                            bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
                        }
                        $sqlvalues = array();

                        $this->removeFromQueue('folders', $removeFoldersFromQueueIds);
                        $this->saveState(false, __LINE__);
                    }
                }

                // Save to the database
                if (is_array($sqlvalues) && count($sqlvalues)) {
                    $this->db->setQuery('/*7*/INSERT INTO bf_files
                         (filewithpath, fileperms, filemtime, currenthash, size) VALUES '
                        .implode(', ', $sqlvalues));
                    if (!$this->db->query()) {
                        bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
                    }
                    $sqlvalues = array();
                }

                // set up for the while loop again
                if (count($removeFoldersFromQueueIds)) {
                    $this->db->setQuery('SELECT count(*) FROM bf_folders WHERE queued = 1 AND id NOT IN ('.implode(', ', $removeFoldersFromQueueIds).')');
                } else {
                    $this->db->setQuery('SELECT COUNT(*) FROM bf_folders WHERE queued = 1');
                }

                // are we nearly there yet?
                if ($this->_timer->getTimeLeft() <= _BF_CONFIG_FILES_TIMER_TWO) {
                    $this->removeFromQueue('folders', $removeFoldersFromQueueIds);
                    $this->saveState(false, __LINE__);
                }
            }
        }
        $this->removeFromQueue('folders', $removeFoldersFromQueueIds);
    }

    /**
     * Function taken from Akeeba filesystem.php.
     *
     * Akeeba Engine
     * The modular PHP5 site backup engine
     *
     * @copyright Copyright (c)2009 Nicholas K. Dionysopoulos
     * @license   GNU GPL version 3 or, at your option, any later version
     *
     * @version   Id: scanner.php 158 2010-06-10 08:46:49Z nikosdion
     */
    private function getFiles($folder)
    {
        // Initialize variables
        $arr   = array();
        $false = false;

        $folder = trim($folder);

        if (!is_dir($folder) && !is_dir($folder.DIRECTORY_SEPARATOR) || is_link($folder.DIRECTORY_SEPARATOR) || is_link($folder) || !$folder) {
            return $false;
        }

        if (@file_exists($folder.DIRECTORY_SEPARATOR.'.myjoomla.ignore.files')) {
            return array();
        }

        $handle = @opendir($folder);
        if (false === $handle) {
            $handle = @opendir($folder.'/');
        }
        // If directory is not accessible, just return FALSE
        if (false === $handle) {
            return $false;
        }

        while ((false !== ($file = @readdir($handle)))) {
            if (('.' != $file) && ('..' != $file)) {
                $ds    = ('' == $folder) || (DIRECTORY_SEPARATOR == $folder) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) || (DIRECTORY_SEPARATOR == @substr($folder, -1)) ? '' : DIRECTORY_SEPARATOR;
                $dir   = $folder.$ds.$file;
                $isDir = @is_dir($dir);
                if (!$isDir) {
                    $arr[] = $this->_cleanupFileFolderName($file);
                }
            }
        }
        @closedir($handle);

        return $arr;
    }

    /**
     * @param       $tbl
     * @param array $updateIds
     *
     * @return array
     */
    private function removeFromQueue($tbl, $updateIds = array())
    {
        if (count($updateIds)) {
            bfLog::log('Removing '.count($updateIds).' '.$tbl.' from the queue');
            $sql = 'UPDATE bf_'.$tbl.' SET queued = 0 WHERE id IN ('.implode(', ', $updateIds).')';
            $this->db->setQuery($sql);
            if (!$this->db->query()) {
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
        }

        return array();
    }

    /**
     * There are a lot of error supression @'s in this method, mainly to handle
     * fringe cases where we dont have permissions or some other fringe error
     * happens.
     *
     * @param string $file
     *
     * @return array
     */
    private function _getFileInfo($file)
    {
        // clean up
        $file     = stripslashes($this->_cleanupFileFolderName($file));
        $fileInfo = array();

        // Get the File Permissions - if we are allowed (Hence the @)
        $fileInfo['perms'] = @substr(@decoct(@fileperms($file)), 2);

        // Get the File Modification Time - if we are allowed (Hence the @)
        $fileInfo['mtime'] = @filemtime($file);

        // Get the File Size - if we are allowed (Hence the @)
        $size             = @filesize($file);
        $fileInfo['size'] = $size;

        if (!$fileInfo['size']) {
            $fileInfo['size'] = '0';
        }

        // only hash small files
        if ($size < 1048576) { // 1 megabyte = 1048576 bytes
            // We need a @ incase of "failed to
            // open stream: Permission denied"
            $hash = @md5_file($file);

            // something went wrong
            if (!$hash) {
                $hash = 'Unable To Calc Hash';
            }
        } else {
            $hash = 'Too Big To Hash';
        }

        // save the has
        $fileInfo['currenthash'] = $hash;

        return $fileInfo;
    }

    /**
     * Scan folders and find more files in them.
     */
    private function initialscanningfoldersAction()
    {
        $deleteFoldersIds = array();
        $addToScanQueue   = array();
        $break            = false;
        $count            = 0;

        // See if we have any folders to scan
        $this->db->setQuery('SELECT COUNT(*)  FROM bf_folders WHERE queued = 1');
        $totalLeft = $this->db->loadResult();

        // re-set the sql because mysqlpdo in Joomla borks when trying to run loadResult twice, with 0 - 00000, , :-(
        // Time wasted: days and days and days...
        $this->db->setQuery('SELECT COUNT(*)  FROM bf_folders WHERE queued = 1');

        if (!$totalLeft) {
            $addToScanQueue = $this->addDirToScanQueue(array('/'), 0);
            $this->toggleQueued('folders', 1);

            // move on, and die
            $this->noMoreFoldersToScan = true;
            $this->nextStepPlease(true);
        }

        // We have some folders to look into and we have some time left
        while ($this->db->loadResult() > 0 && $this->_timer->getTimeLeft() > _BF_CONFIG_FOLDERS_TIMER_ONE) {
            // ok so we have a load of folders...
            if (count($deleteFoldersIds)) {
                $this->db->setQuery('SELECT id, folderwithpath FROM bf_folders WHERE queued = 1 AND id NOT IN ('.implode(',', $deleteFoldersIds).') ORDER BY id ASC LIMIT '._BF_CONFIG_FOLDERS_COUNT_ONE);
            } else {
                $this->db->setQuery('SELECT id, folderwithpath FROM bf_folders WHERE queued = 1 ORDER BY id ASC LIMIT '._BF_CONFIG_FOLDERS_COUNT_ONE);
            }
            $dirs_to_scan = $this->db->loadObjectList();

            $COUNTER = 0;
            while (count($dirs_to_scan) && $this->_timer->getTimeLeft() > _BF_CONFIG_FOLDERS_TIMER_ONE) {
                $dirToScanObj = array_pop($dirs_to_scan);

//                $dirToScan = stripslashes($dirToScanObj->folderwithpath);

//                $dirToScan = str_replace('////', '/', $dirToScan);
                $dirToScan           = $this->wp_normalize_path($dirToScanObj->folderwithpath);

                // Redundant?
                if ($this->_timer->getTimeLeft() <= _BF_CONFIG_FOLDERS_TIMER_TWO) {
                    $addToScanQueue   = $this->addDirToScanQueue($addToScanQueue);
                    $deleteFoldersIds = $this->removeFromQueue('folders', $deleteFoldersIds);
                    $this->saveState(false, __LINE__); // Exits with reply
                }

                // Get the subdirectories in this folder and add to the list of folders to scan enforce only from base root...
//                $dirToScanWithPath = JPATH_BASE.preg_replace('#^'.JPATH_BASE.'#i', '', $dirToScan, 1);
                $dirToScanWithPath = $this->ensureRooted($dirToScan);

                // but if our$dirToScanWithPath is now blank it means a path of /var/www/var/www !
                if (JPATH_BASE == $dirToScanWithPath) {
                    // need this else we loop when /home/public_html/home/public_html is found!!
                    $dirToScanWithPath = $this->wp_normalize_path(JPATH_BASE.$dirToScan);
                }

                $subDirectorys = $this->getFolders($dirToScanWithPath);

                bfLog::log('Found '.count($subDirectorys).' subfolders in '.$this->removeJPATHBASE($dirToScan));

                if (count($subDirectorys)) {
                    foreach ($subDirectorys as $folder) {
//                    $folder           = str_replace('////', '/', $folder);
                        $folder           = $this->wp_normalize_path($folder);
                        $addToScanQueue[] = $folder;
                    }
                } else {
                    bfLog::log('Found NO subfolders in '.$this->removeJPATHBASE($dirToScan));
                }

                $deleteFoldersIds[] = $dirToScanObj->id;

                if ((count($deleteFoldersIds) > 1000) || (count($addToScanQueue) > 1000) || $this->_timer->getTimeLeft() <= _BF_CONFIG_FOLDERS_TIMER_TWO) {
                    // remove this current dir form the scan queue;
//                    $addToScanQueue   = str_replace('////', '/', $addToScanQueue);
                    $addToScanQueue   = $this->wp_normalize_path($addToScanQueue);
                    $addToScanQueue   = $this->addDirToScanQueue($addToScanQueue);
                    $deleteFoldersIds = $this->removeFromQueue('folders', $deleteFoldersIds);
                    $this->saveState(false, __LINE__); // Exits with reply
                }
            }

            $this->db->setQuery('SELECT count(*)  FROM bf_folders WHERE queued = 1 AND id NOT IN ('.implode(',', $deleteFoldersIds).')');
        }

        $this->addDirToScanQueue($addToScanQueue);
        $this->removeFromQueue('folders', $deleteFoldersIds);

        $this->saveState(false, __LINE__); // Exits with reply
    }

    /**
     * @param $tblSuffix
     * @param $queued
     */
    private function toggleQueued($tblSuffix, $queued)
    {
        $sql = 'UPDATE bf_'.$tblSuffix.' SET queued = '.$queued;
        $this->db->setQuery($sql);
        $this->db->query();
    }

    /**
     * Deep scan.
     */
    private function deepscanAction()
    {
        if (file_exists('tmp/corefiles.sql')) {
            bfLog::log('Found core files - marking them as such');
            $this->db->setQuery(file_get_contents('tmp/corefiles.sql'));
            $this->db->query();
            unlink('tmp/corefiles.sql');
            $this->saveState(false, __LINE__);
        }
        if (file_exists('tmp/hashfailed.sql')) {
            bfLog::log('Found modified core files - adding to deepscan');
            $this->db->setQuery(file_get_contents('tmp/hashfailed.sql'));
            $this->db->query();
            unlink('tmp/hashfailed.sql');
            $this->saveState(false, __LINE__);
        }

        try {
            // if we are not complete
            $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE queued = 1');
            $queueCount = $this->db->loadResult();

            if (0 == $queueCount && true == $this->deepscancomplete) {
                // left here in case needed again.
            }

            if (!$queueCount && !$this->deepscancomplete) {
                bfLog::log('Adding files to the scan queue');

                /**
                 * Yes I know that this sql gives places for hackers to hide, however its based on extensive, active,
                 * experience and is often changed to reflect current trends.
                 */
                $sql = "SELECT id FROM bf_files
                            WHERE
                                (
                                  SIZE < 800000                                 -- 0.4mb Limit
                                AND
                                  SIZE > 0                                      -- Must have content!
                                )
                            AND
                                (
                                  iscorefile = 0                                -- No Core Files
                                OR
                                  iscorefile IS NULL                            -- No Core Files - NULL !== 0 -- IDIOT PHIL!!!!
                                OR
                                  hashfailed = 1                                -- Or core files which hash has failed
                                )
                            AND                                                 -- Filter out the probably ok file extensions and other stuff we are 'fairly' happy to ignore
                            (
                                currenthash != 'f96aa8838dffa02a4a8438f2a8596025' -- ok blank index.html file

                                AND filewithpath NOT LIKE '/plugins/system/bfnetwork%' -- Our stuff
                                AND filewithpath NOT LIKE '%.DS_Store%'         -- Mac finder files
                                AND filewithpath NOT LIKE '%.zip'               -- cant preg_match inside a zip!
                                AND filewithpath NOT LIKE '%.gzip'              -- cant preg_match inside a zip!
                                AND filewithpath NOT LIKE '%.gz'                -- cant preg_match inside a zip!
                                AND filewithpath NOT LIKE '%.doc'
                                AND filewithpath NOT LIKE '%.docx'
                                AND filewithpath NOT LIKE '%.xls'
                                AND filewithpath NOT LIKE '%.ppt'
                                AND filewithpath NOT LIKE '%.pdf'
                                AND filewithpath NOT LIKE '%.rtf'               -- never seen anything bad in a rtf
                                AND filewithpath NOT LIKE '%.mno'
                                AND filewithpath NOT LIKE '%.ashx'
                                AND filewithpath NOT LIKE '%.png'               -- never seen anything bad in a png
                                AND filewithpath NOT LIKE '%.psd'               -- Photoshop, normally a massive file too
                                AND filewithpath NOT LIKE '%.wott'              -- font file
                                AND filewithpath NOT LIKE '%.ttf'               -- font file
                                AND filewithpath NOT LIKE '%.css'               -- plain text css, never seen Joomla hack in css file
                                AND filewithpath NOT LIKE '%.swf'               -- flash
                                AND filewithpath NOT LIKE '%.flv'               -- flash
                                AND filewithpath NOT LIKE '%.po'                -- language files
                                AND filewithpath NOT LIKE '%.mo'
                                AND filewithpath NOT LIKE '%.pot'
                                AND filewithpath NOT LIKE '%.eot'
                                AND filewithpath NOT LIKE '%.ini'
                                AND filewithpath NOT LIKE '%.svg'
                                AND filewithpath NOT LIKE '%.mpeg'              -- No need to audit inside audio files, never seen a Joomla hack in these
                                AND filewithpath NOT LIKE '%.mvk'               -- No need to audit inside audio files, never seen a Joomla hack in these
                                AND filewithpath NOT LIKE '%.mp3'               -- No need to audit inside audio files, never seen a Joomla hack in these
                                AND filewithpath NOT LIKE '%.less'
                                AND filewithpath NOT LIKE '%.sql'
                                AND filewithpath NOT LIKE '%.wsdl'
                                AND filewithpath NOT LIKE '%.woff'
                                AND filewithpath NOT LIKE '%.woff2'
                                AND filewithpath NOT LIKE '%.otf'
                                AND filewithpath NOT LIKE '%.xml'               -- never seen a hack in an xml file
                                AND filewithpath NOT LIKE '%.php_expire'        -- Expired cache file
                                AND filewithpath NOT LIKE '%.jpa'               -- Akeeba backup files
                                AND filewithpath NOT LIKE '%/akeeba_json.%'           -- Akeeba json state file
                                AND filewithpath NOT LIKE '%/administrator/components/com_akeeba/backup/akeeba%'           -- Akeeba json state file
                                AND filewithpath NOT LIKE '%/akeeba_backend.id%'           -- Akeeba json state file
                                AND filewithpath NOT LIKE '%/akeeba_backend.php'           -- Akeeba json state file
                                AND filewithpath NOT LIKE '%/akeeba_backend.log'           -- Akeeba json state file
                                AND filewithpath NOT LIKE '%/akeeba_lazy.php'           -- Akeeba json state file
                                AND filewithpath NOT LIKE '%/akeeba_frontend.php'           -- Akeeba json state file
                                AND filewithpath NOT LIKE '%/cacert.pem'           -- cacert.pem
                                AND filewithpath NOT LIKE '%/GeoIP.dat'          -- never seen a hack in an GeoIP.dat file but the one in RSFirewall/Admin Tools kills the audit :-(
                                AND filewithpath NOT LIKE '%/ca-certificates.crt'          -- never seen a hack in an ca-certificates.crt file but the one in RSFirewall/Admin Tools kills the audit :-(
                                AND filewithpath NOT LIKE '%error_log'      -- PHP error logs, we alert to ALL these in another check
                                AND filewithpath NOT LIKE '%/stats/webalizer.current'           -- Crappy file
                                AND filewithpath NOT LIKE '%/stats/usage_%.html'           -- Crappy file
                                AND filewithpath NOT LIKE '%/components/libraries/cmslib/cache/cache__%' -- Massive folder of cache files
                                AND filewithpath NOT LIKE '%/plugins/system/akgeoip/lib/vendor/guzzle/guzzle/%' -- Akeeba GeoIP Docs
                                AND filewithpath NOT LIKE '%/components/com_jce/editor/tiny_mce/plugins/code/img/icons.gif' -- JCE Code icons
                                AND filewithpath NOT LIKE '%/components/com_jce/editor/libraries/js/pdf.js' -- JCE PDF JS 900kb+
                            )";
                $this->db->setQuery($sql);

                $ids = array();
                if (method_exists($this->db, 'loadColumn')) {
                    $ids = $this->db->loadColumn();
                } else {
                    $ids = $this->db->loadResultArray();
                }

                bfLog::log('FOUND SOME IDS TO QUEUE: '.count($ids));
                bfLog::log($this->db->getErrorMsg());

                if (!count($ids)) {
                    bfLog::log('NO FILES TO DEEP SCAN = THIS CANNOT BE POSSIBLE RIGHT?');
                    bfEncrypt::reply(bfReply::ERROR, 'We could not identify any files to audit, please contact phil@phil-taylor.com to debug this for you.');
                } else {
                    $sql = 'UPDaTE bf_files SET queued = 1 WHERE id IN ( %s )';

                    $len                = strlen(sprintf($sql, implode(', ', $ids)));
                    $max_allowed_packet = $this->max_allowed_packet;

                    // ffs - I hate badly configured servers
                    if (!$this->max_allowed_packet) {
                        $this->db->setQuery('SHOW VARIABLES LIKE "max_allowed_packet"');
                        $max_allowed_packet = $this->db->loadObjectList();
                        if (!$this->max_allowed_packet) {
                            $max_allowed_packet = 1048576 / 1.2; // default - safety margin
                        }
                    }

                    bfLog::log(sprintf('The len is %s and the $max_allowed_packet is %s, and this means %s',
                        $len,
                        $max_allowed_packet,
                        ($len > $max_allowed_packet)
                    ));

                    if ($len > $max_allowed_packet) {
                        $parts = $this->array_split($ids, 4);

                        $sqlToRun1 = sprintf($sql, implode(', ', $parts[0]));
                        bfLog::log('sql size 1= '.strlen($sqlToRun1));
                        $this->db->setQuery($sqlToRun1);
                        $this->db->query();

                        $sqlToRun2 = sprintf($sql, implode(', ', $parts[1]));
                        bfLog::log('sql size 2= '.strlen($sqlToRun2));
                        $this->db->setQuery($sqlToRun2);
                        $this->db->query();

                        $sqlToRun3 = sprintf($sql, implode(', ', $parts[2]));
                        bfLog::log('sql size 3= '.strlen($sqlToRun3));
                        $this->db->setQuery($sqlToRun3);
                        $this->db->query();

                        $sqlToRun4 = sprintf($sql, implode(', ', $parts[3]));
                        bfLog::log('sql size 4= '.strlen($sqlToRun4));
                        $this->db->setQuery($sqlToRun4);
                        $this->db->query();
                    } else {
                        $sql = 'UPdATE bf_files SET queued = 1 WHERE id IN
                        (
                        '.implode(', ', $ids).'
                        )';
                        $this->db->setQuery($sql);
                        $this->db->query();
                    }
                }

                // DEQUEUE known clean files not changed
                bfLog::log('DONE Adding '.count($ids).' files to the scan queue db table');

                bfLog::log('Retrieving global whitelist from cdn');
                $url = 'https://cdn.myjoomla.com/public/global/whitelist';

                $options = array(
                    'http' => array(
                        'method' => 'GET',
                        'header' => "Accept-language: en\r\n".
                            'User-Agent: '.$_SERVER['HTTP_HOST']."\r\n",
                    ),
                );

                $context = stream_context_create($options);

                // get the data from the request
                $whitelist = file_get_contents($url, false, $context);

                // F.M.L - I hate crap servers!
                if (!$whitelist) {
                    $ch = curl_init();

                    // Set up bare minimum CURL Options needed for myJoomla.com
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
                    curl_setopt($ch, CURLOPT_HEADER, false);
                    curl_setopt($ch, CURLOPT_URL, $url);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_HOST']);

                    // Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to TRUE
                    $whitelist = curl_exec($ch);

                    // Did we succeed in getting something?????
                    if (!$whitelist) {
                        /*
                         * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
                         *
                         * Ok try without validation of the SSL (gulp) but this is needed on some servers without a pem file
                         * and we need to be compatible as possible - even on crappy webhosts when they need us most ;-(
                         */
                        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

                        //  Second Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to FALSE (gulp)
                        $whitelist = curl_exec($ch);
                    }

                    curl_close($ch);
                }

                if (!$whitelist) {
                    bfEncrypt::reply(bfReply::ERROR, 'We could not download a required file from the CDN (w) - seek assistance from phil@phil-taylor.com');
                }

                $whitelistSQL = 'UPDATE bf_files SET queued = 0, falsepositive = 1 WHERE currenthash IN ('.$whitelist.')';
                $this->db->setQuery($whitelistSQL);
                bfLog::log('Applying global whitelist from cdn to db');
                $this->db->query();
                bfLog::log('Global whitelist applied!');

                bfLog::log('Retrieving global hacklist from cdn');
                $url = 'https://cdn.myjoomla.com/public/global/hacklist';

                $options = array(
                    'http' => array(
                        'method' => 'GET',
                        'header' => "Accept-language: en\r\n".
                            'User-Agent: '.$_SERVER['HTTP_HOST']."\r\n",
                    ),
                );

                $context = stream_context_create($options);

                // get the data from the request
                $hacklist = file_get_contents($url, false, $context);

                // F.M.L - I hate crap servers!
                if (!$hacklist) {
                    $ch = curl_init();

                    // Set up bare minimum CURL Options needed for myJoomla.com
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
                    curl_setopt($ch, CURLOPT_HEADER, false);
                    curl_setopt($ch, CURLOPT_URL, $url);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_HOST']);

                    // Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to TRUE
                    $hacklist = curl_exec($ch);

                    // Did we succeed in getting something?????
                    if (!$hacklist) {
                        /*
                         * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
                         *
                         * Ok try without validation of the SSL (gulp) but this is needed on some servers without a pem file
                         * and we need to be compatible as possible - even on crappy webhosts when they need us most ;-(
                         */
                        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

                        //  Second Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to FALSE (gulp)
                        $hacklist = curl_exec($ch);
                    }

                    curl_close($ch);
                }

                if (!$hacklist) {
                    bfEncrypt::reply(bfReply::ERROR, 'We could not download a required file from the CDN (h) - seek assistance from phil@phil-taylor.com');
                }

                $hacklistSQL = 'UPDATE bf_files SET queued = 0, suspectcontent = 1, hacked = 1 WHERE currenthash IN ('.$hacklist.')';
                $this->db->setQuery($hacklistSQL);
                bfLog::log('Applying global hacklist from cdn to db');
                $this->db->query();
                bfLog::log('Global hacklist applied!');

                // Cache our patterns
                $pattern = file_get_contents('tmp/tmp.pattern');
                if (file_exists('tmp/tmp.pattern.lastmd5')) {
                    $lastPatternmd5 = file_get_contents('tmp/tmp.pattern.lastmd5');
                } else {
                    $lastPatternmd5 = '';
                }

                // if encrypted - decrypt
                if ('RC4:' == substr($pattern, 0, 4)) {
                    $pattern = base64_decode(substr($pattern, 4, strlen($pattern) - 4));
                    $RC4     = new Crypt_RC4();
                    $RC4->setKey('NotMeantToBeSecure'); // just to hide from other server side scanners
                    $pattern = $RC4->decrypt($pattern);

                    /*
                     * When developing/debugging we might want to cache the unencrypted patterns
                     * We dont do the normally because some webhost scanners see them as hacks
                     * when they are not!
                     */
                    //file_put_contents('tmp/tmp.pattern.unenc', $pattern); //sss

                    bfLog::log('LAST PATTERN TEST =   '.$lastPatternmd5.'=='.md5($pattern));
                    if ($lastPatternmd5 == md5($pattern)) {
                        bfLog::log('SPEEDUP - Yes, we will speedup');
                        $doSpeedup = true;
                    } else {
                        bfLog::log('SPEEDUP - No, we will not speedup');
                        $doSpeedup = false;
                    }
                }

                if ($doSpeedup && (_BF_SPEED == 'DEFAULT' || _BF_SPEED == 'FAST')) {
                    $this->db->setQuery('SHOW TABLES LIKE "bf_files_last"');
                    if ($this->db->loadResult()) {
                        $speedupSQL = 'UPDATE bf_files AS NEWTABLE
                                INNER JOIN  (
                                    SELECT
                                        bf_files_last.filewithpath, bf_files_last.suspectcontent,  bf_files_last.falsepositive,  bf_files_last.encrypted  FROM bf_files_last
                                    LEFT JOIN
                                        bf_files ON bf_files_last.filewithpath = bf_files.filewithpath
                                    WHERE
                                        bf_files_last.currenthash = bf_files.currenthash
                                    AND
                                        bf_files_last.filemtime = bf_files.filemtime
                                    AND
                                        bf_files_last.fileperms = bf_files.fileperms
                                    AND
                                        bf_files_last.filewithpath = bf_files.filewithpath
                                ) AS
                                    OLDTABLE
                                   ON
                                    NEWTABLE.filewithpath = OLDTABLE.filewithpath
                                SET
                                    NEWTABLE.filewithpath = OLDTABLE.filewithpath,
                                    NEWTABLE.suspectcontent = OLDTABLE.suspectcontent,
                                    NEWTABLE.falsepositive = OLDTABLE.falsepositive,
                                    NEWTABLE.encrypted = OLDTABLE.encrypted,
                                    NEWTABLE.queued = 0
                                WHERE
                                  OLDTABLE.suspectcontent != 1
                             ';

                        bfLog::log('SPEEDUP - saving the sql to run for the speedup');
                        file_put_contents('tmp/speedup.sql', $speedupSQL);
                    }
                }
                // ok this took a lot of time, so to be careful we will re-tick...
                $this->saveState(false, __LINE__);
            }

            $pattern = file_get_contents('tmp/tmp.pattern');

            // if encrypted - decrypt
            if ('RC4:' == substr($pattern, 0, 4)) {
                $pattern = base64_decode(substr($pattern, 4, strlen($pattern) - 4));
                $RC4     = new Crypt_RC4();
                $RC4->setKey('NotMeantToBeSecure'); // just to hide from other server side scanners
                $pattern = $RC4->decrypt($pattern);
            }

            if (file_exists('tmp/speedup.sql') && (_BF_SPEED == 'DEFAULT' || _BF_SPEED == 'FAST')) {
                bfLog::log('SPEEDUP Found speedup sql files - removing files to deepscan');

                // get contents and delete the file quickly in case the sql fails and then we dont end up in a loop
                $speedSQL = file_get_contents('tmp/speedup.sql');

                bfLog::log('SPEEDUP - removing speedup file after applying it');
                unlink('tmp/speedup.sql');

                $this->db->setQuery('SHOW TABLES LIKE "bf_files_last"');
                if ($this->db->loadResult()) {
                    $this->db->setQuery($speedSQL);
                    $this->db->query();
                }

                // force at least one file to be audited to prevent broken loop
                $this->db->setQuery('UPDATE bf_files SET queued = 1 WHERE filewithpath = "/configuration.php"');
                $this->db->query();

                $this->saveState(false, __LINE__);
            } else {
                if (file_exists(dirname(__FILE__).'/tmp/speedup.sql')) {
                    bfLog::log('SPEEDUP - removing speedup file without applying it  as _BF_SPEED = '._BF_SPEED);
                    @unlink(dirname(__FILE__).'/tmp/speedup.sql');
                }
            }

            // A nice while loop while we have time left
            if (count($this->getmergedIds())) {
                $this->db->setQuery('SELECT count(*) FROM bf_files WHERE queued = 1 AND id NOT IN ('.implode(',', $this->getmergedIds()).')');
            } else {
                $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE queued = 1');
            }

            while ($this->db->loadResult() > 0 && $this->_timer->getTimeLeft() > _BF_CONFIG_DEEPSCAN_TIMER_ONE) {
                // ok so we have a load of files....
                if (count($this->getmergedIds())) {
                    $this->db->setQuery('SELECT * FROM bf_files WHERE queued = 1 AND id NOT IN ('.implode(',', $this->getmergedIds()).') ORDER BY id ASC LIMIT '._BF_CONFIG_DEEPSCAN_COUNT_ONE);
                } else {
                    $this->db->setQuery('SELECT * FROM bf_files WHERE queued = 1 ORDER BY id ASC LIMIT '._BF_CONFIG_DEEPSCAN_COUNT_ONE);
                }

                $files_to_scan = $this->db->loadObjectList();

                // still, while we have files and time left
                while (count($files_to_scan) && $this->_timer->getTimeLeft() > _BF_CONFIG_DEEPSCAN_TIMER_ONE) {
                    // get one file
                    $file_to_scan = array_pop($files_to_scan);

                    /**
                     * If this is a large JS file like jquery.ui.src.js then we need more time dammit!
                     * Also need to do this on WSDL files for some reason.
                     */
                    $size = filesize(JPATH_BASE.$file_to_scan->filewithpath);
                    if (((strpos($file_to_scan->filewithpath, 'wsdl') || strpos($file_to_scan->filewithpath, 'jquery'))
                            && $this->_timer->getTimeLeft() < 4
                        ) ||
                        ($size > 100000 && (_BF_SPEED != 'DEFAULT' && _BF_SPEED != 'FAST') && $this->_timer->getTimeLeft() < 4)
                    ) {
                        bfLog::log('Next file is a problematic JS/wsdl is of size '.$size.' and we only had '.$this->_timer->getTimeLeft().' left so we are Zzz... and will come back next tick');
                        $this->updateFilesFromDeepscan(__LINE__);
                        $this->saveState(false, __LINE__);
                    }

                    // toggle if we can safely skip it   } else if
                    $skip = 0;

                    // Is this a suspect file
                    // Is this file encrypted
                    // is this file an uploader
                    // is this file a mailer
                    $isSuspect  = false;
                    $encrypted  = false;
                    $isUploader = false;
                    $isMailer   = false;
                    $isHacked   = false;

                    $file_extension = strtolower(pathinfo(JPATH_BASE.$file_to_scan->filewithpath, PATHINFO_EXTENSION));

                    // If the file no longer exists then skip
                    if (!file_exists(JPATH_BASE.$file_to_scan->filewithpath)) {
                        bfLog::log('SKIP: FILE WAS SKIPPED AS DOES NOT EXIST!!! '.$file_to_scan->filewithpath);
                        $skip = -1;
                    } elseif ('gif' == $file_extension) {
                        if ($this->is_ani(JPATH_BASE.$file_to_scan->filewithpath)) {
                            bfLog::log('SKIP: FILE WAS ANIMATED GIF - skipping '.$file_to_scan->filewithpath);
                            $skip = -2;
                        }
                    } elseif ('/backups/akeeba_json.php' == $file_to_scan->filewithpath) {
                        bfLog::log('SKIP: skipping '.$file_to_scan->filewithpath);
                        $skip = -3;
                    } elseif ('/stats/webalizer.current' == $file_to_scan->filewithpath) {
                        bfLog::log('SKIP: skipping '.$file_to_scan->filewithpath);
                        $skip = -4;
                    } elseif (preg_match('/\.(gif|jpg|png|ico|jpeg|bmp)/ism', basename($file_to_scan->filewithpath))
                        && $this->isValidImage($file_to_scan->filewithpath)
                    ) {
                        bfLog::log('SKIP: skipping VALID IMAGE '.$file_to_scan->filewithpath);
                        $skip = -6;
                    } elseif (preg_match('/\/stats\/usage_.*\.html/', $file_to_scan->filewithpath)) {
                        bfLog::log('SKIP: skipping '.$file_to_scan->filewithpath);
                        $skip = -5;
                    } elseif (0 == $skip && filesize(JPATH_BASE.$file_to_scan->filewithpath) > 1024288) {
                        bfLog::log('SKIP: FILE WAS OVER 1Mb - skipping '.$file_to_scan->filewithpath);
                        $skip = -7;
                    } elseif ('/components/com_dtregister/assets/js/jquery-ui.js' == $file_to_scan->filewithpath) {
                        $skip = -7;
                    } elseif ('/administrator/components/com_akeeba/backup/akeeba.json.log' == $file_to_scan->filewithpath) {
                        $skip = -7;
                    } elseif (filesize(JPATH_BASE.$file_to_scan->filewithpath) > 800000) {
                        bfLog::log('SKIP: FILE WAS SKIPPED AS OVER 8000000!!! '.$file_to_scan->filewithpath);
                        $skip = -1;
                    }
                    if (0 !== $skip) {
                        // mark it as false positive (-2) or skipped (-1)
                        $sql = sprintf("UPDATE bf_files SET queued = 0, suspectcontent = '%s' WHERE id = '%s'",
                            $skip,
                            addslashes($file_to_scan->id)
                        );
                        $this->db->setQuery($sql);
                        $this->db->query();
                        bfLog::log('SKIP:CONTINUE');
                        continue; // no more processing on this file - skipped
                    }

                    // cleanup
                    $fff = JPATH_BASE.stripslashes($file_to_scan->filewithpath);

                    // WINDOWS I HATE YOU! - bodge it
                    $fff = str_replace('\:', '/:', $fff);

                    // need a @ to prevent access denied
                    $chunk = @file_get_contents($fff);

                    // remove stuff that is likely to be marked as suspect, when we are happy its not...
                    $chunk = $this->applyStringExceptions($chunk, $file_to_scan);

                    // Not really a chunk now, as we load the whole file into memory
                    if (trim($chunk)) {
                        // Need at least 3 seconds to run the preg_match on
                        // average slow machine
                        if ($this->_timer->getTimeLeft() < _BF_CONFIG_DEEPSCAN_TIMER_TWO) {
                            bfLog::log('Need at least 3 seconds to run the preg_match on average slow machine');
                            $this->saveState(false, __LINE__);
                        }

                        // hard to audit c99 clones
                        preg_match('/(auth_pass).*(default_use_ajax)/ism', $chunk, $matches);
                        if (count($matches) >= 3) {
                            $isSuspect = true;
                        } else {
                            if (preg_match('/\.php/', $file_to_scan->filewithpath)) {
                                preg_match('/move_uploaded_file/ism', $chunk, $matches);
                                if (count($matches) >= 1) {
                                    $isUploader = true;
                                }

                                preg_match('/[^a-zA-Z0-9\-]{1}\s*mail\s*\(/ism', $chunk, $matches);
                                if (count($matches) >= 1) {
                                    $isMailer = true;
                                }
                            }

                            //100% Certain if a file matches this regex then its hacked
                            if (preg_match('/index\.html\.bak\.bak/i', $chunk)) {
                                $isHacked = true;
                            } else {
                                $isHacked = false;
                            }

                            if (!$isHacked) {
                                // Test if suspect
                                bfLog::log('Auditing File: '.$file_to_scan->filewithpath.' - '.$file_to_scan->size.' bytes');
                                $isSuspect = (preg_match('/'.$pattern.'/ism', $chunk) ? true : false);
                            }

                            // Test If encrypted
                            $regex     = "/OOO000000|if\(!extension_loaded\('ionCube\sLoader'\)\)|<\?php\s@Zend;|This\sfile\swas\sencoded\sby\sthe.*Zend Encoder/i";
                            $encrypted = (preg_match($regex, $chunk) ? 1 : 0);
                        }
                    } else {
                        bfLog::log('FILE WAS EMPTY!!! '.$file_to_scan->filewithpath);
                    }

                    // free up memory
                    unset($chunk);

                    $encrypted = (int) $encrypted;
                    $isSuspect = (int) $isSuspect;
                    $isHacked  = (int) $isHacked;

                    if ($encrypted && $isSuspect) {
                        bfLog::log(' + isEncrypted/suspect');
                        $this->_encryptedAndSuspectIds[] = $file_to_scan->id;
                    } elseif ($isHacked) {
                        bfLog::log(' + isHacked');
                        $this->_hackedIds[] = $file_to_scan->id;
                    } elseif ($encrypted) {
                        bfLog::log(' + isEncrypted');
                        $this->_encryptedIds[] = $file_to_scan->id;
                    } elseif ($isSuspect) {
                        bfLog::log(' + isSuspect');
                        $this->_suspectIds[] = $file_to_scan->id;
                    } elseif ($isMailer) {
                        bfLog::log(' + isMailer');
                        $this->_mailerIds[] = $file_to_scan->id;
                    } elseif ($isUploader) {
                        bfLog::log(' + isUploader');
                        $this->_uploaderIds[] = $file_to_scan->id;
                    } else {
                        bfLog::log(' + OK');
                        $this->_notencryptedAndSuspectIds[] = $file_to_scan->id;
                    }

                    if (_BF_SPEED == 'CRAPPYWEBHOST' || $this->_timer->getTimeLeft() < _BF_CONFIG_DEEPSCAN_TIMER_TWO) {
                        $this->updateFilesFromDeepscan(__LINE__);
                        $this->saveState(false, __LINE__);
                    }
                }

                if ($this->_timer->getTimeLeft() < _BF_CONFIG_DEEPSCAN_TIMER_TWO) {
                    $this->updateFilesFromDeepscan(__LINE__);
                    $this->saveState(false, __LINE__);
                }

                // needed to go back up to the top of the loop
                if (count($this->getmergedIds())) {
                    $this->db->setQuery('SELECT count(*) FROM bf_files WHERE queued = 1 AND id NOT IN ('.implode(',', $this->getmergedIds()).')');
                } else {
                    $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE queued = 1');
                }
            }

            if (count($this->getmergedIds())) {
                $this->db->setQuery('SELECT count(*) FROM bf_files WHERE queued = 1 AND id NOT IN ('.implode(',', $this->getmergedIds()).')');
            } else {
                $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE queued = 1');
            }

            if (0 == $this->db->loadResult()) {
                bfLog::log(' ======== deepscancomplete ========');
                $this->deepscancomplete = true;
                $this->updateFilesFromDeepscan(__LINE__);

                // save our latest pattern match
                // decrypt then save the md5!
                file_put_contents('tmp/tmp.pattern.lastmd5', md5($pattern));

                $this->nextStepPlease();
            } else {
                bfLog::log(' ======== deepscancomplete NOT COMPLETE========');
                $this->updateFilesFromDeepscan(__LINE__);
                $this->saveState(false, __LINE__);
            }
        } catch (Exception $e) {
            // Just continue...
            if (!defined('_BF_LAST_BREATH')) {
                define('_BF_LAST_BREATH', $e->getMessage());
            }
            bfLog::log(' ======== EXCEPTION ========='.$e->getMessage().$this->db->getQuery());
        }
    }

    /**
     * @return array
     */
    private function getmergedIds()
    {
        return array_merge($this->_encryptedAndSuspectIds,
            $this->_notencryptedAndSuspectIds,
            $this->_encryptedIds,
            $this->_mailerIds,
            $this->_uploaderIds,
            $this->_suspectIds,
            $this->_hackedIds
        );
    }

    /**
     * @param $line
     */
    private function updateFilesFromDeepscan($line)
    {
        // reconnect to the database
        $this->db = JFactory::getDBO();

        $this->dbPing();

        bfLog::log(' =updateFilesFromDeepscan called from line '.$line);
        bfLog::log(' =Marking this number of files as _encryptedAndSuspectIds= '.count($this->_encryptedAndSuspectIds));
        if (count($this->_encryptedAndSuspectIds)) {
            $sql = 'UPDATE bf_files SET encrypted = %s, suspectcontent = %s, queued = 0 WHERE id IN(%s)';
            $sql = sprintf($sql, 1, 1, implode(', ', $this->_encryptedAndSuspectIds));
            $this->db->setQuery($sql);
            if ($this->db->query()) {
                bfLog::log(' = Removed success = ');
            } else {
                bfLog::log('=============================================');
                bfLog::log($this->db->getErrorMsg().$sql);
                bfLog::log('=============================================');
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
            $this->_encryptedAndSuspectIds = array();
        }

        bfLog::log(' =Marking this number of files as _encryptedIds = '.count($this->_encryptedIds));
        if (count($this->_encryptedIds)) {
            $sql = 'UPDATE bf_files SET encrypted = %s, suspectcontent = %s, queued = 0 WHERE id IN(%s)';
            $sql = sprintf($sql, 1, 0, implode(', ', $this->_encryptedIds));
            $this->db->setQuery($sql);
            if ($this->db->query()) {
                bfLog::log(' = Removed success = ');
            } else {
                bfLog::log('=============================================');
                bfLog::log($this->db->getErrorMsg().$sql);
                bfLog::log('=============================================');
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
            $this->_encryptedIds = array();
        }

        bfLog::log(' =Marking this number of files as _suspectIds = '.count($this->_suspectIds));
        if (count($this->_suspectIds)) {
            $sql = 'UPDATE bf_files SET encrypted = %s, suspectcontent = %s, queued = 0 WHERE id IN(%s)';
            $sql = sprintf($sql, 0, 1, implode(', ', $this->_suspectIds));
            $this->db->setQuery($sql);
            if ($this->db->query()) {
                bfLog::log(' = Removed success = ');
            } else {
                bfLog::log('=============================================');
                bfLog::log($this->db->getErrorMsg().$sql);
                bfLog::log('=============================================');
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
            $this->_suspectIds = array();
        }

        bfLog::log(' =Marking this number of files as NOT _notencryptedAndSuspectIds = '.count($this->_notencryptedAndSuspectIds));
        if (count($this->_notencryptedAndSuspectIds)) {
            $sql = 'UPDATE bf_files SET encrypted = %s, suspectcontent = %s, queued = 0 WHERE id IN(%s)';
            $sql = sprintf($sql, 0, 0, implode(', ', $this->_notencryptedAndSuspectIds));
            $this->db->setQuery($sql);
            if ($this->db->query()) {
                bfLog::log(' = Removed success = ');
            } else {
                bfLog::log('=============================================');
                bfLog::log($this->db->getErrorMsg().$sql);
                bfLog::log('=============================================');
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
            $this->_notencryptedAndSuspectIds = array();
        }

        bfLog::log(' =Marking this number of files as _mailer = '.count($this->_mailerIds));
        if (count($this->_mailerIds)) {
            $sql = 'UPDATE bf_files SET mailer = 1, queued = 0  WHERE id IN(%s)';
            $sql = sprintf($sql, implode(', ', $this->_mailerIds));
            $this->db->setQuery($sql);
            if ($this->db->query()) {
                bfLog::log(' = mailer success = ');
            } else {
                bfLog::log('=============================================');
                bfLog::log($this->db->getErrorMsg().$sql);
                bfLog::log('=============================================');
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
            $this->_mailerIds = array();
        }

        bfLog::log(' =Marking this number of files as _uploader = '.count($this->_uploaderIds));
        if (count($this->_uploaderIds)) {
            $sql = 'UPDATE bf_files SET `uploader` = 1, queued = 0  WHERE id IN(%s)';
            $sql = sprintf($sql, implode(', ', $this->_uploaderIds));
            $this->db->setQuery($sql);
            if ($this->db->query()) {
                bfLog::log(' = mailer success = ');
            } else {
                bfLog::log('=============================================');
                bfLog::log($this->db->getErrorMsg().$sql);
                bfLog::log('=============================================');
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
            $this->_uploaderIds = array();
        }

        bfLog::log(' =Marking this number of files as _hacked = '.count($this->_hackedIds));
        if (count($this->_hackedIds)) {
            $sql = 'UPDATE bf_files SET `hacked` = 1, queued = 0  WHERE id IN(%s)';
            $sql = sprintf($sql, implode(', ', $this->_hackedIds));
            $this->db->setQuery($sql);
            if ($this->db->query()) {
                bfLog::log(' = _hackedIds success = ');
            } else {
                bfLog::log('=============================================');
                bfLog::log($this->db->getErrorMsg().$sql);
                bfLog::log('=============================================');
                bfEncrypt::reply(bfReply::ERROR, $this->db->getErrorMsg());
            }
            $this->_hackedIds = array();
        }
    }

    /**
     * An animated gif contains multiple "frames", with each frame having a header made up of:
     *  - a static 4-byte sequence (\x00\x21\xF9\x04)
     *  - 4 variable bytes
     *  - a static 2-byte sequence (\x00\x2C).
     *
     * @see    http://www.php.net/manual/en/function.imagecreatefromgif.php#88005
     * @thanks Mike H.
     *
     * We read through the file til we reach the end of the file, or we've found
     * at least 2 frame headers
     *
     * @param $filename string complete path to the file
     *
     * @return bool
     */
    private function is_ani($filename)
    {
        if (!($fh = @fopen($filename, 'rb'))) {
            return false;
        }

        $count = 0;

        while (!feof($fh) && $count < 2) {
            $chunk = fread($fh, 1024 * 100);
        } //read 100kb at a time
        $count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00\x2C#s', $chunk, $matches);

        fclose($fh);

        return $count > 1;
    }

    /**
     * Not the correct way to check for a valid image but "good enough" for our purposes
     * Fast and cross PHP version compatible...
     *
     * @param $path
     *
     * @return bool
     */
    private function isValidImage($path)
    {
        bfLog::log('isValidImage? '.JPATH_BASE.$path);
        $a          = @getimagesize(JPATH_BASE.$path);
        $image_type = $a[2];

        if (in_array($image_type, array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP))) {
            return true;
        }

        return false;
    }

    /**
     * Lets munge the files contents to reduce the number of false hits we get for eval and stuff
     * Try to keep this list as small as possible.
     *
     * @param $chunk
     * @param $file_to_scan
     *
     * @return mixed
     *
     * @todo add this to the configurable audit configuration
     * @todo benchmark this against a preg_replace
     */
    private function applyStringExceptions($chunk, $file_to_scan)
    {
        $chunk = str_replace('matheval', '_RETRACTED_', $chunk);

        // NoNumber Extensions
        $chunk = str_replace('parseVal', '_RETRACTED_', $chunk);

        // com_avreloaded
        $chunk = str_replace('$this->_data = unserialize(base64_decode($rdata));', '_RETRACTED_', $chunk);

        // plugins/system/k2/k2.php
        $chunk = str_replace('$output = \'<div style="display:none', '_RETRACTED_', $chunk);

        // com_community Extensions
        $chunk = str_replace('doubleval', '_RETRACTED_', $chunk);

        // com_breezingforms Extensions
        $chunk = str_replace('Zend_Json::decode(base64_decode', '_RETRACTED_', $chunk);

        // Joomla Core
        $chunk = str_replace('setRedirect(base64_decode($return)', '_RETRACTED_', $chunk);
        $chunk = str_replace('passthru(\'kill -9 \' . $pid);', '_RETRACTED_', $chunk);
        $chunk = str_replace('system(\'export HOME="\' . $info[\'dir\'] . \'"\');', '_RETRACTED_', $chunk);
        $chunk = str_replace('\'c'.'u'.'r'.'l'.'_version\',\'current\',\'cvsclient_connect\',\'cvsclient_log\'', '_RETRACTED_', $chunk);
        $chunk = str_replace('$mainframe->redirect(base64_decode', '_RETRACTED_', $chunk);
        $chunk = str_replace('$return = base64_encode(base64_decode($return).\'#content\');', '_RETRACTED_', $chunk); //1.5.26
        $chunk = str_replace('json_decode(base64_decode', '_RETRACTED_', $chunk); //2.5.8+ Returns a stdClass so cannot be eval'ed

        // com_weblinks
        $chunk = str_replace('JUri::isInternal(base64_decode', '_RETRACTED_', $chunk);

        // highside.js //
        $chunk = str_replace("y[o.position == 'above' ? 'p1' : 'p2'] = o.offsetHeight;", '_RETRACTED_', $chunk);

        // Admincredible
        // /components/com_admincredible/libraries/vendor/oauth-php/library/OAuthRequestVerifier.php
        $chunk = str_replace('if(isset($_REQUEST[\'oauth_signature\']))', '_RETRACTED_', $chunk);

        // com_k2
        $chunk = str_replace('<div style="display:none">\'.JHTML::_(\'select.ra', '_RETRACTED_', $chunk);
        $chunk = str_replace('use exec() rather than shell_exec(), to play b', '_RETRACTED_', $chunk);

        // Master Htaccess File from Akeeba
        if (strpos($file_to_scan->filewithpath, 'htaccess')) {
            $chunk = str_replace('RewriteCond %{HTTP_REFERER} (<|>|\'|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]', '_RETRACTED_', $chunk);
            $chunk = str_replace('RewriteCond %{HTTP_REFERER} ([a-zA-Z0-9]{32}) [NC]', '_RETRACTED_', $chunk);
        }

        // Joomla & Akeeba distribute cacert.pem which has Wells Fargo in it
        $chunk = str_replace('Wells Fargo Root CA', '_RETRACTED_', $chunk);

        // Gantry
        $chunk = str_replace('if (!function_exists(\'c'.'u'.'r'.'l_version\'))', '_RETRACTED_', $chunk);

        // Smarty Template
        $chunk = str_replace('$smarty->_eval', '_RETRACTED_', $chunk);

        // JCE
        $chunk = str_replace('$version = '.'c'.'u'.'r'.'l'.'_version();', '_RETRACTED_', $chunk);
        $chunk = str_replace('$ssl_supported = ($version[\'features\'] & C'.'U'.'R'.'L'.'_VERSION_SSL);', '_RETRACTED_', $chunk);

        // Sparkline
        $chunk = str_replace('this.shapes[shape.id] = \'p1\';', '_RETRACTED_', $chunk);

        // com_rsform
        $chunk = str_replace('eval($form->', '_RETRACTED_', $chunk);

        // akeeba
        $chunk = str_replace('base64_decode(\'eyJhcHAiOiJqZn', '_RETRACTED_', $chunk);
        $chunk = str_replace('unserialize(base64_decode', '_RETRACTED_', $chunk);

        $iframe = '<iframe style="width: 0px; height: 0px; border: none;" frameborder="0" marginheight="0" marginwidth="0" height="0" width="0"';
        $chunk  = str_replace($iframe, '_RETRACTED_', $chunk);

        // jQuery
        $iframe = "<iframe frameborder='0' width='0' height='0'/>";
        $chunk  = str_replace($iframe, '_RETRACTED_', $chunk);

        // /media/foundry/2.1/scripts/jplayer.js
        $iframe = '0000" width="0" height="0">';
        $chunk  = str_replace($iframe, '_RETRACTED_', $chunk);

        // Google Tag MAanager
        //        <iframe src="//www.googletagmanager.com/ns.html?id=XXX-XXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe>
        $chunk = preg_replace('#\<iframe\ssrc=\"\/\/www.googletagmanager.com\/ns\.html\?id\=.*\"\sheight\=\"0\"\swidth\=\"0\"\sstyle\=\"display:none;visibility:hidden\"\>\<\/iframe\>#ism', '', $chunk);

        return $chunk;
    }

    /**
     * Find out some basic information about this site and its setup.
     */
    private function bestpracticesecurityAction()
    {
        bfLog::log('=============================================');
        bfLog::log('=========bestpracticesecurityAction==========');
        bfLog::log('=============================================');

        $this->platform = 'Joomla';

        //8192029
        $this->db->setQuery("UPDATE bf_files SET hacked = 1, suspectcontent = 1 WHERE size = '8192029'");
        $this->db->query();

        // flag filenames that are 100% a hack

        // first get a subset to check
        $this->db->setQuery("select * from bf_files 
WHERE falsepositive is null 
AND (iscorefile is null and hashfailed is null)
AND filewithpath NOT LIKE '%Diff3.php'
AND filewithpath NOT LIKE '%com_gantry/models/template.php.suspected'
AND filewithpath NOT LIKE '%tcpdf.php.suspected'
AND filewithpath NOT LIKE '%favicon_unused.ico'
AND filewithpath NOT LIKE '%favicon_houven.ico'
AND filewithpath NOT LIKE '%favicon_master.ico'
AND filewithpath NOT LIKE '%favicon_joomla.ico'
AND filewithpath NOT LIKE '%favicon_backup.ico'
AND
 (
filewithpath like '%cache\-%'
or 
filewithpath like '%\/\.%\.ico'
or 
filewithpath like '%favicon\_%'
or 
filewithpath like '%cache\_%'
or 
filewithpath like '\/libraries\/joomla\/exporter\.php'
or 
filewithpath like '%db\.php'
or 
filewithpath like '%sql%\.php%'
or 
filewithpath like '%diff%\.php%'
or 
filewithpath like '%proxy%\.php%'
or 
filewithpath like '%dirs%\.php%'
or 
filewithpath like '%start%\.php%'
or 
filewithpath like '%\.suspected'
or 
filewithpath like '%timezone_tranositions_get%'
or 
filewithpath like '%stream_bucketd_make_writeable%'
or 
filewithpath like '%countt_chars%'
or 
filewithpath like '%variantf_imp%'
or 
filewithpath like '%com_contact_info%'
or 
filewithpath like '%banner_copys%'
or 
filewithpath like '%x\.php'
or 
filewithpath like '%cgi\-%'
or 
filewithpath like '%backup\-%'
or 
filewithpath like '%sort\-%'
or 
filewithpath like '%memcache\-%'
or 
filewithpath like '%sql\-%'
or 
filewithpath like '%reverse\-%'
or 
filewithpath like '%conf\-%'
or 
filewithpath like '%cache\-%'
or 
filewithpath like '%bin\-%'
or 
filewithpath like '%utf8\-%'
)
");
        $hacked = $this->db->loadObjectList();

        bfLog::log('hackCheck = count - '.count($hacked));

        foreach ($hacked as $row) {
            bfLog::log('hackCheck = row - '.$row->filewithpath);
            // run it though a PHP regex that is very specific on what its looking for as the mysql one is very very dodgy in old mysql versions
            if (preg_match('!.*\/(cache-[0-9]{2}[a-z]\.php|\.[0-9a-z]{8}\.ico|cache_tpeowiol|1ndex\.php|favicon\_[a-z0-9]{6}\.ico|db[0-9]{2}\.php|cp1251-[0-9a-z]{3}\.php|sql\-[0-9]{2}[a-z]\.php|diff[0-9]{1,2}\.php|proxy[0-9]{1,2}\.php|dirs[0-9]{1,2}\.php|start[0-9]{1,2}\.php|.*\.suspected|libraries\/joomla\/exporter\.php|x\.php|timezone_tranositions_get\.php|cmhiuup\.php|stream_bucketd_make_writeable\.php|countt_chars\.php|variantf_imp\.php|com_contact_info\.php|banner_copys\.php|(cgi|backup|sort|memcache|sql|reverse|conf|cache|bin|utf8)\-([a-z][0-9]*|[0-9]*|[a-z][a-z]|[0-9][a-z]|[a-z][a-z][a-z]|[0-9][a-z][0-9]|[0-9][a-z][a-z]|[a-z][0-9][a-z])\.php$)!', $row->filewithpath)) {
                bfLog::log('hackCheck = row IS HACKED - '.$row->filewithpath);
                $this->db->setQuery('UPDATE bf_files SET hacked = 1, suspectcontent = 1 WHERE id = '.$row->id);
                $this->db->query();
            }
        }

        // Am I hacked?
        $this->hacked = $this->checkIfHackedSite();

        // Mark PHP in places PHP should not be!
        if ($ids = $this->_phpInWrongPlaces()) {
            $this->db->setQuery('UPDATE bf_files SET `suspectcontent` = 1 WHERE id IN ('.implode(',', $ids).')');
            $this->db->query();
        }

        // Remove OUR stuff as we dont need to report on that
        $this->db->setQuery("DELETE FROM bf_files WHERE
                filewithpath = '/plugins/system/j15_bfnetwork.xml'
                OR filewithpath = '/plugins/system/j25_30_bfnetwork.xml'
                OR filewithpath = '%.myjoomla.ignore.files'
                OR filewithpath = '%.myjoomla.ignore.folder'
                OR filewithpath LIKE '/plugins/system/bfnetwork%'");
        $this->db->query();

        // Remove OUR stuff as we dont need to report on that
        $this->db->setQuery("DELETE FROM bf_folders WHERE folderwithpath LIKE '/plugins/system/bfnetwork%'");
        $this->db->query();

        // Report count of all .htaccess files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%.htaccess"');
        $this->htaccess_files = $this->db->LoadResult();

        // Report count of all files with 777 permissions
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE fileperms LIKE "%777%"');
        $this->files_777 = $this->db->LoadResult();

        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE size = 0');
        $this->zerobytes = $this->db->LoadResult();

        // Report count of all folders with 777 permissions
        $this->db->setQuery('SELECT COUNT(*) FROM bf_folders WHERE folderinfo LIKE "%777%"');
        $this->folders_777 = $this->db->LoadResult();

        // Report all hidden folders like .git or .svn
        $this->db->setQuery('SELECT COUNT(*) FROM bf_folders WHERE folderwithpath LIKE "%/.%"');
        $this->hidden_folders = $this->db->LoadResult();

        // Report all hidden files like .htaccess .hack
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%/.%"');
        $this->hidden_files = $this->db->LoadResult();

        // Report nested Joomla versions
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%/administrator/index.php"');
        $this->nestedinstalls = $this->db->LoadResult();

        // Report file what might have been renamed to hide
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%.old%" OR filewithpath LIKE "%.bak%" OR filewithpath LIKE "%.backup%"');
        $this->renamedtohidefiles = $this->db->LoadResult();

        // Report any error_log files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%error_log"');
        $this->error_logs_seen = $this->db->LoadResult();

        // Report files in the /tmp folder
        $this->db->setQuery('SELECT count(*) FROM bf_files WHERE filewithpath LIKE "/tmp%" AND filewithpath != "/tmp/index.html"');
        $this->tmp_install_folders = $this->db->LoadResult();

        // Report any encrypted files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE encrypted = 1');
        $this->encrypted_files = $this->db->LoadResult();

        // Report suspect files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE suspectcontent = 1');
        $this->suspectfiles = $this->db->LoadResult();

        // Report mailer files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE mailer = 1');
        $this->mailer = $this->db->LoadResult();

        // Report uploader files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE uploader = 1');
        $this->uploader = $this->db->LoadResult();

        // php.ini files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%php.ini%" OR filewithpath LIKE "%.user.ini%"');
        $this->phpiniseen = $this->db->LoadResult();

        // look for akeeba sql files
        $this->db->setQuery('SELECT count(*) FROM bf_files WHERE 
        (
        (filewithpath LIKE \'%.sql\' or filewithpath LIKE \'%sql/site.%\')
        and 
        (iscorefile = 0 or iscorefile is null)
        )');
        $this->sqlfilesseen = $this->db->LoadResult();

        $this->db->setQuery('SELECT count(*) FROM bf_files WHERE filewithpath LIKE \'%DS_Store%\'');
        $this->dotunderscorefilesseen = $this->db->LoadResult();

        $this->db->setQuery('SELECT count(*) FROM bf_files WHERE filewithpath LIKE \'%admintools_breaches.log%\'');
        $this->admintoolbreaches = $this->db->LoadResult();

        // count of non core files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE iscorefile is null');
        $this->notcorefiles = $this->db->LoadResult();

        $sql = "SELECT count(*) from `bf_core_hashes`
                    WHERE filewithpath NOT IN (
                        SELECT filewithpath from bf_files
                    )
                    AND filewithpath NOT LIKE '/installation/%'
                    AND filewithpath != '/robots.txt.dist'
                    AND filewithpath != '/administrator/manifests/packages/pkg_weblinks.xml'
                    AND filewithpath != '/'
                    AND filewithpath != '/robots.txt.dist'
                    AND filewithpath != '/web.config.txt'
                    AND filewithpath != '/joomla.xml'
                    AND filewithpath != '/build.xml'
                    AND filewithpath != '/LICENSE.txt'
                    AND filewithpath != '/README.txt'
                    AND filewithpath != '/htaccess.txt'
                    AND filewithpath != '/LICENSES.php'
                    AND filewithpath != '/configuration.php-dist'
                    AND filewithpath != '/CHANGELOG.php'
                    AND filewithpath != '/COPYRIGHT.php'
                    AND filewithpath != '/CREDITS.php'
                    AND filewithpath != '/INSTALL.php'
                    AND filewithpath != '/LICENSE.php'
                    AND filewithpath != '/CONTRIBUTING.md'
                    AND filewithpath != '/phpunit.xml.dist'
                    AND filewithpath != '/README.md'
                    AND filewithpath != '/.travis.yml'
                    AND filewithpath != '/travisci-phpunit.xml'
                    AND filewithpath != '/images/banners/osmbanner1.png'
                    AND filewithpath != '/images/banners/osmbanner2.png'
                    AND filewithpath != '/images/banners/shop-ad-books.jpg'
                    AND filewithpath != '/images/banners/shop-ad.jpg'
                    AND filewithpath != '/images/banners/white.png'
                    AND filewithpath != '/images/headers/blue-flower.jpg'
                    AND filewithpath != '/images/headers/maple.jpg'
                    AND filewithpath != '/images/headers/raindrops.jpg'
                    AND filewithpath != '/images/headers/walden-pond.jpg'
                    AND filewithpath != '/images/headers/windows.jpg'
                    AND filewithpath != '/images/joomla_black.gif'
                    AND filewithpath != '/images/joomla_black.png'
                    AND filewithpath != '/images/joomla_green.gif'
                    AND filewithpath != '/images/joomla_logo_black.jpg'
                    AND filewithpath != '/images/powered_by.png'
                    AND filewithpath != '/images/sampledata/fruitshop/apple.jpg'
                    AND filewithpath != '/images/sampledata/fruitshop/bananas_2.jpg'
                    AND filewithpath != '/images/sampledata/fruitshop/fruits.gif'
                    AND filewithpath != '/images/sampledata/fruitshop/tamarind.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/180px_koala_ag1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/180px_wobbegong.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/200px_phyllopteryx_taeniolatus1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/220px_spottedquoll_2005_seanmcclean.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/789px_spottedquoll_2005_seanmcclean.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/800px_koala_ag1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/800px_phyllopteryx_taeniolatus1.jpg'
                    AND filewithpath != '/images/sampledata/parks/animals/800px_wobbegong.jpg'
                    AND filewithpath != '/images/sampledata/parks/banner_cradle.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/120px_pinnacles_western_australia.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/120px_rainforest_bluemountainsnsw.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/180px_ormiston_pound.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/250px_cradle_mountain_seen_from_barn_bluff.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/727px_rainforest_bluemountainsnsw.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/800px_cradle_mountain_seen_from_barn_bluff.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/800px_ormiston_pound.jpg'
                    AND filewithpath != '/images/sampledata/parks/landscape/800px_pinnacles_western_australia.jpg'
                    AND filewithpath != '/images/sampledata/parks/parks.gif'
                    ";
        $this->db->setQuery($sql);
        $this->missingcorefiles = $this->db->LoadResult();

        $this->db->setQuery('SHOW TABLES LIKE "bf_files_last"');
        if ($this->db->loadResult()) {
            $sql = 'select count(*) from `bf_files` as new
                  LEFT JOIN bf_files_last as old ON old.filewithpath = new.filewithpath
                  WHERE old.currenthash != new.currenthash';
            $this->db->setQuery($sql);
            $this->modifiedfilessincelastaudit = $this->db->LoadResult();
        }

        // has_robots_modified
        $sql = 'SELECT c.ch as core_hash,  my.ch as my_hash FROM (
                        SELECT core.hash as ch
                            FROM bf_core_hashes AS core
                        WHERE
                            core.filewithpath = "/robots.txt"
                        OR
                            core.filewithpath = "/robots.txt.dist"
                            LIMIT 1
                        )	as c, (
                        SELECT bf_files.currenthash as ch
                            FROM bf_files
                        WHERE
                            bf_files.filewithpath = "/robots.txt"
                            LIMIT 1
                        )	as my';
        $this->db->setQuery($sql);
        $row = $this->db->loadAssocList();
        if ($row) {
            if ($row[0]['core_hash'] && $row[0]['my_hash'] && ($row[0]['core_hash'] === $row[0]['my_hash'])) {
                $this->has_robots_modified = 0;
            } else {
                $this->has_robots_modified = 1;
            }
        } else {
            $this->has_robots_modified = 0;
        }

        // Files over 2Mb
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE SIZE > 2097152');
        $this->large_files = $this->db->LoadResult();

        // Doing this again here now that I refactored the audit for perfomance I now need to do this much later on :-(
        $this->hashfailedcount = $this->gethashfailurecountAction(true);

        // Report if we have default user ids
        $this->user_hasdefaultuserids = $this->_hasDefaultUserids();

        // PhP in wrong places
        $phpInWrongPlaces      = $this->_phpInWrongPlaces();
        $this->phpinwrongplace = $phpInWrongPlaces ? count($phpInWrongPlaces) : 0;

        /*
         * @todo add these http://en.wikipedia.org/wiki/List_of_archive_formats
         */
        // Report all archives
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE
        filewithpath LIKE "%.zip"
        OR filewithpath LIKE "%.tar"
        OR filewithpath LIKE "%.tar.gz"
        OR filewithpath LIKE "%.bz2"
        OR filewithpath LIKE "%.gzip"
        OR filewithpath LIKE "%.bzip2"');
        $this->archive_files = $this->db->LoadResult();

        $this->nextStepPlease(true);
    }

    /**
     * Run some very specific checks to see if this site is hacked or not.
     */
    private function checkIfHackedSite()
    {
        $this->db->setQuery('SELECT count(*) FROM bf_files WHERE hacked = 1');

        return $this->db->loadResult();
    }

    /**
     * @return mixed
     */
    private function _phpInWrongPlaces()
    {
        $idsSql = "SELECT id FROM bf_files AS b WHERE filewithpath REGEXP '^/images/.*\.php$'"; // OR filewithpath REGEXP '^/media/.*\.php$'
        $this->db->setQuery($idsSql);
        if (method_exists($this->db, 'loadColumn')) {
            $ids = $this->db->loadColumn();
        } else {
            $ids = $this->db->loadResultArray();
        }

        return $ids;
    }

    /**
     * Count how many core files failed their hash checks.
     */
    private function gethashfailurecountAction($internal = false)
    {
        $sql = 'SELECT COUNT(*) FROM bf_files WHERE iscorefile = 1 AND hashfailed = 1';
        $this->db->setQuery($sql);
        $this->hashfailedcount = $this->db->LoadResult();

        if (false === $internal) {
            // move onto the next step
            $this->nextStepPlease();
        } else {
            return $this->hashfailedcount;
        }
    }

    /**
     * Do we have any default ids.
     *
     * @return int
     */
    private function _hasDefaultUserids()
    {
        $this->db->setQuery('SELECT COUNT(*) FROM #__users WHERE id IN (62 , 42)');

        return $this->db->loadResult();
    }
}
PK��#]p��(system/bfnetwork/bfnetwork/bfnetwork.phpnu�[���<?php

/*
 * @package   bfNetwork
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Blue Flame Digital Solutions Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 *
 * @see       https://myJoomla.guru/
 * @see       https://myWP.guru/
 * @see       https://mySites.guru/
 * @see       https://www.phil-taylor.com/
 *
 * @author    Phil Taylor / Blue Flame Digital Solutions Limited.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 *
 * If you have any questions regarding this code, please contact phil@phil-taylor.com
 */

// no direct access
defined('_JEXEC') or die('Restricted access');

/*
 * All our code is in the sub folder, as that is what is auto-upgraded
 * and fully maintained by the automated processes at myJoomla.com.
 */
if (file_exists(dirname(__FILE__).'/bfnetwork/bfPlugin.php')) {
    require dirname(__FILE__).'/bfnetwork/bfPlugin.php';
}
PK��#]8�lJ��system/bfnetwork/bfnetwork.phpnu�[���<?php
/**
 * @package Blue Flame Network (bfNetwork)
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 Blue Flame IT Ltd. All rights reserved.
 * @license GNU General Public License version 3 or later
 * @link https://myJoomla.com/
 * @author Phil Taylor / Blue Flame IT Ltd.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */

// no direct access
defined('_JEXEC') or die('Restricted access');

/**
 * All our code is in the sub folder, as that is what is auto-upgraded
 * and fully maintained by the automated processes at myJoomla.com
 */
require 'bfnetwork/bfPlugin.php';
PK��#]<�U\"\"&system/bfnetwork/install.bfnetwork.phpnu�[���<?php
/**
 * @package   Blue Flame Network (bfNetwork)
 * @copyright Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 Blue Flame IT Ltd. All rights reserved.
 * @license   GNU General Public License version 3 or later
 * @link      https://myJoomla.com/
 * @author    Phil Taylor / Blue Flame IT Ltd.
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
defined('_JEXEC') or die();

class plgsystembfnetworkInstallerScript
{
    /**
     * @param $type
     * @param $parent
     *
     * @return bool
     */
    public function preflight($type, $parent)
    {
        return TRUE;
    }

    /**
     * @return bool
     */
    public function uninstall()
    {
        return TRUE;
    }

    /**
     * Pass request to our abstracted out function
     *
     * @param $parent
     *
     * @return bool
     */
    public function update($parent)
    {
        return TRUE;
    }

    /**
     * Pass request to our abstracted out function
     *
     * @param $parent
     */
    public function install($parent)
    {
        return $this->registerSiteToMyJoomla('install');
    }

    /**
     * Send the most basic information back to myJoomla service so
     * that we can register your site, after which we use a dedicated secure
     * connection through out connector.
     *
     * Some people call this "calling home" which has a negative reputation
     * However the whole premise of the SasS myJoomla.com is an active connection between
     * your site and our service so this is perfectly acceptable and lets us know your site
     * has a connector installed so we can continue with the installation/connection process
     *
     * @param $type string update|install
     */
    public function registerSiteToMyJoomla($type)
    {
        /**
         * Init some Joomla Classes we will need...
         * @todo Confirm these are available back to Joomla 1.5.0
         */
        $config  = JFactory::getConfig();
        $version = new JVersion ();

        // init our data holder...
        $data = new stdClass();

        // Is this an install or an update
        $data->type = $type;

        /**
         * Get the friendly name of the website
         * Bloody Joomla version issues here too...
         */
        if (method_exists($config, 'getValue')) { //Old Joomla Versions
            $data->friendlyname = $config->getValue('config.sitename');
        } else {
            $data->friendlyname = $config->get('sitename');
        }

        // Get Joomla's Site URL
        $data->siteurl = str_replace('/administrator/', '/', JURI::base());

        // get Joomla's version number
        $data->version = $version->getShortVersion();

        /**
         * Check for our version file in two locations, again Joomla being a pain and changing the paths in 2.5.0+
         */
        if (file_exists('../plugins/system/bfnetwork/VERSION')) {

            $data->connectorversion = file_get_contents('../plugins/system/bfnetwork/VERSION');

        } else if (file_exists('../plugins/system/bfnetwork/bfnetwork/VERSION')) {

            $data->connectorversion = file_get_contents('../plugins/system/bfnetwork/bfnetwork/VERSION');
        }

        /**
         * Get the has form the URL, crazy way to do it for maximum compatibility with
         * crappy servers!
         *
         * @todo test on all versions of Joomla
         */
        if (count($_FILES) && array_key_exists('install_package', $_FILES['install_package'])) { // Install by Zip file Upload
            $data->hash = trim(str_replace(array('connector_',
                                                 '(1)',
                                                 '(2)',
                                                 '(3)',
                                                 '(4)',
                                                 '(5)',
                                                 '.zip'), '', $_FILES['install_package']['name']));
        } else { // Install by Install URL Pasted
            $data->hash = str_replace(array(
                                          'https://local-manage.myjoomla.com/register/site/connect/',
                                          'https://staging.myjoomla.com/register/site/connect/',
                                          'https://manage.myjoomla.com/register/site/connect/'
                                      ),
                                      '',
                                      $_POST['install_url']);
        }

        /**
         *  If in local development which developing myJoomla.com services
         *  If developing we want to see what happens instead of having it happen in the background :)
         */
        if (getenv('APPLICATION_ENV') == 'local' && ($_SERVER['REMOTE_ADDR'] == '127.0.0.1' OR $_SERVER['REMOTE_ADDR'] == '::1')) {

            $registerUrl = 'https://local-manage.myjoomla.com/register/site/yooohooo/';
            $url         = $registerUrl . base64_encode(json_encode($data));

            echo '<a href="' . $url . '">TEST</a>';
            echo json_encode($data);
            echo var_dump(str_replace(array('connector_',
                                            '(1)',
                                            '(2)',
                                            '(3)',
                                            '(4)',
                                            '(5)',
                                            '.zip'), '', $_FILES['install_package']['name']));
            die;
        } else {

            if (@file_exists('./bfnetwork/STAGING')) {
                $registerUrl = 'https://staging.myjoomla.com/register/site/yooohooo/';
            } else {
                $registerUrl = 'https://manage.myjoomla.com/register/site/yooohooo/';
            }

            $url = trim($registerUrl . base64_encode(json_encode($data)));


            $options = array(
                'http'=>array(
                    'method'=>"GET",
                    'header'=>"Accept-language: en\r\n" .
                        "User-Agent: ".$_SERVER['HTTP_HOST']."\r\n"
                )
            );

            $context = stream_context_create($options);

            // get the data from the request
            $ok = @file_get_contents($url, false, $context);

            /**
             * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
             */
            if (!$ok) {

                $ch = curl_init();

                // Set up bare minimum CURL Options needed for myJoomla.com
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
                curl_setopt($ch, CURLOPT_HEADER, FALSE);
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
                curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_HOST']);

                // Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to TRUE
                $ok = curl_exec($ch);

                // Did we succeed in getting something?
                if (!$ok) {

                    /**
                     * ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT ** CRAPPY SERVER ALERT **
                     *
                     * Ok try without validation of the SSL (gulp) but this is needed on some servers without a pem file
                     * and we need to be compatible as possible - even on crappy webhosts when they need us most ;-(
                     */
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

                    //  Second Attempt to download using CURL and CURLOPT_SSL_VERIFYPEER set to FALSE (gulp)
                    curl_exec($ch);
                }

                curl_close($ch);
            }

            if (!$ok) {
                echo 'We could not auto register to myJoomla.com so you will have to click the manual check button on the awaiting myJoomla.com connection screen';
            }
        }
    }

    /**
     * Pass request to our abstracted out function
     *
     * @param $type
     * @param $parent
     */
    public function postflight($type, $parent)
    {
        return $this->registerSiteToMyJoomla($type);
    }
}
PK��#]7u�˹�system/bfnetwork/bfnetwork.xmlnu�[���<?xml version="1.0" encoding="iso-8859-1"?>
<extension version="2.5" type="plugin" group="system" method="upgrade">
    <name>manage.myJoomla.com Secure Plugin</name>
    <author>Blue Flame IT Ltd.</author>
    <creationDate>2015</creationDate>
    <copyright>Copyright (C) 2011, 2012, 2013, 2014, 2015 Blue Flame IT Ltd. All rights reserved / Phil Taylor.</copyright>
    <license>http://www.gnu.org/copyleft/gpl.html GNU/GPL</license>
    <authorEmail>phil@phil-taylor.com</authorEmail>
    <authorUrl>www.phil-taylor.com</authorUrl>
    <version>n/a</version>
    <description><![CDATA[
        Your connector is now installed - You do not need to do anything else in your Joomla site, please return to myJoomla.com to continue...
	]]></description>
    <files>
        <filename plugin="bfnetwork">bfnetwork.php</filename>
        <folder>bfnetwork</folder>
    </files>
    <scriptfile>install.bfnetwork.php</scriptfile>
    <params/>
</extension>
PK��#]�)��system/bfnetwork/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�#o,,system/rsform/index.htmlnu�[���<html><body bgcolor="#FFFFFF"></body></html>PK��#],:�system/rsform/rsform.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="system" method="upgrade">
	<name>System - RSForm! Pro</name>
	<author>RSJoomla!</author>
	<creationDate>November 2012</creationDate>
	<copyright>(C) 2007-2012 www.rsjoomla.com</copyright>
	<license>GNU General Public License</license>
	<authorEmail>support@rsjoomla.com</authorEmail>
	<authorUrl>www.rsjoomla.com</authorUrl>
	<version>1.4.0</version>
	<description><![CDATA[PLG_SYSTEM_RSFORM_DESC]]></description>
	<files>
		<filename plugin="rsform">rsform.php</filename>
		<filename>index.html</filename>
	</files>
	<languages folder="language/en-GB">
		<language tag="en-GB">en-GB.plg_system_rsform.ini</language>
		<language tag="en-GB">en-GB.plg_system_rsform.sys.ini</language>
	</languages>
</extension>PK��#]0МTUUsystem/rsform/rsform.phpnu�[���<?php
/**
* @version 1.4.0
* @package RSform!Pro 1.4.0
* @copyright (C) 2007-2013 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.plugin.plugin' );

/**
 * RSForm! Pro system plugin
 */
class plgSystemRSForm extends JPlugin
{
	public function __construct( &$subject, $config ) {
		parent::__construct( $subject, $config );
	}
	
	public function onAfterDispatch() {
		// Preload
		$doc = JFactory::getDocument();
		$app = JFactory::getApplication();
		if ($doc->getType() == 'html' && $app->isSite())
		{
			$doc->addStyleSheet(JURI::root(true).'/components/com_rsform/assets/calendar/calendar.css');
			$doc->addStyleSheet(JURI::root(true).'/components/com_rsform/assets/css/front.css');
		
			$doc->addScript(JURI::root(true).'/components/com_rsform/assets/js/script.js');
		}
	}
	
	protected function canRun() {
		if (class_exists('RSFormProHelper')) return true;
		
		$helper = JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/rsform.php';
		if (file_exists($helper))
		{
			require_once($helper);
			return true;
		}
		
		return false;
	}
	
	public function onAfterRender() {
		$mainframe = JFactory::getApplication();
		
		if ($mainframe->isAdmin()) return;
		$option = JRequest::getVar('option');
		$task 	= JRequest::getVar('task');
		if ($option == 'com_content' && $task == 'edit')
			return;
		
		if (!$this->canRun()) return true;
		
		$content = JResponse::getBody();
		
		if (strpos($content, '{rsform ') === false)
			return true;
		
		// expression to search for
		$pattern = '#\{rsform ([0-9]+)\}#i';
		if (preg_match_all($pattern, $content, $matches))
		{
			static $found_textarea;
			
			$lang = JFactory::getLanguage();
			$lang->load('com_rsform', JPATH_SITE);
			
			$db = JFactory::getDBO();
			$head = array('js' => array(), 'css' => array());			
			foreach ($matches[0] as $j => $match)
			{
				// within <textarea>
				$tmp = explode($match, $content, 2);
				$before = strtolower(reset($tmp));
				$before = preg_replace('#\s+#', ' ', $before);
				
				// we have a textarea
				if (strpos($before, '<textarea') !== false)
				{
					// find last occurrence
					$tmp = explode('<textarea', $before);
					$textarea = end($tmp);
					// found & no closing tag
					if (!empty($textarea) && strpos($textarea, '</textarea>') === false)
						continue;
				}
					
				$formId = $matches[1][$j];
				
				$db->setQuery("SELECT `FormId`, `FormLayout`, `ScriptDisplay`, `ErrorMessage`, `FormTitle`, `CSS`, `JS`, `CSSClass`, `CSSId`, `CSSName`, `CSSAction`, `CSSAdditionalAttributes`, `AjaxValidation`, `ThemeParams` FROM #__rsform_forms WHERE FormId='".$formId."' AND `Published`='1'");
				$form = $db->loadObject();
				if (!empty($form))
				{
					if ($form->JS)
						$head['js'][md5($form->JS)] = $form->JS;
					if ($form->CSS)
						$head['css'][md5($form->CSS)] = $form->CSS;
					if ($form->ThemeParams)
					{
						$registry = new JRegistry();
						$registry->loadString($form->ThemeParams, 'INI');
						$form->ThemeParams = $registry;
						
						if ($form->ThemeParams->get('num_css', 0) > 0)
							for ($i=0; $i<$form->ThemeParams->get('num_css'); $i++)
							{
								$css = $form->ThemeParams->get('css'.$i);
								$css = JURI::root(true).'/components/com_rsform/assets/themes/'.$form->ThemeParams->get('name').'/'.$css;
								$head['css'][md5($css)] = '<link rel="stylesheet" href="'.$css.'" type="text/css" />';
							}
						if ($form->ThemeParams->get('num_js', 0) > 0)
							for ($i=0; $i<$form->ThemeParams->get('num_js'); $i++)
							{
								$js = $form->ThemeParams->get('js'.$i);
								$js = JURI::root(true).'/components/com_rsform/assets/themes/'.$form->ThemeParams->get('name').'/'.$js;
								$head['js'][md5($js)] = '<script type="text/javascript" src="'.$js.'"></script>';
							}
					}
					
					$content = str_replace($matches[0][$j], RSFormProHelper::displayForm($formId,true), $content);
				}
			}
			
			if (count($head['css']))
				$content = str_replace('</head>', "\n".implode("\n", $head['css'])."\n".'</head>', $content);
			
			if (count($head['js']))
				$content = str_replace('</head>', "\n".implode("\n", $head['js'])."\n".'</head>', $content);
		}
		
		JResponse::setBody($content);
	}
}PK��#]�)��system/rsform/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�x�.��$system/languagecode/languagecode.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_languagecode</name>
	<author>Joomla! Project</author>
	<creationDate>November 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="languagecode">languagecode.php</filename>
		<folder>language</folder>
	</files>
	<languages>
		<language tag="en-GB">language/en-GB/en-GB.plg_system_languagecode.ini</language>
		<language tag="en-GB">language/en-GB/en-GB.plg_system_languagecode.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<field
				name="languagecodeplugin"
				type="hidden"
				default="true"
			/>
		</fields>
	</config>
</extension>
PK��#]�}`$system/languagecode/languagecode.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.languagecode
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Language Code plugin class.
 *
 * @since  2.5
 */
class PlgSystemLanguagecode extends JPlugin
{
	/**
	 * Plugin that changes the language code used in the <html /> tag.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onAfterRender()
	{
		$app = JFactory::getApplication();

		// Use this plugin only in site application.
		if ($app->isClient('site'))
		{
			// Get the response body.
			$body = $app->getBody();

			// Get the current language code.
			$code = JFactory::getDocument()->getLanguage();

			// Get the new code.
			$new_code  = $this->params->get($code);

			// Replace the old code by the new code in the <html /> tag.
			if ($new_code)
			{
				// Replace the new code in the HTML document.
				$patterns = array(
					chr(1) . '(<html.*\s+xml:lang=")(' . $code . ')(".*>)' . chr(1) . 'i',
					chr(1) . '(<html.*\s+lang=")(' . $code . ')(".*>)' . chr(1) . 'i',
				);
				$replace = array(
					'${1}' . strtolower($new_code) . '${3}',
					'${1}' . strtolower($new_code) . '${3}'
				);
			}
			else
			{
				$patterns = array();
				$replace  = array();
			}

			// Replace codes in <link hreflang="" /> attributes.
			preg_match_all(chr(1) . '(<link.*\s+hreflang=")([0-9a-z\-]*)(".*\s+rel="alternate".*/>)' . chr(1) . 'i', $body, $matches);

			foreach ($matches[2] as $match)
			{
				$new_code = $this->params->get(strtolower($match));

				if ($new_code)
				{
					$patterns[] = chr(1) . '(<link.*\s+hreflang=")(' . $match . ')(".*\s+rel="alternate".*/>)' . chr(1) . 'i';
					$replace[] = '${1}' . $new_code . '${3}';
				}
			}

			preg_match_all(chr(1) . '(<link.*\s+rel="alternate".*\s+hreflang=")([0-9A-Za-z\-]*)(".*/>)' . chr(1) . 'i', $body, $matches);

			foreach ($matches[2] as $match)
			{
				$new_code = $this->params->get(strtolower($match));

				if ($new_code)
				{
					$patterns[] = chr(1) . '(<link.*\s+rel="alternate".*\s+hreflang=")(' . $match . ')(".*/>)' . chr(1) . 'i';
					$replace[] = '${1}' . $new_code . '${3}';
				}
			}

			// Replace codes in itemprop content
			preg_match_all(chr(1) . '(<meta.*\s+itemprop="inLanguage".*\s+content=")([0-9A-Za-z\-]*)(".*/>)' . chr(1) . 'i', $body, $matches);

			foreach ($matches[2] as $match)
			{
				$new_code = $this->params->get(strtolower($match));

				if ($new_code)
				{
					$patterns[] = chr(1) . '(<meta.*\s+itemprop="inLanguage".*\s+content=")(' . $match . ')(".*/>)' . chr(1) . 'i';
					$replace[] = '${1}' . $new_code . '${3}';
				}
			}

			$app->setBody(preg_replace($patterns, $replace, $body));
		}
	}

	/**
	 * Prepare form.
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since	2.5
	 */
	public function onContentPrepareForm(JForm $form, $data)
	{
		// Check we are manipulating the languagecode plugin.
		if ($form->getName() !== 'com_plugins.plugin' || !$form->getField('languagecodeplugin', 'params'))
		{
			return true;
		}

		// Get site languages.
		if ($languages = JLanguageHelper::getKnownLanguages(JPATH_SITE))
		{
			// Inject fields into the form.
			foreach ($languages as $tag => $language)
			{
				$form->load('
					<form>
						<fields name="params">
							<fieldset
								name="languagecode"
								label="PLG_SYSTEM_LANGUAGECODE_FIELDSET_LABEL"
								description="PLG_SYSTEM_LANGUAGECODE_FIELDSET_DESC"
							>
								<field
									name="' . strtolower($tag) . '"
									type="text"
									label="' . $tag . '"
									description="' . htmlspecialchars(JText::sprintf('PLG_SYSTEM_LANGUAGECODE_FIELD_DESC', $language['name']), ENT_COMPAT, 'UTF-8') . '"
									translate_description="false"
									translate_label="false"
									size="7"
									filter="cmd"
								/>
							</fieldset>
						</fields>
					</form>
				');
			}
		}

		return true;
	}
}
PK��#]�����Dsystem/languagecode/language/en-GB/en-GB.plg_system_languagecode.ininu�[���; Joomla! Project
; (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_LANGUAGECODE="System - Language Code"
PLG_SYSTEM_LANGUAGECODE_FIELD_DESC="Changes the language code used for the <em>%s</em> language."
PLG_SYSTEM_LANGUAGECODE_FIELDSET_DESC="Changes the language code for the generated HTML document. Example usage: You have installed the fr-FR language pack and want the Search Engines to recognise the page as aimed at French-speaking Canada. Add the tag 'fr-CA' to the corresponding field for 'fr-FR' to resolve this."
PLG_SYSTEM_LANGUAGECODE_FIELDSET_LABEL="Language codes"
PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION="Provides the ability to change the language code in the generated HTML document to improve SEO.<br />The fields will appear when the plugin is enabled and saved."
PK��#]o���Hsystem/languagecode/language/en-GB/en-GB.plg_system_languagecode.sys.ininu�[���; Joomla! Project
; (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_LANGUAGECODE="System - Language Code"
PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION="Provides ability to change the language code in the generated HTML document to improve SEO"

PK��#]�)��system/languagecode/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]���/�/ system/actionlogs/actionlogs.phpnu�[���<?php
/**
 * @package     Joomla.Plugins
 * @subpackage  System.actionlogs
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\User;

/**
 * Joomla! Users Actions Logging Plugin.
 *
 * @since  3.9.0
 */
class PlgSystemActionLogs extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * Load plugin language file automatically so that it can be used inside component
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// Import actionlog plugin group so that these plugins will be triggered for events
		PluginHelper::importPlugin('actionlog');
	}

	/**
	 * Adds additional fields to the user editing form for logs e-mail notifications
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm($form, $data)
	{
		if (!$form instanceof Form)
		{
			$this->subject->setError('JERROR_NOT_A_FORM');

			return false;
		}

		$formName = $form->getName();

		$allowedFormNames = array(
			'com_users.profile',
			'com_admin.profile',
			'com_users.user',
		);

		if (!in_array($formName, $allowedFormNames))
		{
			return true;
		}

		/**
		 * We only allow users who has Super User permission change this setting for himself or for other users
		 * who has same Super User permission
		 */

		$user = Factory::getUser();

		if (!$user->authorise('core.admin'))
		{
			return true;
		}

		// If we are on the save command, no data is passed to $data variable, we need to get it directly from request
		$jformData = $this->app->input->get('jform', array(), 'array');

		if ($jformData && !$data)
		{
			$data = $jformData;
		}

		if (is_array($data))
		{
			$data = (object) $data;
		}

		if (empty($data->id) || !User::getInstance($data->id)->authorise('core.admin'))
		{
			return true;
		}

		Form::addFormPath(__DIR__ . '/forms');

		if ((!PluginHelper::isEnabled('actionlog', 'joomla')) && (Factory::getApplication()->isClient('administrator')))
		{
			$form->loadFile('information', false);

			return true;
		}

		if (!PluginHelper::isEnabled('actionlog', 'joomla'))
		{
			return true;
		}

		$form->loadFile('actionlogs', false);
	}

	/**
	 * Runs on content preparation
	 *
	 * @param   string  $context  The context for the data
	 * @param   object  $data     An object containing the data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareData($context, $data)
	{
		if (!in_array($context, array('com_users.profile', 'com_admin.profile', 'com_users.user')))
		{
			return true;
		}

		if (is_array($data))
		{
			$data = (object) $data;
		}

		if (!User::getInstance($data->id)->authorise('core.admin'))
		{
			return true;
		}

		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('notify', 'extensions')))
			->from($this->db->quoteName('#__action_logs_users'))
			->where($this->db->quoteName('user_id') . ' = ' . (int) $data->id);

		try
		{
			$values = $this->db->setQuery($query)->loadObject();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		if (!$values)
		{
			return true;
		}

		$data->actionlogs                       = new StdClass;
		$data->actionlogs->actionlogsNotify     = $values->notify;
		$data->actionlogs->actionlogsExtensions = $values->extensions;

		if (!HTMLHelper::isRegistered('users.actionlogsNotify'))
		{
			HTMLHelper::register('users.actionlogsNotify', array(__CLASS__, 'renderActionlogsNotify'));
		}

		if (!HTMLHelper::isRegistered('users.actionlogsExtensions'))
		{
			HTMLHelper::register('users.actionlogsExtensions', array(__CLASS__, 'renderActionlogsExtensions'));
		}

		return true;
	}

	/**
	 * Runs after the HTTP response has been sent to the client and delete log records older than certain days
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRespond()
	{
		$daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);

		if ($daysToDeleteAfter <= 0)
		{
			return;
		}

		// The delete frequency will be once per day
		$deleteFrequency = 3600 * 24;

		// Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if (abs($now - $last) < $deleteFrequency)
		{
			return;
		}

		// Update last run status
		$this->params->set('lastrun', $now);

		$db    = $this->db;
		$query = $db->getQuery(true)
			->update($db->qn('#__extensions'))
			->set($db->qn('params') . ' = ' . $db->q($this->params->toString('JSON')))
			->where($db->qn('type') . ' = ' . $db->q('plugin'))
			->where($db->qn('folder') . ' = ' . $db->q('system'))
			->where($db->qn('element') . ' = ' . $db->q('actionlogs'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		$daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);
		$now = $db->quote(Factory::getDate()->toSql());

		if ($daysToDeleteAfter > 0)
		{
			$conditions = array($db->quoteName('log_date') . ' < ' . $query->dateAdd($now, -1 * $daysToDeleteAfter, ' DAY'));

			$query->clear()
				->delete($db->quoteName('#__action_logs'))->where($conditions);
			$db->setQuery($query);

			try
			{
				$db->execute();
			}
			catch (RuntimeException $e)
			{
				// Ignore it
				return;
			}
		}
	}

	/**
	 * Utility method to act on a user after it has been saved.
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isNew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the database.
	 * @param   string   $msg      Message.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($user, $isNew, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		// Clear access rights in case user groups were changed.
		$userObject = new User($user['id']);
		$userObject->clearAccessRights();
		$authorised = $userObject->authorise('core.admin');

		$query = $this->db->getQuery(true)
			->select('COUNT(*)')
			->from($this->db->quoteName('#__action_logs_users'))
			->where($this->db->quoteName('user_id') . ' = ' . (int) $user['id']);

		try
		{
			$exists = (bool) $this->db->setQuery($query)->loadResult();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		// If preferences don't exist, insert.
		if (!$exists && $authorised && isset($user['actionlogs']))
		{
			$values  = array((int) $user['id'], (int) $user['actionlogs']['actionlogsNotify']);
			$columns = array('user_id', 'notify');

			if (isset($user['actionlogs']['actionlogsExtensions']))
			{
				$values[]  = $this->db->quote(json_encode($user['actionlogs']['actionlogsExtensions']));
				$columns[] = 'extensions';
			}

			$query = $this->db->getQuery(true)
				->insert($this->db->quoteName('#__action_logs_users'))
				->columns($this->db->quoteName($columns))
				->values(implode(',', $values));
		}
		elseif ($exists && $authorised && isset($user['actionlogs']))
		{
			// Update preferences.
			$values = array($this->db->quoteName('notify') . ' = ' . (int) $user['actionlogs']['actionlogsNotify']);

			if (isset($user['actionlogs']['actionlogsExtensions']))
			{
				$values[] = $this->db->quoteName('extensions') . ' = ' . $this->db->quote(json_encode($user['actionlogs']['actionlogsExtensions']));
			}

			$query = $this->db->getQuery(true)
				->update($this->db->quoteName('#__action_logs_users'))
				->set($values)
				->where($this->db->quoteName('user_id') . ' = ' . (int) $user['id']);
		}
		elseif ($exists && !$authorised)
		{
			// Remove preferences if user is not authorised.
			$query = $this->db->getQuery(true)
				->delete($this->db->quoteName('#__action_logs_users'))
				->where($this->db->quoteName('user_id') . ' = ' . (int) $user['id']);
		}

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Removes user preferences
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$query = $this->db->getQuery(true)
			->delete($this->db->quoteName('#__action_logs_users'))
			->where($this->db->quoteName('user_id') . ' = ' . (int) $user['id']);

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1))
	{
		$conf = Factory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $clientId)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $clientId ? JPATH_ADMINISTRATOR . '/cache' :
							$conf->get('cache_path', JPATH_SITE . '/cache')
					);

					$cache = Cache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}

	/**
	 * Method to render a value.
	 *
	 * @param   integer|string  $value  The value (0 or 1).
	 *
	 * @return  string  The rendered value.
	 *
	 * @since   3.9.16
	 */
	public static function renderActionlogsNotify($value)
	{
		return Text::_($value ? 'JYES' : 'JNO');
	}

	/**
	 * Method to render a list of extensions.
	 *
	 * @param   array|string  $extensions  Array of extensions or an empty string if none selected.
	 *
	 * @return  string  The rendered value.
	 *
	 * @since   3.9.16
	 */
	public static function renderActionlogsExtensions($extensions)
	{
		// No extensions selected.
		if (!$extensions)
		{
			return Text::_('JNONE');
		}

		// Load the helper.
		JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR . '/components/com_actionlogs/helpers/actionlogs.php');

		foreach ($extensions as &$extension)
		{
			// Load extension language files and translate extension name.
			ActionlogsHelper::loadTranslationFiles($extension);
			$extension = Text::_($extension);
		}

		return implode(', ', $extensions);
	}
}
PK��#]؞��� system/actionlogs/actionlogs.xmlnu�[���<?xml version="1.0" encoding="UTF-8"?>
<extension version="3.9" type="plugin" group="system" method="upgrade">
	<name>PLG_SYSTEM_ACTIONLOGS</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_SYSTEM_ACTIONLOGS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="actionlogs">actionlogs.php</filename>
		<folder>forms</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_actionlogs.ini</language>
		<language tag="en-GB">en-GB.plg_system_actionlogs.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="logDeletePeriod"
					type="number"
					label="PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD"
					description="PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD_DESC"
					default="0"
					min="0"
					filter="int"
					validate="number"
				/>
				<field
					name="lastrun"
					type="hidden"
					default="0"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]��<__&system/actionlogs/forms/actionlogs.xmlnu�[���<?xml version="1.0" encoding="UTF-8"?>
<form>
	<fieldset name="actionlogs" label="PLG_SYSTEM_ACTIONLOGS_OPTIONS" addfieldpath="/administrator/components/com_actionlogs/models/fields">
		<fields name="actionlogs">
			<field
				name="actionlogsNotify"
				type="radio"
				label="PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS"
				description="PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS_DESC"
				class="btn-group btn-group-yesno"
				default="0"
				filter="integer"
				required="true"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
			<field
				name="actionlogsExtensions"
				type="logtype"
				label="PLG_SYSTEM_ACTIONLOGS_EXTENSIONS_NOTIFICATIONS"
				description="PLG_SYSTEM_ACTIONLOGS_EXTENSIONS_NOTIFICATIONS_DESC"
				multiple="true"
				validate="options"
				showon="actionlogsNotify:1"
			/>
		</fields>
	</fieldset>
</form>
PK��#]�����'system/actionlogs/forms/information.xmlnu�[���<?xml version="1.0" encoding="UTF-8"?>
<form>
	<fields name="params">
		<fieldset name="information" label="PLG_SYSTEM_ACTIONLOGS_OPTIONS" addfieldpath="/administrator/components/com_actionlogs/models/fields">
			<field
				name="Information"
				type="plugininfo"
				label="PLG_SYSTEM_ACTIONLOGS_INFO_LABEL"
				description="PLG_SYSTEM_ACTIONLOGS_INFO_DESC"
			/>
		</fieldset>
	</fields>
</form>
PK��#]�)��system/actionlogs/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��system/languagefilter/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�ա�b�b(system/languagefilter/languagefilter.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.languagefilter
 *
 * @copyright   (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;
use Joomla\String\StringHelper;

JLoader::register('MenusHelper', JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php');

/**
 * Joomla! Language Filter Plugin.
 *
 * @since  1.6
 */
class PlgSystemLanguageFilter extends JPlugin
{
	/**
	 * The routing mode.
	 *
	 * @var    boolean
	 * @since  2.5
	 */
	protected $mode_sef;

	/**
	 * Available languages by sef.
	 *
	 * @var    array
	 * @since  1.6
	 */
	protected $sefs;

	/**
	 * Available languages by language codes.
	 *
	 * @var    array
	 * @since  2.5
	 */
	protected $lang_codes;

	/**
	 * The current language code.
	 *
	 * @var    string
	 * @since  3.4.2
	 */
	protected $current_lang;

	/**
	 * The default language code.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $default_lang;

	/**
	 * The logged user language code.
	 *
	 * @var    string
	 * @since  3.3.1
	 */
	private $user_lang_code;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.3
	 */
	protected $app;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   1.6
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$this->app = JFactory::getApplication();

		// Setup language data.
		$this->mode_sef     = $this->app->get('sef', 0);
		$this->sefs         = JLanguageHelper::getLanguages('sef');
		$this->lang_codes   = JLanguageHelper::getLanguages('lang_code');
		$this->default_lang = JComponentHelper::getParams('com_languages')->get('site', 'en-GB');

		// If language filter plugin is executed in a site page.
		if ($this->app->isClient('site'))
		{
			$levels = JFactory::getUser()->getAuthorisedViewLevels();

			foreach ($this->sefs as $sef => $language)
			{
				// @todo: In Joomla 2.5.4 and earlier access wasn't set. Non modified Content Languages got 0 as access value
				// we also check if frontend language exists and is enabled
				if (($language->access && !in_array($language->access, $levels))
					|| (!array_key_exists($language->lang_code, JLanguageHelper::getInstalledLanguages(0))))
				{
					unset($this->lang_codes[$language->lang_code], $this->sefs[$language->sef]);
				}
			}
		}
		// If language filter plugin is executed in an admin page (ex: JRoute site).
		else
		{
			// Set current language to default site language, fallback to en-GB if there is no content language for the default site language.
			$this->current_lang = isset($this->lang_codes[$this->default_lang]) ? $this->default_lang : 'en-GB';

			foreach ($this->sefs as $sef => $language)
			{
				if (!array_key_exists($language->lang_code, JLanguageHelper::getInstalledLanguages(0)))
				{
					unset($this->lang_codes[$language->lang_code]);
					unset($this->sefs[$language->sef]);
				}
			}
		}
	}

	/**
	 * After initialise.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onAfterInitialise()
	{
		$this->app->item_associations = $this->params->get('item_associations', 0);

		// We need to make sure we are always using the site router, even if the language plugin is executed in admin app.
		$router = JApplicationCms::getInstance('site')->getRouter('site');

		// Attach build rules for language SEF.
		$router->attachBuildRule(array($this, 'preprocessBuildRule'), JRouter::PROCESS_BEFORE);
		$router->attachBuildRule(array($this, 'buildRule'), JRouter::PROCESS_DURING);

		if ($this->mode_sef)
		{
			$router->attachBuildRule(array($this, 'postprocessSEFBuildRule'), JRouter::PROCESS_AFTER);
		}
		else
		{
			$router->attachBuildRule(array($this, 'postprocessNonSEFBuildRule'), JRouter::PROCESS_AFTER);
		}

		// Attach parse rules for language SEF.
		$router->attachParseRule(array($this, 'parseRule'), JRouter::PROCESS_DURING);
	}

	/**
	 * After route.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function onAfterRoute()
	{
		// Add custom site name.
		if ($this->app->isClient('site') && isset($this->lang_codes[$this->current_lang]) && $this->lang_codes[$this->current_lang]->sitename)
		{
			$this->app->set('sitename', $this->lang_codes[$this->current_lang]->sitename);
		}
	}

	/**
	 * Add build preprocess rule to router.
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function preprocessBuildRule(&$router, &$uri)
	{
		$lang = $uri->getVar('lang', $this->current_lang);
		$uri->setVar('lang', $lang);

		if (isset($this->sefs[$lang]))
		{
			$lang = $this->sefs[$lang]->lang_code;
			$uri->setVar('lang', $lang);
		}
	}

	/**
	 * Add build rule to router.
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function buildRule(&$router, &$uri)
	{
		$lang = $uri->getVar('lang');

		if (isset($this->lang_codes[$lang]))
		{
			$sef = $this->lang_codes[$lang]->sef;
		}
		else
		{
			$sef = $this->lang_codes[$this->current_lang]->sef;
		}

		if ($this->mode_sef
			&& (!$this->params->get('remove_default_prefix', 0)
			|| $lang !== $this->default_lang
			|| $lang !== $this->current_lang))
		{
			$uri->setPath($uri->getPath() . '/' . $sef . '/');
		}
	}

	/**
	 * postprocess build rule for SEF URLs
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function postprocessSEFBuildRule(&$router, &$uri)
	{
		$uri->delVar('lang');
	}

	/**
	 * postprocess build rule for non-SEF URLs
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function postprocessNonSEFBuildRule(&$router, &$uri)
	{
		$lang = $uri->getVar('lang');

		if (isset($this->lang_codes[$lang]))
		{
			$uri->setVar('lang', $this->lang_codes[$lang]->sef);
		}
	}

	/**
	 * Add parse rule to router.
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function parseRule(&$router, &$uri)
	{
		// Did we find the current and existing language yet?
		$found = false;

		// Are we in SEF mode or not?
		if ($this->mode_sef)
		{
			$path = $uri->getPath();
			$parts = explode('/', $path);

			$sef = StringHelper::strtolower($parts[0]);

			// Do we have a URL Language Code ?
			if (!isset($this->sefs[$sef]))
			{
				// Check if remove default URL language code is set
				if ($this->params->get('remove_default_prefix', 0))
				{
					if ($parts[0])
					{
						// We load a default site language page
						$lang_code = $this->default_lang;
					}
					else
					{
						// We check for an existing language cookie
						$lang_code = $this->getLanguageCookie();
					}
				}
				else
				{
					$lang_code = $this->getLanguageCookie();
				}

				// No language code. Try using browser settings or default site language
				if (!$lang_code && $this->params->get('detect_browser', 0) == 1)
				{
					$lang_code = JLanguageHelper::detectLanguage();
				}

				if (!$lang_code)
				{
					$lang_code = $this->default_lang;
				}

				if ($lang_code === $this->default_lang && $this->params->get('remove_default_prefix', 0))
				{
					$found = true;
				}
			}
			else
			{
				// We found our language
				$found = true;
				$lang_code = $this->sefs[$sef]->lang_code;

				// If we found our language, but its the default language and we don't want a prefix for that, we are on a wrong URL.
				// Or we try to change the language back to the default language. We need a redirect to the proper URL for the default language.
				if ($lang_code === $this->default_lang && $this->params->get('remove_default_prefix', 0))
				{
					// Create a cookie.
					$this->setLanguageCookie($lang_code);

					$found = false;
					array_shift($parts);
					$path = implode('/', $parts);
				}

				// We have found our language and the first part of our URL is the language prefix
				if ($found)
				{
					array_shift($parts);

					// Empty parts array when "index.php" is the only part left.
					if (count($parts) === 1 && $parts[0] === 'index.php')
					{
						$parts = array();
					}

					$uri->setPath(implode('/', $parts));
				}
			}
		}
		// We are not in SEF mode
		else
		{
			$lang_code = $this->getLanguageCookie();

			if (!$lang_code && $this->params->get('detect_browser', 1))
			{
				$lang_code = JLanguageHelper::detectLanguage();
			}

			if (!isset($this->lang_codes[$lang_code]))
			{
				$lang_code = $this->default_lang;
			}
		}

		$lang = $uri->getVar('lang', $lang_code);

		if (isset($this->sefs[$lang]))
		{
			// We found our language
			$found = true;
			$lang_code = $this->sefs[$lang]->lang_code;
		}

		// We are called via POST or the nolangfilter url parameter was set. We don't care about the language
		// and simply set the default language as our current language.
		if ($this->app->input->getMethod() === 'POST'
			|| $this->app->input->get('nolangfilter', 0) == 1
			|| count($this->app->input->post) > 0
			|| count($this->app->input->files) > 0)
		{
			$found = true;

			if (!isset($lang_code))
			{
				$lang_code = $this->getLanguageCookie();
			}

			if (!$lang_code && $this->params->get('detect_browser', 1))
			{
				$lang_code = JLanguageHelper::detectLanguage();
			}

			if (!isset($this->lang_codes[$lang_code]))
			{
				$lang_code = $this->default_lang;
			}
		}

		// We have not found the language and thus need to redirect
		if (!$found)
		{
			// Lets find the default language for this user
			if (!isset($lang_code) || !isset($this->lang_codes[$lang_code]))
			{
				$lang_code = false;

				if ($this->params->get('detect_browser', 1))
				{
					$lang_code = JLanguageHelper::detectLanguage();

					if (!isset($this->lang_codes[$lang_code]))
					{
						$lang_code = false;
					}
				}

				if (!$lang_code)
				{
					$lang_code = $this->default_lang;
				}
			}

			if ($this->mode_sef)
			{
				// Use the current language sef or the default one.
				if ($lang_code !== $this->default_lang
					|| !$this->params->get('remove_default_prefix', 0))
				{
					$path = $this->lang_codes[$lang_code]->sef . '/' . $path;
				}

				$uri->setPath($path);

				if (!$this->app->get('sef_rewrite'))
				{
					$uri->setPath('index.php/' . $uri->getPath());
				}

				$redirectUri = $uri->base() . $uri->toString(array('path', 'query', 'fragment'));
			}
			else
			{
				$uri->setVar('lang', $this->lang_codes[$lang_code]->sef);
				$redirectUri = $uri->base() . 'index.php?' . $uri->getQuery();
			}

			// Set redirect HTTP code to "302 Found".
			$redirectHttpCode = 302;

			// If selected language is the default language redirect code is "301 Moved Permanently".
			if ($lang_code === $this->default_lang)
			{
				$redirectHttpCode = 301;

				// We cannot cache this redirect in browser. 301 is cachable by default so we need to force to not cache it in browsers.
				$this->app->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true);
				$this->app->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
				$this->app->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false);
				$this->app->setHeader('Pragma', 'no-cache');
				$this->app->sendHeaders();
			}

			// Redirect to language.
			$this->app->redirect($redirectUri, $redirectHttpCode);
		}

		// We have found our language and now need to set the cookie and the language value in our system
		$array = array('lang' => $lang_code);
		$this->current_lang = $lang_code;

		// Set the request var.
		$this->app->input->set('language', $lang_code);
		$this->app->set('language', $lang_code);
		$language = JFactory::getLanguage();

		if ($language->getTag() !== $lang_code)
		{
			$language_new = JLanguage::getInstance($lang_code, (bool) $this->app->get('debug_lang'));

			foreach ($language->getPaths() as $extension => $files)
			{
				if (strpos($extension, 'plg_system') !== false)
				{
					$extension_name = substr($extension, 11);

					$language_new->load($extension, JPATH_ADMINISTRATOR)
					|| $language_new->load($extension, JPATH_PLUGINS . '/system/' . $extension_name);

					continue;
				}

				$language_new->load($extension);
			}

			JFactory::$language = $language_new;
			$this->app->loadLanguage($language_new);
		}

		// Create a cookie.
		if ($this->getLanguageCookie() !== $lang_code)
		{
			$this->setLanguageCookie($lang_code);
		}

		return $array;
	}

	/**
	 * Reports the privacy related capabilities for this plugin to site administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_SYSTEM_LANGUAGEFILTER') => array(
				JText::_('PLG_SYSTEM_LANGUAGEFILTER_PRIVACY_CAPABILITY_LANGUAGE_COOKIE'),
			)
		);
	}

	/**
	 * Before store user method.
	 *
	 * Method is called before user data is stored in the database.
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isnew  True if a new user is stored.
	 * @param   array    $new    Holds the new user data.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onUserBeforeSave($user, $isnew, $new)
	{
		if (array_key_exists('params', $user) && $this->params->get('automatic_change', 1) == 1)
		{
			$registry = new Registry($user['params']);
			$this->user_lang_code = $registry->get('language');

			if (empty($this->user_lang_code))
			{
				$this->user_lang_code = $this->current_lang;
			}
		}
	}

	/**
	 * After store user method.
	 *
	 * Method is called after user data is stored in the database.
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was succesfully stored in the database.
	 * @param   string   $msg      Message.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		if ($success && array_key_exists('params', $user) && $this->params->get('automatic_change', 1) == 1)
		{
			$registry = new Registry($user['params']);
			$lang_code = $registry->get('language');

			if (empty($lang_code))
			{
				$lang_code = $this->current_lang;
			}

			if ($lang_code === $this->user_lang_code || !isset($this->lang_codes[$lang_code]))
			{
				if ($this->app->isClient('site'))
				{
					$this->app->setUserState('com_users.edit.profile.redirect', null);
				}
			}
			else
			{
				if ($this->app->isClient('site'))
				{
					$this->app->setUserState('com_users.edit.profile.redirect', 'index.php?Itemid='
						. $this->app->getMenu()->getDefault($lang_code)->id . '&lang=' . $this->lang_codes[$lang_code]->sef
					);

					// Create a cookie.
					$this->setLanguageCookie($lang_code);
				}
			}
		}
	}

	/**
	 * Method to handle any login logic and report back to the subject.
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (remember, autoregister, group).
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   1.5
	 */
	public function onUserLogin($user, $options = array())
	{
		$menu = $this->app->getMenu();

		if ($this->app->isClient('site'))
		{
			if ($this->params->get('automatic_change', 1))
			{
				$assoc = JLanguageAssociations::isEnabled();
				$lang_code = $user['language'];

				// If no language is specified for this user, we set it to the site default language
				if (empty($lang_code))
				{
					$lang_code = $this->default_lang;
				}

				jimport('joomla.filesystem.folder');

				// The language has been deleted/disabled or the related content language does not exist/has been unpublished
				// or the related home page does not exist/has been unpublished
				if (!array_key_exists($lang_code, $this->lang_codes)
					|| !array_key_exists($lang_code, JLanguageMultilang::getSiteHomePages())
					|| !JFolder::exists(JPATH_SITE . '/language/' . $lang_code))
				{
					$lang_code = $this->current_lang;
				}

				// Try to get association from the current active menu item
				$active = $menu->getActive();

				$foundAssociation = false;

				/**
				 * Looking for associations.
				 * If the login menu item form contains an internal URL redirection,
				 * This will override the automatic change to the user preferred site language.
				 * In that case we use the redirect as defined in the menu item.
				 *  Otherwise we redirect, when available, to the user preferred site language.
				 */
				if ($active && !$active->params['login_redirect_url'])
				{
					if ($assoc)
					{
						$associations = MenusHelper::getAssociations($active->id);
					}

					// Retrieves the Itemid from a login form.
					$uri = new JUri($this->app->getUserState('users.login.form.return'));

					if ($uri->getVar('Itemid'))
					{
						// The login form contains a menu item redirection. Try to get associations from that menu item.
						// If any association set to the user preferred site language, redirect to that page.
						if ($assoc)
						{
							$associations = MenusHelper::getAssociations($uri->getVar('Itemid'));
						}

						if (isset($associations[$lang_code]) && $menu->getItem($associations[$lang_code]))
						{
							$associationItemid = $associations[$lang_code];
							$this->app->setUserState('users.login.form.return', 'index.php?Itemid=' . $associationItemid);
							$foundAssociation = true;
						}
					}
					elseif (isset($associations[$lang_code]) && $menu->getItem($associations[$lang_code]))
					{
						/**
						 * The login form does not contain a menu item redirection.
						 * The active menu item has associations.
						 * We redirect to the user preferred site language associated page.
						 */
						$associationItemid = $associations[$lang_code];
						$this->app->setUserState('users.login.form.return', 'index.php?Itemid=' . $associationItemid);
						$foundAssociation = true;
					}
					elseif ($active->home)
					{
						// We are on a Home page, we redirect to the user preferred site language Home page.
						$item = $menu->getDefault($lang_code);

						if ($item && $item->language !== $active->language && $item->language !== '*')
						{
							$this->app->setUserState('users.login.form.return', 'index.php?Itemid=' . $item->id);
							$foundAssociation = true;
						}
					}
				}

				if ($foundAssociation && $lang_code !== $this->current_lang)
				{
					// Change language.
					$this->current_lang = $lang_code;

					// Create a cookie.
					$this->setLanguageCookie($lang_code);

					// Change the language code.
					JFactory::getLanguage()->setLanguage($lang_code);
				}
			}
			else
			{
				if ($this->app->getUserState('users.login.form.return'))
				{
					$this->app->setUserState('users.login.form.return', JRoute::_($this->app->getUserState('users.login.form.return'), false));
				}
			}
		}
	}

	/**
	 * Method to add alternative meta tags for associated menu items.
	 *
	 * @return  void
	 *
	 * @since   1.7
	 */
	public function onAfterDispatch()
	{
		$doc = JFactory::getDocument();

		if ($this->app->isClient('site') && $this->params->get('alternate_meta', 1) && $doc->getType() === 'html')
		{
			$languages             = $this->lang_codes;
			$homes                 = JLanguageMultilang::getSiteHomePages();
			$menu                  = $this->app->getMenu();
			$active                = $menu->getActive();
			$levels                = JFactory::getUser()->getAuthorisedViewLevels();
			$remove_default_prefix = $this->params->get('remove_default_prefix', 0);
			$server                = JUri::getInstance()->toString(array('scheme', 'host', 'port'));
			$is_home               = false;
			$currentInternalUrl    = 'index.php?' . http_build_query($this->app->getRouter()->getVars());

			if ($active)
			{
				$active_link  = JRoute::_($active->link . '&Itemid=' . $active->id);
				$current_link = JRoute::_($currentInternalUrl);

				// Load menu associations
				if ($active_link === $current_link)
				{
					$associations = MenusHelper::getAssociations($active->id);
				}

				// Check if we are on the home page
				$is_home = ($active->home
					&& ($active_link === $current_link || $active_link === $current_link . 'index.php' || $active_link . '/' === $current_link));
			}

			// Load component associations.
			$option = $this->app->input->get('option');
			$cName = ucfirst(substr($option, 4)) . 'HelperAssociation';
			JLoader::register($cName, JPath::clean(JPATH_SITE . '/components/' . $option . '/helpers/association.php'));

			if (class_exists($cName) && is_callable(array($cName, 'getAssociations')))
			{
				$cassociations = call_user_func(array($cName, 'getAssociations'));
			}

			// For each language...
			foreach ($languages as $i => $language)
			{
				switch (true)
				{
					// Language without frontend UI || Language without specific home menu || Language without authorized access level
					case (!array_key_exists($i, JLanguageHelper::getInstalledLanguages(0))):
					case (!isset($homes[$i])):
					case (isset($language->access) && $language->access && !in_array($language->access, $levels)):
						unset($languages[$i]);
						break;

					// Home page
					case ($is_home):
						$language->link = JRoute::_('index.php?lang=' . $language->sef . '&Itemid=' . $homes[$i]->id);
						break;

					// Current language link
					case ($i === $this->current_lang):
						$language->link = JRoute::_($currentInternalUrl);
						break;

					// Component association
					case (isset($cassociations[$i])):
						$language->link = JRoute::_($cassociations[$i] . '&lang=' . $language->sef);
						break;

					// Menu items association
					// Heads up! "$item = $menu" here below is an assignment, *NOT* comparison
					case (isset($associations[$i]) && ($item = $menu->getItem($associations[$i]))):

						$language->link = JRoute::_('index.php?Itemid=' . $item->id . '&lang=' . $language->sef);
						break;

					// Too bad...
					default:
						unset($languages[$i]);
				}
			}

			// If there are at least 2 of them, add the rel="alternate" links to the <head>
			if (count($languages) > 1)
			{
				// Remove the sef from the default language if "Remove URL Language Code" is on
				if ($remove_default_prefix && isset($languages[$this->default_lang]))
				{
					$languages[$this->default_lang]->link
									= preg_replace('|/' . $languages[$this->default_lang]->sef . '/|', '/', $languages[$this->default_lang]->link, 1);
				}

				foreach ($languages as $i => $language)
				{
					$doc->addHeadLink($server . $language->link, 'alternate', 'rel', array('hreflang' => $i));
				}

				// Add x-default language tag
				if ($this->params->get('xdefault', 1))
				{
					$xdefault_language = $this->params->get('xdefault_language', $this->default_lang);
					$xdefault_language = ($xdefault_language === 'default') ? $this->default_lang : $xdefault_language;

					if (isset($languages[$xdefault_language]))
					{
						// Use a custom tag because addHeadLink is limited to one URI per tag
						$doc->addCustomTag('<link href="' . $server . $languages[$xdefault_language]->link . '" rel="alternate" hreflang="x-default" />');
					}
				}
			}
		}
	}

	/**
	 * Set the language cookie
	 *
	 * @param   string  $languageCode  The language code for which we want to set the cookie
	 *
	 * @return  void
	 *
	 * @since   3.4.2
	 */
	private function setLanguageCookie($languageCode)
	{
		// If is set to use language cookie for a year in plugin params, save the user language in a new cookie.
		if ((int) $this->params->get('lang_cookie', 0) === 1)
		{
			// Create a cookie with one year lifetime.
			$this->app->input->cookie->set(
				JApplicationHelper::getHash('language'),
				$languageCode,
				time() + 365 * 86400,
				$this->app->get('cookie_path', '/'),
				$this->app->get('cookie_domain', ''),
				$this->app->isHttpsForced(),
				true
			);
		}
		// If not, set the user language in the session (that is already saved in a cookie).
		else
		{
			JFactory::getSession()->set('plg_system_languagefilter.language', $languageCode);
		}
	}

	/**
	 * Get the language cookie
	 *
	 * @return  string
	 *
	 * @since   3.4.2
	 */
	private function getLanguageCookie()
	{
		// Is is set to use a year language cookie in plugin params, get the user language from the cookie.
		if ((int) $this->params->get('lang_cookie', 0) === 1)
		{
			$languageCode = $this->app->input->cookie->get(JApplicationHelper::getHash('language'));
		}
		// Else get the user language from the session.
		else
		{
			$languageCode = JFactory::getSession()->get('plg_system_languagefilter.language');
		}

		// Let's be sure we got a valid language code. Fallback to null.
		if (!array_key_exists($languageCode, $this->lang_codes))
		{
			$languageCode = null;
		}

		return $languageCode;
	}
}
PK��#]aVOuss(system/languagefilter/languagefilter.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_languagefilter</name>
	<author>Joomla! Project</author>
	<creationDate>July 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_LANGUAGEFILTER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="languagefilter">languagefilter.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_system_languagefilter.ini</language>
		<language tag="en-GB">en-GB.plg_system_languagefilter.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="detect_browser"
					type="list"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_DETECT_BROWSER_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_DETECT_BROWSER_DESC"
					default="0"
					filter="integer"
					>
					<option value="0">PLG_SYSTEM_LANGUAGEFILTER_SITE_LANGUAGE</option>
					<option value="1">PLG_SYSTEM_LANGUAGEFILTER_BROWSER_SETTINGS</option>
				</field>

				<field
					name="automatic_change"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_AUTOMATIC_CHANGE_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_AUTOMATIC_CHANGE_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="item_associations"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ITEM_ASSOCIATIONS_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ITEM_ASSOCIATIONS_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="alternate_meta"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ALTERNATE_META_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ALTERNATE_META_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="xdefault"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					showon="alternate_meta:1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="xdefault_language"
					type="contentlanguage"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LANGUAGE_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LANGUAGE_DESC"
					default="default"
					showon="alternate_meta:1[AND]xdefault:1"
					>
					<option value="default">PLG_SYSTEM_LANGUAGEFILTER_OPTION_DEFAULT_LANGUAGE</option>
				</field>

				<field
					name="remove_default_prefix"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_REMOVE_DEFAULT_PREFIX_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_REMOVE_DEFAULT_PREFIX_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="lang_cookie"
					type="list"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_COOKIE_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_COOKIE_DESC"
					default="0"
					filter="integer"
					>
					<option value="1">PLG_SYSTEM_LANGUAGEFILTER_OPTION_YEAR</option>
					<option value="0">PLG_SYSTEM_LANGUAGEFILTER_OPTION_SESSION</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>PK��#]�R��((system/jce/js/media.jsnu�[���/* jce - 2.9.38 | 2023-06-27 | https://www.joomlacontenteditor.net | Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved | GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html */
!function($){function uid(){var i,guid=(new Date).getTime().toString(32);for(i=0;i<5;i++)guid+=Math.floor(65535*Math.random()).toString(32);return"wf_"+guid+(counter++).toString(32)}function parseUrl(url){var data={};return url?(url=url.substring(url.indexOf("?")+1),$.each(url.replace(/\+/g," ").split("&"),function(i,value){var val,param=value.split("="),key=decodeURIComponent(param[0]);2===param.length&&(val=decodeURIComponent(param[1]),"string"==typeof val&&val.length&&(data[key]=val))}),data):data}function upload(url,file){return new Promise(function(resolve,reject){var xhr=new XMLHttpRequest,formData=new FormData;xhr.upload&&(xhr.upload.onprogress=function(e){e.lengthComputable&&(file.loaded=Math.min(file.size,e.loaded))}),xhr.onreadystatechange=function(){4==xhr.readyState&&(200===xhr.status?resolve(xhr.responseText):reject(),file=formData=null)};var name=file.target_name||file.name;name=name.replace(/[\+\\\/\?\#%&<>"\'=\[\]\{\},;@\^\(\)\xa3\u20ac$~]/g,"");var args={method:"upload",id:uid(),inline:1,name:name},Joomla=window.Joomla||{};if(Joomla.getOptions){var token=Joomla.getOptions("csrf.token")||"";token&&(args[token]=1)}xhr.open("post",url,!0),xhr.setRequestHeader("X-Requested-With","XMLHttpRequest"),$.each(args,function(key,value){formData.append(key,value)}),formData.append("file",file),xhr.send(formData)})}function checkMimeType(file,filter){filter=filter.replace(/[^\w_,]/gi,"").toLowerCase();var map={images:"jpg,jpeg,png,apng,gif,webp",media:"avi,wmv,wm,asf,asx,wmx,wvx,mov,qt,mpg,mpeg,m4a,m4v,swf,dcr,rm,ra,ram,divx,mp4,ogv,ogg,webm,flv,f4v,mp3,ogg,wav,xap",html:"html,htm,txt",files:"doc,docx,dot,dotx,ppt,pps,pptx,ppsx,xls,xlsx,gif,jpeg,jpg,png,webp,apng,pdf,zip,tar,gz,swf,rar,mov,mp4,m4a,flv,mkv,webm,ogg,ogv,qt,wmv,asx,asf,avi,wav,mp3,aiff,oga,odt,odg,odp,ods,odf,rtf,txt,csv,htm,html"},mimes=map[filter]||filter;return new RegExp(".("+mimes.split(",").join("|")+")$","i").test(file.name)}function getModalURL(elm){var url="",$wrapper=$(elm).parents(".field-media-wrapper"),inst=$wrapper.data("fieldMedia")||$wrapper.get(0);return inst&&(url=inst.options?inst.options.url||"":inst.getAttribute("data-url")||inst.getAttribute("url")||""),url||$(elm).siblings("a.modal").attr("href")||""}function isAdmin(value){return value&&value.indexOf("/administrator/")!=-1}function getBasePath(elm){var path="",$wrapper=$(elm).parents(".field-media-wrapper"),inst=$wrapper.data("fieldMedia")||$wrapper.get(0);return inst&&(path=inst.options?inst.options.basepath||"":inst.basePath||""),path=path||$(elm).data("basepath")||"",path&&!isAdmin(path)&&isAdmin(document.location.href)&&(path+="administrator/"),path}function createElementMedia(elm,options){if(0!=$(elm).is("joomla-field-media, .wf-media-wrapper-custom")&&0!=$(elm).hasClass("wf-media-wrapper-custom")){var modalElement=$(".joomla-modal",elm).get(0);modalElement&&window.bootstrap&&window.bootstrap.Modal&&(Joomla.initialiseModal(modalElement,{isJoomla:!0}),$(".button-select",elm).on("click",function(e){e.preventDefault(),modalElement.open()})),$(".button-clear",elm).on("click",function(e){e.preventDefault(),$(".wf-media-input",elm).val("").trigger("change")}),$(".wf-media-input",elm).not(".wf-media-input-converted").on("change",function(){var path=Joomla.getOptions("system.paths",{}).root||"",src="";isImage(this.value)&&(src=path+"/"+this.value),$(".field-media-preview img",elm).attr("src",src)}).trigger("change")}}function updateMediaUrl(row,options,repeatable){$(row).find(".field-media-wrapper").add(row).each(function(){if($(this).find(".wf-media-input-upload").length&&!repeatable)return!0;var $inp=$(this).find(".field-media-input"),id=$inp.attr("id");if(!id)return!0;id=id.replace("rowX","row"+$(row).index()),createElementMedia(this,options),$(this).addClass("wf-media-wrapper");var dataUrl=$(this).data("url")||$(this).attr("url")||"",$linkBtn=$(this).find('a[href*="index.php?option=com_media"].modal.btn');$linkBtn.length&&!dataUrl&&(dataUrl=$linkBtn.attr("href")||"");var params=parseUrl(dataUrl),mediatype="images",plugin=params.plugin?params.plugin:"";params.mediatype?mediatype=params.mediatype:"files"==params.view&&(mediatype="files");var url=getBasePath($inp)+"index.php?option=com_jce&task=mediafield.display&plugin="+plugin+"&fieldid="+id+"&mediatype="+mediatype;if(options.context&&(url+="&context="+options.context),$(this).data("url")&&$(this).data("url",url),$(this).is("joomla-field-media, .wf-media-wrapper-custom")){$(this).attr("url",url);var ifrHtml=Joomla.sanitizeHtml('<iframe src="'+url+'" class="iframe" title="" width="100%" height="100%"></iframe>',{iframe:["src","class","title","width","height"]});$(this).find(".joomla-modal").attr("data-url",url).attr("data-iframe",ifrHtml)}$linkBtn.length&&$linkBtn.attr("href",url)})}function cleanInputValue(elm){var val=$(elm).val()||"";val.indexOf("#joomlaImage")!=-1&&(val=val.substring(0,val.indexOf("#")),$(elm).val(val).attr("value",val))}function isImage(value){return value&&/\.(jpg|jpeg|png|gif|svg|apng|webp)$/.test(value)}var counter=0;$.fn.WfMediaUpload=function(){return this.each(function(){function insertFile(value){var $wrapper=$(elm).parents(".field-media-wrapper"),inst=$wrapper.data("fieldMedia")||$wrapper.get(0);return inst&&inst.setValue?inst.setValue(value):$(elm).val(value).trigger("change"),!0}function uploadAndInsert(url,file){if(!file.name)return!1;var params=parseUrl(url),url=getBasePath(elm)+"index.php?option=com_jce",validParams=["task","context","plugin","filter","mediatype"],filter=params.filter||params.mediatype||"images";return checkMimeType(file,filter)?(params.task="plugin.rpc",$.each(params,function(key,value){$.inArray(key,validParams)===-1&&delete params[key]}),url+="&"+$.param(params),$(elm).prop("disabled",!0).addClass("wf-media-upload-busy"),void upload(url,file).then(function(response){$(elm).prop("disabled",!1).removeAttr("disabled").removeClass("wf-media-upload-busy");try{var o=JSON.parse(response),error="Unable to upload file";if($.isPlainObject(o)){o.error&&(error=o.error.message||error);var r=o.result;if(r){var files=r.files||[],item=files.length?files[0]:{};if(item.file)return insertFile(item.file)}}alert(error)}catch(e){alert("The server returned an invalid JSON response")}},function(){return $(elm).prop("disabled",!1).removeAttr("disabled").removeClass("wf-media-upload-busy"),!1})):(alert("The selected file is not supported."),!1)}var elm=this,url=getModalURL(elm);if(!url)return!1;var $uploadBtn=$('<a title="Upload" role="button" class="btn btn-outline-secondary wf-media-upload-button" aria-label="Upload"><i role="presentation" class="icon-upload"></i><input type="file" aria-hidden="true" /></a>');$('input[type="file"]',$uploadBtn).on("change",function(e){if(e.preventDefault(),this.files){var file=this.files[0];file&&uploadAndInsert(url,file)}});var $selectBtn=$(elm).parent().find(".button-select, .modal.btn");$uploadBtn.insertAfter($selectBtn),$(elm).on("drag dragstart dragend dragover dragenter dragleave drop",function(e){e.preventDefault(),e.stopPropagation()}).on("dragover dragenter",function(e){$(this).addClass("wf-media-upload-hover")}).on("dragleave",function(e){$(this).removeClass("wf-media-upload-hover")}).on("drop",function(e){var dataTransfer=e.originalEvent.dataTransfer;if(dataTransfer&&dataTransfer.files&&dataTransfer.files.length){var file=dataTransfer.files[0];file&&uploadAndInsert(url,file)}$(this).removeClass("wf-media-upload-hover")})})},$(document).ready(function($){function canProcessField(elm){return options.convert_mediafield||$(elm).find(".wf-media-input").length}var options=Joomla.getOptions("plg_system_jce",{});$("[data-wf-converted]").addClass("wf-media-input-converted"),$(".wf-media-input-converted").addClass("wf-media-input"),$(".wf-media-input").parents(".field-media-wrapper, .fc-field-value-properties-box").addClass("wf-media-wrapper"),options.convert_mediafield&&$(".field-media-wrapper, .fc-field-value-properties-box").not(".wf-media-wrapper").addClass("wf-media-wrapper").find(".field-media-input").addClass("wf-media-input wf-media-input-converted"),$(".wf-media-input").removeAttr("readonly"),$(".wf-media-input").parents(".subform-repeatable-group").each(function(i,row){updateMediaUrl(row,options,!0)}),$("joomla-field-media.wf-media-wrapper").each(function(){var field=this;if(field.inputElement){if($(this).find("input.wf-media-input-converted").length){updateMediaUrl(this,options,!0);var setValueFunction=field.setValue||function(){};return void(field.setValue=function(value,data){if(field.markValid){if(field.markValid(),value&&value.indexOf("://")===-1){var parts=value.split("/"),base=parts.shift();value+="#joomlaImage://local-"+base+"/"+parts.join("/"),data&&"object"==typeof data&&(value+="?width="+data.width+"&height="+data.height)}setValueFunction(value)}})}cleanInputValue(field.inputElement);var markValidFunction=field.markValid||function(){};field.markValid=function(){cleanInputValue(this.inputElement),field.querySelector('label[for="'+this.inputElement.id+'"]')&&markValidFunction.apply(this)},field.inputElement.addEventListener("change",function(e){e.stopImmediatePropagation(),cleanInputValue(this),field.querySelector('label[for="'+this.id+'"]')&&markValidFunction.apply(this),field.updatePreview(),$(document).trigger("t4:media-selected",{selectedUrl:field.basePath+this.value})},!0)}updateMediaUrl(this,options)}),$(".wf-media-wrapper-custom").each(function(){updateMediaUrl(this,options,!0)}),$(document).on("subform-row-add",function(evt,row){var originalEvent=evt.originalEvent;originalEvent&&originalEvent.detail&&(row=originalEvent.detail.row||row),canProcessField(row)&&(options.convert_mediafield&&$(row).find(".field-media-input").addClass("wf-media-input wf-media-input-converted"),$(row).find(".wf-media-input").removeAttr("readonly").addClass("wf-media-input-active"),updateMediaUrl(row,options,!0),$(row).find(".wf-media-input-upload").WfMediaUpload())}),$(".wf-media-input-upload").not('[name*="media-repeat"]').WfMediaUpload(),$(".wf-media-wrapper .modal-header h3").html("&nbsp;")})}(jQuery);PK��#]��}�]]system/jce/jce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="system" method="upgrade">
  <name>plg_system_jce</name>
  <version>2.9.38</version>
  <creationDate>27-06-2023</creationDate>
  <author>Ryan Demmer</author>
  <authorEmail>info@joomlacontenteditor.net</authorEmail>
  <authorUrl>http://www.joomlacontenteditor.net</authorUrl>
  <copyright>Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved</copyright>
  <license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
  <description>PLG_SYSTEM_JCE_XML_DESCRIPTION</description>
  <files folder="plugins/system/jce">
    <file plugin="jce">jce.php</file>
    <folder>css</folder>
    <folder>js</folder>
    <folder>templates</folder>
  </files>
  <languages folder="administrator/language/en-GB">
    <language tag="en-GB">en-GB.plg_system_jce.ini</language>
    <language tag="en-GB">en-GB.plg_system_jce.sys.ini</language>
  </languages>

  <config>
    <fields name="params">
      <fieldset name="options">
        <field name="column_styles" type="radio" default="1" label="PLG_SYSTEM_JCE_COLUMN_STYLES_LABEL" description="PLG_SYSTEM_JCE_COLUMN_STYLES_DESC" class="btn-group btn-group-yesno">
          <option value="1">JYES</option>
          <option value="0">JNO</option>
        </field>
      </fieldset>
    </fields>
  </config>

</extension>
PK��#]mP��$($(system/jce/jce.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2015 Ryan Demmer. All rights reserved
 * @copyright   Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;

/**
 * JCE.
 *
 * @since       2.5.5
 */
class PlgSystemJce extends CMSPlugin
{
    /**
     * Flag to set / check if media assests have been loaded
     *
     * @var boolean
     */
    private $mediaLoaded = false;
    
    public function onPlgSystemJceContentPrepareForm($form, $data)
    {
        return $this->onContentPrepareForm($form, $data);
    }

    private function getMediaRedirectOptions()
    {
        $app = Factory::getApplication();

        require_once JPATH_ADMINISTRATOR . '/components/com_jce/helpers/browser.php';

        $id = $app->input->get('fieldid', '');
        $mediatype = $app->input->getVar('mediatype', $app->input->getVar('view', 'images'));
        $context = $app->input->getVar('context', '');
        $plugin = $app->input->getCmd('plugin', '');

        $options = WFBrowserHelper::getMediaFieldOptions(array(
            'element' => $id,
            'converted' => true,
            'mediatype' => $mediatype,
            'context' => $context,
            'plugin' => $plugin,
        ));

        if (empty($options['url'])) {
            return false;
        }

        return $options;
    }

    private function redirectMedia()
    {
        $options = $this->getMediaRedirectOptions();

        if ($options && isset($options['url'])) {
            Factory::getApplication()->redirect($options['url']);
        }
    }

    private function isEditorEnabled()
    {
        return ComponentHelper::isEnabled('com_jce') && PluginHelper::isEnabled('editors', 'jce');
    }

    private function canRedirectMedia()
    {
        $app = Factory::getApplication();
        $params = ComponentHelper::getParams('com_jce');

        // must have fieldid
        if (!$app->input->get('fieldid')) {
            return false;
        }

        // jce converted mediafield
        if ($app->input->getCmd('option') == 'com_jce' && $app->input->getCmd('task') == 'mediafield.display') {
            return true;
        }

        if ((bool) $params->get('replace_media_manager', 1) == true) {
            // flexi-content mediafield
            if ($app->input->getCmd('option') == 'com_media' && $app->input->getCmd('asset') == 'com_flexicontent') {
                return true;
            }
        }

        return false;
    }

    public function onAfterRoute()
    {
        if (false == $this->isEditorEnabled()) {
            return false;
        }

        if ($this->canRedirectMedia() && $this->isEditorEnabled()) {
            // redirect to file browser
            $this->redirectMedia();
        }
    }

    public function onAfterDispatch()
    {
        $app = Factory::getApplication();

        // only in "site"
        if ($app->getClientId() !== 0) {
            return;
        }

        $document = Factory::getDocument();

        // must be an html doctype
        if($document->getType() !== 'html') {
            return true;
        }

        // only if enabled
        if ((int) $this->params->get('column_styles', 1)) {
            $hash = md5_file(__DIR__ . '/css/content.css');
            $document->addStyleSheet(JURI::root(true) . '/plugins/system/jce/css/content.css?' . $hash);
        }
    }

    public function onWfContentPreview($context, &$article, &$params, $page)
    {
        $article->text = '<style type="text/css">@import url("' . JURI::root(true) . '/plugins/system/jce/css/content.css");</style>' . $article->text;
    }

    private function loadMediaFiles($form, $replace_media_manager = true)
    {
        if ($this->mediaLoaded) {
            return;
        }
        
        $app = Factory::getApplication();

        $option = $app->input->getCmd('option');
        $component = ComponentHelper::getComponent($option);

        $document = JFactory::getDocument();

        $document->addScriptOptions('plg_system_jce', array(
            'convert_mediafield' => $replace_media_manager,
            'context' => $component->id,
        ), true);

        $form->addFieldPath(JPATH_PLUGINS . '/fields/mediajce/fields');

        // Include jQuery
        HTMLHelper::_('jquery.framework');

        $document = JFactory::getDocument();
        $document->addScript(JURI::root(true) . '/plugins/system/jce/js/media.js', array('version' => 'auto'));
        $document->addStyleSheet(JURI::root(true) . '/plugins/system/jce/css/media.css', array('version' => 'auto'));

        $this->mediaLoaded = true;
    }

    public function onCustomFieldsPrepareDom($field, $fieldset, $form)
    {
        if ($field->type == 'mediajce') {
            $this->loadMediaFiles($form);
        }
    }

    /**
     * adds additional fields to the user editing form.
     *
     * @param JForm $form The form to be altered
     * @param mixed $data The associated data for the form
     *
     * @return bool
     *
     * @since   2.5.20
     */
    public function onContentPrepareForm($form, $data)
    {
        $app = Factory::getApplication();
        $docType = Factory::getDocument()->getType();

        // must be an html doctype
        if($docType !== 'html') {
            return true;
        }

        $version = new Joomla\CMS\Version();

        // Joomla 3.10 or later...
        if (!$version->isCompatible('3.9')) {
            return true;
        }

        if (!($form instanceof Form)) {
            $this->_subject->setError('JERROR_NOT_A_FORM');
            return false;
        }

        // editor not enabled
        if (false == $this->isEditorEnabled()) {
            return true;
        }

        // Get File Browser options
        $options = $this->getMediaRedirectOptions();

        // not enabled
        if (false == $options) {
            return true;
        }

        $params = ComponentHelper::getParams('com_jce');

        $hasMedia = false;
        $fields = $form->getFieldset();

        // should the Joomla Media field be converted?
        $replace_media_manager = (bool) $params->get('replace_media_manager', 1) && $options['converted'];

        foreach ($fields as $field) {
            if (method_exists($field, 'getAttribute') === false) {
                continue;
            }

            $name = $field->getAttribute('name');

            // avoid processing twice
            if ($form->getFieldAttribute($name, 'class') && strpos($form->getFieldAttribute($name, 'class'), 'wf-media-input') !== false) {
                continue;
            }

            $type = $field->getAttribute('type');

            if ($type) {
                // jce media field
                if (strtolower($type) == 'mediajce' || strtolower($type) == 'extendedmedia') {
                    $hasMedia = true;
                }

                // joomla media field and flexi-content converted media field
                if (strtolower($type) == 'media' || strtolower($type) == 'fcmedia') {

                    // media replacement disabled, skip...
                    if ($replace_media_manager == false) {
                        continue;
                    }

                    $group = (string) $field->group;
                    $form->setFieldAttribute($name, 'type', 'mediajce', $group);
                    $form->setFieldAttribute($name, 'converted', '1', $group);

                    // set converted attribute flag instead of class attribute (extension conflict?)
                    $form->setFieldAttribute($name, 'data-wf-converted', '1', $group);

                    $hasMedia = true;
                }
            }
        }

        // form has a media field
        if ($hasMedia) {
            $this->loadMediaFiles($form, $replace_media_manager);
        }

        return true;
    }

    public function onBeforeWfEditorLoad()
    {
        $items = glob(__DIR__ . '/templates/*.php');

        $app = Factory::getApplication();

        if (method_exists($app, 'getDispatcher')) {
            $dispatcher = Factory::getApplication()->getDispatcher();
        } else {
            $dispatcher = JEventDispatcher::getInstance();
        }

        foreach ($items as $item) {
            $name = basename($item, '.php');

            $className = 'WfTemplate' . ucfirst($name);

            require_once $item;

            if (class_exists($className)) {
                // Instantiate and register the event
                $plugin = new $className($dispatcher);

                if ($plugin instanceof \Joomla\CMS\Extension\PluginInterface) {
                    $plugin->registerListeners();
                }
            }
        }
    }

    public function onWfPluginInit($instance)
    {
        $app = Factory::getApplication();
        $user = Factory::getUser();

        // set mediatype values for Template Manager parameters
        if ($app->input->getCmd('plugin') == 'browser.templatemanager') {

            // only in "admin"
            if ($app->getClientId() !== 1) {
                return;
            }

            // restrict to admin with component manage access
            if (!$user->authorise('core.manage', 'com_jce')) {
                return false;
            }

            // check for element and standalone should indicate mediafield
            if ($app->input->getVar('element') && $app->input->getInt('standalone')) {
                $mediatype = $app->input->getVar('mediatype');

                if (!$mediatype) {
                    return false;
                }

                $accept = $instance->getParam('templatemanager.extensions', '');

                if ($accept) {
                    $instance->setFileTypes($accept);
                    $accept = $instance->getFileTypes();
                    $mediatype = implode(',', array_intersect(explode(',', $mediatype), $accept));
                }

                $instance->setFileTypes($mediatype);
            }
        }
    }
}
PK��#]#P]3LL system/jce/templates/astroid.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateAstroid extends JPlugin
{
    public function onWfGetTemplateStylesheets(&$files, $template)
    {                        
        // Joomla 4
        $path = JPATH_SITE . '/media/templates/site/' . $template->name;
            
        if (is_dir($path . '/astroid')) {
            $items = glob($path . '/css/compiled-*.css');

            foreach($items as $item) {
                $files[] = 'media/templates/site/' . $template->name . '/css/' . basename($item);
            }

            return true;
        }
        
        // Joomla 3
        $path = JPATH_SITE . '/templates/' . $template->name;

        if (is_dir($path . '/astroid')) {
            $items = glob($path . '/css/compiled-*.css');

            foreach($items as $item) {
                // add compiled css file
                $files[] = 'templates/' . $template->name . '/css/' . basename($item);
            }
        }
    }
}PK��#]t:+��system/jce/templates/wright.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateWright extends JPlugin
{
    public function onWfGetTemplateStylesheets(&$files, $template)
    {                        
        $path = JPATH_SITE . '/templates/' . $template->name;

        // not a wright template
        if (!is_dir($path . '/wright')) {
            return false;
        }

        // add bootstrap
        $files[] = 'templates/' . $template->name . '/wright/css/bootstrap.min.css';

        $params = new JRegistry($template->params);
        $style = $params->get('style', 'default');

        // check style-custom.css file
        $file = $path . '/css/style-' . $style . '.css';

        // add base theme.css file
        if (is_file($file)) {
            $files[] = 'templates/' . $template->name . '/css/style-' . $style . '.css';
        }
    }
}PK��#]S��OO!system/jce/templates/yootheme.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateYootheme extends JPlugin
{
    public function onWfGetTemplateStylesheets(&$files, $template)
    {                        
        $path = JPATH_SITE . '/templates/' . $template->name;

        // not a yootheme / warp template
        if (!is_dir($path . '/warp') && !is_dir($path . '/vendor/yootheme')) {
            return false;
        }

        if (is_dir($path . '/warp')) {
            $file = 'css/theme.css';

            $config = $path . '/config.json';

            if (is_file($config)) {
                $data = file_get_contents($config);
                $json = json_decode($data);

                $style = '';

                if ($json) {
                    if (!empty($json->layouts->default->style)) {
                        $style = $json->layouts->default->style;
                    }
                }

                if ($style && $style !== 'default') {
                    $file = 'styles/' . $style . '/css/theme.css';
                }
            }

            // add base theme.css file
            if (is_file($path . '/' . $file)) {
                $files[] = 'templates/' . $template->name . '/' . $file;
            }

            // add custom css file
            if (is_file($path . '/css/custom.css')) {
                $files[] = 'templates/' . $template->name . '/css/custom.css';
            }
        }

        if (is_dir($path . '/vendor/yootheme')) {
            $files[] = 'templates/' . $template->name . '/css/theme.css';

            // add custom css file
            if (is_file($path . '/css/custom.css')) {
                $files[] = 'templates/' . $template->name . '/css/custom.css';
            }
        }
    }
}PK��#]��:��system/jce/templates/gantry.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateGantry extends JPlugin
{
    public function onWfGetTemplateStylesheets(&$files, $template)
    {
        $path = JPATH_SITE . '/templates/' . $template->name;

        // not a gantry template
        if (!is_dir($path . '/gantry') && !is_file($path . '/gantry.config.php')) {
            return false;
        }

        $name = substr($template->name, strpos($template->name, '_') + 1);

        // try Gantry5 templates
        $gantry5 = $path . '/custom/css-compiled';
        $gantry4 = $path . '/css-compiled';

        if (is_dir($gantry5)) {
            // update url
            $url = 'templates/' . $template->name . '/custom/css-compiled';

            // editor.css file
            $editor_css = $gantry5 . '/editor.css';

            // check for editor.css file
            if (is_file($editor_css) && filesize($editor_css) > 0) {
                $files[] = $url . '/' . basename($editor_css);
                return true;
            }

            // load gantry base files
            $files[] = 'media/gantry5/assets/css/bootstrap-gantry.css';
            $files[] = 'media/gantry5/engines/nucleus/css-compiled/nucleus.css';

            $items  = array();
            $custom = array();

            $list = glob($gantry5 . '/*_[0-9]*.css');

            foreach ($list as $file) {
                if (strpos(basename($file), 'custom_') !== false) {
                    $custom[filemtime($file)] = $file;
                } else {
                    $items[filemtime($file)] = $file;
                }
            }

            if (!empty($items)) {
                // sort items by modified time key
                ksort($items, SORT_NUMERIC);

                // get the last item in the array
                $item = end($items);

                $path = dirname($item);
                $file = basename($item);

                // load css files
                $files[] = $url . '/' . $file;
            }

            // load custom css file if it exists
            if (!empty($custom)) {
                // sort custom by modified time key
                ksort($custom, SORT_NUMERIC);
                
                // get the last custom file in the array
                $custom_file = end($custom);
                // create custom file url
                $files[] = $url . '/' . basename($custom_file);
            }
        }

        if (is_dir($gantry4)) {
            // update url
            $url = 'templates/' . $template->name . '/css-compiled';
            // load gantry bootstrap files
            $files[] = $url . '/bootstrap.css';

            $items = array();

            $list = glob($gantry4 . '/master-*.css');

            if (!empty($list)) {
                foreach ($list as $file) {
                    $items[filemtime($file)] = $file;
                }

                // sort by modified time key
                ksort($items, SORT_NUMERIC);

                // get the last item in the array
                $item = end($items);

                // load css files
                $files[] = $url . '/' . basename($item);
            }
        }
    }
}
PK��#]���A��!system/jce/templates/joomlart.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateJoomlart extends JPlugin
{
    public function onWfGetTemplateStylesheets(&$files, $template)
    {                        
        $path = JPATH_SITE . '/templates/' . $template->name;

        if (!is_file($path . '/templateInfo.php')) {
            return false;
        }

        // add base template.css file
        $files[] = 'templates/' . $template->name . '/css/template.css';

        // add custom.css
        if (is_file($path . '/css/custom.css')) {
            $files[] = 'templates/' . $template->name . '/css/custom.css';
        }

        $items = array();
            
        $list = glob(JPATH_SITE . '/media/t4/css/*.css');

        foreach($list as $file) {
            $items[filemtime($file)] = $file;
        }

        // sort by modified time key
        ksort($items, SORT_NUMERIC);

        // get the last item in the array
        $item = end($items);

        // add compiled css file
        $files[] = 'media/t4/css/' . basename($item);
    }
}PK��#]$�bbsystem/jce/templates/helix.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateHelix extends JPlugin
{
    public function onWfGetTemplateStylesheets(&$files, $template)
    {                        
        $path = JPATH_SITE . '/templates/' . $template->name;

        if (!is_file($path . '/comingsoon.php')) {
            return false;
        }

        // add bootstrap
        $files[] = 'templates/' . $template->name . '/css/bootstrap.min.css';

        // add font-awesome
        $files[] = 'templates/' . $template->name . '/css/font-awesome.min.css';

        // add base template.css file
        $files[] = 'templates/' . $template->name . '/css/template.css';

        $params = new JRegistry($template->params);
        $preset = $params->get('preset', '');

        $data = json_decode($preset);

        if ($data) {
            if (isset($data->preset)) {
                $files[] = 'templates/' . $template->name . '/css/presets/' . $data->preset . '.css';
            }
        }
    }
}PK��#]���ˤ�system/jce/templates/core.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateCore extends JPlugin
{
    private function findFile($template, $name) 
    {
        // template.css
        $file = JPath::find(array(
            JPATH_SITE . '/templates/' . $template . '/css',
            JPATH_SITE . '/media/templates/site/' . $template . '/css'
        ), $name);

        if ($file) {
            // make relative
            $file = str_replace(JPATH_SITE, '', $file);
            
            // remove leading slash
            $file = trim($file, '/');

            return $file;
        }

        return false;
    }
    
    public function onWfGetTemplateStylesheets(&$files, $template)
    {                        
        // already processed by a framework
        if (!empty($files)) {
            return false;
        }

        if ($template->parent) {
            foreach(array('template.css', 'user.css') as $name) {
                $file = $this->findFile($template->parent, $name);

                if ($file) {
                    $files[] = $file;
                }
            }
        }

        foreach(array('template.css', 'user.css') as $name) {
            $file = $this->findFile($template->name, $name);

            if ($file) {
                $files[] = $file;
            }
        }
    }
}PK��#]L���system/jce/templates/sun.phpnu�[���<?php

/**
 * @copyright   Copyright (C) 2021 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later
 */
defined('JPATH_BASE') or die;

class WfTemplateSun extends JPlugin
{
    public function onWfGetTemplateStylesheets(&$files, $template)
    {                        
        $path = JPATH_SITE . '/templates/' . $template->name;

        if (!is_file($path . '/template.defines.php')) {
            return false;
        }

        // add bootstrap
        $files[] = 'plugins/system/jsntplframework/assets/3rd-party/bootstrap/css/bootstrap-frontend.min.css';

        // add base template.css file
        $files[] = 'templates/' . $template->name . '/css/template.css';

        $params = new JRegistry($template->params);
        $preset = $params->get('preset', '');

        $data = json_decode($preset);

        if ($data) {
            if (isset($data->templateColor)) {
                $files[] = 'templates/' . $template->name . '/css/color/' . $data->templateColor . '.css';
            }

            if (isset($data->fontStyle) && isset($data->fontStyle->style)) {
                $files[] = 'templates/' . $template->name . '/css/styles/' . $data->fontStyle->style . '.css';
            }
        }
    }
}PK��#]�)��system/jce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]b��O* * system/jce/css/content.cssnu�[���.wf-columns{display:flex;gap:1rem}.wf-columns .wf-column{max-width:100%;box-sizing:border-box;flex:1}.wf-columns-stack-large,.wf-columns-stack-medium,.wf-columns-stack-small,.wf-columns-stack-xlarge{flex-wrap:wrap}.wf-columns-align-left{justify-content:flex-start}.wf-columns-align-center{justify-content:center}.wf-columns-align-right{justify-content:flex-end}.wf-columns-layout-1-2>.wf-column:last-child,.wf-columns-layout-2-1>.wf-column:first-child{width:calc(100% * 2 / 3.001);flex:none}.wf-columns-layout-1-1-2>.wf-column:last-child,.wf-columns-layout-1-2-1>.wf-column:nth-child(2),.wf-columns-layout-2-1-1>.wf-column:first-child{width:50%;flex:none}.wf-columns-layout-1-3>.wf-column:last-child,.wf-columns-layout-3-1>.wf-column:first-child{width:75%;flex:none}.wf-columns-layout-1-1-3>.wf-column:last-child,.wf-columns-layout-1-3-1>.wf-column:nth-child(2),.wf-columns-layout-2-3>.wf-column:last-child,.wf-columns-layout-3-1-1>.wf-column:first-child,.wf-columns-layout-3-2>.wf-column:first-child{width:60%;flex:none}.wf-columns-layout-1-1-1-2>.wf-column:last-child,.wf-columns-layout-2-1-1-1>.wf-column:first-child{width:40%;flex:none}.wf-columns-layout-1-4>.wf-column:last-child,.wf-columns-layout-4-1>.wf-column:first-child{width:80%;flex:none}.wf-columns-gap-small{gap:.5rem}.wf-columns-gap-medium{gap:1rem}.wf-columns-gap-large{gap:2rem}.wf-columns-gap-none{gap:0}.wf-columns-align-top{align-items:flex-start}.wf-columns-align-middle{align-items:center}.wf-columns-align-bottom{align-items:flex-end}.wf-columns-align-stretch{align-items:stretch}@media (max-width:640px){.wf-columns-stack-small>.wf-column{width:100%;flex:auto!important}}@media (max-width:960px){.wf-columns-stack-medium>.wf-column{width:100%;flex:auto!important}}@media (max-width:1200px){.wf-columns-stack-large>.wf-column{width:100%;flex:auto!important}}@media (max-width:1600px){.wf-columns-stack-xlarge>.wf-column{width:100%}}[data-wf-columns]>div>figure img,[data-wf-columns]>div>figure video{object-fit:cover;height:calc(100% - 2rem)}[data-wf-columns]>div>figure{margin:0;display:block;position:relative;height:100%}[data-wf-columns]>div>figure figcaption{text-align:center;line-height:2rem;display:inline-block;width:100%}[data-wf-columns]>div>figure>a.wfpopup+figcaption{pointer-events:none}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.wf-columns .wf-column{margin-left:1rem}.wf-columns .wf-column:first-child{margin-left:inherit}.wf-columns .wf-column:last-child{margin-right:inherit}.wf-columns-gap-small .wf-column{margin-left:.5rem}.wf-columns-gap-medium .wf-column{margin-left:1rem}.wf-columns-gap-large .wf-column{margin-left:2rem}.wf-columns-gap-none .wf-column{margin-left:inherit}}@media all and (-ms-high-contrast:none) and (max-width:640px),(-ms-high-contrast:active) and (max-width:640px){.wf-columns-stack-small .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-small .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-small.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-small.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-small.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-small.wf-columns-gap-large .wf-column{margin-top:2rem}}@media all and (-ms-high-contrast:none) and (max-width:960px),(-ms-high-contrast:active) and (max-width:960px){.wf-columns-stack-medium .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-medium .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-medium.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-medium.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-medium.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-medium.wf-columns-gap-large .wf-column{margin-top:2rem}}@media all and (-ms-high-contrast:none) and (max-width:1200px),(-ms-high-contrast:active) and (max-width:1200px){.wf-columns-stack-large .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-large .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-large.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-large.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-large.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-large.wf-columns-gap-large .wf-column{margin-top:2rem}}@media all and (-ms-high-contrast:none) and (max-width:1600px),(-ms-high-contrast:active) and (max-width:1600px){.wf-columns-stack-xlarge .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-xlarge .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-xlarge.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-xlarge.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-xlarge.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-xlarge.wf-columns-gap-large .wf-column{margin-top:2rem}}@supports (not (scale:-1)) and (-webkit-hyphens:none){.wf-columns .wf-column{margin-left:1rem}.wf-columns .wf-column:first-child{margin-left:inherit}.wf-columns .wf-column:last-child{margin-right:inherit}.wf-columns-gap-small .wf-column{margin-left:.5rem}.wf-columns-gap-medium .wf-column{margin-left:1rem}.wf-columns-gap-large .wf-column{margin-left:2rem}.wf-columns-gap-none .wf-column{margin-left:inherit}@media (max-width:640px){.wf-columns-stack-small .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-small .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-small.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-small.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-small.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-small.wf-columns-gap-large .wf-column{margin-top:2rem}}@media (max-width:960px){.wf-columns-stack-medium .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-medium .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-medium.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-medium.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-medium.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-medium.wf-columns-gap-large .wf-column{margin-top:2rem}}@media (max-width:1200px){.wf-columns-stack-large .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-large .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-large.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-large.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-large.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-large.wf-columns-gap-large .wf-column{margin-top:2rem}}@media (max-width:1600px){.wf-columns-stack-xlarge .wf-column{margin-left:inherit;margin-right:inherit;margin-top:1rem}.wf-columns-stack-xlarge .wf-column:first-child{margin-top:inherit!important}.wf-columns-stack-xlarge.wf-columns-gap-none .wf-column{margin-top:inherit}.wf-columns-stack-xlarge.wf-columns-gap-small .wf-column{margin-top:.5rem}.wf-columns-stack-xlarge.wf-columns-gap-medium .wf-column{margin-top:1rem}.wf-columns-stack-xlarge.wf-columns-gap-large .wf-column{margin-top:2rem}}}[data-wf-columns].uk-flex,[data-wf-columns].uk-flex-gap-small{gap:.5rem}[data-wf-columns].uk-flex-gap-medium{gap:1rem}[data-wf-columns].uk-flex-gap-large{gap:2rem}[data-wf-columns].uk-flex-gap-none{gap:0}[data-wf-columns].row{gap:.5rem;margin:0}[data-wf-columns].row>[class*=col]{padding:0}[data-wf-columns].flex-gap-sm{gap:.5rem}[data-wf-columns].flex-gap-md{gap:1rem}[data-wf-columns].flex-gap-lg{gap:2rem}[data-wf-columns].flex-gap-none{gap:0}[data-wf-columns].flex-top{align-items:flex-start}[data-wf-columns].flex-middle{align-items:center}[data-wf-columns].flex-bottom{align-items:flex-end}[data-wf-columns].flex-stretch{align-items:stretch}figure[data-wf-figure]{display:table;margin-block-start:inherit;margin-block-end:inherit;margin-inline-start:inherit;margin-inline-end:inherit}figure[data-wf-figure] figcaption{display:table-caption;caption-side:bottom}PK��#]9�YY<	<	system/jce/css/media.cssnu�[���div[data-url].wf-media-wrapper>div.modal,div[data-url]>div.modal-dialog>div.modal-content{height:90vh}.wf-media-wrapper{max-width:100%}.wf-media-wrapper .modal .modal-header h3{font-size:0}.wf-media-wrapper .modal .modal-body{max-height:100%!important;width:auto;overflow:hidden;padding:0}.wf-media-wrapper .modal .modal-body iframe{height:calc(100% - 27px)!important}.wf-media-wrapper .modal .modal-body iframe[name=field-media-modal]{height:calc(90vh - 54px)!important;max-height:100vh}.wf-media-wrapper .modal .modal-footer{display:none}#sbox-window{padding:5px!important}#sbox-window #sbox-content,#sbox-window #sbox-content iframe{margin:0!important;padding:0!important}.input-append a[role=button].wf-media-upload-button,.input-group a[role=button].wf-media-upload-button{position:relative;border-radius:0;overflow:hidden}.wf-media-upload-button>input[type=file]{position:absolute;left:0;top:0;width:100%;height:100%;font-size:100px;opacity:0;cursor:pointer;overflow:hidden}input.wf-media-upload-busy,input.wf-media-upload-hover{background-color:#eee}@media (max-width:1400px){.input-append input.wf-media-input-upload{width:100px}}.wf-media-wrapper .field-media-preview{display:flex;align-items:center;justify-content:center;height:180px;padding:10px;overflow:hidden;background-color:#f2f2f2;border:1px solid rgba(0,0,0,.15);border-width:1px 1px 0;border-radius:.25rem .25rem 0 0}.wf-media-wrapper .field-media-preview .field-media-preview-icon{width:7rem;height:7rem;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='rgba(0,0,0,.25)' d='M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 336H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v276a6 6 0 0 1-6 6zM128 152c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zM96 352h320v-80l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L192 304l-39.515-39.515c-4.686-4.686-12.284-4.686-16.971 0L96 304v48z'/%3E%3C/svg%3E");background-size:7rem}.wf-media-wrapper .field-media-preview img{max-width:100%;max-height:100%}.wf-media-wrapper .field-media-preview img+.field-media-preview-icon,.wf-media-wrapper .field-media-preview img[src=""]{display:none}.wf-media-wrapper .field-media-preview img[src=""]+.field-media-preview-icon{display:block}PK��#]����__"system/jcemediabox/jcemediabox.phpnu&1i�<?php

/**
 * @package JCE MediaBox
 * @copyright Copyright (C) 2006-2017 Ryan Demmer. All rights reserved.
 * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL 3, see LICENCE
 * This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 *
 * Light Theme inspired by Slimbox by Christophe Beyls
 * @ http://www.digitalia.be
 *
 * Shadow Theme inspired by ShadowBox
 * @ http://mjijackson.com/shadowbox/
 *
 * Squeeze theme inspired by Squeezebox by Harald Kirschner
 * @ http://digitarald.de/project/squeezebox/
 *
 */
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

/**
 * JCE MediaBox Plugin
 *
 * @package         JCE MediaBox
 * @subpackage    System
 */
class plgSystemJCEMediabox extends JPlugin
{
    /**
     * Create a list of translated labels for popup window
     * @return Key : Value labels string
     */
    protected function getLabels()
    {
        JPlugin::loadLanguage('plg_system_jcemediabox', JPATH_ADMINISTRATOR);

        $words = array('close', 'next', 'previous', 'cancel', 'numbers', 'numbers_count', 'download');

        $v = array();

        foreach ($words as $word) {
            $v[$word] = htmlspecialchars(JText::_('PLG_SYSTEM_JCEMEDIABOX_LABEL_' . strtoupper($word)));
        }

        return $v;
    }

    private function getAssetPath($relative)
    {
        $path = __DIR__ . '/' . $relative;
        $hash = md5_file($path);

        return JURI::base(true) . '/plugins/system/jcemediabox/' . $relative . '?' . $hash;
    }

    /**
     * OnAfterRoute function
     * @return Boolean true
     */
    public function onAfterDispatch()
    {
        $app = JFactory::getApplication();

        // only in "site"
        if ($app->getClientId() !== 0) {
            return;
        }

        $document = JFactory::getDocument();
        $docType = $document->getType();

        // only in html pages
        if ($docType != 'html') {
            return;
        }

        $db = JFactory::getDBO();

        // Causes issue in Safari??
        $pop = $app->input->getInt('pop');
        $print = $app->input->getInt('print');
        $task = $app->input->getCmd('task');
        $tmpl = $app->input->getWord('tmpl');

        // don't load mediabox on certain pages
        if ($pop || $task == 'new' || $task == 'edit') {
            return;
        }

        // load in print
        if ($tmpl == 'component' && !$print) {
            return;
        }

        $params = $this->params;

        $components = $params->get('components');

        if (!empty($components)) {
            if (is_string($components)) {
                $components = explode(',', $components);
            }

            $option = $app->input->get('option', '');

            foreach ($components as $component) {
                if ($option === 'com_' . $component || $option === $component) {
                    return;
                }
            }
        }

        // get active menu
        $menus = $app->getMenu();
        $menu = $menus->getActive();

        // get menu items from parameter
        $menuitems = (array) $params->get('menu');

        // is there a menu assignment?
        if (!empty($menuitems) && !empty($menuitems[0])) {
            if ($menu && !in_array($menu->id, (array) $menuitems)) {
                return;
            }
        }

        // get excluded menu items from parameter
        $menuitems_exclude = (array) $params->get('menu_exclude');

        // is there a menu exclusion?
        if (!empty($menuitems_exclude) && !empty($menuitems_exclude[0])) {
            if ($menu && in_array($menu->id, (array) $menuitems_exclude)) {
                return;
            }
        }

        $theme = $params->get('theme', 'standard');

        if ($params->get('dynamic_themes', 0)) {
            $theme = $app->input->getWord('theme', $theme);
        }

        $config = array(
            'base' => JURI::base(true) . '/',
            'theme' => $theme,
            //'mediafallback' => (int) $params->get('mediafallback', 0),
            //'mediaselector' => $params->get('mediaselector', 'audio,video'),
            'width' => $params->get('width', ''),
            'height' => $params->get('height', ''),
            'lightbox' => (int) $params->get('lightbox', 0),
            'shadowbox' => (int) $params->get('shadowbox', 0),
            'icons' => (int) $params->get('icons', 1),
            'overlay' => (int) $params->get('overlay', 1),
            'overlay_opacity' => (float) $params->get('overlayopacity'),
            'overlay_color' => $params->get('overlaycolor', ''),
            'transition_speed' => (int) $params->get('transition_speed', $params->get('scalespeed', 300)),
            'close' => (int) $params->get('close', 2),
            'scrolling' => (string) $params->get('scrolling', 'fixed'),
            'labels' => $this->getLabels(),
        );

        if ($this->params->get('jquery', 1)) {
            // Include jQuery
            JHtml::_('jquery.framework');
        }

        $document->addScript($this->getAssetPath('js/jcemediabox.min.js'));
        $document->addStyleSheet($this->getAssetPath('css/jcemediabox.min.css'));

        $document->addScriptDeclaration('jQuery(document).ready(function(){WfMediabox.init(' . json_encode($config) . ');});');

        return true;
    }

    public function onExtensionAfterInstall($installer, $eid)
    {
        if ($eid) {
            // extension path
            $path = $installer->getPath('extension_root');

            // extension name
            $name = basename($path);

            // bail if not jcemediabox
            if ($name !== 'jcemediabox') {
                return;
            }

            jimport('joomla.filesystem.folder');

            // cleanup legacy folders
            $folders = array('fonts', 'mediaplayer');

            foreach ($folders as $folder) {
                if (is_dir($path . '/' . $folder)) {
                    @JFolder::delete($path . '/' . $folder);
                }
            }
        }
    }
}
PK��#]6���"system/jcemediabox/jcemediabox.xmlnu&1i�<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="system" method="upgrade">
    <name>plg_system_jcemediabox</name>
    <author>Ryan Demmer</author>
    <creationDate>23-09-2021</creationDate>
    <copyright>Copyright (C) 2006 - 2021 Ryan Demmer. All rights reserved</copyright>
    <license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
    <authorEmail>info@joomlacontenteditor.net</authorEmail>
    <authorUrl>www.joomlacontenteditor.net</authorUrl>
    <version>2.1.2</version>
    <description>PLG_SYSTEM_JCEMEDIABOX_XML_DESC</description>

    <config>
        <fields name="params">
            <fieldset name="options" group="options" addfieldpath="/plugins/system/jcemediabox/fields">
                <field name="theme" type="list" default="standard" label="PLG_SYSTEM_JCEMEDIABOX_THEME" description="PLG_SYSTEM_JCEMEDIABOX_THEME_DESC">
                  <option value="standard">PLG_SYSTEM_JCEMEDIABOX_THEME_STANDARD</option>
                  <option value="light">PLG_SYSTEM_JCEMEDIABOX_THEME_LIGHT</option>
                  <option value="shadow">PLG_SYSTEM_JCEMEDIABOX_THEME_SHADOW</option>
                  <option value="squeeze">PLG_SYSTEM_JCEMEDIABOX_THEME_SQUEEZE</option>
                  <!--option value="bootstrap">PLG_SYSTEM_JCEMEDIABOX_THEME_BOOTSTRAP</option>
                  <option value="uikit">PLG_SYSTEM_JCEMEDIABOX_THEME_UIKIT</option-->
                </field>

                <field name="transitionspeed" type="number" default="500" step="50" min="50" class="span1" label="PLG_SYSTEM_JCEMEDIABOX_TRANSITIONSPEED" description="PLG_SYSTEM_JCEMEDIABOX_TRANSITIONSPEED_DESC"/>
                
                <field name="overlay" type="radio" default="1" label="PLG_SYSTEM_JCEMEDIABOX_OVERLAY" description="PLG_SYSTEM_JCEMEDIABOX_OVERLAY_DESC" class="btn-group btn-group-yesno">
                    <option value="1">JYES</option>
                    <option value="0">JNO</option>
                </field>
                <field name="overlayopacity" type="number" default="" step="0.1" min="0" max="1" class="span1" label="PLG_SYSTEM_JCEMEDIABOX_OVERLAYOPACITY" description="PLG_SYSTEM_JCEMEDIABOX_OVERLAYOPACITY_DESC" />
                <field name="overlaycolor" type="color" default="" class="color" label="PLG_SYSTEM_JCEMEDIABOX_OVERLAYCOLOR" description="PLG_SYSTEM_JCEMEDIABOX_OVERLAYCOLOR_DESC" />
                
                <field name="width" type="text" default="" class="span1" label="PLG_SYSTEM_JCEMEDIABOX_WIDTH" description="PLG_SYSTEM_JCEMEDIABOX_WIDTH_DESC" />
                <field name="height" type="text" default="" class="span1" label="PLG_SYSTEM_JCEMEDIABOX_HEIGHT" description="PLG_SYSTEM_JCEMEDIABOX_HEIGHT_DESC" />

                <field name="close" type="list" default="2" label="PLG_SYSTEM_JCEMEDIABOX_CLOSE_ACTION" description="PLG_SYSTEM_JCEMEDIABOX_CLOSE_ACTION_DESC">
                    <option value="1">PLG_SYSTEM_JCEMEDIABOX_CLOSE_BUTTON</option>
                    <option value="2">PLG_SYSTEM_JCEMEDIABOX_CLOSE_BUTTON_OVERLAY</option>
                </field>

                <field name="scrolling" type="list" default="0" label="PLG_SYSTEM_JCEMEDIABOX_SCROLLING" description="PLG_SYSTEM_JCEMEDIABOX_SCROLLING_DESC">
                    <option value="fixed">PLG_SYSTEM_JCEMEDIABOX_SCROLLING_FIXED</option>
                    <option value="scroll">PLG_SYSTEM_JCEMEDIABOX_SCROLLING_SCROLL</option>
                </field>
                
                <field name="icons" type="radio" default="1" label="PLG_SYSTEM_JCEMEDIABOX_ICONS" description="PLG_SYSTEM_JCEMEDIABOX_ICONS_DESC" class="btn-group btn-group-yesno">
                    <option value="1">JYES</option>
                    <option value="0">JNO</option>
                </field>

                <field name="components" type="components" multiple="true" default="" label="PLG_SYSTEM_JCEMEDIABOX_COMPONENTS" description="PLG_SYSTEM_JCEMEDIABOX_COMPONENTS_DESC" layout="joomla.form.field.list-fancy-select" />
                
                <field name="menu" type="menuitem" state="1" default="" multiple="multiple" size="10" label="PLG_SYSTEM_JCEMEDIABOX_MENU" description="PLG_SYSTEM_JCEMEDIABOX_MENU_DESC" />
                
                <field name="menu_exclude" type="menuitem" state="1" default="" multiple="multiple" size="10" label="PLG_SYSTEM_JCEMEDIABOX_MENU_EXCLUDE" description="PLG_SYSTEM_JCEMEDIABOX_MENU_EXCLUDE_DESC" />
                
                <field name="dynamic_themes" type="radio" default="0" label="PLG_SYSTEM_JCEMEDIABOX_DYNAMICTHEMES" description="PLG_SYSTEM_JCEMEDIABOX_DYNAMICTHEMES_DESC" class="btn-group btn-group-yesno">
                    <option value="1">JYES</option>
                    <option value="0">JNO</option>
                </field>

                <field name="lightbox" type="radio" default="0" label="PLG_SYSTEM_JCEMEDIABOX_LIGHTBOX" description="PLG_SYSTEM_JCEMEDIABOX_LIGHTBOX_DESC" class="btn-group btn-group-yesno">
                    <option value="1">JYES</option>
                    <option value="0">JNO</option>
                </field>

                <field name="shadowbox" type="radio" default="0" label="PLG_SYSTEM_JCEMEDIABOX_SHADOWBOX" description="PLG_SYSTEM_JCEMEDIABOX_SHADOWBOX_DESC" class="btn-group btn-group-yesno">
                    <option value="1">JYES</option>
                    <option value="0">JNO</option>
                </field>

                <!--field name="mediafallback" type="radio" default="0" label="PLG_SYSTEM_JCEMEDIABOX_MEDIAFALLBACK" class="btn-group btn-group-yesno" description="PLG_SYSTEM_JCEMEDIABOX_MEDIAFALLBACK_DESC">
                    <option value="1">JYES</option>
                    <option value="0">JNO</option>
                </field-->

                <!--field name="mediaselector" type="text" size="50" default="audio,video" label="PLG_SYSTEM_JCEMEDIABOX_MEDIASELECTOR" description="PLG_SYSTEM_JCEMEDIABOX_MEDIASELECTOR_DESC"/-->
            </fieldset>
        </fields>
    </config>

    <files folder="plugins/system/jcemediabox">
        <file plugin="jcemediabox">jcemediabox.php</file>
        <folder>css</folder>
        <folder>fields</folder>
        <folder>img</folder>
        <folder>js</folder>
    </files>

    <languages folder="plugins/system/jcemediabox/language/en-GB">
        <language tag="en-GB">en-GB.plg_system_jcemediabox.ini</language>
        <language tag="en-GB">en-GB.plg_system_jcemediabox.sys.ini</language>
    </languages>

    <updateservers>
	<server type="extension" priority="1" name="JCE MediaBox Updates"><![CDATA[https://cdn.joomlacontenteditor.net/updates/xml/mediabox/plg_system_jcemediabox2.xml]]></server>
    </updateservers>
</extension>
PK��#]�)��system/jcemediabox/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�#o,,!system/jcemediabox/css/index.htmlnu&1i�<html><body bgcolor="#FFFFFF"></body></html>PK��#]�O]e""&system/jcemediabox/css/jcemediabox.cssnu&1i�@media print{a.jcepopup span.jcemediabox-zoom-image{background:0 0!important}}.jcepopup.hide,.jcepopup.noshow{display:none}#jcemediabox-popup-body,#jcemediabox-popup-container,#jcemediabox-popup-content,#jcemediabox-popup-iframe,#jcemediabox-popup-img,#jcemediabox-popup-loader,#jcemediabox-popup-object,#jcemediabox-popup-overlay,#jcemediabox-popup-page{left:0;top:0;margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:0 0;height:100%;width:100%}#jcemediabox-popup-body,#jcemediabox-popup-container,#jcemediabox-popup-content,#jcemediabox-popup-overlay{box-sizing:content-box}#jcemediabox-popup-page{position:fixed!important;z-index:10000}#jcemediabox-popup-page.scrolling{position:absolute!important}#jcemediabox-popup-overlay{position:absolute;cursor:pointer}#jcemediabox-popup-frame{position:relative;overflow:visible;height:100%;z-index:10001;cursor:pointer}#jcemediabox-popup-body{position:relative;overflow:visible;margin:0 auto;width:300px;height:300px;z-index:10002;cursor:default}#jcemediabox-popup-loader{text-align:center;line-height:0}#jcemediabox-popup-info-bottom,#jcemediabox-popup-info-top{overflow:hidden;position:relative;margin:0;padding:0;border:0;visibility:hidden}#jcemediabox-popup-container{overflow:hidden}#jcemediabox-popup-content{width:100%;height:auto}#jcemediabox-popup-content.broken-image{background:url(../img/broken-image.png) center no-repeat}#jcemediabox-popup-content.broken-media{background:url(../img/broken-media.png) center no-repeat}#jcemediabox-popup-content.broken-page{background:url(../img/broken-page.png) center no-repeat}#jcemediabox-popup-content p.media-support{font-size:20px;color:#888;font-weight:700;text-align:center;height:100%;position:relative;top:50%;margin-top:-10px}#jcemediabox-popup-iframe,#jcemediabox-popup-img,#jcemediabox-popup-object{text-align:center}#jcemediabox-popup-content>embed,#jcemediabox-popup-content>img,#jcemediabox-popup-content>object,#jcemediabox-popup-content>video{width:100%;height:auto}#jcemediabox-popup-content object[type="application/x-shockwave-flash"]{height:inherit}#jcemediabox-popup-page.android #jcemediabox-popup-content,#jcemediabox-popup-page.ios #jcemediabox-popup-content{overflow:scroll}#jcemediabox-popup-ajax{overflow:auto;border:0;padding:0;margin:0;width:auto;height:100%;background-color:#fff;position:relative}a.jcemediabox-image{line-height:0!important;font-size:0!important}.wf_caption a.jcepopup{display:block}a.jcepopup span.jcemediabox-zoom-span{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:0 0;cursor:pointer;display:inline-block;position:relative;float:none}a.jcepopup span.jcemediabox-zoom-image{margin:0;padding:0;border:0;outline:0;vertical-align:baseline;display:block;background:url(../img/zoom-img.png) bottom right no-repeat;width:100%;height:100%;position:absolute;z-index:1;bottom:0;left:0}a.jcepopup.icon-bottom-left span.jcemediabox-zoom-image,a.jcepopup.icon-left span.jcemediabox-zoom-image,a.jcepopup.zoom-bottom-left span.jcemediabox-zoom-image{background-position:bottom left}a.jcepopup.icon-top-left span.jcemediabox-zoom-image,a.jcepopup.zoom-top-left span.jcemediabox-zoom-image{background-position:top left}a.jcepopup.icon-top span.jcemediabox-zoom-image,a.jcepopup.icon-top-right span.jcemediabox-zoom-image,a.jcepopup.zoom-top-right span.jcemediabox-zoom-image{background-position:top right}a.jcepopup.icon-center span.jcemediabox-zoom-image,a.jcepopup.zoom-center span.jcemediabox-zoom-image{background-position:center center}a.jcepopup.icon-center-left span.jcemediabox-zoom-image,a.jcepopup.zoom-center-left span.jcemediabox-zoom-image{background-position:center left}a.jcepopup.icon-center-right span.jcemediabox-zoom-image,a.jcepopup.zoom-center-right span.jcemediabox-zoom-image{background-position:center right}a.jcepopup.icon-center-bottom span.jcemediabox-zoom-image,a.jcepopup.icon-center-top span.jcemediabox-zoom-image,a.jcepopup.zoom-center-bottom span.jcemediabox-zoom-image,a.jcepopup.zoom-center-top span.jcemediabox-zoom-image{background-position:center top}a.jcepopup span.jcemediabox-zoom-link,a.jcepopup span.jcemediabox-zoom-link.icon-right,a.jcepopup span.jcemediabox-zoom-link.zoom-right{padding-right:16px;background:url(../img/zoom-link.gif) center right no-repeat;display:inherit}a.jcepopup span.jcemediabox-zoom-link.icon-left,a.jcepopup span.jcemediabox-zoom-link.zoom-left{padding-left:18px;background:url(../img/zoom-link.gif) center left no-repeat}#jcemediabox-popup-caption,#jcemediabox-popup-caption h4,#jcemediabox-popup-caption p{margin:0;padding:0;border:0}div.jcemediabox-tooltip,div.jcemediabox-tooltip-simple{z-index:10010;width:180px;text-align:left;color:#000;background-color:#fff;border:1px solid #000;padding:4px;float:none;max-width:100%;position:absolute;top:0;left:0;visibility:hidden}div.jcemediabox-tooltip h4,div.jcemediabox-tooltip-simple h4{font-weight:700;font-size:11px;margin:0;background:0 0;padding:0}div.jcemediabox-tooltip p,div.jcemediabox-tooltip-simple p{font-size:11px;background:0 0;margin:0;padding:0}a.jcepopup.ie6 span.jcemediabox-zoom-image{background:url(../img/zoom-img.png) no-repeat;width:20px;height:20px;left:auto;top:auto;right:0}a.jcepopup.ie6 span.jcemediabox-zoom-link{display:inline-block}a.jcepopup.icon-bottom-left span.jcemediabox-zoom-image,a.jcepopup.ie6.icon-left span.jcemediabox-zoom-image{top:auto;right:0}a.jcepopup.icon-top-right span.jcemediabox-zoom-image,a.jcepopup.ie6.icon-top span.jcemediabox-zoom-image{top:0}a.jcepopup.ie6.icon-left span.jcemediabox-zoom-image{left:0;right:auto}.wf-mediaplayer-object{background-color:transparent;background-repeat:no-repeat;background-size:cover;background-position:center}.wf-mediaplayer-object i{padding:5px 0;display:inline-block;text-align:center;background-color:#fff}.wf-mediaplayer-object img{width:inherit;height:inherit}.wf-mediaplayer-container{display:block}PK��#]��T�w`w`*system/jcemediabox/css/jcemediabox.min.cssnu�[���.wf-mediabox-numbers *,[class^=wf-mediabox]{left:0;top:0;margin:0;padding:0;border:0;outline:0;vertical-align:top;background:0 0;text-decoration:none;color:#444;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:inherit;text-shadow:none;text-transform:none;float:none;position:relative;width:auto;height:auto;white-space:normal;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:400;text-align:left;box-sizing:border-box;direction:ltr;max-width:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-shadow:none;-webkit-box-shadow:none;-webkit-appearance:none}.wf-mediabox-scrolling{position:relative}.wf-mediabox{position:fixed;z-index:10000;width:100%;height:100%;font-size:16px}.wf-mediabox-cache{position:absolute;left:-99999px}.wf-mediabox-scrolling .wf-mediabox{position:absolute;top:0;left:0;bottom:0;right:0}.wf-mediabox-overlay{position:absolute;cursor:pointer;background-color:#000;width:100%;height:100%}.wf-mediabox-overlay-transition .wf-mediabox-overlay{opacity:0;transition:opacity .3s ease-in-out}.wf-mediabox-open .wf-mediabox-overlay{opacity:.7}.wf-mediabox-loader:before{content:"";position:absolute;width:100%;height:100%;left:0;top:0;z-index:10000;box-sizing:border-box}.wf-mediabox-loader:after{content:"";display:block;border:.25em solid rgba(255,255,255,.5);border-left-color:#fff;border-radius:50%;width:2em;height:2em;animation:donut-spin 1.2s linear infinite;z-index:10001;position:absolute;top:50%;left:50%;margin:-1em 0 0 -1em;box-sizing:border-box}.wf-mediabox-body,.wf-mediabox-frame:after{display:inline-block;vertical-align:middle}@keyframes donut-spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.wf-mediabox-frame:after{content:"";height:100%}.wf-mediabox-frame{box-sizing:border-box;height:100%;left:0;position:absolute;text-align:center;top:0;width:100%}.wf-mediabox-body{z-index:10002;cursor:default;margin:0 auto;position:relative;text-align:left;width:100%;visibility:hidden;box-shadow:0 0 30px rgba(0,0,0,.5);max-width:260px}.wf-mediabox-broken-image,.wf-mediabox-broken-media>div,.wf-mediabox-loading .wf-mediabox-content-image{min-width:240px;min-height:135px}.wf-mediabox-loader{text-align:center;line-height:0;display:none;width:100%;height:100%;position:absolute}.wf-mediabox-loading .wf-mediabox-loader{display:inline-block!important}.wf-mediabox-info-bottom,.wf-mediabox-info-top{overflow:hidden;position:relative;margin:0;padding:0;border:0}.wf-mediabox-container{overflow:hidden;max-width:100%;height:auto}[class*=wf-mediabox-transition-] .wf-mediabox-body{opacity:0;transition:.3s ease-in;transition-property:opacity,transform}.wf-mediabox-transition-scale .wf-mediabox-body{transform:scale3d(.9,.9,1)}.wf-mediabox-transition-slide-in .wf-mediabox-body{transform:translateX(300%) translateY(0)}.wf-mediabox-transition-slide-out .wf-mediabox-body{transform:translateX(-200%) translateY(0)}.wf-mediabox-body:after{content:"";position:absolute;width:100%;height:100%;left:0;top:0;background:#fff}.wf-mediabox-show .wf-mediabox-body{visibility:visible}.wf-mediabox-caption-hidden *,.wf-mediabox-content-ajax iframe,.wf-mediabox-theme-uikit .wf-mediabox-content nav,.wf-zoom-image-hover .wf-icon-zoom-image{visibility:hidden}.wf-mediabox-transition-scale .wf-mediabox-body.wf-mediabox-transition{opacity:1;transform:scale3d(1,1,1)}.wf-mediabox-transition-slide-in .wf-mediabox-body.wf-mediabox-transition,.wf-mediabox-transition-slide-out .wf-mediabox-body.wf-mediabox-transition{opacity:1;transform:translateX(0) translateY(0)}.wf-mediabox-body.wf-mediabox-transition:after{content:"";width:0;height:0}.wf-mediabox-content{width:auto;height:auto;overflow:hidden;display:block}.wf-mediabox-content-item>figure{margin:0;position:absolute;width:100%;height:100%;left:0;top:0;display:block}.wf-mediabox-content-item>figure>figcaption{text-align:center;position:absolute;width:100%;display:block;bottom:0;background:#fff;padding:.25em}.wf-mediabox-scroll .wf-mediabox-content-image{overflow:auto}.wf-mediabox-scroll .wf-mediabox-content-image img{max-width:inherit}.wf-mediabox-content-ajax .wf-mediabox-content-item,.wf-mediabox-content-iframe .wf-mediabox-content-item,.wf-mediabox-content-object .wf-mediabox-content-item,.wf-mediabox-content-video .wf-mediabox-content-item{padding-bottom:56.25%;width:100%;height:0;overflow:inherit}.wf-mediabox-content-ratio-4by3 .wf-mediabox-content-item{padding-bottom:75%}.wf-mediabox-content-ratio-flex .wf-mediabox-content-item{padding-bottom:0}.wf-mediabox-container .wf-mediabox-content-height{padding:initial;min-height:320px}.wf-mediabox-content-ajax{overflow:auto}.wf-mediabox-content-audio,.wf-mediabox-content-image{text-align:center;width:100%;height:auto}.wf-mediabox-content p.media-support{font-size:20px;color:#888;font-weight:700;text-align:center;height:100%;position:relative;top:50%;margin-top:-10px}.wf-mediabox-content-iframe iframe,.wf-mediabox-content-object embed,.wf-mediabox-content-object object,.wf-mediabox-content-video video{border:0;position:absolute;top:0;left:0;width:100%;height:100%}.wf-mediabox-content-audio audio,.wf-mediabox-content-image img{text-align:center;width:100%;height:auto}.wf-mediabox-content-audio audio{min-height:40px}.wf-mediabox.ios .wf-mediabox-content{overflow:scroll;-webkit-overflow-scrolling:touch}.wf-mediabox-ajax{overflow:auto;border:0;margin:0;background-color:#fff}a.wf-mediabox-img{line-height:0;font-size:0}.wf-mediabox-caption,.wf-mediabox-nav{display:block}.wf-mediabox-nav button{padding:0!important;font-size:inherit!important}.wf-mediabox-caption,.wf-mediabox-caption h4,.wf-mediabox-caption p{margin:0;padding:0;border:0;line-height:normal;white-space:normal}.wf-mediabox-caption p{max-height:25vh;overflow:auto}.wf-zoom-image{position:relative;line-height:0;font-size:0;display:inline-block}.wf-mediabox-has-float{display:block}.wf-mediabox-is-centered{display:block;margin:auto}.wf-zoom-image-hover:hover .wf-icon-zoom-image{visibility:visible}.wf-icon-zoom-image:before,.wf-icon-zoom-image>svg{color:#fff;font-size:24px;height:28px;position:absolute;text-align:center;width:24px;opacity:.8;top:auto;bottom:5px;left:auto;right:5px;z-index:1}.wf-icon-zoom-image>svg{fill:#fff;transform:scale(-1)}.wf-zoom-image-invert .wf-icon-zoom-image:before{color:#444}.wf-zoom-image-invert .wf-icon-zoom-image>svg{fill:#444}.wf-icon-zoom-left-top .wf-icon-zoom-image:before,.wf-icon-zoom-left-top .wf-icon-zoom-image>svg,.wf-icon-zoom-top-left .wf-icon-zoom-image:before,.wf-icon-zoom-top-left .wf-icon-zoom-image>svg{top:5px;bottom:auto;left:5px;right:auto}.wf-icon-zoom-right-top .wf-icon-zoom-image:before,.wf-icon-zoom-right-top .wf-icon-zoom-image>svg,.wf-icon-zoom-top-right .wf-icon-zoom-image:before,.wf-icon-zoom-top-right .wf-icon-zoom-image>svg{top:5px;bottom:auto}.wf-icon-zoom-bottom-left .wf-icon-zoom-image:before,.wf-icon-zoom-bottom-left .wf-icon-zoom-image>svg,.wf-icon-zoom-left-bottom .wf-icon-zoom-image:before,.wf-icon-zoom-left-bottom .wf-icon-zoom-image>svg{top:auto;bottom:5px;left:5px;right:auto}.wf-icon-zoom-center-top .wf-icon-zoom-image:before,.wf-icon-zoom-center-top .wf-icon-zoom-image>svg,.wf-icon-zoom-top-center .wf-icon-zoom-image:before,.wf-icon-zoom-top-center .wf-icon-zoom-image>svg{left:50%;margin-left:-12px;top:5px;bottom:auto;right:auto}.wf-icon-zoom-bottom-center .wf-icon-zoom-image:before,.wf-icon-zoom-bottom-center .wf-icon-zoom-image>svg,.wf-icon-zoom-center-bottom .wf-icon-zoom-image:before,.wf-icon-zoom-center-bottom .wf-icon-zoom-image>svg{left:50%;margin-left:-12px;right:auto}.wf-icon-zoom-center-right .wf-icon-zoom-image:before,.wf-icon-zoom-right .wf-icon-zoom-image:after,.wf-icon-zoom-right-center .wf-icon-zoom-image:before{margin-top:-12px;top:50%;bottom:auto}.wf-icon-zoom-center-left .wf-icon-zoom-image:before,.wf-icon-zoom-center-left .wf-icon-zoom-image>svg,.wf-icon-zoom-left .wf-icon-zoom-image:before,.wf-icon-zoom-left .wf-icon-zoom-image>svg,.wf-icon-zoom-left-center .wf-icon-zoom-image:before,.wf-icon-zoom-left-center .wf-icon-zoom-image>svg{margin-top:-12px;top:50%;bottom:auto;left:5px;right:auto}.wf-icon-zoom-center .wf-icon-zoom-image:before,.wf-icon-zoom-center .wf-icon-zoom-image>svg{margin-top:-12px;margin-left:-12px;top:50%;bottom:auto;left:50%;right:auto}.wf-icon-zoom-image{background:0 0;border:0;cursor:pointer;display:inline-block;float:none;font-size:100%;margin:0;outline:0;overflow:hidden;padding:0;vertical-align:baseline;position:absolute;width:100%;height:100%;left:0;top:0;pointer-events:none}.wf-hidden,.wf-mediabox-caption:empty,a.wfpopup.hide,a.wfpopup.noshow{display:none}.wf-icon-zoom-link:before{padding:0 0 0 5px;vertical-align:middle}.wf-icon-zoom-link>svg{padding:2px 0 0 5px;vertical-align:middle;width:16px;height:16px;transform:scaleY(-1);line-height:1}.wf-mediaplayer-object{background-color:#000;background-repeat:no-repeat;background-size:cover}.wf-mediabox-close,.wf-mediabox-next,.wf-mediabox-numbers a,.wf-mediabox-prev{cursor:pointer}.wf-mediabox-numbers a{color:inherit}.wf-mediabox figure{margin:0}.wf-mediabox figcaption{text-align:initial}.wf-icon-404{visibility:visible;background-color:#fff}.wf-icon-404>svg{width:5em;height:5em;margin:auto;transform:scale(-1);fill:#444}.wf-mediabox-frame{padding:.5em}.wf-mediabox-container{background-color:#fff;border-radius:.25em;padding:.5em}.wf-mediabox-body:after{border-radius:.25em}.wf-mediabox-info-bottom{padding:.5em 0 0}.wf-mediabox-nav{background-color:#fff;padding:1em}.wf-mediabox-close,.wf-mediabox-next,.wf-mediabox-prev{display:block;height:2em;left:auto;position:absolute;width:2em;z-index:1;color:#444;text-align:center;vertical-align:middle;line-height:2em}.wf-mediabox-close>svg,.wf-mediabox-next>svg,.wf-mediabox-prev>svg{fill:#444;vertical-align:middle}.wf-mediabox-close:after,.wf-mediabox-next:after,.wf-mediabox-prev:after{font-size:1.5em}.wf-mediabox-close:before,.wf-mediabox-next:before,.wf-mediabox-prev:before{line-height:inherit}.wf-mediabox-close{top:0;right:0}.wf-mediabox-close:focus,.wf-mediabox-close:hover,.wf-mediabox-next:focus,.wf-mediabox-next:hover,.wf-mediabox-prev:focus,.wf-mediabox-prev:hover{color:#888;text-decoration:none;outline:0}.wf-mediabox-close:focus>svg,.wf-mediabox-close:hover>svg,.wf-mediabox-next:focus>svg,.wf-mediabox-next:hover>svg,.wf-mediabox-prev:focus>svg,.wf-mediabox-prev:hover>svg{fill:#888}.wf-mediabox-prev{left:0;top:2em}.wf-mediabox-next{right:0;top:2em;left:auto}.wf-mediabox-numbers{text-align:center;display:block;line-height:2em;top:1em}.wf-mediabox-numbers ol{text-align:center}.wf-mediabox-numbers button{border:none;display:inline-block;width:100%;height:100%;border-radius:100%;font-size:14px!important;text-align:center;cursor:pointer}.wf-mediabox-numbers button:hover{font-weight:700;text-decoration:none;color:inherit;background-color:transparent;background-image:none}.wf-mediabox-numbers button.active{cursor:default;background:#444;color:#fff;font-weight:700;border:6px solid #fff}.wf-mediabox-numbers button:focus{background-color:#444;color:#fff}.wf-mediabox-caption{padding:.5em 0 .25em;background-color:#fff}.wf-mediabox-caption h4{font-size:1.2em;line-height:1.2}.wf-mediabox-caption h4 a,.wf-mediabox-caption h4 a:active,.wf-mediabox-caption h4 a:hover,.wf-mediabox-caption h4 a:visited,.wf-mediabox-caption p a,.wf-mediabox-caption p a:active,.wf-mediabox-caption p a:hover,.wf-mediabox-caption p a:visited{color:#444;font-weight:700;text-decoration:none}.wf-mediabox-numbers>ol li{display:inline-block;box-sizing:border-box;width:2em;height:2em;vertical-align:middle;line-height:1.75}.wf-mediabox-content a[download]{padding:.5em 0;display:block;text-align:right;text-decoration:none;color:#444}.wf-mediabox-content a[download]:active,.wf-mediabox-content a[download]:visited{text-decoration:none;color:#444}.wf-mediabox-content a[download]:hover{text-decoration:underline}.wf-mediabox-broken-image img{display:none}.wf-mediabox-broken-image .wf-mediabox-content-image:before{position:absolute;font-size:100px;height:auto;width:100%;text-align:center;left:0;top:50%;margin-top:-50px;opacity:.5}.wf-mediabox-broken-image .wf-icon-404{position:absolute;left:0;top:0;right:0;bottom:0;display:flex;align-content:center;text-align:center}.wf-mediabox-broken-image .wf-icon-404:after{font-size:5em;display:block;width:100%;height:100%;position:relative;line-height:1.75}.wf-mediabox-thumbnails{display:flex;max-height:4rem;align-content:center;justify-content:center;flex-flow:row nowrap;gap:1%;z-index:10;margin-top:-4em;background:rgba(0,0,0,.3);padding:.5em;overflow:hidden;transition:all .5s ease-in-out 0s;opacity:0}.wf-mediabox-container:hover .wf-mediabox-thumbnails{opacity:1}.wf-mediabox-thumbnails img{cursor:pointer;object-fit:contain;max-height:4rem;min-width:1rem;max-width:4rem;height:auto}.wf-mediabox-thumbnails img.active{outline:#fff solid 1px}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.wf-mediabox-theme-bootstrap{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px}.wf-mediabox-theme-bootstrap.wf-mediabox .modal{width:auto;margin:inherit;padding:0;position:relative;left:inherit}.wf-mediabox-theme-bootstrap .modal-header{min-height:30px;padding:9px 30px 9px 15px}.wf-mediabox-theme-bootstrap .modal-header h4{font-size:18px;font-weight:500;line-height:2}.wf-mediabox-theme-bootstrap .modal-body{padding:5px;width:auto;max-height:inherit}.wf-mediabox-theme-bootstrap .carousel{margin-bottom:inherit}.wf-mediabox-theme-bootstrap .wf-mediabox-caption{padding:0;background-color:inherit}.wf-mediabox-theme-bootstrap .wf-mediabox-close{float:none;left:auto;position:absolute;right:15px;top:10px;z-index:1}.wf-mediabox-theme-bootstrap .modal-header .close{margin-top:0}.wf-mediabox-theme-bootstrap .wf-mediabox-close:hover{background-color:transparent}.wf-mediabox-theme-bootstrap .wf-mediabox-nav{position:absolute;left:0;width:100%;height:100%;top:0;background:0 0;padding:0}.wf-mediabox-theme-bootstrap .wf-mediabox-next::after,.wf-mediabox-theme-bootstrap .wf-mediabox-prev::after{content:""}.wf-mediabox-theme-bootstrap .wf-mediabox-content-image{padding:10px}.wf-mediabox-theme-bootstrap .wf-mediabox-content-audio,.wf-mediabox-theme-bootstrap .wf-mediabox-content-image{width:auto}.glyphicon-chevron-left:before{content:"\2039"}.glyphicon-chevron-right:before{content:"\203A"}.wf-mediabox-theme-light .wf-mediabox-container{border-radius:0}.wf-mediabox-theme-light .wf-mediabox-close::before{content:"×";font-size:1.5em;font-weight:700;vertical-align:middle;display:inline-block;margin-bottom:.25em}.wf-mediabox-theme-light .wf-mediabox-close{border:none;color:#666;display:block;font-family:Verdana,Geneva,Arial,Helvetica,sans-serif;font-size:1em;left:auto;min-height:2em;position:absolute;right:0;text-transform:uppercase;z-index:1;background-color:transparent;width:auto;line-height:1;top:0}.wf-mediabox-theme-light .wf-mediabox-caption:empty+.wf-mediabox-nav{padding:1.5em 0}.wf-mediabox-theme-light .wf-mediabox-caption:empty+.wf-mediabox-nav>*{top:1em}.wf-mediabox-theme-light .wf-mediabox-close:focus,.wf-mediabox-theme-light .wf-mediabox-close:hover,.wf-mediabox-theme-light .wf-mediabox-close:visited{text-decoration:none;color:inherit;outline:0;background-color:transparent}.wf-mediabox-theme-light .wf-mediabox-next,.wf-mediabox-theme-light .wf-mediabox-prev{width:25%;height:100%;background-color:transparent;z-index:10003;position:absolute;top:0;font-family:Verdana,Geneva,Arial,Helvetica,sans-serif;outline:0}.wf-mediabox-theme-light .wf-mediabox-prev{left:0}.wf-mediabox-theme-light .wf-mediabox-next{right:0;left:auto}.wf-mediabox-theme-light .wf-mediabox-next:after,.wf-mediabox-theme-light .wf-mediabox-prev:after{background-color:#fff;content:"\00ab";display:none;position:absolute;top:50%;color:#666;line-height:1.25em;text-align:center;margin-top:-1em;padding:.25em 1em;font-weight:700}.wf-mediabox-theme-light .wf-mediabox-prev:after{left:0;box-shadow:rgba(0,0,0,.3) 2px 2px 2px}.wf-mediabox-theme-light .wf-mediabox-next:after{content:"\00bb";left:auto;right:-1px;box-shadow:rgba(0,0,0,.3) -2px 2px 2px}.wf-mediabox-next:focus,.wf-mediabox-theme-light .wf-mediabox-next:hover,.wf-mediabox-theme-light .wf-mediabox-prev:focus,.wf-mediabox-theme-light .wf-mediabox-prev:hover{background-color:transparent}.wf-mediabox-theme-shadow .wf-mediabox-body:after,.wf-mediabox-theme-shadow .wf-mediabox-container.wf-mediabox-loading{background-color:#000}.wf-mediabox-theme-light .wf-mediabox-next:hover:after,.wf-mediabox-theme-light .wf-mediabox-prev:hover:after{display:block}.wf-mediabox-theme-light .wf-mediabox-numbers{color:#666;display:block;padding:0;text-align:left;line-height:2em;top:0;position:absolute}.wf-mediabox-theme-light .wf-mediabox-caption{margin:0}.wf-mediabox-theme-light .wf-mediabox-caption h4,.wf-mediabox-theme-light .wf-mediabox-caption p{color:#666}.wf-mediabox-theme-light .wf-mediabox-caption h4 a,.wf-mediabox-theme-light .wf-mediabox-caption h4 a:active,.wf-mediabox-theme-light .wf-mediabox-caption h4 a:hover,.wf-mediabox-theme-light .wf-mediabox-caption h4 a:visited,.wf-mediabox-theme-light .wf-mediabox-caption p a,.wf-mediabox-theme-light .wf-mediabox-caption p a:active,.wf-mediabox-theme-light .wf-mediabox-caption p a:hover,.wf-mediabox-theme-light .wf-mediabox-caption p a:visited{color:#666;font-weight:700;text-decoration:none}.wf-mediabox-theme-light .wf-mediabox-page.idevice .wf-mediabox-container{margin-bottom:-1px}.wf-mediabox-theme-shadow .wf-mediabox-body{box-shadow:none}.wf-mediabox-theme-shadow .wf-mediabox-container{border:1px solid #666;border-radius:0;padding:0}.wf-mediabox-theme-shadow .wf-mediabox-loader{text-align:center;z-index:auto}.wf-mediabox-theme-shadow .wf-mediabox-close{border-radius:0;background-color:transparent;top:0}.wf-mediabox-theme-shadow .wf-mediabox-cancel{cursor:pointer;color:#fff;z-index:1;top:calc(50% - 3rem)}.wf-mediabox-theme-shadow .wf-mediabox-info-bottom{padding:0}.wf-mediabox-theme-shadow .wf-mediabox-nav{padding:0;background-color:transparent}.wf-mediabox-theme-shadow .wf-mediabox-close,.wf-mediabox-theme-shadow .wf-mediabox-next,.wf-mediabox-theme-shadow .wf-mediabox-prev{display:block;left:auto;z-index:1;float:right;position:relative}.wf-mediabox-theme-shadow .wf-mediabox-next>svg,.wf-mediabox-theme-shadow .wf-mediabox-prev>svg{width:1em;height:1em;line-height:1;margin-bottom:2px;fill:#fff}.wf-mediabox-theme-shadow .wf-mediabox-next,.wf-mediabox-theme-shadow .wf-mediabox-prev{border:none;border-radius:0;background-color:transparent;left:auto;top:0;color:#fff}.wf-mediabox-theme-shadow .wf-mediabox-close:after,.wf-mediabox-theme-shadow .wf-mediabox-next:after,.wf-mediabox-theme-shadow .wf-mediabox-prev:after{color:#fff;display:block;font-family:Arial;font-weight:700;line-height:2;text-align:center;text-decoration:none}.wf-mediabox-theme-shadow .wf-mediabox-close:after{content:"\00d7";line-height:1;font-size:1.75em}.wf-mediabox-theme-shadow .wf-mediabox-numbers button{color:#fff}.wf-mediabox-theme-shadow .wf-mediabox-numbers button.active{border:0;background:0 0;text-decoration:underline}.wf-mediabox-theme-shadow .wf-mediabox-close:focus,.wf-mediabox-theme-shadow .wf-mediabox-close:hover,.wf-mediabox-theme-shadow .wf-mediabox-next:focus,.wf-mediabox-theme-shadow .wf-mediabox-next:hover,.wf-mediabox-theme-shadow .wf-mediabox-prev:focus,.wf-mediabox-theme-shadow .wf-mediabox-prev:hover{background-color:transparent;color:#fff}.wf-mediabox-theme-shadow .wf-mediabox-numbers{text-align:left;display:block;color:#fff;margin-right:6em;float:left;line-height:2em;top:0;margin-top:0}.wf-mediabox-theme-shadow .wf-mediabox-cancel:active,.wf-mediabox-theme-shadow .wf-mediabox-cancel:visited,.wf-mediabox-theme-shadow .wf-mediabox-numbers a:active,.wf-mediabox-theme-shadow .wf-mediabox-numbers a:hover,.wf-mediabox-theme-shadow .wf-mediabox-numbers a:link,.wf-mediabox-theme-shadow .wf-mediabox-numbers a:visited{text-decoration:none;color:#fff}.wf-mediabox-theme-shadow .wf-mediabox-cancel:hover,.wf-mediabox-theme-shadow .wf-mediabox-caption h4 a,.wf-mediabox-theme-shadow .wf-mediabox-caption h4 a:active,.wf-mediabox-theme-shadow .wf-mediabox-caption h4 a:hover,.wf-mediabox-theme-shadow .wf-mediabox-caption h4 a:visited,.wf-mediabox-theme-shadow .wf-mediabox-caption p a,.wf-mediabox-theme-shadow .wf-mediabox-caption p a:active,.wf-mediabox-theme-shadow .wf-mediabox-caption p a:hover,.wf-mediabox-theme-shadow .wf-mediabox-caption p a:visited{text-decoration:underline;color:#fff}.wf-mediabox-theme-shadow .wf-mediabox-caption{padding:0;min-height:2em;background-color:transparent}.wf-mediabox-theme-shadow .wf-mediabox-content-ajax{margin:.5em}.wf-mediabox-theme-shadow .wf-mediabox-caption h4,.wf-mediabox-theme-shadow .wf-mediabox-caption p{color:#fff}.wf-mediabox-theme-shadow .wf-mediabox-content a[download]{position:fixed;top:0;right:0;color:#fff}.wf-mediabox-theme-squeeze .wf-mediabox-frame{padding:1em}.wf-mediabox-theme-squeeze .wf-mediabox-container{overflow:inherit}.wf-mediabox-theme-squeeze .wf-mediabox-close,.wf-mediabox-theme-squeeze .wf-mediabox-next,.wf-mediabox-theme-squeeze .wf-mediabox-prev{line-height:1em;position:absolute;text-align:center;color:#fff}.wf-mediabox-theme-squeeze .wf-mediabox-close:before,.wf-mediabox-theme-squeeze .wf-mediabox-next:before,.wf-mediabox-theme-squeeze .wf-mediabox-prev:before{content:"";border-radius:100%;box-shadow:1px 1px .25em #000;background-color:#000;width:1.2em;height:1.2em;position:absolute;z-index:-1;left:.4em;top:.3em;box-sizing:border-box}.wf-mediabox-theme-squeeze .wf-mediabox-close{right:-1em;top:-1em}.wf-mediabox-theme-squeeze .wf-mediabox-close>svg,.wf-mediabox-theme-squeeze .wf-mediabox-next>svg,.wf-mediabox-theme-squeeze .wf-mediabox-prev>svg{fill:#fff}.wf-mediabox-theme-squeeze .wf-mediabox-numbers button.active{background-color:#000}.wf-mediabox-theme-uikit .uk-modal-dialog{opacity:1;width:auto;transform:translateY(0);overflow:inherit;margin:inherit;max-width:inherit;border:0}.uk-modal-dialog-lightbox>.uk-close{height:20px}.wf-mediabox-theme-uikit .uk-modal-dialog-lightbox>.uk-close:first-child{left:auto;z-index:2}.wf-mediabox-theme-uikit .wf-mediabox-caption{padding:inherit;background-color:transparent}.wf-mediabox-theme-uikit .wf-mediabox-caption h4,.wf-mediabox-theme-uikit .wf-mediabox-caption p{color:inherit}.wf-mediabox-theme-uikit .uk-modal-dialog .wf-mediabox-content{z-index:1}.wf-mediabox-theme-uikit .uk-modal-dialog .wf-mediabox-loader{width:inherit;height:inherit;z-index:3}.wf-mediabox-theme-uikit .wf-mediabox-loading .wf-mediabox-loader{display:inline-flex}.wf-mediabox-theme-uikit .uk-modal-dialog .wf-mediabox-caption{top:auto;bottom:inherit;margin:inherit}.wf-mediabox-theme-uikit .wf-mediabox-content nav{position:absolute;left:0;top:0;right:0;bottom:0}.wf-mediabox-theme-uikit .wf-mediabox-content:hover nav{visibility:visible}.wf-mediabox-theme-uikit .wf-mediabox-next,.wf-mediabox-theme-uikit .wf-mediabox-next:focus,.wf-mediabox-theme-uikit .wf-mediabox-next:hover,.wf-mediabox-theme-uikit .wf-mediabox-prev,.wf-mediabox-theme-uikit .wf-mediabox-prev:focus,.wf-mediabox-theme-uikit .wf-mediabox-prev:hover{background-color:transparent}.wf-mediabox-theme-uikit .uk-modal-dialog-lightbox,.wf-mediabox-theme-uikit .wf-mediabox-close:hover{background-color:#fff}.wf-mediabox-theme-uikit .uk-slidenav-position .uk-slidenav-next{left:auto}.wf-mediabox-theme-uikit .wf-mediabox-next:after,.wf-mediabox-theme-uikit .wf-mediabox-prev:after{content:""}.wf-mediabox-theme-uikit .wf-mediabox-close:after{color:inherit;font-size:inherit;font-weight:inherit;margin:inherit}.wf-mediabox-theme-uikit .wf-mediabox-broken-image .uk-slidenav-contrast{color:rgba(50,50,50,.4)}PK��#]���}��&system/jcemediabox/img/broken-page.pngnu&1i��PNG


IHDR���>a�HIDATx��{lT�ǿ�9g��v�7J�@����R����r�BVwW~nĨ�E1�.Y�)���11(��T�l"*�Uw��X.DS�B���P��L�~���N3�\�̙i�'��s��>��y��y��c��}���13O��
�3�0�ǕB��h�˲w:��?>��l須���iɒ%������p8ʔ�g��z��ۋ��^D"�����'�|���x���ѣ �-c*�����U6��?Z[[2�z%��u�n7��ڰp�B�>}ڿf͚����O�j˖,L�7 ��=���c������������̙3M_|��?����;w�R�eK6��y����3}�t����_PYY	��Dx��H��K�.��f���ͫ-c"�m"��Y	A��Á����a��SOMx��w_?~�����"��K��@��TTT��� �}���cKK˟�FcKmm�]M�A�ƣ�k�FD�QD"�!�'O���ܹ�	&��v�m�*���=�� ��WQQn:^UUż��{��v��3f4(�=+͘5�JQXX������UUU1���]�����̙3?��%��ib�X�r��v������M555�5k֢,�7"J��͋-jka %�󨮮!��jre(**"�g϶����B����UC�Xh M


�F�_� �8q"ټy���ڷ��뗨 jL4H��B��cB�EJEEټy�3f�pJ�,�p��t���[ɢU���0�oΉɿ��'��^{���W^yK�דcǎ�_�䌅b
�L.��p��p(U���A�B!#� ��������7n|Kr���͆��к`�`0n��;زe��I�&�>{���l�+E�.���'ﻀ��:X���d��� �����׽���f�z�ĉ��u8U�D���Dee�Eg�a��<��(&q�*&UM"��۫ͯ��궙3g�>y����&���u@`8�u��gq�=���ɴ���ܒiy��b�N'�N�E�EYY�M�v�q��I�!�,Z����׷t���o]�t���W*�*
0ڢ��<���\I!x��G����b������<CU`����MQ@2O?E��cݺu�����F/9r�o�+C�( ��xtuu�b����A�
a�X�iӦ��ׯmnn����ߊ,A��j���v#����7�6m���7���9s.?~��b���A
 FXy�7>��S�2�ׯ��l6���YE�����zzz�*Zu.^��T��(����'�|������>o޼>x��En,A)��3ں�s�Ρ���p����GB�e0BH�!�,_�������?�|�'���]��eY��P(���AD"�e�q��N��N��q`Y,˂�8��YD��z��Ҟ����H�cǎ�UI�U�F���hoo�ѣGņ�y�HD|�<�p8<��L&�j����(//��l-��hċ/�X��3�<���ݱcǎ)%�f�l6cɒ%Al�P(�ߏ@ p�+��#
!��󡯯�ΝC(B4EEE�O����j���6l��q��7/^�Pkk��k
�X��^}�$�0�8:�z�F��`f��p�PHT�KB ��������p����N��#��ٳg�f땐U�DZ�e�0���K�{��1�0�F��08�Tqt:�N'Ο?�{�ĉ�H���C��']�5�A�5�����	!�PkRPP��p��,[������I��]]]C��lA=���l(..V�<����XO>�sA�X6�,+Z�N���tuuq���uw�y�-�}�]Z�HQ�d�ɓ'a4��a�
$}�x��y�G?����z��W ��d��l��l��bAuu5�^ttt���s/1�8Ni�(�4t��t���%�&M�9����U��'�0��t�Dz�sx��ٳgq���={���hooO�7a���hnnƊ+0gΜ�g���D"��bH��!d^�B�+�\	�V+���B4��)@��X2�@A__�9��qH��h���Ç�u�V�r�-x�'��c���=йR8����+�C@Ϳ��[���t ����<�zӞ4��p0�e��ckkkî]�p���dN���lذ[�l�ڵkq��w+^FQQ�8ɔ�Q
H3�A���I1 �y�x>��s)'N��J�K�x<x���q��A������<��,�4YDc�H��4���@��XZ1�?�z��@`�9�_�x6ٿ?�.]�}��ŝ��0LL�"��T���_�\B@p��,�����Ȼ�eQRR�aPXX�P(�@ �p8�Hf�u&8}�4�͛��۷c���ƴ���o�(�~�P�2�4S���D�Z����F��7)B.�v��s�N|��#*d�&[��\Ɍ�*��N���h��b��h�^�g��_��3�����ш���!a��|��7��F</ה����1�<����8��6����/���f���S�LI8똉G�J>�^
=.
��%ʔ)S�p8`����ׇ���{�$K ��kװx�bE�MTQ�H$���A�L&��p1�tp�b
gRKJJ�r�J̝;


��n�^#�.��o��G}�Ç�U��{��]H�1	�B����QTT���b��D"A|��)R����Ę9V�n�c͚5X�bŐ��/!W�^�%K�`�ҥhkkêU�R6�ǏO�TP�T%@�v�<���s��|�B�~���n�c���X�l�V+ÐĊ|�X�9566b۶mX�vmRu�tvv����J:���n=qɵ<o0y�d̟?��͘;w.t:�^/�^/���b��f��`p�
��#�Z�b���+���&]z����T��P%
�z�*�^/B�X���b��b���P�O�.j.\���&�)S&<<�8���x�Qm0IJ���ޚ�7��&���+���p�@7nܐy:w�N��y~�_�����f��b���2�,>��@`��lJ(���ƕ+W���1q�DL�:5�z��|BU@J$��`�Z������px�!�h4
��
��
�^���"ѢЧ^:�k8:���;崮�j�ɓ'>ܸq�0aBJe)�*���=⤎�@�k��Hc�P.�n�&�	z��Ah���M���"�B]]���S�VMT�>�O�V-��+chC'��
}��o���4\dFT���8Bą?��sJu_�`A�e(A�}cA"�S��Ě�M��.ΐB?'������'��?~|��O�;�J?)R������|�h�4̤���ԩSI�_VV��~8鱀\@5�f��I�1�@�6_�7��ᇛN&?O~n(—_~�R}^z饼l|@�Dߏ�@��2�g��'=7�b�޽)9����K�s�3f�t������P#}����<��~(��S��ر���)]KI�K�{�&k�lHi�Pj��Ǥ絷����%n�9/���.ͻߊ�*@�׋C��	�k���O2I!\.��ك�\��˗/O)l���2D�,yol6���nv�b5�pV@���H$�_����ؿʲB��ocժU)�#�P��\�R�b���v�СChmmž}�R�5H���صkTM���>�`Jq},��.l߾}�� �H��*���X�n/^,.�M�j�MMMX�n�ϟ���\Cѵ���l��.X��?�<��qǍ�()�B����ݻ�$��c>��h`�Z�r�p��%����t�h��:u*k&���eeeI_��Q@YYYJO麃D�>}z�[��3�6q2�yo\.\.W��I����T�e娒(--Eii��E�$�.`ڴi��=����~0b����D5���˸|��EK.w�X��]�(������%uʹi�Fu�OΨ��d�!��!'��۝�. �������P@I�Ĺ%%%y�e�
J�'-
㨒�93�g�}������]�vm��jYEU|�lT���_�uJ�nݺ5�2�шr�r0
H���K������|mgggƗz�#�J���X��e���bI��)S��{e�T���*V#w���tdɵ���,��bh��0��2�X�X����9b��L���i�;v�P[��@HyM�h�f���d<UT��V+�V�RE���r.
��쓓��d6��z���E��bU�r��Z`̣�V�׮]�]��jEQQQ��B���0/��O�|���X�G1��
hy�����h"�@��As�8Z������h �,��bhQ�G�cM�8i+!�4۟���^�p႟a����v��`ړ*Ҷ���n��#�aLm��m!0�� ���S�E�����[�l1=���S�6�/��\.��|��~�t�\��{?��&�ݾ�j�ֳ,��?��'�<��|�N��+_!�MÔR=�*A�.2E���Ii/�R��&Jؠ)A&�� �A��������?V�}��<oIEND�B`�PK��#]#��#system/jcemediabox/img/zoom-img.pngnu&1i��PNG


IHDR��
sBIT|d�	pHYs��~�tEXtSoftwareAdobe FireworksO�NtEXtXML:com.adobe.xmp<?xpacket begin="   " id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.1-c034 46.272976, Sat Jan 27 2007 22:37:37        ">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:xap="http://ns.adobe.com/xap/1.0/">
         <xap:CreatorTool>Adobe Fireworks CS3</xap:CreatorTool>
         <xap:CreateDate>2008-03-10T08:35:17Z</xap:CreateDate>
         <xap:ModifyDate>2008-03-10T08:35:44Z</xap:ModifyDate>
      </rdf:Description>
      <rdf:Description rdf:about=""
            xmlns:dc="http://purl.org/dc/elements/1.1/">
         <dc:format>image/png</dc:format>
      </rdf:Description>
   </rdf:RDF>
</x:xmpmeta>
                                                                                                    
                                                                                                    
                                                                                           �T͋mIDAT8���MH�A����j�a�R�m����)Z�E�c��P�Q��]Z�Tt萷�P��R��cQH jA�
Q�X�K���3o��-\��?��<��73�3�9�Z�\S
(�{b��%��a��X����^O�:t�wp�	G�[ۄ,��X/����k��D�N%۝% EA����m%Pd�p��%(da�j��j�m�>��}-�wV%S
G�<[6�bB�[cb��#v�"�
8X��5:� �w�rJ��@i:Y���\�N�>����m{�
@���3�[ezҟ\<ek�X��e����&���P{��5�t�e��8�M*��V��։F��=k�x��
�ZO��MJݲ��ٞ�� 0
āD�?zv��zOQ�gD/�N.������m�'�keb��}F�k�T��xm˾���b'j!���~f�~��tw`"'�� FȐ����x���tW�aJʷ#�d��G�>~a�MU���f"'�����Z�vTF� E�e�q&�
�w`,P����á�?�0_5����|z�e?3�Ƙ�1Ij~��@i�sn�{���I[�U-�Ȧ���2�<U���o���~"�/�7�##��w��Tk~c��v7�"��iIEND�B`�PK��#]�h�Lj�(system/jcemediabox/img/loader-shadow.gifnu�[���GIF89a  ����444rrrCCC]]]������###===������!�NETSCAPE2.0!�Created with ajaxload.info!�	
,  ��Iia����bK�$�F�RA�T�,�2S�*05//�m�p!z���0;$�0C�.I*!�HC(A@o�!39T5�\�8)�
��`�dwxG=Y
g�wHb�vA=�0	V\�\�;	����;���H��������0��t%�Hs��rY<H.�ʼn��	��b�Zb�OEg:�GY].�=�A�OQ�s���\b�h.9�=sg��c��e��*�ֆf7D!�	
,  ��IiY��ͧYF5�F�ԢRÔTbG�J����L��d��&�Ymx莔� \@���� �1�&R���H
41Q��|V%zv#j0�
�l�Gg{0~�<�<	�[�[�h�x��G�
y���������[�0���G����P�z��hɾ�Ękz�i��y����h|z�h�G݄�VŢ�����\h�[���Ǥ���&�+��W�7�8��!!�	
,  ��I)1����1G5d]�(��RDz�T2��jL�{��< [�5�M��
0�)�
 L��I��m��E��`�p�U
�^f%�^���u;zz}0�X	
�S0ewyk<�%	�O����	��z��{����|������%����F�i�1”0�����˼Y����8�x����	z��@���<ݫ���������8��Y<���ɥ8�\�P$���!��
!�	
,  ��I����gEU�� ՠR�a�TB٤�p>'���e�$��"�\�#E1Cn�Ď��~��J,�,Aa���Uw^4I%P��uQ33{0�i1T�Ggwy}%�%'R����	���=���������3��G�%��p��0�
��JRo�5Ȇ0IĦmyk��x�T�_}�(���^��yK��s���>i_�%���n�=����q�4e�-M¤D!�	
,  ��I)*���')E�d]����PR	A�:!��zr����bw�
%6�"G�(d$["���J��Fh��aQP�`p%†/BFP\cU
�
?T�tW/pG&OtDa_sylD'M����q	�tc�������b��2��D��M:�����d��%��4%s)���u��E3��YU��tږ���D�$�JiM�<�Y�;�ذ��d<� O�tX�<q'+B!�	
,  ��IiR��ͧ"J% �����EQZ�����Ld���-Y��
�h��k�Q�|��5�u�4Y�I���N
bW���u��5�
�r��	�%yb>^%o/rvl9'L����;��9�����������9�%��i9���� C�"�BB��Ds��^Xf}$P	�{L�?P���O4��E��咛V�$���dJ�#)�pV�$!�	
,  ��IiR��ͧ"J�d]� �R�ZN�*P*��;�$P{*�N���\EА�!1UO2�D	�_r6I�b
�����H��8	B�;	��"'��Z��t��b�K#C'K����w}?�����K��iz6��:x�KAC���&}9�tz\\���D5;x���Q�d(�	��KW���MB���I��ڈM=�ˤs�⸽8Da��J`@LG!�	
,  ��IiR��ͧ"J�d]� �R�ZN�*P*��;�$P{*�N���\EА�!1UO2�D	�_r6I�b
�����H��8	B�;	��"'��Z��t��b�K#C'K��Gziz6��8}z����~��%X�K9�:���0}�%	�tz\B��lcL�bQ���	������lj���ųK����ň������x�(țP�X,��ւ|/"!�	
,  ��IiR��ͧ"J�d]� �R�ZN�*P*��;�$P{*�N���\EА�!1UO2�D	�_r6I�b
�����H��8	B�;	��"'��Z��t��b�K#C'K��Gziz6��8}z����~��%�:�A/C}���u\��h}b��D��]=����	��V)��
ڊ����9C���D�K����K���u�	��*00�S�tD!�	
,  ��IiR��ͧ"J�d]� �R�ZN�*P*��;�$P{*�N���\EА�!1UO2�D	�_r6I�b
�����H��8	B�;	��"'��Z��t��b�K#C'K��Gz���z5
���������C�:	�A/C}���u\��Eh}b��6�[=�����Wx&)���I9�Ԭ�@oC��T?K����d���]��B7����6ЫD!�	
,  ��IiR��ͧ"J�d]� �R�ZN�*P*��;�$P{*�N���\EА�!1UO2�D	�_r6I�ƀ��H��03���hո��a��j U{CIkmbK#�cK���8	�{a��8�n��������V�:�/q:M�
��Cu�~���Eh�k��6	�[_���6P</U�YHF��9?M�%
�G���C�k�v���>.]�6��!�)V�!�	
,  ��IiR��ͧ"J�d]U�R�ZN	��J�j�N2sK6�
��d�I��)
L�H�W�G6	�KX��젱�.6�d��~z�h��uur/6 X5�I;_�tO#E	{O���9V����9��4��������;V�C/
��6�Ø~*�'��Mo����n��bX�:~]+V*�m�K_�O�rK�N@.��d�~�qЦ��D�B֋5D;PK��#]`&h�zz$system/jcemediabox/img/zoom-link.gifnu&1i�GIF89a�~����������ϯ����!�,?x���@+0����d��X�_8�D����B!�5�+ �w(;[q5�`�Rr�Y��,6;PK��#]
�7��'system/jcemediabox/img/broken-media.pngnu&1i��PNG


IHDR���>a��IDATx��oL��6&�����	�
ğ�隙(B���hI�����VES���Lӆ�&�,e/�(b�#��,LR75QF�5�EЦ+��&. 32��6v��P�E��C���s~~�g�y�3_���k�AAai+�w�޼�֑.�&:88 �c%4<V�Y�ηn�[yy�_F=���`o��
�2�y�L��k�yqq�cP�yH��S-�Pg�@��
�8h����
<	����Ғi��������m�cjj��8h�!�v����-�����I�,�c���ڱ0�q���`4�\��	����Ғi����zai����ڱ0�q0
&5�cLjj��8h�A0�q���D,�����XSSS(�q���y-���u���>y�$�����H(�ܻw�300�pnn.*��(d�Csw��m޴iӆ���₂�"�N��R�R:۵�����gvvvf```�…_�b����j�`���]�v}���������h4��juN�s�T*��`(2E���o8p`~lll���ӟ����K��m�����w��� B����8No�Z�vuu����8v��-	�� i��I�ޔ���<�Drss�;v��j}��ѣ�

�DL�v�RA�=��2�����V�'
�*J������Ǐ������ڵ���_04%y�G>e��.ĥ��t�R�4>�/�e�I�z�\e���`0@ww7���|*���2jkk��p��!
4�D����^�'-#e�]j��������>����ڋ����@ 0��@ ��hrA���x��S�Ti_.��88u�ԇv�}�f�����oNw~��6
��.--]u��q܊Qm4���r}6::�E__������A����Z�ꊌE�kXBccc�ٳg����F������F� S�D�o޼����ZK�:::F:::F<Xy�С�M

�׸+F�R
�|���7�p0\3Gww�k����755�%f<�q:����pX1	��
�v�gy��lxx������P(���'N��Z��f��*ձ*�JUUU���Ұ�Qtl��`P2EOq��3b�D��ߏQ0P��\�٭[���v����\F���es�$ܿ�l5b�XDI�
���,�ż3H4@6l�P f���Ԥ�Z�
������Ō��Z�ܠ�a��^1��Lu\4
_�|yJI�Br�[x����!��f3����$f��۷�^�`I���I��|J�� h��z}�?�E�N�)��vl`�X�M&S���W�\�`zz:"��L��(X
>\k��p�3��ݻC'O��ZW�Pt�۶m+jmm�QVV��
������X[[�"�b�����\��V�}�v��l���M���_ݸq��G��D����$'�[��b��߿�j�ƍ�&��U�Z�V��h4t�ܹ�z{{�$#�
�p8���t�R���xf�v���ܹ���>#�
 ~��s����;;;G��fϋ@���Ǐg�^��љ3g��� 	s��龿�}t���{���
 	o������?^�0	d4�l{�A�6�!-����I`��#VFF��[��d�%|}��gԬ�cBM�$
�L��ŋW���֥2&qoFj_Yuuu}NZ��kơ���x��z����M^"-`5�5�񸑴�l�f�����jq�۷oD�r],��:
����͛7���j�4F���84k����h4�� �%�3rrr���v����&
����?UVVN�3GIIɏ�\�؆���?|�0�S��G��&&&~��<r��@�(��Ԟ�Q0�PS;��A0�q�]JAss�Ik�<0�3@3�'a��p���LCM�$
0K��B:H@M��
�8����1
&5�c`4�
�8h�(��ԎQ0��[��d�)$ޟ�[�����I���Mjj��8h�A0�q���Q0���`2PS;��
����G�W	�|T_�Z�B�7].כ�ud;����1
&5��2�q��#���")!��S2Xz!IAA����!�
��IEND�B`�PK��#]�@��
�
'system/jcemediabox/img/loader-light.gifnu�[���GIF89a  ������������������򺺺���444��ė�����TTT!�NETSCAPE2.0!�
,  �H��
*\�p�	h�p�����"��8��G>D)����R4�C���I��Ë\��9p��:ȹs��1_2`�p`��
u�<	u�SY�ڐkǞ`�F�hv�ƴ6S>u��+�ryJ�/Q�M.0@�p_�+�+���/�KY&]����9�ى
Mr�	�`i�x�r\����˪	vf��jMO�&*Z��؇o�>;��ܦŝ"�,<yQ���:w��a��+g5N1 !�
,�H� �*d�!AFT8���	h,�P�
j����6�h$ņ&$RfƆZl�R VTY�eN��=J��ЗH�B,5�O�U&=�Ua��]�z@�,تf͊%PvAY�!�
,�Hp�*\(a��H��E�"4`�bCPɐ�-�$�q�ɔ
Y2\�q�� Eĩ��I��8��C@9�f�M	.8z�R�<�x��Q�W	0��T�W�.4z cO�c52��P�F�!�
,����*���� �ЀE�2.0��Ł7r,0��A�"&$���@��\�%E0	0���@�8?�D��'Ǜ�4��
���fϦU!����I�`�&<@���`͚���!�
,�, ����,@`A�,4����' `�"D�;���3(���G�
�(���
�ɀ&F�����НF�t��iӤ)oJuz� ��N�`z���~���c@ř֣�d!�
,�(����HȰ�,X���B�/&�hP"ŊN�Ȑ#��
��р	h$�ҥƆj �P�˔mE8p�Q��*��P��\��Ճ�~4p� ��
	88���0Vm��ۃ��@���@Ͼ�j���v���z�%À!�
,��@���a��
#.$� ��+
�Q�Ǝ9z�qŊ1j,�Q#Ǔ#	�I���8h���@Şt�JsB==Zs�҆:[
<�T�O�u2x�+��$#v=@k±�VDK��T�g8P�Э��j!�
,}H� �(`��@�
:L� !�3b�1�;�H�ȁ�4�@�&	�y��h�r$��(�@�
`S�Io:,�rdR�O}5��*Ƭ�b=P�kY�s�=I�c@!�
,�H��A$�@�A$<h�	F�X@�ŏ5n�(���d$�q�H�'[&\`p�4BTY�@�?`d@@��&>,�@C�Pؼr�S�E.�ٴjT�WYR
Y�+ѫ�����K��b
��ڌ!�
,�H���*<X��‡	t0�ŋ10��ゎ�� a@d�@�	���%G�,E0��̙U�!ϛ?]Zd�qgσ3�|���ѧPi.Mx��օV��D8bS����@ل!�
,w8`���8pA‡d0"�XL``��A�I��ɓ(7.`��$K� _���%��txp�5H !��
Z"ҦL!@z0�C�E
ZM���֡	x�:�X!�
,�`��8� !…8�D�^\`�`C�?z����Q�$0q�G��y@�5[2�����=��	�gΣI^`��R��JuhP�B�$0���N	�R�ׁ�(�P-ۄ\��T�Sn�o;PK��#]"C�+JJ'system/jcemediabox/img/broken-image.pngnu&1i��PNG


IHDR�mi�i�IDATx��]K�Ŗ��U����꧱��kL[2HYs%@�H�͌t7w��
�O`6Hh���+6l�H�#a趍1���Տz�{�I�����*7�'��*3"ND��8q2
�b�)���/
)���ӧ��yޒ�(5��jfE)��oS$��8��$I-�qZ�$5VWW�D�	�����r��̫����.��V��333���/��ZΫӞ����D�{�Z��3c���l�Z��+W�\}��w��z����m���g����?���K��q��񿇕ˊ)�GN���_�|�w>�����ڵk��P�+++�/������[�577wS�9ӕj���/>���v��j�l6�=����(���\�t�y��QcR̚$�$t�B���_�G�\~��7�N�>���^{�?.^��O�h��e����fgg�$��?��c��ܥ�C��.��!b�ab„�J�>��9��؋C�(J�R�,���)�'K�V�-+�Rc���V�T�0L�?y��Ri�X��	��T*�)q�2���[.�̰�xPTUUυ��2����i��Gq,�Ĕ�>ݑ	������H`��C7w�2�p��U��?|ts�)�']5-����}�*�J�&2A�F����p����y�P�;;;x�W��OD�/��u]�8q�����!2��2�:
�,�	*�ea���?��Sd;qH-�~gdY�W>ͽ�r�b,{R���_KjJ2	�,ˑ��17/�ʲEQ�y�I����u������ac.EQ03�Fw]��a~~ޟ��4M����#�&�8E��i�J�1��37N%K��cǎAUU�;9��~ߟ��BKKK�v����
�
I�U��/-K���� 2W�^�^�U=h���/��0M�a����2��"z�,��27�q�!��7 �ރ��8(��J�2�,SU��eTU��(p��&�]"���41`�pF�?	 l�f®�܋�?��ZK���*
���g@�e� ˲�X,�q�۶웈B���`�N���9�Bfc�L@�u����ߓe�R	�B��@UU
�_�l�Hu]�`0�eY�u]�!I��nl�5MC�P@�߇뺹�[���9"f`R��+K�\�u(�EQ|�<�5}�Η�i���y���mx�M�`Y��.4M�͈���t:���# v'�Qya�2(I]I�P(P,���.��<�q���"��²,ߜ�Y��yJ��o:��g=33�4a���,��@3)F��0�3W��|�+�Y��8��Gt����	�Xڶ��#�����,jf�
R�������C�VC�\����:Ҭ4�f�~_��h_	�E���i0c�]UUa�f�>@� )s�fgg!I��D2cH���MӰ�����e��ΦV��,�X,�X,�V�������t:��T6�/�|H{eE�P0����dA�TU�����J����boo�@�)gΜ��B��V��V��zX__�!-�
M���7�w,�	�����,��4y�{{{��r��G�N�<��w�b{{[�nS rPY� �Q�>���if�P�L��$	�z��m�I3M3�I5�Y:�=�<�C�ٌ,�N�{�*E��	���_^�J�P�(��/���"<��`0�w���x�>�(Z�V����*dY��3�}0�›���:�(z#M��ZX��S����
�,�ĉX[[�J%�J��Y*���t�Z�"�i�rUU����"N���t�����8UH���i��8��A�^��J�]����~��>�ɜEA���_d����� �.��T�B����.vww��t��t��|
/9���6��t��1�Z-_����>��	]�>��Y
�&�#�
���e�Y�%�*�I�2���l��l1�@�5I�`�3�
�9s&�F(�~L_4���:J��S���f,Y�|�'��[��y,���6���}� �̯&��>�ܹ��\��Z#�C�V�Ckx^�]ׅm۱���KkR���#ˑ�j7���?��*�]�0A�4���v���	d�ԡ�n�亮�$mECQtƞ�J:s���6b>]/�J0MӟI�,%��X��z�֏sjyP?�ڦ�i�ڶm?ۈ�7��P�ѣ����#��u]�Z6��bǠ�'
�q�=�zV�"3�D��	d�.�TRu�%RƖag��yCK0���u\6@�#nf�0#v�8��0����/�r`�Pr��j��x~�g"D��T8}�S��2�ыBd�8jSKd�|}VӉ�5�H`P#�eacc�O_:r��;����SE%i&�G�T"�c
"�bD[.�r���K$0LRm�S�M��/����Ǐ�[�l� �]-��UAΜ�8����	{Ћ���V�B�]���֖0��F���D?�9)�/��/�'e�wfw��"*��|��.�h�0�-EQ��:��**�
���Q�ׅǹ��+����b5d�<�N2%��u]lll��lb~~~(՚R��@��׶ۧ|۶�!r��VIb㴵Laa�T*8{�,����g�&�����g�G�+,�EȚ�9)4�eassS��eaww���~�4cEIf���XYY�ɓ'd����~;�}'�^�m�m'
�d繖M���A�k�8�����E=z�<�p���j������֟�k+i�c
���y�;wdJ������8u�T�5>���5|����7���2fgg#��yP/�$��0�M B�`����A�@7"_�$��ϧb���VWW������_����b������ГR��6��ׇ6v��u���X,�����y�e���
yƪ��R�$V�"�4r�Qd��H�����ښ����)���������
i(۶}�m���^��^��Ӡ�"Z��R:N(�J�'������lX
PU���+�<A�=�Sƪؤ[խV�|�
Z��ߞ�����h4P�T�%p�ш���B��v�T7EQ|a��	��N,)T�$���H�����h`kk���8r�H�pk�@�]*�Z-��l�$�i���'�������Z��z��S�#K
Mډf��V��'N�\�7�hw�v��a�	��N�n�j�OC�P��{-	�k�������B��cǎ�V�	�7Ҥ�4�,�o����2�����q����v�^'��ˋ�H�0p��5T*,,,�V�
�ذwH(���Ð6<nY�޽�Z���Ǐ'���2�޷{��#7�L�D��G��K�V�d�5Mt�X��T��gT�$��8�Z-ܽ{7�X�B�����֭[x衇P�V���a�z�v�Byq�y���������T*��>�A%P,���Y��N��%=���<�y���'ݍHx�������@Q��΢^��\.�2a|j:�V�T x'|���^��v�=t:��(�4
�b18O~�����W_Ŗ���(8��gS��\.�g$u
i���[�lcM�b�c��X�BiV��b��4M��.
C[�y�T,9������޻wo$�h۶��̣�^�T�|I�E����C�����4-r�j�I���ױD�Iٯ�6���&�^�O�,�C�����eY�}
A�&	K{�營%I�5+���mGu�^��J�]:>�Cd Y�x�K �K�A7�`��C9����"z�P$�k0��Mnoo��x饗p�ԩT�Km���ڻq�ܹsx������'���/{�TV�dh��C�Ʉ����4|��X,��ѣ��-�LY�����XYY.��u�o��<MI�		�9333���	������4/�����`�`�6vvvp��=���˩��tT� L0hk�}��
/�/��w�O��2�G�)962e��P�q�.%��|9b$��I�`�G(�~g5��[@�:93e������F������f�}&!�zQ�_$�9�3��D���hU~�ض}`۔�c�~!��U�,����g	��M=/+#���$�!SVp^5�f�&��R��i��mKTu�M�o����.�"�Q�<D�3s"�E�>._��˗/��m7l#/F��N�U��%2��������C��1�|��)�f�{�}�X(@�8jF��$y12��4�i7���n���E�G��ig#�=�}�k7)#�:~|��2������W��)Ȇ!G��dm7��c~#E���
��k����"�Q	"L��m���ƖK��8fƵ�?�>r�Z�'r��U?�}��i�t-+3������9L��E�#G��8:|�,uEgx\��?�:,IR�2W��砇v?��{��eE��KTݨ�l����B��{"cd������P�=n,|[Y�NRWQ�L	6�C��,�9�"B7����{�g�Z}�rA�y"c*���#�c�P��O?�+W�]SEag	�����z����"�k�~�O�:�=�\�	��������e�����joR�E��"�e)�7ݼ�;��F$S�g+�7���.S�g+�7���*S�g+�7�Vs�$��\�t�n��|��q˲�Q�2<�k��8�y
��t:��HK[.o�y���3?
�nw��hC IR��n�6�ga~�t'�(ڝNgO���c�x����	�UdABiʉbW����|h�ZM�q�@���g�}�m\C��a��0�Q"���O��$��^����;�޿���nf!4*L�~z�kkk7�������a�Xʲ|���~�3��:u�300�o����,_��x���h칎[�z������/,,,��ԟ�����?�|�7��ڵk�oܸ�)?�F��mە?������(��`0�;��h��*��L�?���������۷o���~��7���������B7�O�:�$Iҿ��eY5��(%��J�,O�|�)�u][����8}M�Z����y_ݺu�T'.���SO�G\��E)���y�7�㾧�I�۶-�qLY�-]�7����U�o񊦝�?���~�_�u���j���S�I�<۶��``�J%�ƍ۱��b��0�xHaYU!$^IEND�B`�PK��#]J��r(system/jcemediabox/img/loader-circle.gifnu�[���GIF89a������������������������Ž�����������������������{{{ssskkkcccZZZRRR���!�NETSCAPE2.0!�,��%��BP�,{�i+���z⯍�@ 	K�fAP*J�85v�V
:�q�T-���J 6������<��!QW��V8,^D�-F�9#	
#AA��#
^S��I�h��`�th�A�u_�z�|h���^���Sk�3�,��Ҍ^j:��-u�%���
�u����M���h��π�~��C����r~�!���,H% &�4,6`"�u�V@/���>�!�,ؠ%��(�P�,y����c�*=C��2 ���`��d�T �X���S�h�U�@KLݕg5/�WE���U��Ee4}9$L:kb#�:$
��{�,��A�$���%����#���"�	�%		��+
�����Ĵ���"
�:��
���Z��������������˵	��L�`lF!�,ՠ%��8HQ�,K p�Ϋ������H ���`�ݘ�� h%��B��M���U4o���+�ʅHP�k6�@��_U+p�,xSm,
��&0�:$#�~�#DDF��9�����f���D��r��D	�L��F����a

��"��VҘB-��3��߽�$���%����&���	��n
l�!�,נ%��X,�Q�,k00��4�F��{3
Q`0��d�wP��L&s?F!�
V��aa2BZX�ɇhp@�-�5"W�!-OkS+
bE-]<.
�4w%
A:-#	���"�_��|�����
�����d����3���_�r����	IhөD_,�:�4����%����B���#����
����W"!�,Ҡ%���@	����������	!"�WcT(VIeɰ��c�0�&�,B�����F���<E��DDP,rN6#E�W3RlV#e:	`
+@C:vx��G�3�>�*��b�D���#���"��"�������"�����˝���̖������,���֛���G��3��#����Ǹ��:!!�,ՠ%�$2Q��lBU尴J�x�Լ����p�|��„���N�l�$�aAT����p D�/$%V-�綊Q��W	�cw�}+��"���������l}�O�	�qY�		�#�X+�<��"���,��#���"����������кŦ�����������Ф������F�ˁ��B��!�,Ϡ%�diZ2�l�RUE%n=�xU���
^��<�,DQ�dAr�M��H'@ h��( (Md
9X��r�G`�
q3����ye{6~kpq�5�4�gMvX"[[^

n&d+6�-��,��%��,��&���������))��S$dz����;Ƨ+���­ўس���"�	�B긘$�)��#��-!!�	,ؠ%�di�h��l[஀`��ַ
�Wϖ�C�����"dOIcU��8H(�"aL��t%a��ϕA�� �䁫AOO�cz-}inof-�o�.t#�:	l'�)		�%�*��
'��`&������""
��&����l�ɍ&�w��������ѳ՝�'`���3��U��Y#
,`pOE;PK��#]t�M++ system/jcemediabox/img/blank.gifnu&1i�GIF89a�����!�,D;PK��#]�#o,,!system/jcemediabox/img/index.htmlnu&1i�<html><body bgcolor="#FFFFFF"></body></html>PK��#]i��}
}
(system/jcemediabox/fields/components.phpnu�[���<?php

/**
 * @package     Joomla.Platform
 * @subpackage  Form
 *
 * @copyright   Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */
defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('list');

/**
 * Form Field class for the Joomla Framework.
 *
 * @package     Joomla.Platform
 * @subpackage  Form
 * @since       11.4
 */
class JFormFieldComponents extends JFormFieldList {

    /**
     * The field type.
     *
     * @var    string
     * @since  11.4
     */
    protected $type = 'Components';

    /**
     * Method to get a list of options for a list input.
     *
     * @return	array  An array of JHtml options.
     *
     * @since   11.4
     */
    protected function getOptions() {
        $language = JFactory::getLanguage();
        
        $exclude = array(
            'com_admin',
            'com_cache',
            'com_checkin',
            'com_config',
            'com_cpanel',
            'com_fields',
            'com_finder',
            'com_installer',
            'com_languages',
            'com_jce',
            'com_login',
            'com_mailto',
            'com_menus',
            'com_media',
            'com_messages',
            'com_newsfeeds',
            'com_plugins',
            'com_redirect',
            'com_templates',
            'com_users',
            'com_wrapper',
            'com_search',
            'com_user',
            'com_updates'
        );
        
        // Get list of plugins
        $db = JFactory::getDbo();
        $query = $db->getQuery(true)
                ->select('element AS value, name AS text')
                ->from('#__extensions')
                ->where('type = ' . $db->quote('component'))
                ->where('enabled = 1')
                ->order('ordering, name');
        $db->setQuery($query);

        $components = $db->loadObjectList();
        
        $options = array();

        // load component languages
        for ($i = 0; $i < count($components); $i++) {
            if (!in_array($components[$i]->value, $exclude)) {
                // load system language file
                $language->load($components[$i]->value . '.sys', JPATH_ADMINISTRATOR);
                // translate name
                $components[$i]->text = JText::_($components[$i]->text, true);
                
                $components[$i]->disable = "";
                
                $options[] = $components[$i];
            }
        }

        // Merge any additional options in the XML definition.
        return array_merge(parent::getOptions(), $options);
    }

}
PK��#]T%r����(system/jcemediabox/js/jcemediabox.min.jsnu�[���/* jcemediabox - 2.1.2 | 2021-09-23 | https://www.joomlacontenteditor.net | Copyright (C) 2006 - 2021 Ryan Demmer. All rights reserved | GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html */
if("undefined"===window.jQuery)throw new Error("JQuery is required to run Mediabox!");!function($){function scrollIntoView(el,pos){var supported="scrollBehavior"in document.documentElement.style;if(supported)try{return void $(el).get(0).scrollIntoView({block:"center"})}catch(e){}var boxCenter=$(el).offset().top+$(el).outerHeight(!0)/2,windowCenter=window.innerHeight/2;window.scrollTo(0,boxCenter-windowCenter)}var autoplayInterval,MediaBox={util:{},settings:{selector:".jcepopup, .wfpopup, [data-mediabox]",labels:{close:"Close",next:"Next",previous:"Previous"},convert_local_url:!0,autoplay:0},popups:[],items:[],activator:null,getSite:function(){var base=this.settings.base||"";if(base){var site=document.location.href,parts=site.split("://"),port=parts[0],url=parts[1];return url=url.indexOf(base)!==-1?url.substr(0,url.indexOf(base)):url.substr(0,url.indexOf("/"))||url,port+"://"+url+base}return null},isPrint:function(){var site=document.location.href;return site.indexOf("&print=1")!==-1},init:function(settings){var self=this;return this.isPrint()?($(this.settings.selector).children().unwrap(),!0):($.extend(this.settings,settings),this.site=this.getSite(),self.create(),void $(".jcetooltip, .jce_tooltip").each(function(){var text=$(this).attr("title")||"",title="",cls=$(this).attr("class");if(text.indexOf("::")!==-1){var parts=text.split("::");title=$.trim(parts[0]),text=$.trim(parts[1])}$(this).attr("title",text);var pos=/tooltip-(top|bottom|left|right)/.exec(cls);pos=pos?pos[1]:"top",window.UIkit&&UIkit.tooltip?UIkit.tooltip(this,{title:text,position:pos}):"undefined"!=typeof $.fn.tooltip&&$(".jcetooltip, .jce_tooltip").tooltip({title:text,placement:pos})}))},getPopups:function(s,p){var selector=s||this.settings.selector;return $(selector,p).filter("a[href], area[href]")},translate:function(s){var o=this.settings,labels=o.labels;return s&&(s="{{"===s.substr(0,2)?s.replace(/\{\{(\w+?)\}\}/g,function(a,b){return labels[b]||a}):labels[s]||s),s},getStyles:function(o){var x=[];return o?($.each(o.split(";"),function(i,s){s=s.replace(/(.*):(.*)/,function(a,b,c){return'"'+b+'":"'+c+'"'}),x.push(s)}),$.parseJSON("{"+x.join(",")+"}")):{}},islocal:function(s){return!/^(\w+):\/\//.test(s)||new RegExp("^("+Env.url+")").test(s)},auto:function(){function makeID(src){var url=document.location.href,key=window.btoa(url+src);return key=key.replace(/[^\w]/g,""),key=key.substr(0,24)}var key,self=this;$(this.popups).each(function(i,el){if(el.auto)if("single"==el.auto){key=el.id||makeID(el.src);var cookie=MediaBox.Storage.get("wf_mediabox_"+key+"_"+i);cookie||(MediaBox.Storage.set("wf_mediabox_"+key+"_"+i,1),self.start(el))}else"multiple"==el.auto&&self.start(el)})},getData:function(n){var data,o={},re=/\w+\[[^\]]+\]/;if(data=$(n).attr("data-mediabox")||$(n).attr("data-json"))n.removeAttribute("data-json"),n.removeAttribute("data-mediabox"),re.test(data)&&(o=MediaBox.Parameter.parse(data));else{var rel=$(n).attr("rel");if(rel&&re.test(rel)){var args=[];return rel=rel.replace(/\b((\w+)\[(.*?)\])(;?)/g,function(a,b,c){return args.push(b),""}),o=MediaBox.Parameter.parse(args)||{},$(n).attr("rel",rel||o.rel||""),o}}var i,attrs=n.attributes;for(i=attrs.length-1;i>=0;i--){var attrName=attrs[i].name;if(attrName&&attrName.indexOf("data-mediabox-")!==-1){var attr=attrName.replace("data-mediabox-","");o[attr]=attrs[i].value}}return o},preloadMedia:function(){},process:function(el){var data,match,s=this.settings,o={},group="",auto=!1,src=el.getAttribute("href");if(src){src=src.replace(/b(w|h)=([0-9]+)/g,function(s,k,v){return k="w"===k?"width":"height",k+"="+v}),data=this.getData(el)||{};var title=data.title||el.title||"",caption=data.caption||"",type=data.type||el.type||"",rel=el.rel||"";if(!MediaBox.Env.mobile||!/\.pdf$/i.test(src)&&"pdf"!==type){if(!/\w+\[[^\]]+\]/.test(rel)){var rx="alternate|stylesheet|start|next|prev|contents|index|glossary|copyright|chapter|section|subsection|appendix|help|bookmark|nofollow|noopener|noreferrer|licence|tag|friend",lb="(lightbox([(.*?)])?)",lt="(lyte(box|frame|show)([(.*?)])?)";group=$.trim(rel.replace(new RegExp("(^|\\s+)"+rx+"|"+lb+"|"+lt+"(\\s+|$)","g"),"","gi"))}"AREA"==el.nodeName&&(data||(data=MediaBox.Parameter.parse(src)),group=group||"AREA_ELEMENT",data.type||(match=/\b(ajax|iframe|image|flash|director|shockwave|mplayer|windowsmedia|quicktime|realaudio|real|divx|pdf)\b/.exec(el.className))&&(data.type=match[0])),/autopopup-(single|multiple)/.test(el.className)&&(auto=/(multiple)/.test(el.className)?"multiple":"single"),auto=auto||data.autopopup||"",group=$(el).hasClass("nogroup")?"":group||data.group||"";var width=data.width||s.width,height=data.height||s.height;return $.each(["src","title","caption","group","width","height"],function(i,k){delete data[k]}),/!\D/.test(width)&&(width=parseInt(width)),/!\D/.test(height)&&(height=parseInt(height)),$.extend(o,{node:el,src:src,title:title,caption:caption,group:group,width:width,height:height,params:data,auto:auto,type:type}),src=src.replace(/&type=(ajax|text\/html|text\/xml)/,""),el.setAttribute("href",src),o}}},create:function(elements){function imageIsCentered(img){var elm=$(img).get(0);return"auto"==elm.style.marginLeft&&"auto"==elm.style.marginRight&&"block"==elm.style.display}var self=this,s=this.settings,pageload=!1;elements||(pageload=!0,this.popups=[],1===s.legacy&&MediaBox.Convert.legacy(),1===s.lightbox&&MediaBox.Convert.lightbox(),1===s.shadowbox&&MediaBox.Convert.shadowbox()),this.elements=elements||this.getPopups(),$(this.elements).removeClass("jcelightbox jcebox jcepopup").addClass("wfpopup").each(function(i){var o=self.process(this);if(!o)return!0;if(self.popups.push(o),pageload||(i=self.popups.length-1),"_blank"===$(this).attr("target")){var rel=$(this).attr("rel")||"";rel.indexOf("noopener")===-1&&(rel+=" noopener"),rel.indexOf("noreferrer")===-1&&(rel+=" noreferrer"),$(this).attr("rel",$.trim(rel))}if($(this).attr("class",function(i,v){return v.replace(/(zoom|icon)-(top|right|bottom|left|center)(-(top|right|bottom|left|center))?/,function(match,prefix,pos1,pos2){var str="wf-icon-zoom-"+pos1;return pos2&&(str+=pos2),str})}),1===s.icons&&!$(this).hasClass("noicon")){var $img=$("img:first",this);if($img.length){var styles={};$('<span class="wf-icon-zoom-image" />').html(function(){return MediaBox.getSVGIcon("search")}).insertAfter($img);var flt=$img.css("float");flt&&"none"!==flt&&($img.parent().css("float",flt),$img.css("float",""),$(this).addClass("wf-mediabox-has-float")),$.each(["top","right","bottom","left"],function(i,pos){var m=$img.css("margin-"+pos),p=$img.css("padding-"+pos);m&&/\d/.test(m)&&parseInt(m)>0&&$img.parent().css("margin-"+pos,m),p&&/\d/.test(p)&&parseInt(p)>0&&$img.parent().css("padding-"+pos,p)}),imageIsCentered($img)&&(styles["max-width"]=$img.width(),$(this).addClass("wf-mediabox-is-centered"),styles["margin-left"]="",styles["margin-right"]=""),$img.css({margin:0,padding:0,float:"none"}),$img.parent().css(styles),$(this).addClass("wf-zoom-image")}else $('<span class="wf-icon-zoom-link" />').html(function(){return MediaBox.getSVGIcon("link")}).appendTo(this).find("svg").css("fill",$(this).css("color"))}$(this).on("click",function(e){return e.preventDefault(),o.src=this.getAttribute("href"),self.activator=this,self.start(o,i)})}),0===$(".wf-mediabox").length&&self.auto()},open:function(data,title,group,type,params){var i,x=0,o={};if("string"==typeof data&&$.extend(o,{src:data,title:title,group:group,type:type,params:params||{}}),data.nodeName&&("A"===data.nodeName||"AREA"===data.nodeName))if(i=$.inArray(this.elements,data),i>=0)o=this.popups[i],x=i;else{var o=this.process(data);x=this.popups.push(o),x--}return this.start(o,x)},start:function(p,i){var len,self=this,n=0,items=[];if(this.build()){p.group?($.each(this.popups,function(x,o){o.group===p.group&&(len=items.push(o),i&&x===i&&(n=len-1))}),p.auto||"undefined"!=typeof i||(items.push(p),n=items.length-1)):items.push(p);var overlayDuration=$(".wf-mediabox-overlay").css("transition-duration");return overlayDuration=1e3*parseFloat(overlayDuration)||300,window.setTimeout(function(){return self.show(items,n)},overlayDuration),!0}return!1},build:function(){var self=this,s=this.settings;if(0===$(".wf-mediabox").length){var $page=$('<div class="wf-mediabox" role="dialog" aria-modal="true" aria-labelledby="" aria-describedby="" tabindex="-1" />').appendTo("body");$page.addClass("wf-mediabox-overlay-transition"),MediaBox.Env.ie6&&$page.addClass("ie6"),MediaBox.Env.iOS&&$page.addClass("ios"),1===s.overlay&&$('<div class="wf-mediabox-overlay" tabindex="-1" />').appendTo($page).css("background-color",s.overlay_color),$page.append('<div class="wf-mediabox-frame" role="document" tabindex="-1"><div class="wf-mediabox-loader" role="status" aria-label="'+this.translate("loading")+'" tabindex="-1"></div><div class="wf-mediabox-body" aria-hidden="true" tabindex="-1" /></div>'),$page.addClass("wf-mediabox-theme-"+s.theme),MediaBox.Addons.Theme.parse(s.theme,function(s){return self.translate(s)},".wf-mediabox-body"),$(".wf-mediabox-frame").children().hide(),MediaBox.Env.iOS&&$(".wf-mediabox-content").css({webkitOverflowScrolling:"touch",overflow:"auto"}),2===s.close&&$(".wf-mediabox-frame").on("click",function(e){e.target&&e.target===this&&self.close()}),$(".wf-mediabox-close, .wf-mediabox-cancel").on("click",function(e){e.preventDefault(),self.close()}).attr("tabindex",0).attr("svg-icon",function(i,val){val&&$(this).append(MediaBox.getSVGIcon(val))}),$(".wf-mediabox-next").on("click",function(e){e.preventDefault(),self.nextItem()}).attr("tabindex",0).attr("svg-icon",function(i,val){val&&$(this).append(MediaBox.getSVGIcon(val))}),$(".wf-mediabox-prev").on("click",function(e){e.preventDefault(),self.previousItem()}).attr("tabindex",0).attr("svg-icon",function(i,val){val&&$(this).append(MediaBox.getSVGIcon(val))}),$(".wf-mediabox-numbers").data("html",$(".wf-mediabox-numbers").html()).attr("aria-hidden",!0),$page.addClass("wf-mediabox-open"),$(".wf-mediabox-overlay").css("opacity",s.overlayopacity||.8)}return!0},show:function(items,n){var s=this.settings;return this.items=items,this.bind(!0),$(".wf-mediabox-body").show(),1===s.overlay&&$(".wf-mediabox-overlay").length&&s.overlay_opacity&&$(".wf-mediabox-overlay").css("opacity",0).animate({opacity:parseFloat(s.overlay_opacity)},s.transition_speed),$(".wf-mediabox").addClass("wf-mediabox-transition-scale"),this.change(n)},bind:function(open){var self=this,s=this.settings;if(open){$(document).on("keydown.wf-mediabox",function(e){self.addListener(e)});var xDown,yDown;$(".wf-mediabox-body").on("touchstart",function(e){1===e.originalEvent.touches.length&&1!==self.items.length&&(xDown=e.originalEvent.touches[0].clientX,yDown=e.originalEvent.touches[0].clientY)}).on("touchmove",function(e){if(xDown&&yDown&&1===e.originalEvent.touches.length&&1!==self.items.length){var xUp=e.originalEvent.touches[0].clientX,yUp=e.originalEvent.touches[0].clientY,xDiff=xDown-xUp,yDiff=yDown-yUp;Math.abs(xDiff)>Math.abs(yDiff)&&(xDiff>0?self.nextItem():self.previousItem(),e.preventDefault()),xDown=null,yDown=null}})}else $(document).off("keydown.wf-mediabox"),$(".wf-mediabox").off("keydown.wf-mediabox");var resize=MediaBox.Tools.debounce(function(){var popup=self.items[self.index];popup&&self.updateBodyWidth(popup)},300);$(window).on("resize.wf-mediabox, orientationchange.wf-mediabox",resize),s.autoplay&&(autoplayInterval=setInterval(function(){self.nextItem()===!1&&clearInterval(autoplayInterval)},1e3*s.autoplay))},updateBodyWidth:function(popup){var w,h,ratio,ww=$(window).width(),wh=$(window).height(),fw=$(".wf-mediabox-frame").width(),fh=$(".wf-mediabox-frame").height();if("scroll"===this.settings.scrolling){var framePaddingLeft=$(".wf-mediabox-frame").css("padding-left"),framePaddingTop=$(".wf-mediabox-frame").css("padding-top");fw=ww-2*parseInt(framePaddingLeft),fh=wh-2*parseInt(framePaddingTop)}if(w=MediaBox.Tools.parseWidth(popup.width),h=MediaBox.Tools.parseHeight(popup.height||fh),$(".wf-mediabox-content").hasClass("wf-mediabox-content-ratio-flex")){var modh=$(".wf-mediabox-body").height()-$(".wf-mediabox-content").height();h=Math.min(h,fh),modh+=wh-h,$(".wf-mediabox-content-item").css("height","calc(100vh - "+modh+"px)")}var dim=MediaBox.Tools.resize(w,h,fw,fh),bw=dim.width;$(".wf-mediabox-body").css("max-width",bw);var bh=$(".wf-mediabox-body").height();ratio=fw>fh?(bw/bh).toFixed(1):(bh/bw).toFixed(1),bh>fh&&(bw=ratio*(fh-16)-32,$(".wf-mediabox-body").css("max-width",bw))},addListener:function(e){switch(e.keyCode){case 27:this.close();break;case 37:this.previousItem();break;case 39:this.nextItem()}},queue:function(n){var self=this,changed=!1,callback=function(){if(!changed)return changed=!0,$(".wf-mediabox-body").removeClass("wf-mediabox-transition"),self.change(n)};callback()},nextItem:function(){if(1===this.items.length)return!1;var n=this.index+1;return!(n<0||n>=this.items.length)&&this.queue(n)},previousItem:function(){if(1===this.items.length)return!1;var n=this.index-1;return!(n<0||n>=this.items.length)&&this.queue(n)},info:function(){function processRe(h){return h=h.replace(ex,'<a href="mailto:$1" target="_blank">$1</a>'),h=h.replace(ux,'<a href="$1" target="_blank">$1</a>')}var popup=this.items[this.index];if($(".wf-mediabox-focus").removeClass("wf-mediabox-focus"),$("a[download]",".wf-mediabox-content").remove(),popup.params.download&&$('<a href="'+popup.src+'" target="_blank" download>'+this.translate("download")+"</a>").appendTo(".wf-mediabox-content"),$(".wf-mediabox-caption").length){var title=popup.title||"",text=popup.caption||"",h="",ex=/([-!#$%&\'\*\+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'\*\+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+)/gi,ux="((news|telnet|nttp|file|http|ftp|https)://[-!#$%&'*+\\/0-9=?A-Z^_`a-z{|}~]+.[-!#$%&'*+\\./0-9=?A-Z^_`a-z{|}~]+)",ux=/([a-zA-Z]{3,9}:\/\/[^\s]+)/gi;if(title=MediaBox.Entities.decode(title),text=MediaBox.Entities.decode(text),title.indexOf("::")!==-1){var parts=title.split("::");title=$.trim(parts[0]),text=$.trim(parts[1])}title&&(h+='<h4 id="wf-mediabox-modal-title">'+title+"</h4>",$(".wf-mediabox").attr("aria-labelledby","wf-mediabox-modal-title")),text&&(h+='<p id="wf-mediabox-modal-description">'+text+"</p>",$(".wf-mediabox").attr("aria-describedby","wf-mediabox-modal-description")),$(".wf-mediabox-caption").html(h).addClass("wf-mediabox-caption-hidden"),h&&$(".wf-mediabox-caption").find(":not(a)").each(function(){var s=$(this).html();s&&/(@|:\/\/)/.test(s)&&s.indexOf("<")===-1&&(s=processRe(s))&&$(this).replaceWith(s)})}var self=this,len=this.items.length;if($(".wf-mediabox-numbers").length&&len>1){var html=$(".wf-mediabox-numbers").data("html")||"{{numbers}}";if(html.indexOf("{{numbers}}")!==-1){$(".wf-mediabox-numbers").empty().append("<ol />");for(var i=0;i<len;i++){var n=i+1,title=this.items[i].title||n,link=$('<button aria-label="'+title+'" tabindex="0" class="wf-mediabox-number" />').html(n);this.index===i&&$(link).addClass("active"),$("<li />").append(link).appendTo($("ol",".wf-mediabox-numbers")),$(link).on("click",function(e){var x=parseInt(e.target.innerHTML)-1;return self.index!=x&&self.queue(x)})}}html.indexOf("{{current}}")!==-1&&$(".wf-mediabox-numbers").html(html.replace("{{current}}",this.index+1).replace("{{total}}",len)),$(".wf-mediabox-numbers").attr("aria-hidden",!1)}else $(".wf-mediabox-numbers").empty().attr("aria-hidden",!0);$(".wf-mediabox-info-top, .wf-mediabox-info-bottom").show(),$(".wf-mediabox-next, .wf-mediabox-prev").hide().attr("aria-hidden",!0),len>1?(this.index>0?$(".wf-mediabox-prev").show().attr("aria-hidden",!1).addClass("wf-mediabox-focus"):$(".wf-mediabox-prev").hide().attr("aria-hidden",!0),this.index<len-1?$(".wf-mediabox-next").show().attr("aria-hidden",!1).addClass("wf-mediabox-focus"):$(".wf-mediabox-next").hide().attr("aria-hidden",!0)):$(".wf-mediabox-close").addClass("wf-mediabox-focus"),popup.params.css&&$(".wf-mediabox-body").addClass(popup.params.css),len>1&&($(".wf-mediabox-thumbnails").empty(),$.each(this.items,function(i,item){$('<img src="'+item.src+'" class="loading" />').on("click",function(){return self.queue(i)}).toggleClass("active",self.index==i).on("load",function(){$(this).removeClass("loading")}).appendTo(".wf-mediabox-thumbnails")}))},change:function(n){var popup,self=this;this.settings;if(n<0||n>=this.items.length)return!1;this.index=n,$(".wf-mediabox-container, .wf-mediabox-cancel").show(),$(".wf-mediabox").addClass("wf-mediabox-loading").find(".wf-mediabox-loader").attr("aria-hidden",!1),popup=this.items[n];var type="error",html="",plugin=MediaBox.Addons.Plugin.getPlugin(popup);return plugin&&(html=plugin.html(popup),type=plugin.type,!popup.width&&plugin.width&&(popup.width=plugin.width),!popup.height&&plugin.height&&(popup.height=plugin.height),popup.type=type),$(".wf-mediabox-content").attr("class","wf-mediabox-content").addClass("wf-mediabox-content-"+type).css("height",""),popup.html=html,this.items[n]=popup,self.setup(),!1},setup:function(){this.info(),MediaBox.Env.ie&&$(".wf-mediabox-content img").css("-ms-interpolation-mode","bicubic");var tabIndex=0;return $(".wf-mediabox").on("keydown.wf-mediabox",function(e){if(9===e.keyCode){e.preventDefault();var $items=$(".wf-mediabox").find("[tabindex]:visible").filter(function(){return parseInt(this.getAttribute("tabindex"))>=0});$items.each(function(i){$(this).hasClass("wf-mediabox-focus")&&(tabIndex=i)}),tabIndex=Math.max(tabIndex,0),e.shiftKey?tabIndex--:tabIndex++,tabIndex=Math.max(tabIndex,0),tabIndex===$items.length&&(tabIndex=0),$items.removeClass("wf-mediabox-focus"),$items.eq(tabIndex).focus().addClass("wf-mediabox-focus")}}),this.animate()},animate:function(){function itemLoaded(){if($cache.empty().remove(),"IFRAME"!==this.nodeName&&$(".wf-mediabox-content-item").html(popup.html),$(".wf-mediabox").removeClass("wf-mediabox-loading").find(".wf-mediabox-loading").attr("aria-hidden",!0),$(".wf-mediabox-content-item").css("padding-bottom",""),$(".wf-mediabox").addClass("wf-mediabox-show"),$(".wf-mediabox-info-top, .wf-mediabox-info-bottom").addClass("wf-info-show"),"IMG"===this.nodeName)cw=cw||this.naturalWidth||this.width,ch=ch||this.naturalHeight||this.height,cw=MediaBox.Tools.parseWidth(cw),ch=MediaBox.Tools.parseWidth(ch),popup.width=cw,popup.height=ch;else{if("VIDEO"===this.nodeName&&(cw=cw||this.videoWidth||0,ch=ch||this.videoHeight||0),cw=cw||640,cw&&ch){var w=MediaBox.Tools.parseWidth(cw),h=MediaBox.Tools.parseHeight(ch),ratio=parseFloat((h/w).toFixed(2));$(this).is(".wf-mediabox-iframe-video, .wf-mediabox-video, .wf-mediabox-audio")&&(ratio=.56),.75===ratio?$(".wf-mediabox-content").addClass("wf-mediabox-content-ratio-4by3"):.56!==ratio&&$(".wf-mediabox-content").addClass("wf-mediabox-content-ratio-flex")}$(".wf-mediabox-content-item").addClass("wf-mediabox-content-ratio"),popup.width=cw}if(self.updateBodyWidth(popup),"scroll"===s.scrolling&&($("body").addClass("wf-mediabox-scrolling"),scrollIntoView(".wf-mediabox-body")),$(".wf-mediabox-body").addClass("wf-mediabox-transition").attr("aria-hidden",!1),$(".wf-mediabox-focus").focus(),"IFRAME"===this.nodeName){var ifr=this;setTimeout(function(){ifr.contentWindow.focus()},10)}"VIDEO"!==this.nodeName&&"AUDIO"!==this.nodeName||MediaBox.Env.ie&&this.autoplay&&this.play(),$(this).trigger("mediabox:load")}function itemError(e){var n=this;$cache.empty().remove(),$(".wf-mediabox").removeClass("wf-mediabox-loading"),$(".wf-mediabox-content").addClass(function(){return"IMG"===n.nodeName?"wf-mediabox-broken-image":"wf-mediabox-broken-media"}),$(".wf-mediabox-body").addClass("wf-mediabox-transition").css("max-width","").attr("aria-hidden",!1),$(".wf-mediabox").addClass("wf-mediabox-show"),$(".wf-mediabox-content > div").addClass("wf-icon-404").html(function(){return MediaBox.getSVGIcon("404")})}var self=this,s=this.settings,popup=this.items[this.index],cw=popup.width||0,ch=popup.height||0;$(".wf-mediabox-content").removeClass("wf-mediabox-broken-image wf-mediabox-broken-media"),$(".wf-mediabox-content .wf-icon-404").removeClass("wf-icon-404").find("svg").remove(),$(".wf-mediabox-caption").removeClass("wf-mediabox-caption-hidden"),$(".wf-mediabox-content").hasClass("wf-mediabox-content-ajax")&&$(".wf-mediabox-body").css("max-width",640);var $cache=$('<div class="wf-mediabox-cache" />');"iframe"==popup.type||"ajax"==popup.type?$(".wf-mediabox-content-item").html(popup.html):$cache.html(popup.html).appendTo(".wf-mediabox"),$("img, video, audio, object, embed",$cache).add("iframe",".wf-mediabox-content").one("load loadedmetadata",function(e){var node=this;setTimeout(function(){itemLoaded.apply(node)},300)}).on("error",itemError)},close:function(keepopen){var self=this,transitionDuration=$(".wf-mediabox-container").css("transition-duration");transitionDuration=1e3*parseFloat(transitionDuration)||300,$(".wf-mediabox-body").removeClass("wf-mediabox-transition");var transitionTimer=setTimeout(function(){if($("iframe, video",".wf-mediabox-content-item").attr("src",""),$(".wf-mediabox-content-item").empty(),clearTimeout(transitionTimer),!keepopen){self.bind(!1),$(".wf-mediabox-info-bottom, .wf-mediabox-info-top").hide(),$(".wf-mediabox-frame").remove();var overlayDuration=$(".wf-mediabox-overlay").css("transition-duration");overlayDuration=1e3*parseFloat(overlayDuration)||300,$(".wf-mediabox").removeClass("wf-mediabox-open wf-mediabox-show"),$(".wf-mediabox-overlay").css("opacity",0);var overlayTimer=setTimeout(function(){$(".wf-mediabox").remove(),$("body").removeClass("wf-mediabox-scrolling"),clearTimeout(overlayTimer)},overlayDuration);self.activator&&$(self.activator).focus()}},transitionDuration);return $(".wf-mediabox-close").hide(),window.clearInterval(autoplayInterval),!1}};window.WfMediabox=window.jcepopup=MediaBox}(jQuery),function(){var opera,webkit,ie,ie6,gecko,mac,iDevice,Android,video,audio,nav=navigator,userAgent=nav.userAgent;opera=window.opera&&window.opera.buildNumber,android=/Android/.test(userAgent),webkit=/WebKit/.test(userAgent),ie=!webkit&&!opera&&/MSIE/gi.test(userAgent)&&/Explorer/gi.test(nav.appName),ie=ie&&/MSIE (\w+)\./.exec(userAgent)[1],ie=ie&&!webkit,ie6=ie&&!window.XMLHttpRequest,ie11=userAgent.indexOf("Trident/")!=-1&&(userAgent.indexOf("rv:")!=-1||nav.appName.indexOf("Netscape")!=-1)&&11,ie=ie||ie11,gecko=!webkit&&!ie&&/Gecko/.test(userAgent),mac=userAgent.indexOf("Mac")!=-1,iDevice=/(iPad|iPhone)/.test(userAgent),Android=/Android/.test(userAgent),Mobile=iDevice||Android,video=function(){var el=document.createElement("video"),o={};try{if(el.canPlayType){o.ogg=el.canPlayType('video/ogg; codecs="theora"');var h264='video/mp4; codecs="avc1.42E01E';return o.mp4=el.canPlayType(h264+'"')||el.canPlayType(h264+', mp4a.40.2"'),o.webm=el.canPlayType('video/webm; codecs="vp8, vorbis"'),o}}catch(e){}return!1}(),audio=function(){var el=document.createElement("audio"),o={};try{if(el.canPlayType)return o.ogg=el.canPlayType('audio/ogg; codecs="vorbis"'),o.mp3=el.canPlayType("audio/mpeg;"),o.wav=el.canPlayType('audio/wav; codecs="1"'),o.m4a=el.canPlayType("audio/x-m4a;")||el.canPlayType("audio/aac;"),o.webm=el.canPlayType('audio/webm; codecs="vp8, vorbis"'),o}catch(e){}return!1}();var Env={opera:opera,webkit:webkit,ie6:ie6,ie:ie,gecko:gecko,mac:mac,iOS:iDevice,android:Android,video:video,audio:audio,mobile:Mobile};window.WfMediabox.Env=Env}(),function($){var lookup={},mimes={},mediaTypes={flash:{classid:"CLSID:D27CDB6E-AE6D-11CF-96B8-444553540000",type:"application/x-shockwave-flash",codebase:"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,1,53,64"},shockwave:{classid:"CLSID:166B1BCA-3F9C-11CF-8075-444553540000",type:"application/x-director",codebase:"http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=10,2,0,023"},windowsmedia:{classid:"CLSID:6BF52A52-394A-11D3-B153-00C04F79FAA6",type:"application/x-mplayer2",codebase:"http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=10,00,00,3646"},quicktime:{classid:"CLSID:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",type:"video/quicktime",codebase:"http://www.apple.com/qtactivex/qtplugin.cab#version=7,3,0,0"},divx:{classid:"CLSID:67DABFBF-D0AB-41FA-9C46-CC0F21721616",type:"video/divx",codebase:"http://go.divx.com/plugin/DivXBrowserPlugin.cab"},realmedia:{classid:"CLSID:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA",type:"audio/x-pn-realaudio-plugin"},java:{classid:"CLSID:8AD9C840-044E-11D1-B3E9-00805F499D93",type:"application/x-java-applet",codebase:"http://java.sun.com/products/plugin/autodl/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"},silverlight:{classid:"CLSID:DFEAF541-F3E1-4C24-ACAC-99C30715084A",type:"application/x-silverlight-2"},video:{type:"video/mpeg"},audio:{type:"audio/mpeg"},iframe:{}};!function(data){var i,y,ext,items=data.split(/,/);for(i=0;i<items.length;i+=2)for(ext=items[i+1].split(/ /),y=0;y<ext.length;y++)mimes[ext[y]]=items[i]}("application/x-director,dcr,video/divx,divx,application/pdf,pdf,application/x-shockwave-flash,swf swfl,audio/mpeg,mpga mpega mp2 mp3,audio/ogg,ogg spx oga,audio/x-wav,wav,video/mpeg,mpeg mpg mpe,video/mp4,mp4 m4v,video/ogg,ogg ogv,video/webm,webm,video/quicktime,qt mov,video/x-flv,flv,video/vnd.rn-realvideo,rv","NaNvideo/x-matroska,mkv"),$.each(mediaTypes,function(key,value){value.name=key,value.classid&&(lookup[value.classid]=value),value.type&&(lookup[value.type]=value),lookup[key.toLowerCase()]=value});var Mimetype={props:function(value){return lookup[value]||!1},guess:function(value){return mimes[value]||!1}};window.WfMediabox.Mimetype=Mimetype}(jQuery),function(){var entities={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;"},Entities={encode:function(str){return(""+str).replace(/[<>&\"\']/g,function(c){return entities[c]||c})},decode:function(str){var el;try{str=decodeURIComponent(str)}catch(e){}return el=document.createElement("div"),el.innerHTML=str,el.innerHTML||str}};window.WfMediabox.Entities=Entities}(),function($,Entities){var Parameter={parse:function(s){var a=[],x=[];if("string"==typeof s){if(/^\{[\w\W]+\}$/.test(s))return $.parseJSON(s);if(/\w+\[[^\]]+\]/.test(s)){var items=[];return $.each(s.split(";"),function(i,item){var matches=item.match(/([\w]+)\[([^\]]+)\]/);3==matches.length&&items.push('"'+matches[1]+'":"'+matches[2]+'"')}),$.parseJSON("{"+items.join(",")+"}")}s.indexOf("=")!==-1&&(s.indexOf("&")!==-1?x=s.split(/&(amp;)?/g):x.push(s))}return $.isArray(s)&&(x=s),$.each(x,function(i,n){n&&(n=n.replace(/^([^\[]+)(\[|=|:)([^\]]*)(\]?)$/,function(a,b,c,d){return d?/[^0-9]/.test(d)?'"'+b+'":"'+Entities.encode($.trim(d))+'"':'"'+b+'":'+parseInt(d):""}),n&&a.push(n))}),$.parseJSON("{"+a.join(",")+"}")}};window.WfMediabox.Parameter=Parameter}(jQuery,WfMediabox.Entities),function(){window.sessionStorage||(window.sessionStorage={getItem:function(sKey){return sKey&&this.hasOwnProperty(sKey)?unescape(document.cookie.replace(new RegExp("(?:^|.*;\\s*)"+escape(sKey).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"),"$1")):null},key:function(nKeyId){return unescape(document.cookie.replace(/\s*\=(?:.(?!;))*$/,"").split(/\s*\=(?:[^;](?!;))*[^;]?;\s*/)[nKeyId])},setItem:function(sKey,sValue){sKey&&(document.cookie=escape(sKey)+"="+escape(sValue)+"; path=/",this.length=document.cookie.match(/\=/g).length)},length:0,removeItem:function(sKey){sKey&&this.hasOwnProperty(sKey)&&(document.cookie=escape(sKey)+"=; path=/",this.length--)},hasOwnProperty:function(sKey){return new RegExp("(?:^|;\\s*)"+escape(sKey).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=").test(document.cookie)}},window.sessionStorage.length=(document.cookie.match(/\=/g)||window.sessionStorage).length);var Storage={get:function(n){return sessionStorage.getItem(n)},set:function(n,v){return sessionStorage.setItem(n,v)}};window.WfMediabox.Storage=Storage}(),function(){function _utf8_encode(string){string=string.replace(/\r\n/g,"\n");for(var utftext="",n=0;n<string.length;n++){var c=string.charCodeAt(n);c<128?utftext+=String.fromCharCode(c):c>127&&c<2048?(utftext+=String.fromCharCode(c>>6|192),utftext+=String.fromCharCode(63&c|128)):(utftext+=String.fromCharCode(c>>12|224),utftext+=String.fromCharCode(c>>6&63|128),utftext+=String.fromCharCode(63&c|128))}return utftext}function _utf8_decode(utftext){for(var string="",i=0,c=0,c1=0,c2=0;i<utftext.length;)c=utftext.charCodeAt(i),c<128?(string+=String.fromCharCode(c),i++):c>191&&c<224?(c1=utftext.charCodeAt(i+1),string+=String.fromCharCode((31&c)<<6|63&c1),i+=2):(c1=utftext.charCodeAt(i+1),c2=utftext.charCodeAt(i+2),string+=String.fromCharCode((15&c)<<12|(63&c1)<<6|63&c2),i+=3);return string}var _keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",Base64={encode:function(input){var chr1,chr2,chr3,enc1,enc2,enc3,enc4,output="",i=0;for(input=_utf8_encode(input);i<input.length;)chr1=input.charCodeAt(i++),chr2=input.charCodeAt(i++),chr3=input.charCodeAt(i++),enc1=chr1>>2,enc2=(3&chr1)<<4|chr2>>4,enc3=(15&chr2)<<2|chr3>>6,enc4=63&chr3,isNaN(chr2)?enc3=enc4=64:isNaN(chr3)&&(enc4=64),output=output+_keyStr.charAt(enc1)+_keyStr.charAt(enc2)+_keyStr.charAt(enc3)+_keyStr.charAt(enc4);return output},decode:function(input){var chr1,chr2,chr3,enc1,enc2,enc3,enc4,output="",i=0;for(input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");i<input.length;)enc1=_keyStr.indexOf(input.charAt(i++)),enc2=_keyStr.indexOf(input.charAt(i++)),enc3=_keyStr.indexOf(input.charAt(i++)),enc4=_keyStr.indexOf(input.charAt(i++)),chr1=enc1<<2|enc2>>4,chr2=(15&enc2)<<4|enc3>>2,chr3=(3&enc3)<<6|enc4,output+=String.fromCharCode(chr1),64!=enc3&&(output+=String.fromCharCode(chr2)),64!=enc4&&(output+=String.fromCharCode(chr3));return output=_utf8_decode(output)}};window.btoa||(window.btoa=Base64.encode),window.atob||(window.atob=Base64.decode)}(),function($,Parameter){var Convert={legacy:function(){$("a[href]").each(function(){if(/com_jce/.test(this.href)){var p,s,img,oc=$(this).attr("onclick");if(oc){s=oc.replace(/&#39;/g,"'").split("'"),p=Parameter.parse(s[1]);var img=p.img||"",title=p.title||""}img&&(/http:\/\//.test(img)||("/"===img.charAt(0)&&(img=img.substr(1)),img=JCEMediaBox.site.replace(/http:\/\/([^\/]+)/,"")+img),$(this).attr({href:img,title:title.replace(/_/," "),onclick:""}),$(this).addClass("jcepopup"))}})},lightbox:function(){$("a[rel*=lightbox]").addClass("jcepopup").each(function(){var r=this.rel.replace(/lightbox\[?([^\]]*)\]?/,function(a,b){return b?"group["+b+"]":""});$(this).attr("rel",r)})},shadowbox:function(){$("a[rel*=shadowbox]").addClass("jcepopup").each(function(){var r=this.rel.replace(/shadowbox\[?([^\]]*)\]?/,function(a,b){var attribs="",group="";return b&&(group="group["+b+"]"),/;=/.test(a)&&(attribs=a.replace(/=([^;"]+)/g,function(x,z){return"["+z+"]"})),group&&attribs?group+";"+attribs:group||attribs||""});$(this).attr("rel",r)})}};window.WfMediabox.Convert=Convert}(jQuery,WfMediabox.Parameter),function($){function Addons(){var self=this;self.items=[],self.lookup={}}Addons.prototype={add:function(id,addOn){return this.items.push(addOn),this.lookup[id]={instance:addOn},addOn},get:function(name){return name&&this.lookup[name]?this.lookup[name].instance:this.lookup}},Addons.Plugin=new Addons,Addons.Theme=new Addons,Addons.Plugin.getPlugin=function(v,n){var s,r;return s=this.get(n),$.each(s,function(k,o){var p=o.instance,c=new p(v);if(c&&c.is(v))return r=c,!1}),r},Addons.Theme.parse=function(name,translate,parent){function createNode(o,el){$.each(o,function(k,v){if("string"==typeof v)v=translate(v),"text"===k?$(el).html(v):$(el).attr(k,v);else if($.isArray(v))createNode(v,el);else if("string"==typeof k){var node=document.createElement(k);$(el).append(node),createNode(v,node)}else createNode(v,el)})}var data,theme=this.get(name);if("function"!=typeof theme&&(theme=this.get("standard")),data=new theme)return parent||(parent=document.createElement("div")),translate||(translate=function(s){return s}),createNode(data,parent),parent},window.WfMediabox.Addons=Addons,window.WfMediabox.Plugin=Addons.Plugin,window.WfMediabox.Theme=Addons.Theme}(jQuery),function($){var svg={close:{standard:"M720.571 309.714q0 14.857-10.857 25.714l-103.429 103.429 103.429 103.429q10.857 10.857 10.857 25.714 0 15.429-10.857 26.286l-51.429 51.429q-10.857 10.857-26.286 10.857-14.857 0-25.714-10.857l-103.429-103.429-103.429 103.429q-10.857 10.857-25.714 10.857-15.429 0-26.286-10.857l-51.429-51.429q-10.857-10.857-10.857-26.286 0-14.857 10.857-25.714l103.429-103.429-103.429-103.429q-10.857-10.857-10.857-25.714 0-15.429 10.857-26.286l51.429-51.429q10.857-10.857 26.286-10.857 14.857 0 25.714 10.857l103.429 103.429 103.429-103.429q10.857-10.857 25.714-10.857 15.429 0 26.286 10.857l51.429 51.429q10.857 10.857 10.857 26.286zM941.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z",
squeeze:"M690.857 334.286l-83.429-83.429q-5.714-5.714-13.143-5.714t-13.143 5.714l-78.286 78.286-78.286-78.286q-5.714-5.714-13.143-5.714t-13.143 5.714l-83.429 83.429q-5.714 5.714-5.714 13.143t5.714 13.143l78.286 78.286-78.286 78.286q-5.714 5.714-5.714 13.143t5.714 13.143l83.429 83.429q5.714 5.714 13.143 5.714t13.143-5.714l78.286-78.286 78.286 78.286q5.714 5.714 13.143 5.714t13.143-5.714l83.429-83.429q5.714-5.714 5.714-13.143t-5.714-13.143l-78.286-78.286 78.286-78.286q5.714-5.714 5.714-13.143t-5.714-13.143zM813.714 438.857q0 84.571-41.714 156t-113.143 113.143-156 41.714-156-41.714-113.143-113.143-41.714-156 41.714-156 113.143-113.143 156-41.714 156 41.714 113.143 113.143 41.714 156zM941.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z",shadow:""},next:{standard:"M798.286 438.857q0 15.429-10.286 25.714l-258.857 258.857q-10.286 10.286-25.714 10.286t-25.714-10.286l-52-52q-10.286-10.286-10.286-25.714t10.286-25.714l108-108h-286.857q-14.857 0-25.714-10.857t-10.857-25.714v-73.143q0-14.857 10.857-25.714t25.714-10.857h286.857l-108-108q-10.857-10.857-10.857-25.714t10.857-25.714l52-52q10.286-10.286 25.714-10.286t25.714 10.286l258.857 258.857q10.286 10.286 10.286 25.714zM941.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z",squeeze:"M740.571 438.857q0-21.143-18.286-31.429l-310.857-182.857q-8.571-5.143-18.286-5.143-9.143 0-18.286 4.571-18.286 10.857-18.286 32v365.714q0 21.143 18.286 32 18.857 10.286 36.571-0.571l310.857-182.857q18.286-10.286 18.286-31.429zM813.714 438.857q0 84.571-41.714 156t-113.143 113.143-156 41.714-156-41.714-113.143-113.143-41.714-156 41.714-156 113.143-113.143 156-41.714 156 41.714 113.143 113.143 41.714 156zM941.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z",shadow:"M25.714 7.428q-10.857-10.857-18.286-7.429t-7.429 18.286v841.143q0 14.857 7.429 18.286t18.286-7.429l405.714-405.714q5.143-5.143 7.429-10.857v405.714q0 14.857 7.429 18.286t18.286-7.429l405.714-405.714q10.857-10.857 10.857-25.714t-10.857-25.714l-405.714-405.714q-10.857-10.857-18.286-7.429t-7.429 18.286v405.714q-2.286-5.714-7.429-10.857z"},prev:{standard:"M795.429 402.286v73.143q0 14.857-10.857 25.714t-25.714 10.857h-286.857l108 108q10.857 10.857 10.857 25.714t-10.857 25.714l-52 52q-10.286 10.286-25.714 10.286t-25.714-10.286l-258.857-258.857q-10.286-10.286-10.286-25.714t10.286-25.714l258.857-258.857q10.286-10.286 25.714-10.286t25.714 10.286l52 52q10.286 10.286 10.286 25.714t-10.286 25.714l-108 108h286.857q14.857 0 25.714 10.857t10.857 25.714zM941.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z",squeeze:"M283.429 438.857q0-21.143 18.286-31.429l310.857-182.857q8.571-5.143 18.286-5.143 9.143 0 18.286 4.571 18.286 10.857 18.286 32v365.714q0 21.143-18.286 32-18.857 10.286-36.571-0.571l-310.857-182.857q-18.286-10.286-18.286-31.429zM210.286 438.857q0 84.571 41.714 156t113.143 113.143 156 41.714 156-41.714 113.143-113.143 41.714-156-41.714-156-113.143-113.143-156-41.714-156 41.714-113.143 113.143-41.714 156zM82.286 438.857q0-119.429 58.857-220.286t159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286-58.857 220.286-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286z",shadow:"M925.143 870.286q10.857 10.857 18.286 7.429t7.429-18.286v-841.143q0-14.857-7.429-18.286t-18.286 7.429l-405.714 405.714q-5.143 5.143-7.429 10.857v-405.714q0-14.857-7.429-18.286t-18.286 7.429l-405.714 405.714q-10.857 10.857-10.857 25.714t10.857 25.714l405.714 405.714q10.857 10.857 18.286 7.429t7.429-18.286v-405.714q2.286 5.714 7.429 10.857z"},search:"M292.714 475.428q0 105.714 75.143 180.857t180.857 75.143 180.857-75.143 75.143-180.857-75.143-180.857-180.857-75.143-180.857 75.143-75.143 180.857zM0.143 0q0-29.714 21.714-51.429t51.429-21.714q30.857 0 51.429 21.714l196 195.429q102.286-70.857 228-70.857 81.714 0 156.286 31.714t128.571 85.714 85.714 128.571 31.714 156.286-31.714 156.286-85.714 128.571-128.571 85.714-156.286 31.714-156.286-31.714-128.571-85.714-85.714-128.571-31.714-156.286q0-125.714 70.857-228l-196-196q-21.143-21.143-21.143-51.429z",link:"M804.571 420.571v-182.857q0-68-48.286-116.286t-116.286-48.286h-475.429q-68 0-116.286 48.286t-48.286 116.286v475.429q0 68 48.286 116.286t116.286 48.286h402.286q8 0 13.143-5.143t5.143-13.143v-36.571q0-8-5.143-13.143t-13.143-5.143h-402.286q-37.714 0-64.571-26.857t-26.857-64.571v-475.429q0-37.714 26.857-64.571t64.571-26.857h475.429q37.714 0 64.571 26.857t26.857 64.571v182.857q0 8 5.143 13.143t13.143 5.143h36.571q8 0 13.143-5.143t5.143-13.143zM1024 914.286v-292.571q0-14.857-10.857-25.714t-25.714-10.857-25.714 10.857l-100.571 100.571-372.571-372.571q-5.714-5.714-13.143-5.714t-13.143 5.714l-65.143 65.143q-5.714 5.714-5.714 13.143t5.714 13.143l372.571 372.571-100.571 100.571q-10.857 10.857-10.857 25.714t10.857 25.714 25.714 10.857h292.571q14.857 0 25.714-10.857t10.857-25.714z",404:"M712 248.571q4.571-14.286-2.286-27.714t-21.143-18-28 2.286-18.286 21.714q-14.286 45.714-52.857 74t-86.571 28.286-86.571-28.286-52.857-74q-4.571-14.857-18-21.714t-27.714-2.286q-14.857 4.571-21.714 18t-2.286 27.714q21.143 69.143 78.857 111.429t130.286 42.286 130.286-42.286 78.857-111.429zM429.714 585.143q0-30.286-21.429-51.714t-51.714-21.429-51.714 21.429-21.429 51.714 21.429 51.714 51.714 21.429 51.714-21.429 21.429-51.714zM722.286 585.143q0-30.286-21.429-51.714t-51.714-21.429-51.714 21.429-21.429 51.714 21.429 51.714 51.714 21.429 51.714-21.429 21.429-51.714zM868.571 438.857q0 74.286-29.143 142t-78 116.571-116.571 78-142 29.143-142-29.143-116.571-78-78-116.571-29.143-142 29.143-142 78-116.571 116.571-78 142-29.143 142 29.143 116.571 78 78 116.571 29.143 142zM941.714 438.857q0-119.429-58.857-220.286t-159.714-159.714-220.286-58.857-220.286 58.857-159.714 159.714-58.857 220.286 58.857 220.286 159.714 159.714 220.286 58.857 220.286-58.857 159.714-159.714 58.857-220.286z"};window.WfMediabox.getSVGIcon=function(name,attribs){var $svg=$('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 1024 1024"><g stroke="none" stroke-width="1"></g><path></path></svg>');$svg.attr(attribs||{});var parts=name.split(":"),icon=parts[0],theme=parts[1]||"",data=svg[icon];return"object"==typeof data&&theme&&(data=data[theme]||""),data?($svg.find("path").attr("d",data),$("<div />").append($svg).html()):""}}(jQuery),function($){function now(){return(new Date).getTime()}var Tools={};Tools.debounce=function(func,wait,immediate){var timeout,args,context,timestamp,result,later=function(){var last=now()-timestamp;last<wait&&last>0?timeout=setTimeout(later,wait-last):(timeout=null,immediate||(result=func.apply(context,args),timeout||(context=args=null)))};return function(){context=this,args=arguments,timestamp=now();var callNow=immediate&&!timeout;return timeout||(timeout=setTimeout(later,wait)),callNow&&(result=func.apply(context,args),context=args=null),result}},Tools.resize=function(w,h,x,y){return w>x?(h*=x/w,w=x,h>y&&(w*=y/h,h=y)):h>y&&(w*=y/h,h=y,w>x&&(h*=x/w,w=x)),w=Math.round(w),h=Math.round(h),{width:Math.round(w),height:Math.round(h)}},Tools.parseWidth=function(w){return/%/.test(w)&&(w=Math.floor($(window).width()*parseInt(w)/100)),/\d/.test(w)&&(w=parseInt(w)),w},Tools.parseHeight=function(h){return/%/.test(h)&&(h=Math.floor($(window).height()*parseInt(h)/100)),/\d/.test(h)&&(h=parseInt(h)),h},window.WfMediabox.Tools=Tools}(jQuery),function($,WfMediabox){function isBool(attr){var map=["async","checked","compact","declare","defer","disabled","ismap","multiple","nohref","noresize","noshade","nowrap","readonly","selected","autoplay","loop","controls","itemscope","playsinline","contenteditable","spellcheck","contextmenu","draggable","hidden"];return $.inArray(attr,map)!==-1}function islocal(s){return!/^([a-z]+)?:\/\//.test(s)||new RegExp("("+WfMediabox.site+")").test(s)}function parseURL(url){var o={};return url=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url),$.each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],function(i,v){var s=url[i];s&&(o[v]=s)}),o}function buildURL(o){var url="";return o.protocol&&(url+=o.protocol+"://"),o.userInfo&&(url+=o.userInfo+"@"),o.host&&(url+=o.host),o.port&&(url+=":"+o.port),o.path&&(url+=o.path),o.query&&(url+="?"+o.query),o.anchor&&(url+="#"+o.anchor),url}function createComponentURL(src){if(!WfMediabox.settings.convert_local_url)return src;var uri=parseURL(src);return islocal(src)&&(uri.query?uri.query.indexOf("tmpl")==-1&&(uri.query+="&tmpl=component"):uri.query="tmpl=component"),src=buildURL(uri)}function createObject(data,embed){delete data.group,delete data.title,delete data.caption,delete data.width,delete data.height;var attribs=["id","name","style","codebase","classid","type","data"],html='<object class="wf-mediabox-focus"';for(var n in data)attribs.indexOf(n)!==-1&&"string"==typeof data[n]&&(html+=" "+n+'="'+decodeURIComponent(data[n])+'"',delete data[n]);html+=">";for(var n in data)"string"==typeof data[n]&&(html+=' <param name="'+n+'" value="'+decodeURIComponent(data[n])+'" />');if(embed){html+="<embed";for(var n in data)"string"==typeof data[n]&&(html+=" "+n+'="'+decodeURIComponent(data[n])+'"');html+="></embed>"}return html+="</object>"}function createIframe(src,attribs){return'<iframe src="'+src+'" frameborder="0" scrolling="0" allowfullscreen="allowfullscreen" />'}WfMediabox.Plugin.add("flash",function(){this.type="object",this.html=function(data){return data.type="application/x-shockwave-flash",data.data=data.src,$(createObject(data,!0))},this.is=function(data){return/\.swf\b/.test(data.src)}}),WfMediabox.Plugin.add("video",function(){this.type="video",this.html=function(data){var n,attribs=['class="wf-mediabox-video wf-mediabox-focus"'],params=data.params||{};for(n in params)isBool(n)?attribs.push(n):attribs.push(n+'="'+params[n]+'"');params.autoplay||attribs.push("controls"),WfMediabox.Env.mobile&&attribs.push("playsinline");var ext=data.src.split(".").pop(),type=WfMediabox.Mimetype.guess(ext)||"video/mpeg",video=$("<video "+attribs.join(" ")+' tabindex="0" />').on("loadedmetadata",function(e){$(this).attr({width:this.videoWidth||"",height:this.videoHeight||""})}).append('<source src="'+data.src+'" type="'+type+'" />');return video},this.is=function(data){var src=data.src;return src=src.split("?")[0],(/video\/(mp4|mpeg|webm|ogg)/.test(data.type)||/\.(mp4|webm|ogg)\b/.test(src))&&WfMediabox.Env.video}}),WfMediabox.Plugin.add("audio",function(){this.type="audio",this.html=function(data){var n,attribs=['src="'+data.src+'"','class="wf-mediabox-audio wf-mediabox-focus"'],params=data.params||{};for(n in params)isBool(n)?attribs.push(n):attribs.push(n+'="'+params[n]+'"');return params.autoplay||attribs.push("controls"),$("<audio "+attribs.join(" ")+' tabindex="0" />')},this.is=function(data){var src=data.src;return src=src.split("?")[0],(/audio\/(mp3|mpeg|oga|x-wav)/.test(data.type)||/\.(mp3|oga|wav|m4a)\b/.test(src))&&WfMediabox.Env.audio}}),WfMediabox.Plugin.add("dailymotion",function(){function processURL(s){var u="https://dailymotion.com/embed/video/",m=s.match(/dai\.?ly(motion)?(.+)?\/(swf|video)?\/?([a-z0-9]+)_?/);return m&&(u+=m[4]),u}this.is=function(data){return/dai\.?ly(motion)/.test(data.src)},this.width=480,this.type="iframe",this.html=function(data){var ifr=$(createIframe(processURL(data.src)));return $(ifr).addClass("wf-mediabox-iframe-video"),ifr}}),WfMediabox.Plugin.add("quicktime",function(){this.html=function(data){return data.type="video/quicktime",data.classid="clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b",data.codebase="https://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0",$(createObject(data))},this.type="object",this.width=853,this.is=function(data){return/\.(mov)\b/.test(data.src)}}),WfMediabox.Plugin.add("windowsmedia",function(){this.type="object",this.html=function(data){return data.type="application/x-mplayer2",data.classid="clsid:6bf52a52-394a-11d3-b153-00c04f79faa6",data.codebase="https://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701",$(createObject(data,!0))},this.is=function(data){return/\.(wmv|avi)\b/.test(data.src)}}),WfMediabox.Plugin.add("youtube",function(){function processURL(v){return v=v.replace(/youtu(\.)?be([^\/]+)?\/(.+)/,function(a,b,c,d){return d=d.replace(/(watch\?v=|v\/|embed\/)/,""),b&&!c&&(c=".com"),d.indexOf("?")===-1&&(d=d.replace(/&/,"?")),"youtube"+c+"/embed/"+d}),v=v.replace(/\/\/youtube/i,"//www.youtube"),v=v.replace(/^http:\/\//,"https://")}this.is=function(data){return/youtu(\.)?be([^\/]+)?\/(.+)/.test(data.src)},this.width=560,this.type="iframe",this.html=function(data){var src=processURL(data.src),ifr=$(createIframe(src));if(data.params){var allow=["accelerometer","encrypted-media","gyroscope","picture-in-picture","allowfullscreen"],params={};$.each(data.params,function(key,value){key.indexOf("youtube-")!==-1&&(key=key.replace("youtube-",""),params[key]=value,value&&allow.push(key))}),allow.length&&$(ifr).attr("allow",allow.join(";")),params=$.param(params),params&&(src+=src.indexOf("?")!==-1?"&"+params:"?"+params,$(ifr).attr("src",src))}return $(ifr).addClass("wf-mediabox-iframe-video"),ifr}}),WfMediabox.Plugin.add("vimeo",function(){function processURL(s){return s=s.replace(/(player[\/\.])?vimeo\.com\/(\w+\/)?(\w+\/)?([0-9]+)/,function(a,b,c,d,e){return b?a:"player.vimeo.com/video/"+e}),s=s.replace(/^http:\/\//,"https://")}this.is=function(data){return/vimeo\.com\/(\w+\/)?(\w+\/)?([0-9]+)/.test(data.src)},this.width=500,this.type="iframe",this.html=function(data){var src=processURL(data.src),ifr=$(createIframe(src));if($(ifr).addClass("wf-mediabox-iframe-video"),data.params){var params={};$.each(data.params,function(key,value){key.indexOf("vimeo-")!==-1&&(key=key.replace("vimeo-",""),params[key]=value)}),params=$.param(params),params&&(src+=src.indexOf("?")!==-1?"&"+params:"?"+params,$(ifr).attr("src",src))}return ifr}}),$(".wf-mediabox").on("WfMediabox:plugin",function(e,data){function isImage(data){var src=data.src;return src=src.split("?")[0],/image\/?/.test(data.type)||/\.(jpg|jpeg|png|apng|gif|bmp|tif|webp)$/i.test(src)}if(isImage(data)){var $img=$('<img src="'+data.src+'" class="wf-mediabox-img" alt="'+decodeURIComponent(data.alt||data.title||"")+'" tabindex="0" />');return data.params&&$.each(data.params,function(name,value){"srcset"===name&&(value=value.replace(/(?:[^\s]+)\s*(?:[\d\.]+[wx])?(?:\,\s*)?/gi,function(match){return islocal(match)?WfMediabox.site+match:match})),$img.attr(name,value)}),$img}return""}),WfMediabox.Plugin.add("image",function(){this.type="image",this.html=function(data){var $img=$('<img src="'+data.src+'" class="wf-mediabox-img" alt="'+decodeURIComponent(data.alt||data.title||"")+'" tabindex="0" />');return data.params&&$.each(data.params,function(name,value){"srcset"===name&&(value=value.replace(/(?:[^\s]+)\s*(?:[\d\.]+[wx])?(?:\,\s*)?/gi,function(match){return islocal(match)?WfMediabox.site+match:match})),$img.attr(name,value)}),$img},this.is=function(data){var src=data.src;return src=src.split("?")[0],/image\/?/.test(data.type)||/\.(jpg|jpeg|png|gif|bmp|tif|webp)$/i.test(src)}}),WfMediabox.Plugin.add("pdf",function(){this.type="iframe",this.html=function(data){var label=data.title||"PDF Iframe";return data.width=data.width||"100%",data.height=data.height||"100%",$('<iframe src="'+data.src+'" frameborder="0" aria-label="'+label+'" />')},this.is=function(data){return"pdf"===data.type||/application\/(x-)?pdf/.test(data.type)||/\.pdf$/i.test(data.src)}}),WfMediabox.Plugin.add("content",function(){this.type="ajax",this.html=function(data){src=createComponentURL(data.src),data.width=data.width||"100%",data.height=data.height||"100%";var iframe=$('<iframe src="'+src+'" />').on("mediabox:load",function(){var n=this,$parent=$(this).parent(),html=this.contentWindow.document.body.innerHTML;window.setTimeout(function(){$(n).remove()},10),$parent.append(html);var uri=parseURL(this.src);if(uri.anchor){var elm=$parent.find("#"+uri.anchor).get(0);elm&&elm.scrollIntoView()}$parent.find('a[href^="#"]').on("click",function(e){e.preventDefault();var id=$(this).attr("href"),elm=$parent.find(id).get(0);elm&&elm.scrollIntoView()}),WfMediabox.create(WfMediabox.getPopups("",$parent)),data.params&&data.params.style&&$('<style type="text/css" />').text(".wf-mediabox-content{"+$("<div />").attr("style",data.params.style).get(0).style.cssText+"}").insertBefore($parent)});return iframe},this.is=function(data){return"ajax"===data.type||"text/html"===data.type||$(data.node).hasClass("ajax")}}),WfMediabox.Plugin.add("dom",function(){this.type="dom",this.html=function(data){var node=$(data.src);return node?$(node).get(0).outerHTML:""},this.is=function(data){return"dom"===data.type}}),WfMediabox.Plugin.add("iframe",function(){this.type="iframe",this.html=function(data){data.width=data.width||"100%",data.height=data.height||"100%",src=createComponentURL(data.src);var ifr=createIframe(src);return $(ifr)},this.is=function(data){return!data.type||"iframe"===data.type}})}(jQuery,WfMediabox),WfMediabox.Theme.add("bootstrap",function(){return[{div:{class:"wf-mediabox-container modal",content:[{div:{class:"modal-header",content:[{button:{type:"button",class:"close wf-mediabox-close",title:"{{close}}","aria-label":"{{close}}",content:[{span:{"aria-hidden":"true",text:"&times;"}}]},div:{class:"wf-mediabox-caption"}}]}},{div:{class:"wf-mediabox-content",content:[{nav:{class:"wf-mediabox-nav modal-body carousel",role:"navigation",content:[{a:{role:"button",class:"left carousel-control wf-mediabox-prev",title:"{{previous}}","aria-label":"{{previous}}",content:[{span:{"aria-hidden":"true",class:"glyphicon glyphicon-chevron-left"}}]}},{a:{role:"button",class:"right carousel-control wf-mediabox-next",title:"{{next}}","aria-label":"{{next}}",content:[{span:{"aria-hidden":"true",class:"glyphicon glyphicon-chevron-right"}}]}}]},div:{class:"wf-mediabox-content-item"}}]}}]}}]}),WfMediabox.Theme.add("light",function(){return[{div:{class:"wf-mediabox-container",content:[{div:{class:"wf-mediabox-content",content:[{div:{class:"wf-mediabox-content-item"}},{button:{class:"wf-mediabox-next",title:"{{next}}","aria-label":"{{next}}"}},{button:{class:"wf-mediabox-prev",title:"{{previous}}","aria-label":"{{previous}}"}}]}},{div:{class:"wf-mediabox-caption"}},{nav:{class:"wf-mediabox-nav",role:"navigation",content:[{button:{class:"wf-mediabox-close",title:"{{close}}","aria-label":"{{close}}",text:"{{close}}"}},{span:{class:"wf-mediabox-numbers",text:"{{numbers_count}}"}}]}}]}}]}),WfMediabox.Theme.add("shadow",function(){return[{div:{class:"wf-mediabox-info-top",content:[{div:{class:"wf-mediabox-caption"}}]}},{div:{class:"wf-mediabox-container",content:[{div:{class:"wf-mediabox-content",content:[{div:{class:"wf-mediabox-content-item"}}]}}]}},{div:{class:"wf-mediabox-info-bottom",content:[{div:{class:"wf-mediabox-nav",role:"navigation",content:[{span:{class:"wf-mediabox-numbers",text:"{{numbers}}"}},{button:{class:"wf-mediabox-close",title:"{{close}}","aria-label":"{{close}}"}},{button:{class:"wf-mediabox-next",title:"{{next}}","aria-label":"{{next}}","svg-icon":"next:shadow"}},{button:{class:"wf-mediabox-prev",title:"{{previous}}","aria-label":"{{previous}}","svg-icon":"prev:shadow"}}]}}]}}]}),WfMediabox.Theme.add("squeeze",function(){return[{div:{class:"wf-mediabox-container",content:[{button:{class:"wf-mediabox-close",title:"{{close}}","aria-label":"{{close}}","svg-icon":"close:squeeze"}},{div:{class:"wf-mediabox-content",content:[{div:{class:"wf-mediabox-content-item"}}]}},{div:{class:"wf-mediabox-caption"}},{nav:{class:"wf-mediabox-nav",role:"navigation",content:[{button:{class:"wf-mediabox-prev",title:"{{previous}}","aria-label":"{{previous}}","svg-icon":"prev:squeeze"}},{button:{class:"wf-mediabox-next",title:"{{next}}","aria-label":"{{next}}","svg-icon":"next:squeeze"}},{span:{class:"wf-mediabox-numbers",text:"{{numbers}}"}}]}}]}}]}),function($){$(".wf-mediabox").on("wf-mediabox:template",function(){})}(jQuery),WfMediabox.Theme.add("standard",function(){return[{div:{class:"wf-mediabox-container",content:[{div:{class:"wf-mediabox-content",content:[{div:{class:"wf-mediabox-content-item"}}]}},{div:{class:"wf-mediabox-caption"}},{nav:{class:"wf-mediabox-nav",role:"navigation",content:[{button:{class:"wf-mediabox-close",title:"{{close}}","aria-label":"{{close}}","svg-icon":"close:standard"}},{button:{class:"wf-mediabox-prev",title:"{{previous}}","aria-label":"{{previous}}","svg-icon":"prev:standard"}},{button:{class:"wf-mediabox-next",title:"{{next}}","aria-label":"{{next}}","svg-icon":"next:standard"}},{span:{class:"wf-mediabox-numbers",text:"{{numbers}}"}}]}}]}}]}),WfMediabox.Theme.add("uikit",function(){return[{div:{class:"wf-mediabox-container uk-modal-dialog uk-modal-dialog-lightbox uk-slidenav-position",content:[{a:{class:"wf-mediabox-close uk-modal-close uk-close uk-close-alt",role:"button",title:"{{close}}","aria-label":"{{close}}"}},{div:{class:"wf-mediabox-content uk-lightbox-content",content:[{nav:{role:"navigation",class:"wf-mediabox-nav",content:[{a:{class:"wf-mediabox-prev uk-slidenav uk-slidenav-contrast uk-slidenav-previous uk-hidden-touch",title:"{{previous}}","aria-label":"{{previous}}",role:"button"}},{a:{class:"wf-mediabox-next uk-slidenav uk-slidenav-contrast uk-slidenav-next uk-hidden-touch",title:"{{next}}","aria-label":"{{next}}",role:"button"}}]},div:{class:"wf-mediabox-content-item"}}]}},{div:{class:"wf-mediabox-caption uk-modal-caption"}}]}}]});PK��#]�{�/�O�O(system/jcemediabox/js/jcemediabox-src.jsnu&1i�/**
 * JCEMediaBox 		1.2.3
 * @package 		JCEMediaBox
 * @url				http://www.joomlacontenteditor.net
 * @copyright 		Copyright (C) 2006 - 2016 Ryan Demmer. All rights reserved
 * @copyright		Copyright 2009, Moxiecode Systems AB
 * @license 		GNU/GPL Version 2 - http://www.gnu.org/licenses/gpl-2.0.html
 * @date			18 May 2016
 * This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 *
 */
(function (window) {
    /**
     *
     *  Base64 encode / decode
     *  http://www.webtoolkit.info/
     *
     **/
    var Base64 = {
        // private property
        _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
        // public method for encoding
        encode: function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;

            input = Base64._utf8_encode(input);

            while (i < input.length) {

                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output +
                        Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
                        Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);

            }

            return output;
        },
        // public method for decoding
        decode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            while (i < input.length) {

                enc1 = Base64._keyStr.indexOf(input.charAt(i++));
                enc2 = Base64._keyStr.indexOf(input.charAt(i++));
                enc3 = Base64._keyStr.indexOf(input.charAt(i++));
                enc4 = Base64._keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }

            }

            output = Base64._utf8_decode(output);

            return output;

        },
        // private method for UTF-8 encoding
        _utf8_encode: function (string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";

            for (var n = 0; n < string.length; n++) {

                var c = string.charCodeAt(n);

                if (c < 128) {
                    utftext += String.fromCharCode(c);
                }
                else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
                else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }

            }

            return utftext;
        },
        // private method for UTF-8 decoding
        _utf8_decode: function (utftext) {
            var string = "";
            var i = 0;
            var c = 0, c1 = 0, c2 = 0;

            while (i < utftext.length) {

                c = utftext.charCodeAt(i);

                if (c < 128) {
                    string += String.fromCharCode(c);
                    i++;
                }
                else if ((c > 191) && (c < 224)) {
                    c1 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
                    i += 2;
                }
                else {
                    c1 = utftext.charCodeAt(i + 1);
                    c2 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
                    i += 3;
                }

            }
            return string;
        }
    };

    // patch in btoa
    if (!window.btoa) {
        window.btoa = Base64.encode;
    }
    // patch in atob
    if (!window.atob) {
        window.atob = Base64.decode;
    }

    // html5 element support
    var support = {};

    /*
     * From Modernizr v2.0.6
     * http://www.modernizr.com
     * Copyright (c) 2009-2011 Faruk Ates, Paul Irish, Alex Sexton
     */
    support.video = (function () {
        var elem = document.createElement('video'), bool = false;

        // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
        try {
            if (bool = !!elem.canPlayType) {
                bool = new Boolean(bool);
                bool.ogg = elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, '');

                // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
                bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, '');

                bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, '');
            }

        } catch (e) {
        }

        return bool;
    })();

    var entities = {
        '\"': '&quot;',
        "'": '&#39;',
        '<': '&lt;',
        '>': '&gt;',
        '&': '&amp;'
    };

    /*
     * From Modernizr v2.0.6
     * http://www.modernizr.com
     * Copyright (c) 2009-2011 Faruk Ates, Paul Irish, Alex Sexton
     */
    support.audio = (function () {
        var elem = document.createElement('audio'), bool = false;

        try {
            if (bool = !!elem.canPlayType) {
                bool = new Boolean(bool);
                bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, '');
                bool.mp3 = elem.canPlayType('audio/mpeg;').replace(/^no$/, '');

                // Mimetypes accepted:
                //   developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
                //   bit.ly/iphoneoscodecs
                bool.wav = elem.canPlayType('audio/wav; codecs="1"').replace(/^no$/, '');
                bool.m4a = (elem.canPlayType('audio/x-m4a;') ||
                        elem.canPlayType('audio/aac;')).replace(/^no$/, '');
            }
        } catch (e) {
        }

        return bool;
    })();

    window.JCEMediaBox = {
        domLoaded: false,
        /**
         * Global Options Object
         */
        options: {
            popup: {
                width: '',
                height: '',
                legacy: 0,
                lightbox: 0,
                shadowbox: 0,
                overlay: 1,
                overlayopacity: 0.8,
                overlaycolor: '#000000',
                resize: 0,
                icons: 1,
                fadespeed: 500,
                scalespeed: 500,
                hideobjects: 1,
                scrolling: 'fixed',
                //protect				: 1,
                close: 2,
                labels: {
                    'close': 'Close',
                    'next': 'Next',
                    'previous': 'Previous',
                    'numbers': '{$current} of {$total}',
                    'cancel': 'Cancel'
                },
                cookie_expiry: 7,
                google_viewer: 0,
                pdfjs: 0
            },
            tooltip: {
                speed: 150,
                offsets: {
                    x: 16,
                    y: 16
                },
                position: 'br',
                opacity: 0.8,
                background: '#000000',
                color: '#ffffff'
            },
            base: '/',
            pngfix: false,
            pngfixclass: '',
            theme: 'standard',
            imgpath: 'plugins/system/jcemediabox/img',
            mediafallback: false,
            mediaplayer: "",
            mediaselector: "audio,video"
        },
        init: function (options) {
            this.extend(this.options, options);
            // Clear IE6 background cache
            if (this.isIE6) {
                try {
                    document.execCommand("BackgroundImageCache", false, true);
                } catch (e) {
                }
            }
            // add DOM support for IE < 9
            if (!support.video || !support.audio) {
                document.createElement('source');
            }

            this.ready();
        },
        /**
         * Function to determine if DOM is ready.
         * Based on JQuery ready.js - https://github.com/jquery/jquery/blob/1.11-stable/src/core/ready.js
         * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
         * Released under the MIT license
         * http://jquery.org/license
         */
        ready: function () {
            var win = window, doc = win.document, self = JCEMediaBox;

            if (self.domLoaded) {
                return self._init();
            }

            /**
             * Clean-up method for dom ready events
             */
            function detach() {
                if (doc.addEventListener) {
                    doc.removeEventListener("DOMContentLoaded", completed, false);
                    win.removeEventListener("load", completed, false);

                } else {
                    doc.detachEvent("onreadystatechange", completed);
                    win.detachEvent("onload", completed);
                }
            }

            /**
             * The ready event handler and self cleanup method
             */
            function completed(event) {
                // readyState === "complete" is good enough for us to call the dom ready in oldIE
                //if (doc.addEventListener || event && event.type === "load" || doc.readyState === "complete") {
                    detach();

                    self.domLoaded = true;

                    self._init();
                //}
            }

            if (doc.readyState === "complete") {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                setTimeout(completed);

                // Standards-based browsers support DOMContentLoaded
            } else if (doc.addEventListener) {
                // Use the handy event callback
                doc.addEventListener("DOMContentLoaded", completed, false);

                // A fallback to window.onload, that will always work
                win.addEventListener("load", completed, false);

                // If IE event model is used
            } else {
                // Ensure firing before onload, maybe late but safe also for iframes
                doc.attachEvent("onreadystatechange", completed);

                // A fallback to window.onload, that will always work
                win.attachEvent("onload", completed);

                // If IE and not a frame
                // continually check to see if the document is ready
                var top = false;

                try {
                    top = win.frameElement == null && doc.documentElement;
                } catch (e) {
                }

                if (top && top.doScroll) {
                    (function doScrollCheck() {
                        if (!self.domLoaded) {

                            try {
                                // Use the trick by Diego Perini
                                // http://javascript.nwbox.com/IEContentLoaded/
                                top.doScroll("left");
                            } catch (e) {
                                return setTimeout(doScrollCheck, 50);
                            }

                            // and execute any waiting functions
                            completed();
                        }
                    })();
                }
            }
        },
        /**
         * Get the Site Base URL
         * @method getSite
         * @return {String} Site Base URL
         */
        getSite: function () {
            var base = this.options.base;

            if (base) {
                // Get document location
                var site = document.location.href;
                // Split into port (http) and location
                var parts = site.split(':\/\/');

                var port = parts[0];
                var url = parts[1];

                // Get url part before base
                if (url.indexOf(base) != -1) {
                    url = url.substr(0, url.indexOf(base));
                    // Get url part before first slash
                } else {
                    url = url.substr(0, url.indexOf('/')) || url;
                }
                // Return full url
                return port + '://' + url + base;
            }
            // Can't get site URL!
            return null;
        },
        /**
         * Private internal function
         * Initialize JCEMediaBox
         */
        _init: function () {
            var self = this, na = navigator, ua = na.userAgent;

            /**
             * Constant that is true if the browser is Opera.
             *
             * @property isOpera
             * @type Boolean
             * @final
             */
            self.isOpera = window.opera && opera.buildNumber;

            /**
             * Constant that is true if the browser is WebKit (Safari/Chrome).
             *
             * @property isWebKit
             * @type Boolean
             * @final
             */
            self.isWebKit = /WebKit/.test(ua);

            self.isChrome = /Chrome\//.test(ua);

            self.isSafari = /Safari\//.test(ua);

            /**
             * Constant that is true if the browser is IE.
             *
             * @property isIE
             * @type Boolean
             * @final
             */
            self.isIE = !self.isWebKit && !self.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName) && !!window.ActiveXObject;

            /**
             * Constant that is true if the browser is IE 6 or older.
             *
             * @property isIE6
             * @type Boolean
             * @final
             */
            self.isIE6 = self.isIE && /MSIE [56]/.test(ua) && !window.XMLHttpRequest;

            /**
             * Constant that is true if the browser is IE 7.
             *
             * @property isIE7
             * @type Boolean
             * @final
             */
            self.isIE7 = self.isIE && /MSIE [7]/.test(ua) && !!window.XMLHttpRequest && !document.querySelector;

            /**
             * Constant that tells if the current browser is an iPhone or iPad.
             *
             * @property isiOS
             * @type Boolean
             * @final
             */
            self.isiOS = /(iPad|iPhone)/.test(ua);

            self.isAndroid = /Android/.test(ua);

            self.isMobile = self.isiOS || self.isAndroid;

            /**
             * Get the Site URL
             * @property site
             * @type String
             */
            this.site = this.getSite();

            // Can't get reliable site URL
            if (!this.site) {
                return false;
            }

            // Initialize Popup / Tooltip creation
            this.Popup.init();
            this.ToolTip.init();

            if (this.options.mediafallback) {
                this.mediaFallback();
            }
        },

        mediaFallback: function() {
            var self = this, DOM = this.DOM, each = this.each;

            function toAbsolute(url) {
                var div = document.createElement('div');
                div.innerHTML = '<a href="' + url + '">x</a>';

                return div.firstChild.href;
            }

            function resolveMediaPath(s, absolute) {
                if (s && s.indexOf('://') === -1 && s.charAt(0) !== '/') {
                    s = self.options.base + s;
                }

                if (absolute) {
                    return toAbsolute(s);
                }

                return s;
            }

            // process video
            var selector    = this.options.mediaselector;
            var elms        = DOM.select(selector);
            var swf         = this.options.mediaplayer || 'plugins/system/jcemediabox/mediaplayer/mediaplayer.swf';

            var supportMap = {
                'video': {
                    'h264' : ['video/mp4', 'video/mpeg'],
                    'webm' : ['video/webm'],
                    'ogg'  : ['video/ogg']
                },
                'audio': {
                    'mp3'   : ['audio/mp3', 'audio/mpeg'],
                    'ogg'   : ['audio/ogg'],
                    'webm'  : ['audio/webm']
                }
            };

            function checkSupport(name, type) {
                var hasSupport = false;

                for (var n in supportMap[name]) {
                    if (supportMap[name][n].indexOf(type) !== -1) {
                        hasSupport = support[name] && !!support[name][n];
                    }
                }

                return hasSupport;
            }

            if (elms.length) {
                each(elms, function(el) {
                    var type = el.getAttribute('type'), src = el.getAttribute('src'), name = el.nodeName.toLowerCase(), hasSupport = false;

                    // no src attribute set, try finding in <source>
                    if (!src || !type) {
                        var source = DOM.select('source[type]', el);

                        each(source, function(n) {
                            src = n.getAttribute('src'), type = n.getAttribute('type');

                            // video/x-flv not supported by any browser
                            if (type !== "video/x-flv") {
                                hasSupport = checkSupport(name, type);
                            }

                            if (!hasSupport) {
                                return false;
                            }
                        });

                        // check for flv fallback
                        if (!hasSupport && name === "video") {
                            source = DOM.select('source[type="video/x-flv"]', el);

                            if (source.length) {
                                src = source[0].getAttribute('src'), type = "video/x-flv";
                            }
                        }
                    } else {
                        hasSupport = checkSupport(name, type);
                    }

                    // can't do anything without these!
                    if (!src || !type) {
                        return;
                    }

                    // native audio/video support (exclude flv)
                    if (hasSupport) {
                        return;
                    }

                    var w = el.getAttribute('width'), h = el.getAttribute('height');
                    var html = '', flashvars = [];

                    // not custom player
                    if (!self.options.mediaplayer) {
                        flashvars.push('file=' + resolveMediaPath(src, true));
                    }

                    self.each(['autoplay', 'loop', 'preload', 'controls'], function(at) {
                        var v = el.getAttribute(at);

                        if (typeof v !== "undefined" && v !== null) {
                            if (v === at) {
                                v = true;
                            }

                            flashvars.push(at + '=' + v);
                        }

                    });

                    var i, attrs = el.attributes;

                    for (i = attrs.length - 1; i >= 0; i--) {
                        var attrName = attrs[i].name;
                        if (attrName && (attrName.indexOf('data-video-') !== -1 || attrName.indexOf('data-audio-') !== -1)) {
                            var name = attrName.replace(/data-(video|audio)-/i, '');
                            var value = attrs[i].value;

                            if (typeof value !== "undefined" || value !== null) {
                                flashvars.push(name + '=' + value);
                            }
                        }
                    }

                    html += '<object class="wf-mediaplayer-object" data="' + resolveMediaPath(swf) + '" type="application/x-shockwave-flash"';

                    if (w) {
                        html += ' width="' + w + '"';
                    }

                    if (h) {
                        html += ' height="' + h + '"';
                    }

                    html += '>';

                    html += '<param name="movie" value="' + resolveMediaPath(swf) + '" />';
                    html += '<param name="flashvars" value="' + flashvars.join('&') + '" />';
                    html += '<param name="allowfullscreen" value="true" />';
                    html += '<param name="wmode" value="transparent" />';

                    var poster = el.getAttribute('poster');

                    if (poster) {
                        html += '<img src="' + resolveMediaPath(poster) + '" alt="" />';
                    }

                    html += '<i>Flash is required to play this video. <a href="https://get.adobe.com/flashplayer" target="_blank">Get Adobe® Flash Player</a></i>';
                    html += '</object>';

                    var div = document.createElement('span');
                    div.innerHTML = html;

                    var o = div.firstChild;

                    if (o && o.nodeName === "OBJECT") {
                        el.parentNode.replaceChild(o, el);

                        if (poster) {
                            o.style.backgroundImage = "url('" + resolveMediaPath(poster) + "')";
                        }
                    }
                });
            }
        },

        /**
         * Performs an iteration of all items in a collection such as an object or array. This method will execure the
         * callback function for each item in the collection, if the callback returns false the iteration will terminate.
         * The callback has the following format: cb(value, key_or_index).
         *
         * @method each
         * @param {Object} o Collection to iterate.
         * @param {function} cb Callback function to execute for each item.
         * @param {Object} s Optional scope to execute the callback in.
         * @copyright	Copyright 2009, Moxiecode Systems AB
         */
        each: function (o, cb, s) {
            var n, l;

            if (!o) {
                return 0;
            }

            s = s || o;

            if (o.length !== undefined) {
                // Indexed arrays, needed for Safari
                for (n = 0, l = o.length; n < l; n++) {
                    if (cb.call(s, o[n], n, o) === false) {
                        break;
                    }
                }
            } else {
                // Hashtables
                for (n in o) {
                    if (o.hasOwnProperty(n)) {
                        if (cb.call(s, o[n], n, o) === false) {
                            break;
                        }
                    }
                }
            }

            return o;
        },
        /**
         * Extends an object with the specified other object(s).
         *
         * @method extend
         * @param {Object} o Object to extend with new items.
         * @param {Object} e..n Object(s) to extend the specified object with.
         * @return {Object} o New extended object, same reference as the input object.
         * @copyright	Copyright 2009, Moxiecode Systems AB
         */
        extend: function (obj, ext) {
            var i, l, name, args = arguments, value;

            for (i = 1, l = args.length; i < l; i++) {
                ext = args[i];
                for (name in ext) {
                    if (ext.hasOwnProperty(name)) {
                        value = ext[name];

                        if (value !== undefined) {
                            obj[name] = value;
                        }
                    }
                }
            }

            return obj;
        },
        /**
         * Removes whitespace from the beginning and end of a string.
         *
         * @method trim
         * @param {String} s String to remove whitespace from.
         * @return {String} New string with removed whitespace.
         * @copyright	Copyright 2009, Moxiecode Systems AB
         */
        trim: function (s) {
            return (s ? '' + s : '').replace(/^\s*|\s*$/g, '');
        },
        /**
         * Find index of item in array
         * @param {array} a Array to look in
         * @param {mixed} s Item to find
         * @return {Number, i} Index
         */
        inArray: function (a, s) {
            var i, l;

            if (a) {
                for (i = 0, l = a.length; i < l; i++) {
                    if (a[i] === s) {
                        return i;
                    }
                }
            }

            return -1;
        },
        /**
         * DOM functions
         */
        DOM: {
            /**
             * Get an Element by ID
             * @param {Object} s ID
             */
            get: function (s) {
                if (typeof (s) == 'string')
                    return document.getElementById(s);

                return s;
            },
            /**
             * Return elements matching a simple selector, eg: a, a[id], a.classname
             * @param {Object} o Selector
             * @param {Object} p Parent Element
             */
            select: function (o, p) {
                var t = this, r = [], s, parts, at, tag, cl, each = JCEMediaBox.each;
                p = p || document;
                // Return all elements
                if (o == '*') {
                    return p.getElementsByTagName(o);
                }

                // Use native support if available
                if (p.querySelectorAll) {
                    return p.querySelectorAll(o);
                }

                /**
                 * Internal inArray function
                 * @param {Object} a Array to check
                 * @param {Object} s Key to check for
                 */
                function inArray(a, v) {
                    var i, l;

                    if (a) {
                        for (i = 0, l = a.length; i < l; i++) {
                            if (a[i] === v)
                                return true;
                        }
                    }

                    return false;
                }

                // Split selector
                s = o.split(',');
                each(s, function (selectors) {
                    parts = JCEMediaBox.trim(selectors).split('.');
                    // Element
                    tag = parts[0] || '*';
                    // Class
                    cl = parts[1] || '';
                    // Handle attributes
                    if (/\[(.*?)\]/.test(tag)) {
                        tag = tag.replace(/(.*?)\[(.*?)\]/, function (a, b, c) {
                            at = c;
                            return b;
                        });

                    }
                    // Get all elements for the given parent and tag
                    var elements = p.getElementsByTagName(tag);

                    // If class or attribute
                    if (cl || at) {
                        each(elements, function (el) {
                            // If class
                            if (cl) {
                                if (t.hasClass(el, cl)) {
                                    if (!inArray(r, el)) {
                                        r.push(el);
                                    }
                                }
                            }
                            // If attribute
                            if (at) {
                                if (el.getAttribute(at)) {
                                    if (!inArray(r, el)) {
                                        r.push(el);
                                    }
                                }
                            }
                        });

                    } else {
                        r = elements;
                    }
                });

                return r;
            },
            /**
             * Check if an element has a specific class
             * @param {Object} el Element
             * @param {Object} c Class
             */
            hasClass: function (el, c) {
                return new RegExp(c).test(el.className);
            },
            /**
             * Add a class to an element
             * @param {Object} el Element
             * @param {Object} c Class
             */
            addClass: function (el, c) {
                if (!this.hasClass(el, c)) {
                    el.className = JCEMediaBox.trim(el.className + ' ' + c);
                }
            },
            /**
             * Remove a class from an element
             * @param {Object} el Element
             * @param {Object} c Class to remove
             */
            removeClass: function (el, c) {
                if (this.hasClass(el, c)) {
                    var s = el.className;
                    var re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g");
                    var v = s.replace(re, ' ');
                    v = v.replace(/^\s|\s$/g, '');
                    el.className = v;
                }
            },
            /**
             * Show an element
             * @param {Object} el Element to show
             */
            show: function (el) {
                el.style.display = 'block';
            },
            /**
             * Hide and element
             * @param {Object} el Element to hide
             */
            hide: function (el) {
                el.style.display = 'none';
            },
            /**
             * Remove an element or attribute
             * @param {Object} el Element
             * @param {String} attrib Attribute
             */
            remove: function (el, attrib) {
                if (attrib) {
                    el.removeAttribute(attrib);
                } else {
                    var p = el.parentNode || document.body;
                    p.removeChild(el);
                }
            },
            /**
             * Set or retrieve a style
             * @param {Object} el Target Element
             * @param {Object} s Style to set / get
             * @param {Object} v Value to set
             */
            style: function (n, na, v) {
                var isIE = JCEMediaBox.isIE, r, s;

                if (!n) {
                    return;
                }

                // Camelcase it, if needed
                na = na.replace(/-(\D)/g, function (a, b) {
                    return b.toUpperCase();
                });

                s = n.style;

                // Get value
                if (typeof v == 'undefined') {

                    if (na == 'float')
                        na = isIE ? 'styleFloat' : 'cssFloat';

                    r = s[na];

                    if (document.defaultView && !r) {
                        if (/float/i.test(na))
                            na = 'float';

                        // Remove camelcase
                        na = na.replace(/[A-Z]/g, function (a) {
                            return '-' + a;
                        }).toLowerCase();

                        try {
                            r = document.defaultView.getComputedStyle(n, null).getPropertyValue(na);
                        } catch (e) {
                        }
                    }

                    if (n.currentStyle && !r)
                        r = n.currentStyle[na];

                    return r;

                } else {

                    switch (na) {
                        case 'opacity':
                            v = parseFloat(v);
                            // IE specific opacity
                            if (isIE) {
                                s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";

                                if (!n.currentStyle || !n.currentStyle.hasLayout)
                                    s.display = 'inline-block';
                            }
                            s[na] = v;
                            break;
                        case 'float':
                            na = isIE ? 'styleFloat' : 'cssFloat';
                            break;
                        default:
                            if (v && /(margin|padding|width|height|top|bottom|left|right)/i.test(na)) {
                                // Add pixel value if number
                                v = /^[\-0-9\.]+$/.test(v) ? v + 'px' : v;
                            }
                            break;
                    }
                    s[na] = v;
                }
            },
            /**
             * Set styles
             * @param {Object} el Target Element
             * @param {Object} props Object of style key/values
             */
            styles: function (el, props) {
                var t = this;
                JCEMediaBox.each(props, function (v, s) {
                    return t.style(el, s, v);
                });

            },
            /**
             * Set an Element attribute
             * @param {Object} el
             * @param {Object} s
             * @param {Object} v
             */
            attribute: function (el, s, v) {
                if (typeof v == 'undefined') {
                    if (s == 'class') {
                        return el.className;
                    }
                    v = el.getAttribute(s);
                    // Remove anonymous function from events
                    if (v && /^on/.test(s)) {
                        v = v.toString();
                        v = v.replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/, '$1');
                    }
                    // Fix Hspace
                    if (s == 'hspace' && v == -1) {
                        v = '';
                    }
                    return v;
                }
                // Remove attribute if no value
                if (v === '') {
                    el.removeAttribute(s);
                }

                switch (s) {
                    case 'style':
                        if (typeof v == 'object') {
                            this.styles(el, v);
                        } else {
                            el.style.cssText = v;
                        }
                        break;
                    case 'class':
                        el.className = v || '';
                        break;
                    default:
                        el.setAttribute(s, v);
                        break;
                }
            },
            /**
             * Set Attributes on an Element
             * @param {Object} el Target Element
             * @param {Object} attribs Attributes Object
             */
            attributes: function (el, attribs) {
                var t = this;
                JCEMediaBox.each(attribs, function (v, s) {
                    t.attribute(el, s, v);
                });

            },
            /**
             * Create an Element
             * @param {Object} el Element to create
             * @param {Object} attribs Attributes
             * @param {Object} styles Styles
             * @param {Object} html HTML
             */
            create: function (el, attribs, html) {
                var o = document.createElement(el);
                this.attributes(o, attribs);
                if (typeof html != 'undefined') {
                    o.innerHTML = html;
                }

                return o;
            },
            /**
             * Add an element to another
             * @param {Object} n Element to add to
             * @param {Object} o Element to add. Will be created if string
             * @param {Object} a Optional attributes
             * @param {Object} h Optional HTML
             */
            add: function (n, o, a, h) {
                if (typeof o == 'string') {
                    a = a || {};
                    o = this.create(o, a, h);
                }
                n.appendChild(o);

                return o;
            },
            /**
             * Add an element before the passed in element
             * @param {Object} n Element to insert into
             * @param {Object} o Element to insert
             * @param {Object} c Element to insert before
             */
            addBefore: function (n, o, c) {
                if (typeof c == 'undefined') {
                    c = n.firstChild;
                }
                n.insertBefore(o, c);
            },
            /**
             * IE6 PNG Fix
             * @param {Object} el Element to fix
             */
            png: function (el) {
                var s;
                // Image Elements
                if (el.nodeName == 'IMG') {
                    s = el.src;
                    if (/\.png$/i.test(s)) {
                        this.attribute(el, 'src', JCEMediaBox.site + 'plugins/system/jcemediabox/img/blank.gif');
                        this.style(el, 'filter', "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + s + "')");
                    }
                    // Background-image styles
                } else {
                    s = this.style(el, 'background-image');
                    if (/\.png/i.test(s)) {
                        var bg = /url\("(.*)"\)/.exec(s)[1];
                        this.styles(el, {
                            'background-image': 'none',
                            'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + bg + "', sizingMethod='image')"
                        });
                    }
                }
            },
            encode: function (s) {
                return ('' + s).replace(/[<>&\"\']/g, function (c) {
                    return entities[c] || c;
                });
            },
            decode: function (s) {
                var el;

                s = s.replace(/&lt;/g, '<').replace(/&gt;/g, '>');

                el = document.createElement("div");
                el.innerHTML = s;

                return el.innerHTML || s;
            }

        },
        /**
         * Event Functions
         */
        Event: {
            events: [],
            /**
             * Add an Event handler
             * @param {Object} o Target Element
             * @param {Object} n Event name
             * @param {Object} f Callback function
             * @param {Object} s Scope
             * @copyright	Copyright 2009, Moxiecode Systems AB
             */
            add: function (o, n, f, s) {
                var t = this;

                // Setup event callback
                cb = function (e) {
                    // Is all events disabled
                    if (t.disabled)
                        return;

                    e = e || window.event;

                    // Patch in target, preventDefault and stopPropagation in IE it's W3C valid
                    if (e && JCEMediaBox.isIE) {
                        if (!e.target) {
                            e.target = e.srcElement || document;
                        }

                        if (!e.relatedTarget && e.fromElement) {
                            e.relatedTarget = e.fromElement == e.target ? e.toElement : e.fromElement;
                        }

                        // Patch in preventDefault, stopPropagation methods for W3C compatibility
                        JCEMediaBox.extend(e, {
                            preventDefault: function () {
                                this.returnValue = false;
                            },
                            stopPropagation: function () {
                                this.cancelBubble = true;
                            }

                        });
                    }
                    if (e && JCEMediaBox.isWebKit) {
                        if (e.target.nodeType == 3) {
                            e.target = e.target.parentNode;
                        }
                    }

                    if (!s)
                        return f(e);

                    return f.call(s, e);
                };

                // Internal function to add an event to an object
                function _add(o, n, f) {
                    if (o.attachEvent) {
                        o.attachEvent('on' + n, f);
                    } else if (o.addEventListener) {
                        o.addEventListener(n, f, false);
                    } else {
                        o['on' + n] = f;
                    }
                }

                t.events.push({
                    obj: o,
                    name: n,
                    func: f,
                    cfunc: cb,
                    scope: s
                });

                // Add event
                _add(o, n, cb);
            },
            /**
             * Removes the specified event handler by name and function from a element or collection of elements.
             *
             * @method remove
             * @param {String/Element/Array} o Element ID string or HTML element or an array of elements or ids to remove handler from.
             * @param {String} n Event handler name like for example: "click"
             * @param {function} f Function to remove.
             * @return {bool/Array} Bool state if true if the handler was removed or an array with states if multiple elements where passed in.
             * @copyright	Copyright 2009, Moxiecode Systems AB
             */
            remove: function (o, n, f) {
                var t = this, a = t.events, s = false;

                JCEMediaBox.each(a, function (e, i) {
                    if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {
                        a.splice(i, 1);
                        t._remove(o, n, e.cfunc);
                        s = true;
                        return false;
                    }
                });

                return s;
            },
            /**
             * Internal function to remove an Event
             * @param {Object} o
             * @param {Object} n
             * @param {Object} f
             * @copyright	Copyright 2009, Moxiecode Systems AB
             */
            _remove: function (o, n, f) {
                if (o) {
                    try {
                        if (o.detachEvent)
                            o.detachEvent('on' + n, f);
                        else if (o.removeEventListener)
                            o.removeEventListener(n, f, false);
                        else
                            o['on' + n] = null;
                    } catch (ex) {
                        // Might fail with permission denined on IE so we just ignore that
                    }
                }
            },
            /**
             * Cancels an event for both bubbeling and the default browser behavior.
             *
             * @method cancel
             * @param {Event} e Event object to cancel.
             * @return {Boolean} Always false.
             * @copyright Copyright 2009, Moxiecode Systems AB
             */
            cancel: function (e) {
                if (!e)
                    return false;

                this.stop(e);

                return this.prevent(e);
            },
            /**
             * Stops propogation/bubbeling of an event.
             *
             * @method stop
             * @param {Event} e Event to cancel bubbeling on.
             * @return {Boolean} Always false.
             * @copyright	Copyright 2009, Moxiecode Systems AB
             */
            stop: function (e) {
                if (e.stopPropagation)
                    e.stopPropagation();
                else
                    e.cancelBubble = true;

                return false;
            },
            /**
             * Prevent default browser behvaior of an event.
             *
             * @method prevent
             * @param {Event} e Event to prevent default browser behvaior of an event.
             * @return {Boolean} Always false.
             * @copyright	Copyright 2009, Moxiecode Systems AB
             */
            prevent: function (e) {
                if (e.preventDefault)
                    e.preventDefault();
                else
                    e.returnValue = false;

                return false;
            },
            /**
             * Destroys the instance.
             *
             * @method destroy
             * @copyright	Copyright 2009, Moxiecode Systems AB
             */
            destroy: function () {
                var t = this;

                JCEMediaBox.each(t.events, function (e, i) {
                    t._remove(e.obj, e.name, e.cfunc);
                    e.obj = e.cfunc = null;
                });

                t.events = [];
                t = null;
            },
            /**
             * Adds an unload handler to the document. This handler will be executed when the document gets unloaded.
             * This method is useful for dealing with browser memory leaks where it might be vital to remove DOM references etc.
             *
             * @method addUnload
             * @param {function} f Function to execute before the document gets unloaded.
             * @param {Object} s Optional scope to execute the function in.
             * @return {function} Returns the specified unload handler function.
             * @copyright	Copyright 2009, Moxiecode Systems AB
             */
            addUnload: function (f, s) {
                var t = this;

                f = {
                    func: f,
                    scope: s || this
                };

                if (!t.unloads) {
                    function unload() {
                        var li = t.unloads, o, n;

                        if (li) {
                            // Call unload handlers
                            for (n in li) {
                                o = li[n];

                                if (o && o.func)
                                    o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy
                            }

                            // Detach unload function
                            if (window.detachEvent) {
                                window.detachEvent('onbeforeunload', fakeUnload);
                                window.detachEvent('onunload', unload);
                            } else if (window.removeEventListener)
                                window.removeEventListener('unload', unload, false);

                            // Destroy references
                            t.unloads = o = li = w = unload = 0;

                            // Run garbarge collector on IE
                            if (window.CollectGarbage)
                                CollectGarbage();
                        }
                    }

                    function fakeUnload() {
                        var d = document;

                        // Is there things still loading, then do some magic
                        if (d.readyState == 'interactive') {
                            function stop() {
                                // Prevent memory leak
                                d.detachEvent('onstop', stop);

                                // Call unload handler
                                if (unload)
                                    unload();

                                d = 0;
                            }

                            // Fire unload when the currently loading page is stopped
                            if (d)
                                d.attachEvent('onstop', stop);

                            // Remove onstop listener after a while to prevent the unload function
                            // to execute if the user presses cancel in an onbeforeunload
                            // confirm dialog and then presses the browser stop button
                            window.setTimeout(function () {
                                if (d)
                                    d.detachEvent('onstop', stop);
                            }, 0);

                        }
                    }

                    // Attach unload handler
                    if (window.attachEvent) {
                        window.attachEvent('onunload', unload);
                        window.attachEvent('onbeforeunload', fakeUnload);
                    } else if (window.addEventListener)
                        window.addEventListener('unload', unload, false);

                    // Setup initial unload handler array
                    t.unloads = [f];
                } else
                    t.unloads.push(f);

                return f;
            },
            /**
             * Removes the specified function form the unload handler list.
             *
             * @method removeUnload
             * @param {function} f Function to remove from unload handler list.
             * @return {function} Removed function name or null if it wasn't found.
             */
            removeUnload: function (f) {
                var u = this.unloads, r = null;

                JCEMediaBox.each(u, function (o, i) {
                    if (o && o.func == f) {
                        u.splice(i, 1);
                        r = f;
                        return false;
                    }
                });

                return r;
            }

        },
        Dimensions: {
            /**
             * Get client window width
             */
            getWidth: function () {
                return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0;
            },
            /**
             * Get client window height
             */
            getHeight: function () {
                if (JCEMediaBox.isiOS || JCEMediaBox.isAndroid) {
                    var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
                    return window.innerHeight * zoomLevel;
                }

                return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0;
            },
            /**
             * Get client window scroll height
             */
            getScrollHeight: function () {
                return document.documentElement.scrollHeight || document.body.scrollHeight || 0;
            },
            /**
             * Get client window scroll width
             */
            getScrollWidth: function () {
                return document.documentElement.scrollWidth || document.body.scrollWidth || 0;
            },
            /**
             * Get client window scroll top
             */
            getScrollTop: function () {
                return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
            },
            /**
             * Get the page scrollbar width
             */
            getScrollbarWidth: function () {
                var DOM = JCEMediaBox.DOM;

                if (this.scrollbarWidth) {
                    return this.scrollbarWidth;
                }

                var outer = DOM.add(document.body, 'div', {
                    'style': {
                        position: 'absolute',
                        visibility: 'hidden',
                        width: 200,
                        height: 200,
                        border: 0,
                        margin: 0,
                        padding: 0,
                        overflow: 'hidden'
                    }
                });

                var inner = DOM.add(outer, 'div', {
                    'style': {
                        width: '100%',
                        height: 200,
                        border: 0,
                        margin: 0,
                        padding: 0
                    }
                });

                var w1 = parseInt(inner.offsetWidth);
                outer.style.overflow = 'scroll';
                var w2 = parseInt(inner.offsetWidth);
                if (w1 == w2) {
                    w2 = parseInt(outer.clientWidth);
                }
                document.body.removeChild(outer);
                this.scrollbarWidth = (w1 - w2);

                return this.scrollbarWidth;
            },
            /**
             * Get the outerwidth of an element
             * @param {Object} n Element
             */
            outerWidth: function (n) {
                var v = 0, x = 0;

                x = n.offsetWidth;

                if (!x) {
                    JCEMediaBox.each(['padding-left', 'padding-right', 'border-left', 'border-right', 'width'], function (s) {
                        v = parseFloat(JCEMediaBox.DOM.style(n, s));
                        v = /[0-9]/.test(v) ? v : 0;

                        x = x + v;
                    });

                }
                return x;
            },
            /**
             * Get the outerheight of an Element
             * @param {Object} n Element
             */
            outerHeight: function (n) {
                var v = 0, x = 0;

                x = n.offsetHeight;

                if (!x) {
                    JCEMediaBox.each(['padding-top', 'padding-bottom', 'border-top', 'border-bottom', 'height'], function (s) {
                        v = parseFloat(JCEMediaBox.DOM.style(n, s));
                        v = /[0-9]/.test(v) ? v : 0;
                        x = x + v;
                    });

                }
                return x;
            }

        },
        /**
         * FX Functions
         * @param {Object} t
         * @param {Object} b
         * @param {Object} c
         * @param {Object} d
         */
        FX: {
            animate: function (el, props, speed, cb) {
                var DOM = JCEMediaBox.DOM;
                var options = {
                    speed: speed || 100,
                    callback: cb ||
                            function () {
                            }

                };

                var styles = {}, sv;

                JCEMediaBox.each(props, function (v, s) {
                    // Find start value
                    sv = parseFloat(DOM.style(el, s));
                    styles[s] = [sv, v];
                });

                new JCEMediaBox.fx(el, options).custom(styles);
                return true;
            }

        }
    };

    /**
     * XHR Functions
     * Based on XHR.js (Mootools) and XHR.js (TinyMCE)
     * Copyright 2009, Moxiecode Systems AB, <http://tinymce.moxiecode.com>
     * copyright (c) 2007 Valerio Proietti, <http://mad4milk.net>
     */
    JCEMediaBox.XHR = function (options, scope) {
        this.options = {
            //method: 'GET',
            async: true,
            headers: {
                //'User-Agent' 		: 'XMLHTTP/1.0',
                'X-Requested-With': 'XMLHttpRequest',
                'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
            },
            data: null,
            encoding: 'UTF-8',
            success: function () {
            },
            error: function () {
            }

        };
        // Set options
        JCEMediaBox.extend(this.options, options);
        // optional scope for callback functions
        this.scope = scope || this;
    };

    JCEMediaBox.XHR.prototype = {
        /**
         * Set transport method
         */
        setTransport: function () {
            function get(s) {
                var x = 0;

                try {
                    x = new ActiveXObject(s);
                } catch (ex) {
                }

                return x;
            }

            this.transport = window.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
        },
        /**
         * Process return
         */
        onStateChange: function () {
            if (this.transport.readyState != 4 || !this.running) {
                return;
            }

            this.running = false;

            if ((this.transport.status >= 200) && (this.transport.status < 300)) {
                var s = this.transport.responseText;
                var x = this.transport.responseXML;

                this.options.success.call(this.scope, s, x);
            } else {
                this.options.error.call(this.scope, this.transport, this.options);
            }
            // Clean up
            this.transport.onreadystatechange = function () {
            };

            this.transport = null;
        },
        /**
         * Send request
         * @param {Object} url URL
         * @param {Object} options Request options
         * @param {Object} s Scope
         */
        send: function (url) {
            var t = this, extend = JCEMediaBox.extend;
            if (this.running) {
                return this;
            }
            this.running = true;
            // Set request transport method
            this.setTransport();
            // store request method as uppercase (GET|POST)
            var method = this.options.data ? 'POST' : 'GET';

            // set encoding
            var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding.toUpperCase() : '';

            // Set standard GET header
            var contentType = {
                'Content-type': 'text/html' + encoding
            };

            // Set URL Encoded / POST header options
            if (this.options.data) {
                contentType = {
                    'Content-type': 'application/x-www-form-urlencoded' + encoding
                };
            }

            extend(this.options.headers, contentType);

            // Open transport
            this.transport.open(method, url, this.options.async);
            // Set readystatechange function
            this.transport.onreadystatechange = function () {
                return t.onStateChange();
            };

            /*if (method == 'POST' && this.transport.overrideMimeType) {
             extend(this.options.headers, {
             'Connection': 'close'
             });
             }*/
            // set headers
            for (var type in this.options.headers) {
                try {
                    this.transport.setRequestHeader(type, this.options.headers[type]);
                } catch (e) {
                }
            }
            // send request
            this.transport.send(this.options.data);
        }

    }, /**
     * Core Fx Functions
     * @param {Object} el Element to animate
     * @param {Object} props A set of styles to animate
     * @param {String} speed Speed of animation in milliseconds
     * @param {Object} cb Optional Callback when the animation finishes
     */
    JCEMediaBox.fx = function (el, options) {
        this.element = el;
        this.callback = options.callback;
        this.speed = options.speed;
        this.wait = true;
        this.fps = 50;
        this.now = {};
    };

    /**
     * Based on Moo.Fx.Base and Moo.Fx.Styles
     * @copyright (c) 2006 Valerio Proietti (http://mad4milk.net). MIT-style license.
     */
    JCEMediaBox.fx.prototype = {
        step: function () {
            var time = new Date().getTime();
            if (time < this.time + this.speed) {
                this.cTime = time - this.time;
                this.setNow();

            } else {
                var t = this;
                this.clearTimer();
                this.now = this.to;

                setTimeout(function () {
                    t.callback.call(t.element, t);
                }, 10);

            }
            this.increase();
        },
        setNow: function () {
            var p;

            for (p in this.from) {
                this.now[p] = this.compute(this.from[p], this.to[p]);
            }
        },
        compute: function (from, to) {
            var change = to - from;
            return this.transition(this.cTime, from, change, this.speed);
        },
        clearTimer: function () {
            clearInterval(this.timer);
            this.timer = null;
            return this;
        },
        start: function (from, to) {
            var t = this;
            if (!this.wait)
                this.clearTimer();

            if (this.timer)
                return;

            this.from = from;
            this.to = to;
            this.time = new Date().getTime();
            this.timer = setInterval(function () {
                return t.step();
            }, Math.round(1000 / this.fps));

            return this;
        },
        custom: function (o) {
            if (this.timer && this.wait)
                return;
            var from = {}, to = {}, property;

            for (property in o) {
                from[property] = o[property][0];
                to[property] = o[property][1];
            }
            return this.start(from, to);
        },
        increase: function () {
            for (var p in this.now) {
                this.setStyle(this.element, p, this.now[p]);
            }
        },
        transition: function (t, b, c, d) {
            return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
        },
        setStyle: function (e, p, v) {
            JCEMediaBox.DOM.style(e, p, v);
        }

    },
    /**
     * Core Tooltip Object
     * Create and display tooltips
     * Based on Mootools Tips Class
     * copyright (c) 2007 Valerio Proietti, <http://mad4milk.net>
     */
    JCEMediaBox.ToolTip = {
        /**
         * Initialise the tooltip
         * @param {Object} elements
         * @param {Object} options
         */
        init: function () {
            var t = this;

            // Load tooltip theme
            var theme = JCEMediaBox.options.theme == 'custom' ? JCEMediaBox.options.themecustom : JCEMediaBox.options.theme;

            this.tooltiptheme = '';

            new JCEMediaBox.XHR({
                success: function (text, xml) {
                    var re = /<!-- THEME START -->([\s\S]*?)<!-- THEME END -->/;
                    if (re.test(text)) {
                        text = re.exec(text)[1];
                    }
                    t.tooltiptheme = text;

                    t.create();
                }

            }).send(JCEMediaBox.site + JCEMediaBox.options.themepath + '/' + theme + '/tooltip.html');
        },
        /**
         * Create tooltips in the cuurent document or node
         * @param o Option parent node, defaults to document
         */
        create: function (o) {
            var t = this, each = JCEMediaBox.each, DOM = JCEMediaBox.DOM, Event = JCEMediaBox.Event;

            /**
             * Private internal function to exclude children of element in event
             * @param {Object} el 	Element with event
             * @param {Object} e 	Event object
             * @param {Object} fn 	Callback function
             */
            function _withinElement(el, e, fn) {
                // Get target
                var p = e.relatedTarget;
                // If element is not target and target not within element...
                while (p && p != el) {
                    try {
                        p = p.parentNode;
                    } catch (e) {
                        p = el;
                    }
                }

                if (p != el) {
                    return fn.call(this);
                }
                return false;
            }

            // Add events to each found tooltip element
            each(DOM.select('.jcetooltip, .jce_tooltip', o), function (el) {
                // store away title
                DOM.attribute(el, 'data-title', el.title);
                DOM.remove(el, 'title');

                var n = el;

                // set event element as parent if popup icon
                if (el.nodeName == 'IMG' && el.parentNode.className == 'jcemediabox-zoom-span') {
                    n = el.parentNode;
                }

                Event.add(n, 'mouseover', function (e) {
                    _withinElement(el, e, function () {
                        return t.start(el);
                    });

                });

                Event.add(n, 'mouseout', function (e) {
                    _withinElement(el, e, function () {
                        return t.end(el);
                    });

                });

                Event.add(n, 'mousemove', function (e) {
                    return t.locate(e);
                });

            });

        },
        /**
         * Create the tooltip div
         */
        build: function () {
            if (!this.toolTip) {
                var DOM = JCEMediaBox.DOM;
                this.toolTip = DOM.add(document.body, 'div', {
                    'style': {
                        'opacity': 0
                    },
                    'class': 'jcemediabox-tooltip'
                }, this.tooltiptheme);
                if (JCEMediaBox.isIE6) {
                    DOM.addClass(this.toolTip, 'ie6');
                }
            }
        },
        /**
         * Show the tooltip and build the tooltip text
         * @param {Object} e  Event
         * @param {Object} el Target Element
         */
        start: function (el) {
            var t = this, DOM = JCEMediaBox.DOM;
            if (!this.tooltiptheme)
                return false;
            // Create tooltip if it doesn't exist
            this.build();

            // Get tooltip text from title
            var text = DOM.attribute(el, 'data-title') || '', title = '';

            // Split tooltip text ie: title::text
            if (/::/.test(text)) {
                var parts = text.split('::');
                title = JCEMediaBox.trim(parts[0]);
                text = JCEMediaBox.trim(parts[1]);
            }

            var h = '';
            // Set tooltip title html
            if (title) {
                h += '<h4>' + title + '</h4>';
            }
            // Set tooltip text html
            if (text) {
                h += '<p>' + text + '</p>';
            }

            // Set tooltip html
            var tn = DOM.get('jcemediabox-tooltip-text');
            // Use simple tooltip
            if (typeof tn == 'undefined') {
                this.toolTip.className = 'jcemediabox-tooltip-simple';
                this.toolTip.innerHTML = h;
            } else {
                tn.innerHTML = h;
            }
            // Set visible
            DOM.style(t.toolTip, 'visibility', 'visible');
            // Fade in tooltip
            JCEMediaBox.FX.animate(t.toolTip, {
                'opacity': JCEMediaBox.options.tooltip.opacity
            }, JCEMediaBox.options.tooltip.speed);
        },
        /**
         * Fade Out and hide the tooltip
         * Restore the original element title
         * @param {Object} el Element
         */
        end: function (el) {
            if (!this.tooltiptheme)
                return false;

            // Fade out tooltip and hide

            JCEMediaBox.DOM.styles(this.toolTip, {
                'visibility': 'hidden',
                'opacity': 0
            });
        },
        /**
         * Position the tooltip
         * @param {Object} e Event trigger
         */
        locate: function (e) {
            if (!this.tooltiptheme)
                return false;

            this.build();

            var o = JCEMediaBox.options.tooltip.offsets;
            var page = {
                'x': e.pageX || e.clientX + document.documentElement.scrollLeft,
                'y': e.pageY || e.clientY + document.documentElement.scrollTop
            };
            var tip = {
                'x': this.toolTip.offsetWidth,
                'y': this.toolTip.offsetHeight
            };
            var pos = {
                'x': page.x + o.x,
                'y': page.y + o.y
            };

            var ah = 0;

            switch (JCEMediaBox.options.tooltip.position) {
                case 'tl':
                    pos.x = (page.x - tip.x) - o.x;
                    pos.y = (page.y - tip.y) - (ah + o.y);
                    break;
                case 'tr':
                    pos.x = page.x + o.x;
                    pos.y = (page.y - tip.y) - (ah + o.y);
                    break;
                case 'tc':
                    pos.x = (page.x - Math.round((tip.x / 2))) + o.x;
                    pos.y = (page.y - tip.y) - (ah + o.y);
                    break;
                case 'bl':
                    pos.x = (page.x - tip.x) - o.x;
                    pos.y = (page.y + Math.round((tip.y / 2))) - (ah + o.y);
                    break;
                case 'br':
                    pos.x = page.x + o.x;
                    pos.y = page.y + o.y;
                    break;
                case 'bc':
                    pos.x = (page.x - (tip.x / 2)) + o.x;
                    pos.y = page.y + ah + o.y;
                    break;
            }
            JCEMediaBox.DOM.styles(this.toolTip, {
                top: pos.y,
                left: pos.x
            });
        },
        /**
         * Position the tooltip
         * @param {Object} element
         */
        position: function (element) {
        }

    },
    /**
     * Core Popup Object
     * Creates and displays a media popup
     */
    JCEMediaBox.Popup = {
        /**
         * List of default addon media types
         */
        addons: {
            'flash': {},
            'image': {},
            'iframe': {},
            'html': {},
            'pdf': {}
        },
        /**
         * Extend the addons object with a new addon
         * @param {String} n Addon name
         * @param {Object} o Addon object
         */
        setAddons: function (n, o) {
            JCEMediaBox.extend(this.addons[n], o);
        },
        /**
         * Return an addon object by name or all addons
         * @param {String} n Addon name
         */
        getAddons: function (n) {
            if (n) {
                return this.addons[n];
            }
            return this.addons;
        },
        /**
         * Get / Test an addon object
         * @param {Object} v
         * @param {Object} n
         */
        getAddon: function (v, n) {
            var cp = false, r, each = JCEMediaBox.each;

            addons = this.getAddons(n);

            each(this.addons, function (o, s) {
                each(o, function (fn) {
                    r = fn.call(this, v);
                    if (typeof r != 'undefined') {
                        cp = r;
                    }
                });

            });

            return cp;
        },
        /**
         * Clean an event removing anonymous function etc.
         * @param {String} s Event content
         * Copyright 2009, Moxiecode Systems AB
         */
        cleanEvent: function (s) {
            return s.replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/, '$1');
        },
        /**
         * Create an object from a well formed JSON string
         * @param {String} data JSON String
         * @return {Object}
         * Logic borrowed from JQuery
         * http://jquery.com/
         * Copyright 2010, John Resig
         */
        parseJSON: function (data) {
            if (typeof data !== "string" || !data) {
                return null;
            }

            if (/^[\],:{}\s]*$/
                    .test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
                            .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
                            .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
                // Try to use the native JSON parser first
                return window.JSON && window.JSON.parse ?
                        window.JSON.parse(data) :
                        (new Function("return " + data))();
            }
        },
        /**
         * Get a popup parameter object
         * @param {String} s Parameter string
         */
        params: function (s) {
            var a = [], x = [], self = this, DOM = JCEMediaBox.DOM;

            function trim(s) {
                return s = s.replace(/^\s+/, '').replace(/\s+$/, '');
            }

            if (typeof s == 'string') {
                // if a JSON string return the object
                if (/^\{[\w\W]+\}$/.test(s)) {
                    return this.parseJSON(s);
                }

                // JCE MediaBox parameter format eg: title[title]
                if (/\w+\[[^\]]+\]/.test(s)) {
                    s = s.replace(/([\w]+)\[([^\]]+)\](;)?/g, function (a, b, c, d) {

                        return '"' + b + '":"' + DOM.encode(trim(c)) + '"' + (d ? ',' : '');
                    });

                    return this.parseJSON('{' + s + '}');
                }

                // if url
                if (s.indexOf('&') != -1) {
                    x = s.split(/&(amp;)?/g);
                } else {
                    x.push(s);
                }
            }

            // if array
            if (typeof s == 'object' && s instanceof Array) {
                x = s;
            }

            JCEMediaBox.each(x, function (n, i) {
                if (n) {
                    n = n.replace(/^([^\[]+)(\[|=|:)([^\]]*)(\]?)$/, function (a, b, c, d) {
                        if (d) {
                            if (!/[^0-9]/.test(d)) {
                                return '"' + b + '":' + parseInt(d);
                            }

                            return '"' + b + '":"' + DOM.encode(trim(d)) + '"';
                        }
                        return '';
                    });

                    if (n) {
                        a.push(n);
                    }
                }
            });

            return this.parseJSON('{' + a.join(',') + '}');
        },
        /**
         * Gets the raw data of a cookie by name.
         * Copyright 2009, Moxiecode Systems AB
         *
         * @method get
         * @param {String} n Name of cookie to retrive.
         * @return {String} Cookie data string.
         */
        getCookie: function (n) {
            var c = document.cookie, e, p = n + "=", b;

            // Strict mode
            if (!c)
                return;

            b = c.indexOf("; " + p);

            if (b == -1) {
                b = c.indexOf(p);

                if (b != 0)
                    return null;
            } else {
                b += 2;
            }

            e = c.indexOf(";", b);

            if (e == -1)
                e = c.length;

            return unescape(c.substring(b + p.length, e));
        },
        /**
         * Sets a raw cookie string.
         * Copyright 2009, Moxiecode Systems AB
         *
         * @method set
         * @param {String} n Name of the cookie.
         * @param {String} v Raw cookie data.
         * @param {Date} e Optional date object for the expiration of the cookie.
         * @param {String} p Optional path to restrict the cookie to.
         * @param {String} d Optional domain to restrict the cookie to.
         * @param {String} s Is the cookie secure or not.
         */
        setCookie: function (n, v, e, p, d, s) {
            document.cookie = n + "=" + escape(v) +
                    ((e) ? "; expires=" + e.toGMTString() : "") +
                    ((p) ? "; path=" + escape(p) : "") +
                    ((d) ? "; domain=" + d : "") +
                    ((s) ? "; secure" : "");
        },
        /**
         * Convert legacy popups to new format
         */
        convertLegacy: function () {
            var self = this, each = JCEMediaBox.each, DOM = JCEMediaBox.DOM;
            each(DOM.select('a[href]'), function (el) {

                // Only JCE Popup links
                if (/com_jce/.test(el.href)) {
                    var p, s, img;
                    var oc = DOM.attribute(el, 'onclick');
                    if (oc) {
                        s = oc.replace(/&#39;/g, "'").split("'");
                        p = self.params(s[1]);

                        var img = p.img || '';
                        var title = p.title || '';
                    }

                    if (img) {
                        if (!/http:\/\//.test(img)) {
                            if (img.charAt(0) == '/') {
                                img = img.substr(1);
                            }
                            img = JCEMediaBox.site.replace(/http:\/\/([^\/]+)/, '') + img;
                        }

                        DOM.attributes(el, {
                            'href': img,
                            'title': title.replace(/_/, ' '),
                            'onclick': ''
                        });

                        DOM.addClass(el, 'jcepopup');
                    }
                }
            });

        },
        /**
         * Convert lightbox popups to MediaBox
         */
        convertLightbox: function () {
            var each = JCEMediaBox.each, DOM = JCEMediaBox.DOM;
            each(DOM.select('a[rel*=lightbox]'), function (el) {
                DOM.addClass(el, 'jcepopup');
                r = el.rel.replace(/lightbox\[?([^\]]*)\]?/, function (a, b) {
                    if (b) {
                        return 'group[' + b + ']';
                    }
                    return '';
                });

                DOM.attribute(el, 'rel', r);
            });

        },
        /**
         * Convert shadowbox popups to MediaBox
         */
        convertShadowbox: function () {
            var each = JCEMediaBox.each, DOM = JCEMediaBox.DOM;
            each(DOM.select('a[rel*=shadowbox]'), function (el) {
                DOM.addClass(el, 'jcepopup');
                r = el.rel.replace(/shadowbox\[?([^\]]*)\]?/, function (a, b) {
                    var attribs = '', group = '';
                    // group
                    if (b) {
                        group = 'group[' + b + ']';
                    }
                    // attributes
                    if (/;=/.test(a)) {
                        attribs = a.replace(/=([^;"]+)/g, function (x, z) {
                            return '[' + z + ']';
                        });

                    }
                    if (group && attribs) {
                        return group + ';' + attribs;
                    }
                    return group || attribs || '';
                });

                DOM.attribute(el, 'rel', r);
            });

        },
        /**
         * Translate popup labels
         * @param {String} s Theme HTML
         */
        translate: function (s) {
            if (!s) {
                s = this.popup.theme;
            }
            s = s.replace(/\{#(\w+?)\}/g, function (a, b) {
                return JCEMediaBox.options.popup.labels[b];
            });

            return s;
        },
        /**
         * Returns a styles object from a parameter
         * @param {Object} o
         */
        styles: function (o) {
            var x = [];
            if (!o)
                return {};

            JCEMediaBox.each(o.split(';'), function (s, i) {
                s = s.replace(/(.*):(.*)/, function (a, b, c) {
                    return '"' + b + '":"' + c + '"';
                });

                x.push(s);
            });

            return this.parseJSON('{' + x.join(',') + '}');
        },
        /**
         * Get the file type from the url, type attribute or className
         * @param {Object} el
         */
        getType: function (el) {
            var o = {}, type = '';

            // Media types
            if (el.type && /(director|windowsmedia|mplayer|quicktime|real|divx|flash|pdf)/.test(el.type)) {
                type = /(director|windowsmedia|mplayer|quicktime|real|divx|flash|pdf)/.exec(el.type)[1];
            }

            o = this.getAddon(el.src);

            if (o && o.type) {
                type = o.type;
            }

            return type || el.type || 'iframe';
        },
        /**
         * Determine media type and properties
         * @param {Object} c
         */
        mediatype: function (c) {
            var ci, cb, mt;

            c = /(director|windowsmedia|mplayer|quicktime|real|divx|flash|pdf)/.exec(c);

            switch (c[1]) {
                case 'director':
                case 'application/x-director':
                    ci = '166b1bca-3f9c-11cf-8075-444553540000';
                    cb = 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0';
                    mt = 'application/x-director';
                    break;
                case 'windowsmedia':
                case 'mplayer':
                case 'application/x-mplayer2':
                    ci = '6bf52a52-394a-11d3-b153-00c04f79faa6';
                    cb = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701';
                    mt = 'application/x-mplayer2';
                    break;
                case 'quicktime':
                case 'video/quicktime':
                    ci = '02bf25d5-8c17-4b23-bc80-d3488abddc6b';
                    cb = 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0';
                    mt = 'video/quicktime';
                    break;
                case 'real':
                case 'realaudio':
                case 'audio/x-pn-realaudio-plugin':
                    ci = 'cfcdaa03-8be4-11cf-b84b-0020afbbccfa';
                    cb = '';
                    mt = 'audio/x-pn-realaudio-plugin';
                    break;
                case 'divx':
                case 'video/divx':
                    ci = '67dabfbf-d0ab-41fa-9c46-cc0f21721616';
                    cb = 'http://go.divx.com/plugin/DivXBrowserPlugin.cab';
                    mt = 'video/divx';
                    break;
                case 'pdf':
                case 'application/pdf':
                    ci = 'ca8a9780-280d-11cf-a24d-444553540000';
                    cb = '';
                    mt = 'application/pdf';
                    break;
                default:
                case 'flash':
                case 'application/x-shockwave-flash':
                    ci = 'd27cdb6e-ae6d-11cf-96b8-444553540000';
                    cb = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,124,0';
                    mt = 'application/x-shockwave-flash';
                    break;
            }
            return {
                'classid': ci,
                'codebase': cb,
                'mediatype': mt
            };
        },
        /**
         * Determine whether the url is local
         * @param {Object} s
         */
        islocal: function (s) {
            if (/^(\w+:)?\/\//.test(s)) {
                return new RegExp('^(' + JCEMediaBox.site + ')').test(s);
            } else {
                return true;
            }
        },
        protocolRelative: function (url) {
            if (JCEMediaBox.isIE6) {
                return url;
            }

            var local = document.location.href;

            // external ssl
            if (url.indexOf('https://') !== -1) {
                return url;
            }

            // local ssl, use protocol relative for non-ssl external
            if (local.indexOf('https://') !== -1) {
                return url.replace(/http(s)?:\/\//i, '//');
            }

            return url;
        },
        /**
         * Get the width of the container frame
         */
        frameWidth: function () {
            var w = 0, el = this.frame;

            JCEMediaBox.each(['left', 'right'], function (s) {
                w = w + parseFloat(JCEMediaBox.DOM.style(el, 'padding-' + s));
            });

            return parseFloat(this.frame.clientWidth - w);
        },
        /**
         * Get the height of the container frame
         */
        frameHeight: function () {
            var h = 0, el = this.frame, DIM = JCEMediaBox.Dimensions;

            JCEMediaBox.each(['top', 'bottom'], function (s) {
                h = h + parseFloat(JCEMediaBox.DOM.style(el, 'padding-' + s));
            });

            h = h + ((JCEMediaBox.isIE6 || JCEMediaBox.isIE7) ? DIM.getScrollbarWidth() : 0);

            return parseInt(DIM.getHeight()) - h;
        },
        /**
         * Get the width of the usable window
         */
        width: function () {
            return this.frameWidth() - JCEMediaBox.Dimensions.getScrollbarWidth();
        },
        /**
         * Get the height of the usable window less info divs
         */
        height: function () {
            var h = 0, t = this, each = JCEMediaBox.each, DIM = JCEMediaBox.Dimensions;
            each(['top', 'bottom'], function (s) {
                var el = t['info-' + s];
                if (el) {
                    h = h + parseInt(DIM.outerHeight(el));
                }
            });

            return this.frameHeight() - h;
        },
        /**
         * Print the page contents (TODO)
         */
        printPage: function () {
            return false;
        },
        /**
         * Create a popup zoom icon
         * @param {Object} el Popup link element
         */
        zoom: function (el) {
            var self = this;
            var DOM = JCEMediaBox.DOM, extend = JCEMediaBox.extend, each = JCEMediaBox.each;
            var children = el.childNodes;

            // Create basic zoom element
            var zoom = DOM.create('span');

            // add IE6 identifier class
            if (JCEMediaBox.isIE6) {
                DOM.addClass(el, 'ie6');
            }

            var cls = DOM.attribute(el, 'class');
            // replace icon- with zoom- to avoid bootstrap etc. conflicts
            cls = cls.replace('icon-', 'zoom-', 'g');
            DOM.attribute(el, 'class', cls);

            var img = DOM.select('img', el);

            // If child is an image (thumbnail)
            if (img && img.length) {
                // get first img tag
                var child = img[0];

                var align = child.getAttribute('align');
                var vspace = child.getAttribute('vspace');
                var hspace = child.getAttribute('hspace');

                var styles = {};

                // Transfer margin, padding and border
                each(['top', 'right', 'bottom', 'left'], function (pos) {
                    // Set margin
                    styles['margin-' + pos] = DOM.style(child, 'margin-' + pos);
                    // Set padding
                    styles['padding-' + pos] = DOM.style(child, 'padding-' + pos);
                    // Set border
                    each(['width', 'style', 'color'], function (prop) {
                        styles['border-' + pos + '-' + prop] = DOM.style(child, 'border-' + pos + '-' + prop);
                    });
                });

                // Correct from deprecated align attribute
                if (/\w+/.test(align)) {
                    extend(styles, {
                        'float': /left|right/.test(align) ? align : '',
                        'text-align': /top|middle|bottom/.test(align) ? align : ''
                    });
                }
                // Correct from deprecated vspace attribute
                if (vspace > 0) {
                    extend(styles, {
                        'margin-top': parseInt(vspace),
                        'margin-bottom': parseInt(vspace)
                    });
                }
                // Correct from deprecated hspace attribute
                if (hspace > 0) {
                    extend(styles, {
                        'margin-left': parseInt(hspace),
                        'margin-right': parseInt(hspace)
                    });
                }

                var w = child.getAttribute('width');
                var h = child.getAttribute('height');
                var ws = child.style.width;

                // get 'real' width and height
                var rh = child.height, rw = child.width;

                // we can only render the zoom icon if we have a valid dimensions for the image
                if (!w && !ws && !rw) {
                    // prevent loop
                    if (child.loaded) {
                        return false;
                    }

                    child.onload = function() {
                        child.loaded = true;

                        return self.zoom(el);
                    };

                    child.onerror = function() {
                        return false;
                    };

                    return false;
                }

                // height is set but not width, calculate width
                if (!w && h) {
                    w = h / rh * rw;
                }

                if (!w) {
                    // pixel value
                    if (/([0-9]+)(px)?$/.test(ws)) {
                        w = parseFloat(ws);
                        // other value
                    } else {
                        w = rw;
                    }
                }

                // add width values if set
                if (w) {
                    child.setAttribute('width', w);
                    styles.width = w;
                }

                // Add style alignment
                extend(styles, {
                    'text-align': child.style.textAlign
                });

                var float = DOM.style(child, 'float');

                if (float === "left" || float === "right") {
                    styles.float = float;
                }

                /**
                 * Private Internal function
                 * Build and place the icon
                 * @param {Object} el The Parent Link Element
                 * @param {Object} zoom The Zoom Element
                 * @param {Object} zoom The Child Element (Image)
                 * @param {Object} styles Computed Styles object
                 */
                function _buildIcon(el, zoom, child, styles) {
                    // Clone image as span element
                    var span = DOM.add(el, 'span', {
                        'class': 'jcemediabox-zoom-span',
                        'style': child.style.cssText
                    });

                    // Set styles
                    DOM.styles(span, styles);

                    if (DOM.hasClass(el.parentNode, 'wf_caption')) {
                        span.style.width = null;
                        DOM.style(span, 'max-width', DOM.style(el.parentNode, 'max-width'));
                    }

                    if (span.style.width) {
                        DOM.style(span, 'max-width', span.style.width);
                        span.style.width = null;
                    }

                    // Move the image into the parent SPAN
                    DOM.add(span, child);
                    // Move the zoom icon into the parent SPAN
                    DOM.add(span, zoom);

                    // Remove attributes that may affect layout
                    each(['style', 'align', 'border', 'hspace', 'vspace'], function (v, i) {
                        child.removeAttribute(v);
                    });

                    // Add zoom-image class
                    DOM.addClass(zoom, 'jcemediabox-zoom-image');

                    // Set explicit positions for IE6 when zoom icon is png
                    if (JCEMediaBox.isIE6 && /\.png/i.test(DOM.style(zoom, 'background-image'))) {
                        DOM.png(zoom);
                    }

                    // Remove styles from image
                    DOM.styles(child, {
                        'margin': 0,
                        'padding': 0,
                        'float': 'none',
                        'border': 'none'
                    });
                }
                // build zoom icon
                _buildIcon(el, zoom, child, styles);
            } else {
                DOM.addClass(zoom, 'jcemediabox-zoom-link');
                if (DOM.hasClass(el, 'zoom-left')) {
                    DOM.addBefore(el, zoom);
                } else {
                    DOM.add(el, zoom);
                }
                // IE7 won't accept display:inherit
                if (JCEMediaBox.isIE7) {
                    DOM.style(zoom, 'display', 'inline-block');
                }
            }
            // Return zoom icon element
            return zoom;
        },
        /**
         * Process autopopups
         */
        auto: function () {
            var t = this, expires = JCEMediaBox.options.popup.cookie_expiry, dts, key;

            function makeID(src) {
                // use the current page URL for unique key
                var url = document.location.href;
                // base64 encode key and popup src
                var key = window.btoa(url + src);
                // remove non-word characters
                key = key.replace(/[^\w]/g, '');
                // keep it short
                key = key.substr(0, 24);

                return key;
            }

            JCEMediaBox.each(this.popups, function (el, i) {
                if (el.auto) {
                    if (el.auto == 'single') {
                        // use element ID or base64 key
                        key = el.id || makeID(el.src);

                        // get cookie
                        var cookie = t.getCookie('jcemediabox_' + key + '_' + i);

                        // create cookie with base64 key and expiry
                        if (!cookie) {
                            // create data if expiry set
                            if (expires) {
                                dts = new Date();
                                dts.setHours(expires * 24);
                            }

                            t.setCookie('jcemediabox_' + key + '_' + i, 1, dts);
                            t.start(el);
                        }
                    } else if (el.auto == 'multiple') {
                        t.start(el);
                    }
                }
            });

        },
        /**
         * Initilise popup and create global jcepopup variable
         * @param {Object} elements Optional array of popup elements
         */
        init: function () {
            window.jcepopup = this;
            this.create();
        },
        /**
         * Get popup objects
         * @param {String} s Optional selector
         * @param {Object} p Optional parent element popups contained within
         */
        getPopups: function (s, p) {
            var selector = 'a.jcebox, a.jcelightbox, a.jcepopup, area.jcebox, area.jcelightbox, area.jcepopup';
            return JCEMediaBox.DOM.select(s || selector, p);
        },
        getData: function (n) {
            var DOM = JCEMediaBox.DOM, each = JCEMediaBox.each, o = {}, data;
            var re = /\w+\[[^\]]+\]/;

            data = n.getAttribute('data-mediabox') || n.getAttribute('data-json');

            if (!data) {
                // try data-mediabox-* attributes (since 1.1.23, JCE 2.5.3)
                var i, attrs = n.attributes, x = 0;

                for (i = attrs.length - 1; i >= 0; i--) {
                    var attrName = attrs[i].name;
                    if (attrName && attrName.indexOf('data-mediabox-') !== -1) {
                        var attr = attrName.replace('data-mediabox-', '');
                        o[attr] = attrs[i].value;
                        x++;
                    }
                }

                if (x) {
                    return o;
                }

                var title = DOM.attribute(n, 'title');
                var rel = DOM.attribute(n, 'rel');

                if (title && re.test(title)) {
                    // convert to object
                    o = this.params(title);

                    // restore rel attribute
                    DOM.attribute(n, 'title', o.title || '');

                    return o;
                }

                if (rel && re.test(rel)) {
                    var args = [];

                    rel = rel.replace(/\b((\w+)\[(.*?)\])(;?)/g, function (a, b, c) {
                        args.push(b);
                        return '';
                    });

                    o = this.params(args) || {};

                    // restore rel attribute
                    DOM.attribute(n, 'rel', rel || o.rel || '');

                    return o;
                }
            } else {
                // remove data attributes
                n.removeAttribute('data-json');
                n.removeAttribute('data-mediabox');

                return this.params(data);
            }

            return o;
        },
        /**
         * Process a popup link and return properties object
         * @param {Object} el Popup link element
         */
        process: function (el) {
            var DOM = JCEMediaBox.DOM, data, o = {}, group = '', auto = false;

            // Fix title and rel and move parameters
            var title = el.title || '';
            var rel = el.rel || '';

            var src = el.href;

            // Legacy width/height values
            src = src.replace(/b(w|h)=([0-9]+)/g, function (s, k, v) {
                k = (k == 'w') ? 'width' : 'height';

                return k + '=' + v;
            });

            data = this.getData(el) || {};

            // Process rel attribute
            if (!/\w+\[[^\]]+\]/.test(rel)) {
                var rx = 'alternate|stylesheet|start|next|prev|contents|index|glossary|copyright|chapter|section|subsection|appendix|help|bookmark|nofollow|licence|tag|friend';
                var lb = '(lightbox(\[(.*?)\])?)';
                var lt = '(lyte(box|frame|show)(\[(.*?)\])?)';

                group = JCEMediaBox.trim(rel.replace(new RegExp('\s*(' + rx + '|' + lb + '|' + lt + ')\s*'), '', 'gi'));
            }

            // Get AREA parameters from URL if not set
            if (el.nodeName == 'AREA') {
                if (!data) {
                    data = this.params(src);
                }
                // Set AREA group
                group = group || 'AREA_ELEMENT';
                // set type
                if (!data.type) {
                    if (match = /\b(ajax|iframe|image|flash|director|shockwave|mplayer|windowsmedia|quicktime|realaudio|real|divx|pdf)\b/.exec(el.className)) {
                        data.type = match[0];
                    }
                }
            }

            // check for auto popup
            //if (el.id) {
            if (/autopopup-(single|multiple)/.test(el.className)) {
                auto = /(multiple)/.test(el.className) ? 'multiple' : 'single';
            }
            //}

            // get group from data object
            group = group || data.group || '';

            // Popup object
            JCEMediaBox.extend(o, {
                'src': src,
                'title': data.title || title,
                'group': DOM.hasClass(el, 'nogroup') ? '' : group,
                'type': data.type || el.type || '',
                'params': data,
                //'id'	: el.id || '',
                'auto': auto
            });

            // Remove type
            el.href = el.href.replace(/&type=(ajax|text\/html|text\/xml)/, '');

            return o;
        },
        /**
         * Create a popup from identifiable link or area elements
         * Load the popup theme
         * @param {Object} elements Optional array of popup elements
         */
        create: function (elements) {
            var t = this, each = JCEMediaBox.each, Event = JCEMediaBox.Event, DOM = JCEMediaBox.DOM, pageload = false, auto = false;

            // set pageload marker
            if (!elements) {
                pageload = true;
                this.popups = [];

                // Converts a legacy (window) popup into an inline popup
                if (JCEMediaBox.options.popup.legacy == 1) {
                    t.convertLegacy();
                }

                // Converts a lightbox popup into mediabox popup
                if (JCEMediaBox.options.popup.lightbox == 1) {
                    t.convertLightbox();
                }

                // Converts a shadowbox popup into mediabox popup
                if (JCEMediaBox.options.popup.shadowbox == 1) {
                    t.convertShadowbox();
                }
            }

            // get supplied elements or from jcepopup class
            this.elements = elements || this.getPopups();

            // Iterate through all found or specified popup links
            each(this.elements, function (el, i) {

                if (el.childNodes.length === 1 && el.firstChild.nodeName === "IMG") {
                    DOM.addClass(el, 'jcemediabox-image');
                }

                // Create zoom icon
                if (JCEMediaBox.options.popup.icons == 1 && el.nodeName == 'A' && !/(noicon|icon-none|noshow)/.test(el.className) && el.style.display != 'none') {
                    t.zoom(el);
                }

                // Simplify class identifier for css
                if (/(jcelightbox|jcebox)/.test(el.className)) {
                    DOM.removeClass(el, 'jcelightbox');
                    DOM.removeClass(el, 'jcebox');
                    DOM.addClass(el, 'jcepopup');
                }

                var o = t.process(el);

                t.popups.push(o);

                // new index if not a pageload
                if (!pageload) {
                    i = t.popups.length - 1;
                }

                // Add click event to link
                Event.add(el, 'click', function (e) {
                    Event.cancel(e);
                    return t.start(o, i);
                });

            });

            // if no elements are specified, must be a pageload
            if (pageload) {
                // set theme
                this.popuptheme = '';

                // Load the popup theme
                var theme = JCEMediaBox.options.theme;

                new JCEMediaBox.XHR({
                    success: function (text, xml) {
                        var re = /<!-- THEME START -->([\s\S]*?)<!-- THEME END -->/;
                        if (re.test(text)) {
                            text = re.exec(text)[1];
                        }
                        t.popuptheme = text;
                        // Process auto popups
                        if (!auto) {
                            t.auto();
                            auto = true;
                        }
                    }

                }).send(JCEMediaBox.site + 'plugins/system/jcemediabox/themes/' + theme + '/popup.html');
            }
        },
        /**
         * Public popup method
         * @param {String / Object} data Popup URL string or data object or element
         * @param {String} title Popup Title
         * @param {String} group Popup Group
         * @param {String} type Popup Type, eg: image, flash, ajax
         * @param {Object} params Popup Parameters Object
         */
        open: function (data, title, group, type, params) {
            var i, o = {};

            if (typeof data == 'string') {
                data = {
                    'src': data,
                    'title': title,
                    'group': group,
                    'type': type,
                    'params': params
                };
            }

            // process as an element
            if (typeof (data == 'object') && data.nodeName && (data.nodeName == 'A' || data.nodeName == 'AREA')) {
                i = JCEMediaBox.inArray(this.elements, data);

                if (i >= 0) {
                    return this.start(this.popups[i], i);
                }

                // process element
                var o = this.process(data);

                // add to array
                var x = this.popups.push(o);

                // start
                return this.start(o, x - 1);
            }

            return this.start(data);
        },
        /**
         * Start a popup
         * @param {Object} o The popup link object
         * @param {Object} i The popup index
         */
        start: function (p, i) {
            var n = 0, items = [], each = JCEMediaBox.each, len;

            // build popup window
            if (this.build()) {
                if (p.group) {
                    each(this.popups, function (o, x) {
                        if (o.group == p.group) {
                            len = items.push(o);
                            if (i && x == i) {
                                n = len - 1;
                            }
                        }
                    });

                    // Triggered popup
                    if (!p.auto && typeof i == 'undefined') {
                        items.push(p);
                        n = items.length - 1;
                    }
                } else {
                    items.push(p);
                }
                return this.show(items, n);
            }
        },
        /**
         * Build Popup structure
         */
        build: function () {
            var t = this, each = JCEMediaBox.each, DOM = JCEMediaBox.DOM, Event = JCEMediaBox.Event;

            if (!this.page) {
                // Create main page object
                this.page = DOM.add(document.body, 'div', {
                    id: 'jcemediabox-popup-page'
                });

                if (JCEMediaBox.isIE6) {
                    DOM.addClass(this.page, 'ie6');
                }

                if (JCEMediaBox.isIE7) {
                    DOM.addClass(this.page, 'ie7');
                }

                if (JCEMediaBox.isiOS) {
                    DOM.addClass(this.page, 'ios');
                }

                if (JCEMediaBox.isAndroid) {
                    DOM.addClass(this.page, 'android');
                }

                if (JCEMediaBox.options.popup.overlay == 1) {
                    // Create overlay
                    this.overlay = DOM.add(this.page, 'div', {
                        id: 'jcemediabox-popup-overlay',
                        style: {
                            'opacity': 0,
                            'background-color': JCEMediaBox.options.popup.overlaycolor
                        }
                    });
                }

                // Cancel if no theme
                if (!this.popuptheme) {
                    return false;
                }
                // Remove comments
                this.popuptheme = this.popuptheme.replace(/<!--(.*?)-->/g, '');
                // Translate
                this.popuptheme = this.translate(this.popuptheme);
                // Create Frame
                this.frame = DOM.add(this.page, 'div', {
                    id: 'jcemediabox-popup-frame'
                }, '<div id="jcemediabox-popup-body">' + this.popuptheme + '</div>');

                // Create all Popup structure objects
                each(DOM.select('*[id]', this.frame), function (el) {
                    var s = el.id.replace('jcemediabox-popup-', '');
                    t[s] = el;
                    DOM.hide(el);
                });

                if ((JCEMediaBox.isiOS || JCEMediaBox.isAndroid) && JCEMediaBox.isWebKit) {
                    // add iPad scroll fix
                    DOM.style(this.content, 'webkitOverflowScrolling', 'touch');
                }

                // Add close function to frame on click
                if (JCEMediaBox.options.popup.close == 2) {
                    Event.add(this.frame, 'click', function (e) {
                        if (e.target && e.target == t.frame) {
                            t.close();
                        }
                    });
                }

                // Setup Close link event
                if (this.closelink) {
                    Event.add(this.closelink, 'click', function () {
                        return t.close();
                    });

                }
                // Setup Cancel link event
                if (this.cancellink) {
                    Event.add(this.cancellink, 'click', function () {
                        return t.close();
                    });

                }
                // Setup Next link event
                if (this.next) {
                    Event.add(this.next, 'click', function () {
                        return t.nextItem();
                    });

                }
                // Setup Previous link event
                if (this.prev) {
                    Event.add(this.prev, 'click', function () {
                        return t.previousItem();
                    });

                }
                if (this.numbers) {
                    this.numbers.tmpHTML = this.numbers.innerHTML;
                }

                if (this.print) {
                    Event.add(this.print, 'click', function () {
                        return t.printPage();
                    });

                }
                // PNG Fix
                if (JCEMediaBox.isIE6) {
                    DOM.png(this.body);
                    each(DOM.select('*', this.body), function (el) {
                        // Exclude loaded content
                        if (DOM.attribute(el, 'id') == 'jcemediabox-popup-content') {
                            return;
                        }
                        DOM.png(el);
                    });

                }
            }
            return true;
        },
        /**
         * Show the popup window
         * @param {Array} items Array of popup objects
         * @param {Int} n Index of current popup
         */
        show: function (items, n) {
            var DOM = JCEMediaBox.DOM, DIM = JCEMediaBox.Dimensions, top = 0;
            this.items = items;
            this.bind(true);

            // Show popup
            DOM.show(this.body);

            // Get top position
            if (!/\d/.test(this.body.style.top)) {
                top = (DIM.getHeight() - DIM.outerHeight(this.body)) / 2;
            }

            // Set top position
            DOM.style(this.body, 'top', top);
            // Changes if IE6 or scrollpopup
            if (JCEMediaBox.isIE6 || JCEMediaBox.options.popup.scrolling == 'scroll') {
                DOM.addClass(this.page, 'scrolling');
                DOM.style(this.overlay, 'height', DIM.getScrollHeight());
                DOM.style(this.body, 'top', DIM.getScrollTop() + top);
            }
            // Fade in overlay
            if (JCEMediaBox.options.popup.overlay == 1 && this.overlay) {
                DOM.show(this.overlay);
                JCEMediaBox.FX.animate(this.overlay, {
                    'opacity': JCEMediaBox.options.popup.overlayopacity
                }, JCEMediaBox.options.popup.fadespeed);
            }

            return this.change(n);
        },
        /**
         * Create event / key bindings
         * @param {Boolean} open Whether popup is opened or closed
         */

        // TODO - Resize popup when browser window resizes
        bind: function (open) {
            var t = this, isIE6 = JCEMediaBox.isIE6, each = JCEMediaBox.each, DOM = JCEMediaBox.DOM, Event = JCEMediaBox.Event, DIM = JCEMediaBox.Dimensions;

            if (isIE6) {
                each(DOM.select('select'), function (el) {
                    if (open) {
                        el.tmpStyle = el.style.visibility || '';
                    }
                    el.style.visibility = open ? 'hidden' : el.tmpStyle;
                });

            }
            if (JCEMediaBox.options.popup.hideobjects) {
                each(DOM.select('object, embed'), function (el) {
                    if (el.id == 'jcemediabox-popup-object')
                        return;
                    if (open) {
                        el.tmpStyle = el.style.visibility || '';
                    }
                    el.style.visibility = open ? 'hidden' : el.tmpStyle;
                });

            }
            var scroll = JCEMediaBox.options.popup.scrollpopup;
            if (open) {
                Event.add(document, 'keydown', function (e) {
                    t.listener(e);
                });

                if (isIE6) {
                    Event.add(window, 'scroll', function (e) {
                        DOM.style(t.overlay, 'height', JCEMediaBox.Dimensions.getScrollHeight());
                    });

                    Event.add(window, 'scroll', function (e) {
                        DOM.style(t.overlay, 'width', JCEMediaBox.Dimensions.getScrollWidth());
                    });

                }
            } else {
                if (isIE6 || !scroll) {
                    Event.remove(window, 'scroll');
                    Event.remove(window, 'resize');
                }
                Event.remove(document, 'keydown');
            }
        },
        /**
         * Keyboard listener
         * @param {Object} e Event
         */
        listener: function (e) {
            switch (e.keyCode) {
                case 27:
                    this.close();
                    break;
                case 37:
                    this.previousItem();
                    break;
                case 39:
                    this.nextItem();
                    break;
            }
        },
        /**
         * Process a popup in the group queue
         * @param {Object} n Queue position
         */
        queue: function (n) {
            var t = this;
            // Optional element
            var changed = false;

            JCEMediaBox.each(['top', 'bottom'], function (s) {
                var el = t['info-' + s];
                if (el) {
                    var v = JCEMediaBox.Dimensions.outerHeight(el);
                    var style = {};
                    style['top'] = (s == 'top') ? v : -v;
                    JCEMediaBox.FX.animate(el, style, JCEMediaBox.options.popup.scalespeed, function () {
                        if (!changed) {
                            changed = true;
                            JCEMediaBox.FX.animate(t.content, {
                                'opacity': 0
                            }, JCEMediaBox.options.popup.fadespeed, function () {
                                return t.change(n);
                            });

                        }
                    });

                }
            });

        },
        /**
         * Process the next popup in the group
         */
        nextItem: function () {
            if (this.items.length == 1)
                return false;
            var n = this.index + 1;

            if (n < 0 || n >= this.items.length) {
                return false;
            }
            return this.queue(n);
        },
        /**
         * Process the previous popup in the group
         */
        previousItem: function () {
            if (this.items.length == 1)
                return false;
            var n = this.index - 1;

            if (n < 0 || n >= this.items.length) {
                return false;
            }
            return this.queue(n);
        },
        /**
         * Set the popup information (caption, title, numbers)
         */
        info: function () {
            var each = JCEMediaBox.each, DOM = JCEMediaBox.DOM, Event = JCEMediaBox.Event;
            // Optional Element Caption/Title

            if (this.caption) {
                var title = this.active.title || '', text = this.active.caption || '', h = '';

                var ex = '([-!#$%&\'\*\+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'\*\+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+)';
                var ux = '((news|telnet|nttp|file|http|ftp|https)://[-!#$%&\'\*\+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'\*\+\\./0-9=?A-Z^_`a-z{|}~]+)';

                function processRe(h) {
                    h = h.replace(new RegExp(ex, 'g'), '<a href="mailto:$1" target="_blank" title="$1">$1</a>');
                    h = h.replace(new RegExp(ux, 'g'), '<a href="$1" target="_blank" title="$1">$1</a>');

                    return h;
                }

                if (title) {
                    h += '<h4>' + DOM.decode(title) + '</h4>';
                }

                if (text) {
                    h += '<p>' + DOM.decode(text) + '</p>';
                }

                // set caption html (may be empty)
                this.caption.innerHTML = h;

                // hide caption container if empty
                if (h != '') {
                    // Process e-mail and urls
                    each(DOM.select('*', this.caption), function (el) {
                        if (el.nodeName != 'A') {
                            each(el.childNodes, function (n, i) {
                                if (n.nodeType == 3) {
                                    var s = n.innerText || n.textContent || n.data || null;
                                    if (s && /(@|:\/\/)/.test(s)) {
                                        if (s = processRe(s)) {
                                            n.parentNode.innerHTML = s;
                                        }
                                    }
                                }
                            });

                        }
                    });
                }
            }
            // Optional Element
            var t = this, len = this.items.length;

            if (this.numbers && len > 1) {
                var html = this.numbers.tmpHTML || '{$numbers}';

                if (/\{\$numbers\}/.test(html)) {
                    this.numbers.innerHTML = '';
                    for (var i = 0; i < len; i++) {
                        var n = i + 1;

                        var title = decodeURIComponent(this.items[i].title || n);

                        // Craete Numbers link
                        var link = DOM.add(this.numbers, 'a', {
                            'href': 'javascript:;',
                            'title': title,
                            'class': (this.index == i) ? 'active' : ''
                        }, n);
                        // add click event
                        Event.add(link, 'click', function (e) {
                            var x = parseInt(e.target.innerHTML) - 1;
                            if (t.index == x) {
                                return false;
                            }
                            return t.queue(x);
                        });

                    }
                }

                if (/\{\$(current|total)\}/.test(html)) {
                    this.numbers.innerHTML = html.replace('{$current}', this.index + 1).replace('{$total}', len);
                }
            } else {
                if (this.numbers) {
                    this.numbers.innerHTML = '';
                }
            }

            each(['top', 'bottom'], function (v, i) {
                var el = t['info-' + v];
                if (el) {
                    DOM.show(el);
                    each(DOM.select('*[id]', el), function (s) {
                        DOM.show(s);
                    });
                    DOM.style(el, 'visibility', 'hidden');
                }
            });

            // Show / Hide Previous and Next buttons
            DOM.hide(this.next);
            DOM.hide(this.prev);

            if (len > 1) {
                if (this.prev) {
                    if (this.index > 0) {
                        DOM.show(this.prev);
                    } else {
                        DOM.hide(this.prev);
                    }
                }
                if (this.next) {
                    if (this.index < len - 1) {
                        DOM.show(this.next);
                    } else {
                        DOM.hide(this.next);
                    }
                }
            }
        },
        /**
         * Change the popup
         * @param {Integer} n Popup number
         */
        change: function (n) {
            var t = this, extend = JCEMediaBox.extend, each = JCEMediaBox.each, inArray = JCEMediaBox.inArray, DOM = JCEMediaBox.DOM, Event = JCEMediaBox.Event, isIE = JCEMediaBox.isIE, DIM = JCEMediaBox.Dimensions;

            var p = {}, o, w, h;
            if (n < 0 || n >= this.items.length) {
                return false;
            }
            this.index = n;
            this.active = {};

            // Show Container
            DOM.show(this.container);
            // Show Loader
            if (this.loader) {
                DOM.show(this.loader);
            }
            // Show Cancel
            if (this.cancellink) {
                DOM.show(this.cancellink);
            }
            // Remove object
            if (this.object) {
                this.object = null;
            }

            this.content.innerHTML = '';

            o = this.items[n];

            // Get parameters from addon
            extend(p, this.getAddon(o.src, o.type));

            // delete alternate src
            delete o.params.src;

            // Get set parameters
            extend(p, o.params);

            var width = p.width || JCEMediaBox.options.popup.width || 0;
            var height = p.height || JCEMediaBox.options.popup.height || 0;

            if (width && /%/.test(width)) {
                width = DIM.getWidth() * parseInt(width) / 100;
            }

            if (height && /%/.test(height)) {
                height = DIM.getHeight() * parseInt(height) / 100;
            }

            var title = o.title || p.title || '';
            var caption = p.caption || '';

            if (/::/.test(title)) {
                var parts = title.split('::');
                title = JCEMediaBox.trim(parts[0]);
                caption = JCEMediaBox.trim(parts[1]);
            }

            // decode title
            title = DOM.decode(title);
            // decode caption
            caption = DOM.decode(caption);

            // try decode encoded URI
            try {
              title   = decodeURIComponent(title);
              caption = decodeURIComponent(caption);
            } catch(e){}

            extend(this.active, {
                'src': p.src || o.src,
                'title': title,
                'caption': caption,
                'type': p.type || this.getType(o),
                'params': p || {},
                'width': width,
                'height': height
            });

            function toAbsolute(url) {
                var div = document.createElement('div');
                div.innerHTML = '<a href="' + url + '">x</a>';

                return div.firstChild.href;
            }

            function resolveMediaPath(s, absolute) {
                if (s && s.indexOf('://') === -1 && s.charAt(0) !== '/') {
                    s = JCEMediaBox.options.base + s;
                }

                if (absolute) {
                    return toAbsolute(s);
                }

                return s;
            }

            switch (this.active.type) {
                case 'image':
                case 'image/jpeg':
                case 'image/png':
                case 'image/gif':
                case 'image/bmp':
                    if (this.print && this.options.print) {
                        this.print.style.visibility = 'visible';
                    }

                    this.img = new Image();
                    this.img.onload = function () {
                        return t.setup();
                    };

                    this.img.onerror = function () {
                        t.img.error = true;
                        return t.setup();
                    };

                    this.img.src = this.active.src;

                    // fix for resize / transparency issues in IE
                    if (isIE) {
                        DOM.style(this.content, 'background-color', DOM.style(this.content, 'background-color'));
                    }

                    // allow image to be resized
                    if (p.width && !p.height) {
                        this.active.height = 0;
                    } else if (p.height && !p.width) {
                        this.active.width = 0;
                    }

                    break;
                case 'flash':
                case 'director':
                case 'shockwave':
                case 'mplayer':
                case 'windowsmedia':
                case 'quicktime':
                case 'realaudio':
                case 'real':
                case 'divx':
                    if (this.print) {
                        this.print.style.visibility = 'hidden';
                    }

                    p.src = this.active.src;

                    var base = /:\/\//.test(p.src) ? '' : this.site;
                    this.object = '';

                    w = this.width();
                    h = this.height();

                    var mt = this.mediatype(this.active.type);

                    if (this.active.type == 'flash') {
                        p.wmode = 'transparent';
                        p.base = base;
                    }
                    if (/(mplayer|windowsmedia)/i.test(this.active.type)) {
                        p.baseurl = base;
                        if (isIE) {
                            p.url = p.src;
                            delete p.src;
                        }
                    }
                    // delete some parameters
                    delete p.title;
                    delete p.group;

                    // Set width/height
                    p.width = this.active.width || this.width();
                    p.height = this.active.height || this.height();

                    var flash = /flash/i.test(this.active.type);
                    var pdf = /pdf/i.test(this.active.type);
                    // Create single object for IE / Flash / PDF

                    // set global media type
                    this.active.type = 'media';
                    this.active.width = p.width;
                    this.active.height = p.height;

                    if (flash || isIE) {
                        this.object = '<object id="jcemediabox-popup-object"';
                        // Add type and data attribute
                        if (flash && !isIE) {
                            this.object += ' type="' + mt.mediatype + '" data="' + p.src + '"';
                        } else {
                            this.object += ' classid="clsid:' + mt.classid + '"';
                            if (mt.codebase) {
                                this.object += ' codebase="' + mt.codebase + '"';
                            }
                        }

                        for (n in p) {
                            if (p[n] !== '') {
                                if (/^(id|name|style|width|height)$/.test(n)) {
                                    t.object += ' ' + n + '="' + decodeURIComponent(DOM.decode(p[n])) + '"';
                                    delete p[n];
                                }
                            }
                        }

                        delete p.type;

                        // Close object
                        this.object += '>';
                        // Create param elements
                        for (n in p) {
                            t.object += '<param name="' + n + '" value="' + decodeURIComponent(DOM.decode(p[n])) + '" />';
                        }
                        // Add closing object element
                        this.object += '</object>';
                        // Use embed for non-IE browsers
                    } else {
                        this.object = '<embed id="jcemediabox-popup-object" type="' + mt.mediatype + '"';
                        for (n in p) {
                            if (v !== '') {
                                t.object += ' ' + n + '="' + v + '"';
                            }
                        }
                        this.object += '></embed>';
                    }

                    this.setup();
                    break;
                case 'video/x-flv':
                case 'video/mp4':
                case 'video/mpeg':
                case 'video/ogg':
                case 'audio/ogg':
                case 'audio/mp3':
                case 'video/webm':
                case 'audio/webm':
                    var type = this.active.type, tag = /video/.test(type) ? 'video' : 'audio';

                    var supportMap = {
                        'video': {
                            'h264' : ['video/mp4', 'video/mpeg'],
                            'webm' : ['video/webm'],
                            'ogg'  : ['video/ogg']
                        },
                        'audio': {
                            'mp3'   : ['audio/mp3'],
                            'ogg'   : ['audio/ogg'],
                            'webm'  : ['audio/webm']
                        }
                    };

                    var hasSupport = false;

                    // video/x-flv not supported by any browser
                    if (type !== "video/x-flv") {
                        for (var n in supportMap[tag]) {
                            if (supportMap[tag][n].indexOf(type) !== -1) {
                                hasSupport = support[tag] && !!support[tag][n];
                            }
                        }
                    }

                    this.object = '';

                    var src = resolveMediaPath(this.active.src);

                    if (p.poster) {
                        p.poster = resolveMediaPath(p.poster);
                    }

                    // create <audio> / <video> tag if suported
                    if (hasSupport) {
                        p.width = p.width || this.active.width;
                        p.height = p.height || this.active.height;

                        this.object += '<' + tag + ' type="' + type + '" src="' + this.active.src + '"' ;

                        for (n in p) {
                            if (p[n] !== '') {
                                if (/(loop|autoplay|controls|preload)$/.test(n)) {
                                    t.object += ' ' + n + '="' + n + '"';
                                }

                                if (/(id|style|poster|audio)$/.test(n)) {
                                    t.object += ' ' + n + '="' + decodeURIComponent(DOM.decode(p[n])) + '"';
                                }
                            }
                        }

                        this.object += '></' + tag + '>';

                    } else if (/(video|audio)\/(mp4|mpeg|x-flv|mp3)/.test(type)) {
                        var swf = JCEMediaBox.options.base + 'plugins/system/jcemediabox/mediaplayer/mediaplayer.swf';

                        this.object += '<object type="application/x-shockwave-flash" class="wf-mediaplayer-object" data="' + swf +'"';
                        // create empty style
                        p.style = p.style || "";

                        var flashvars = ['file=' + toAbsolute(src)];

                        // if supported
                        if (p.poster) {
                            //flashvars.push('poster=' + toAbsolute(p.poster));
                            p.style += " background-image:url('" + p.poster + "')";
                        }

                        each(p, function(v, n) {
                            if (v !== "") {
                                n = n.toLowerCase();

                                if (n === "loop" || n === "autoplay" || n === "controls") {
                                    flashvars.push(n + '=' + !!v);
                                }

                                if (n === "preload") {
                                    flashvars.push(n + '=' + v);
                                }

                                if (n === "id" || n === "style") {
                                    v = decodeURIComponent(DOM.decode(v));

                                    v = JCEMediaBox.trim(v);

                                    if (v !== "") {
                                        t.object += ' ' + n + '="' + v + '"';
                                    }
                                }

                                if (n === "width" | n === "height") {
                                    t.object += ' ' + n + '="' + v + '"';
                                }
                            }
                        });

                        this.object += '>';

                        this.object += '<param name="movie" value="' + swf +'" />';
                        this.object += '<param name="flashvars" value="' + flashvars.join('&') + '" />';
                        this.object += '<param name="allowfullscreen" value="true" />';
                        this.object += '<param name="wmode" value="transparent" />';
                        this.object += '<i>Flash is required to play this video. <a href="http://get.adobe.com/flashplayer/" target="_blank">Get Adobe® Flash Player</a></i>';
                        this.object += '</object>';
                    } else {
                        DOM.addClass(this.content, 'broken-media');
                    }

                    // set global media type
                    this.active.type = 'media';

                    this.setup();
                    break;
                case 'ajax':
                case 'text/html':
                case 'text/xml':
                    if (this.print && this.options.print) {
                        this.print.style.visibility = 'visible';
                    }

                    this.active.width = this.active.width || this.width();
                    this.active.height = this.active.height || this.height();

                    if (this.islocal(this.active.src)) {
                        if (!/tmpl=component/i.test(this.active.src)) {
                            this.active.src += /\?/.test(this.active.src) ? '&tmpl=component' : '?tmpl=component';
                        }
                        this.active.type = 'ajax';
                    } else {
                        this.active.type = 'iframe';
                        this.setup();
                    }

                    styles = extend(this.styles(p.styles), {
                        display: 'none'
                    });

                    this.active.src = this.active.src.replace(/\&type=(ajax|text\/html|text\/xml)/, '');

                    // show loader
                    if (this.loader) {
                        DOM.show(this.loader);
                    }

                    // create an iframe to load internal content in rather than using ajax so that javascript in the article is processed
                    var iframe = DOM.add(document.body, 'iframe', {
                        src: this.active.src,
                        style: 'display:none;'
                    });

                    // transfer data and delete iframe when loaded
                    Event.add(iframe, 'load', function () {

                        // Create ajax container
                        t.ajax = DOM.add(t.content, 'div', {
                            id: 'jcemediabox-popup-ajax',
                            'style': styles
                        });

                        // transfer data
                        t.ajax.innerHTML = iframe.contentWindow.document.body.innerHTML;

                        // Corrective stuff for IE6 and IE7
                        if (JCEMediaBox.isIE6) {
                            DOM.style(t.ajax, 'margin-right', JCEMediaBox.Dimensions.getScrollbarWidth());
                        }

                        if (JCEMediaBox.isIE7) {
                            DOM.style(t.ajax, 'padding-right', JCEMediaBox.Dimensions.getScrollbarWidth());
                        }

                        window.setTimeout(function () {
                            // remove iframe
                            DOM.remove(iframe);
                        }, 10);

                        // process any popups in loaded content
                        t.create(t.getPopups('', t.content));

                        // process any tooltips in loaded content
                        JCEMediaBox.ToolTip.create(t.content);

                        // setup
                        return t.setup();
                    });

                    iframe.onerror = function () {
                        DOM.addClass(this.content, 'broken-page');
                        return t.setup();
                    };

                    break;
                case 'iframe':
                case 'pdf':
                case 'video/youtube':
                case 'video/vimeo':
                default:
                    // iOS Safari cannot open PDF files properly
                    if (JCEMediaBox.isMobile && this.active.type === "pdf") {
                        this.close();
                        return window.open(this.active.src);
                    }

                    if (this.print) {
                        this.print.style.visibility = 'hidden';
                    }

                    if (this.islocal(this.active.src)) {
                        // add tmpl=component to internal links, skip pdf
                        if (!/tmpl=component/i.test(this.active.src) && !/\.pdf\b/i.test(this.active.src)) {
                            this.active.src += /\?/.test(this.active.src) ? '&tmpl=component' : '?tmpl=component';
                        }
                    }

                    // make URL protocol relative
                    this.active.src = this.protocolRelative(this.active.src);

                    this.active.width = this.active.width || this.width();
                    this.active.height = this.active.height || this.height();

                    this.active.type = 'iframe';
                    this.setup();

                    break;
            }
            return false;
        },
        /**
         * Proportional resizing method
         * @param {Object} w
         * @param {Object} h
         * @param {Object} x
         * @param {Object} y
         */
        resize: function (w, h, x, y) {
            if (w > x) {
                h = h * (x / w);
                w = x;
                if (h > y) {
                    w = w * (y / h);
                    h = y;
                }
            } else if (h > y) {
                w = w * (y / h);
                h = y;
                if (w > x) {
                    h = h * (x / w);
                    w = x;
                }
            }
            w = Math.round(w);
            h = Math.round(h);

            return {
                width: Math.round(w),
                height: Math.round(h)
            };
        },
        /**
         * Pre-animation setup. Resize images, set width / height
         */
        setup: function () {
            var t = this, DOM = JCEMediaBox.DOM, w, h, o = JCEMediaBox.options.popup;

            w = this.active.width;
            h = this.active.height;

            // Setup info
            this.info();

            // Get image dimensions and resize if necessary
            if (this.active.type == 'image') {
                if (t.img.error) {
                    w = 300;
                    h = 300;
                }

                var x = this.img.width;
                var y = this.img.height;

                if (w && !h) {
                    h = y * (w / x);
                } else if (!w && h) {
                    w = x * (h / y);
                }

                w = w || x;
                h = h || y;
            }

            // Resize to fit screen
            if (parseInt(o.resize) === 1 || (parseInt(o.resize) === 0 && o.scrolling == 'fixed')) {
                var x = this.width();
                var y = this.height();

                var dim = this.resize(w, h, x, y);

                w = dim.width;
                h = dim.height;
            }

            // set content dimensions
            DOM.styles(this.content, {
                width: w,
                height: h
            });

            DOM.hide(this.content);

            if (this.active.type == 'image') {
                if (this.img.error) {
                    DOM.addClass(this.content, 'broken-image');
                } else {
                    this.content.innerHTML = '<img id="jcemediabox-popup-img" src="' + this.active.src + '" title="' + this.active.title + '" />';
                }

                // fix resized images in IE
                if (JCEMediaBox.isIE) {
                    var img = DOM.get('jcemediabox-popup-img');
                    if (img) {
                        DOM.style(img, '-ms-interpolation-mode', 'bicubic');
                    }
                }
            }

            // Animate box
            return this.animate();
        },
        showInfo: function () {
            var t = this, each = JCEMediaBox.each, DOM = JCEMediaBox.DOM, FX = JCEMediaBox.FX, DIM = JCEMediaBox.Dimensions, Event = JCEMediaBox.Event;
            var ss = JCEMediaBox.options.popup.scalespeed, fs = JCEMediaBox.options.popup.fadespeed;

            // Set Information
            var itop = t['info-top'];
            if (itop) {
                each(DOM.select('*[id]', itop), function (el) {
                    if (/jcemediabox-popup-(next|prev)/.test(DOM.attribute(el, 'id'))) {
                        return;
                    }
                    DOM.show(el);
                });

                var h = DIM.outerHeight(itop);
                DOM.styles(itop, {
                    'z-index': -1,
                    'top': h,
                    'visibility': 'visible'
                });

                FX.animate(itop, {
                    'top': 0
                }, ss);
            }

            if (t.closelink) {
                DOM.show(t.closelink);
            }

            var ibottom = t['info-bottom'];
            if (ibottom) {
                each(DOM.select('*[id]', ibottom), function (el) {
                    if (/jcemediabox-popup-(next|prev)/.test(DOM.attribute(el, 'id'))) {
                        return;
                    }
                    DOM.show(el);
                });

                var h = DIM.outerHeight(ibottom);

                DOM.styles(ibottom, {
                    'z-index': -1,
                    'top': -h,
                    'visibility': 'visible'
                });

                FX.animate(ibottom, {
                    'top': 0
                }, ss);
            }
        },
        /**
         * Animate the Popup
         */
        animate: function () {
            var t = this, each = JCEMediaBox.each, DOM = JCEMediaBox.DOM, FX = JCEMediaBox.FX, DIM = JCEMediaBox.Dimensions, Event = JCEMediaBox.Event;
            var ss = JCEMediaBox.options.popup.scalespeed, fs = JCEMediaBox.options.popup.fadespeed;

            var cw = DIM.outerWidth(this.content);
            var ch = DIM.outerHeight(this.content);

            var ih = 0;
            each(['top', 'bottom'], function (v, i) {
                var el = t['info-' + v];
                if (el) {
                    ih = ih + DIM.outerHeight(el);
                }
            });

            var st = DOM.style(this.page, 'position') == 'fixed' ? 0 : DIM.getScrollTop();
            var top = st + (this.frameHeight() / 2) - ((ch + ih) / 2);

            if (top < 0) {
                top = 0;
            }

            DOM.style(this.content, 'opacity', 0);

            // Animate width
            FX.animate(this.body, {
                'height': ch,
                'top': top,
                'width': cw
            }, ss, function () {
                // Iframe
                if (t.active.type == 'iframe') {
                    // Create IFrame
                    var iframe = DOM.add(t.content, 'iframe', {
                        id: 'jcemediabox-popup-iframe',
                        frameborder: 0,
                        allowTransparency: true,
                        allowfullscreen: true,
                        scrolling: t.active.params.scrolling || 'auto',
                        width: '100%',
                        height: '100%'
                    });

                    // use pdf loader
                    if (/\.pdf\b/.test(t.active.src)) {
                        // Hide loader
                        if (t.loader) {
                            DOM.hide(t.loader);
                        }
                    } else {
                        var win = iframe.contentWindow, doc = win.document, _timer;

                        // fallback iframe load for iOS WebKit
                        if (JCEMediaBox.isiOS && JCEMediaBox.isWebKit) {
                            _timer = setInterval(function () {
                                if (doc.readyState === 'complete') {
                                    clearInterval(_timer);

                                    if (t.loader) {
                                        DOM.hide(t.loader);
                                    }
                                }
                            }, 1000);
                        }

                        iframe.onload = function () {
                            if (_timer) {
                                clearInterval(_timer);
                            }

                            // Hide loader
                            if (t.loader) {
                                DOM.hide(t.loader);
                            }
                        };
                    }

                    iframe.setAttribute('src', t.active.src);

                    t.iframe = iframe;

                } else {
                    // Hide loader
                    if (t.loader) {
                        DOM.hide(t.loader);
                    }

                    // If media
                    if (t.active.type == 'media' && t.object) {
                        t.content.innerHTML = t.object;

                        if (/\.pdf\b/.test(t.active.src) && JCEMediaBox.isiOS) {
                            DOM.styles(DOM.get('jcemediabox-popup-object'), {'height': '1000%', 'width': '150%'});
                        }
                    }

                    if (t.active.type == 'ajax') {
                        DOM.show(t.ajax);
                    }
                }

                DOM.show(t.content);
                t.content.focus();

                // Animate fade in for images only and not on IE6!
                if (t.active.type == 'image' && !JCEMediaBox.isIE6) {
                    FX.animate(t.content, {
                        'opacity': 1
                    }, fs, function () {
                        t.showInfo();
                    });

                } else {
                    DOM.style(t.content, 'opacity', 1);
                    t.showInfo();
                }
            });

        },
        /**
         * Close the popup window. Destroy all objects
         */
        close: function (keepopen) {
            var t = this, each = JCEMediaBox.each, DOM = JCEMediaBox.DOM, DIM = JCEMediaBox.Dimensions, FX = JCEMediaBox.FX;

            var ss = JCEMediaBox.options.popup.scalespeed;

            if (this.iframe) {
                DOM.attribute(this.iframe, 'src', '');
            }

            // Destroy objects
            each(['img', 'object', 'iframe', 'ajax'], function (i, v) {
                //t[v] = null;

                if (t[v]) {
                    DOM.remove(t[v]);
                }

                t[v] = null;
            });

            // Hide closelink
            if (this.closelink) {
                DOM.hide(this.closelink);
            }

            // Empty content div
            this.content.innerHTML = '';

            if (!keepopen) {
                // Hide info div
                each(['top', 'bottom'], function (v, i) {
                    var el = t['info-' + v];
                    if (el) {
                        DOM.hide(el);
                    }
                });

                // reset popups
                var popups = this.getPopups();
                while (this.popups.length > popups.length) {
                    this.popups.pop();
                }

                // remove frame
                DOM.remove(this.frame);
                // Fade out overlay
                if (this.overlay) {
                    if (JCEMediaBox.isIE6) {
                        // Remove event bindings
                        this.bind();
                        // Remove body, ie: popup
                        DOM.remove(this.page);
                        this.page = null;
                    } else {
                        JCEMediaBox.FX.animate(this.overlay, {
                            'opacity': 0
                        }, JCEMediaBox.options.popup.fadespeed, function () {
                            t.bind();
                            // destroy page
                            DOM.remove(t.page);
                            t.page = null;
                        });

                    }
                } else {
                    // destroy page
                    DOM.remove(this.page);
                    this.page = null;
                }
            }
            return false;
        }

    };
})(window);
// Cleanup events
JCEMediaBox.Event.addUnload(function () {
    JCEMediaBox.Event.destroy();
});
PK��#]�#o,, system/jcemediabox/js/index.htmlnu&1i�<html><body bgcolor="#FFFFFF"></body></html>PK��#])S�R����$system/jcemediabox/js/jcemediabox.jsnu&1i�/* jcemediabox - 1.2.9 | 2017-04-05 | https://www.joomlacontenteditor.net | Copyright (C) 2006 - 2016 Ryan Demmer. All rights reserved | GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html */
!function(window){var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(input){var chr1,chr2,chr3,enc1,enc2,enc3,enc4,output="",i=0;for(input=Base64._utf8_encode(input);i<input.length;)chr1=input.charCodeAt(i++),chr2=input.charCodeAt(i++),chr3=input.charCodeAt(i++),enc1=chr1>>2,enc2=(3&chr1)<<4|chr2>>4,enc3=(15&chr2)<<2|chr3>>6,enc4=63&chr3,isNaN(chr2)?enc3=enc4=64:isNaN(chr3)&&(enc4=64),output=output+Base64._keyStr.charAt(enc1)+Base64._keyStr.charAt(enc2)+Base64._keyStr.charAt(enc3)+Base64._keyStr.charAt(enc4);return output},decode:function(input){var chr1,chr2,chr3,enc1,enc2,enc3,enc4,output="",i=0;for(input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");i<input.length;)enc1=Base64._keyStr.indexOf(input.charAt(i++)),enc2=Base64._keyStr.indexOf(input.charAt(i++)),enc3=Base64._keyStr.indexOf(input.charAt(i++)),enc4=Base64._keyStr.indexOf(input.charAt(i++)),chr1=enc1<<2|enc2>>4,chr2=(15&enc2)<<4|enc3>>2,chr3=(3&enc3)<<6|enc4,output+=String.fromCharCode(chr1),64!=enc3&&(output+=String.fromCharCode(chr2)),64!=enc4&&(output+=String.fromCharCode(chr3));return output=Base64._utf8_decode(output)},_utf8_encode:function(string){string=string.replace(/\r\n/g,"\n");for(var utftext="",n=0;n<string.length;n++){var c=string.charCodeAt(n);c<128?utftext+=String.fromCharCode(c):c>127&&c<2048?(utftext+=String.fromCharCode(c>>6|192),utftext+=String.fromCharCode(63&c|128)):(utftext+=String.fromCharCode(c>>12|224),utftext+=String.fromCharCode(c>>6&63|128),utftext+=String.fromCharCode(63&c|128))}return utftext},_utf8_decode:function(utftext){for(var string="",i=0,c=0,c1=0,c2=0;i<utftext.length;)c=utftext.charCodeAt(i),c<128?(string+=String.fromCharCode(c),i++):c>191&&c<224?(c1=utftext.charCodeAt(i+1),string+=String.fromCharCode((31&c)<<6|63&c1),i+=2):(c1=utftext.charCodeAt(i+1),c2=utftext.charCodeAt(i+2),string+=String.fromCharCode((15&c)<<12|(63&c1)<<6|63&c2),i+=3);return string}};window.btoa||(window.btoa=Base64.encode),window.atob||(window.atob=Base64.decode);var support={};support.video=function(){var elem=document.createElement("video"),bool=!1;try{(bool=!!elem.canPlayType)&&(bool=new Boolean(bool),bool.ogg=elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),bool.h264=elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),bool.webm=elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""))}catch(e){}return bool}();var entities={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;"};support.audio=function(){var elem=document.createElement("audio"),bool=!1;try{(bool=!!elem.canPlayType)&&(bool=new Boolean(bool),bool.ogg=elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),bool.mp3=elem.canPlayType("audio/mpeg;").replace(/^no$/,""),bool.wav=elem.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),bool.m4a=(elem.canPlayType("audio/x-m4a;")||elem.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(e){}return bool}(),window.JCEMediaBox={domLoaded:!1,options:{popup:{width:"",height:"",legacy:0,lightbox:0,shadowbox:0,overlay:1,overlayopacity:.8,overlaycolor:"#000000",resize:0,icons:1,fadespeed:500,scalespeed:500,hideobjects:1,scrolling:"fixed",close:2,labels:{close:"Close",next:"Next",previous:"Previous",numbers:"{$current} of {$total}",cancel:"Cancel"},cookie_expiry:7,google_viewer:0,pdfjs:0},tooltip:{speed:150,offsets:{x:16,y:16},position:"br",opacity:.8,background:"#000000",color:"#ffffff"},base:"/",pngfix:!1,pngfixclass:"",theme:"standard",imgpath:"plugins/system/jcemediabox/img",mediafallback:!1,mediaplayer:"",mediaselector:"audio,video"},init:function(options){if(this.extend(this.options,options),this.isIE6)try{document.execCommand("BackgroundImageCache",!1,!0)}catch(e){}support.video&&support.audio||document.createElement("source"),this.ready()},ready:function(){function detach(){doc.addEventListener?(doc.removeEventListener("DOMContentLoaded",completed,!1),win.removeEventListener("load",completed,!1)):(doc.detachEvent("onreadystatechange",completed),win.detachEvent("onload",completed))}function completed(event){detach(),self.domLoaded=!0,self._init()}var win=window,doc=win.document,self=JCEMediaBox;if(self.domLoaded)return self._init();if("complete"===doc.readyState)setTimeout(completed);else if(doc.addEventListener)doc.addEventListener("DOMContentLoaded",completed,!1),win.addEventListener("load",completed,!1);else{doc.attachEvent("onreadystatechange",completed),win.attachEvent("onload",completed);var top=!1;try{top=null==win.frameElement&&doc.documentElement}catch(e){}top&&top.doScroll&&!function doScrollCheck(){if(!self.domLoaded){try{top.doScroll("left")}catch(e){return setTimeout(doScrollCheck,50)}completed()}}()}},getSite:function(){var base=this.options.base;if(base){var site=document.location.href,parts=site.split("://"),port=parts[0],url=parts[1];return url=url.indexOf(base)!=-1?url.substr(0,url.indexOf(base)):url.substr(0,url.indexOf("/"))||url,port+"://"+url+base}return null},_init:function(){var self=this,na=navigator,ua=na.userAgent;return self.isOpera=window.opera&&opera.buildNumber,self.isWebKit=/WebKit/.test(ua),self.isChrome=/Chrome\//.test(ua),self.isSafari=/Safari\//.test(ua),self.isIE=!self.isWebKit&&!self.isOpera&&/MSIE/gi.test(ua)&&/Explorer/gi.test(na.appName)&&!!window.ActiveXObject,self.isIE6=self.isIE&&/MSIE [56]/.test(ua)&&!window.XMLHttpRequest,self.isIE7=self.isIE&&/MSIE [7]/.test(ua)&&!!window.XMLHttpRequest&&!document.querySelector,self.isiOS=/(iPad|iPhone)/.test(ua),self.isAndroid=/Android/.test(ua),self.isMobile=self.isiOS||self.isAndroid,this.site=this.getSite(),!!this.site&&(this.Popup.init(),this.ToolTip.init(),void(this.options.mediafallback&&this.mediaFallback()))},mediaFallback:function(){function toAbsolute(url){var div=document.createElement("div");return div.innerHTML='<a href="'+url+'">x</a>',div.firstChild.href}function resolveMediaPath(s,absolute){return s&&s.indexOf("://")===-1&&"/"!==s.charAt(0)&&(s=self.options.base+s),absolute?toAbsolute(s):s}function checkSupport(name,type){var hasSupport=!1;for(var n in supportMap[name])supportMap[name][n].indexOf(type)!==-1&&(hasSupport=support[name]&&!!support[name][n]);return hasSupport}var self=this,DOM=this.DOM,each=this.each,selector=this.options.mediaselector,elms=DOM.select(selector),swf=this.options.mediaplayer||"plugins/system/jcemediabox/mediaplayer/mediaplayer.swf",supportMap={video:{h264:["video/mp4","video/mpeg"],webm:["video/webm"],ogg:["video/ogg"]},audio:{mp3:["audio/mp3","audio/mpeg"],ogg:["audio/ogg"],webm:["audio/webm"]}};elms.length&&each(elms,function(el){var type=el.getAttribute("type"),src=el.getAttribute("src"),name=el.nodeName.toLowerCase(),hasSupport=!1;if(src&&type)hasSupport=checkSupport(name,type);else{var source=DOM.select("source[type]",el);each(source,function(n){if(src=n.getAttribute("src"),type=n.getAttribute("type"),"video/x-flv"!==type&&(hasSupport=checkSupport(name,type)),!hasSupport)return!1}),hasSupport||"video"!==name||(source=DOM.select('source[type="video/x-flv"]',el),source.length&&(src=source[0].getAttribute("src"),type="video/x-flv"))}if(src&&type&&!hasSupport){var w=el.getAttribute("width"),h=el.getAttribute("height"),html="",flashvars=[];self.options.mediaplayer||flashvars.push("file="+resolveMediaPath(src,!0)),self.each(["autoplay","loop","preload","controls"],function(at){var v=el.getAttribute(at);"undefined"!=typeof v&&null!==v&&(v===at&&(v=!0),flashvars.push(at+"="+v))});var i,attrs=el.attributes;for(i=attrs.length-1;i>=0;i--){var attrName=attrs[i].name;if(attrName&&(attrName.indexOf("data-video-")!==-1||attrName.indexOf("data-audio-")!==-1)){var name=attrName.replace(/data-(video|audio)-/i,""),value=attrs[i].value;"undefined"==typeof value&&null===value||flashvars.push(name+"="+value)}}html+='<object class="wf-mediaplayer-object" data="'+resolveMediaPath(swf)+'" type="application/x-shockwave-flash"',w&&(html+=' width="'+w+'"'),h&&(html+=' height="'+h+'"'),html+=">",html+='<param name="movie" value="'+resolveMediaPath(swf)+'" />',html+='<param name="flashvars" value="'+flashvars.join("&")+'" />',html+='<param name="allowfullscreen" value="true" />',html+='<param name="wmode" value="transparent" />';var poster=el.getAttribute("poster");poster&&(html+='<img src="'+resolveMediaPath(poster)+'" alt="" />'),html+='<i>Flash is required to play this video. <a href="https://get.adobe.com/flashplayer" target="_blank">Get Adobe® Flash Player</a></i>',html+="</object>";var div=document.createElement("span");div.innerHTML=html;var o=div.firstChild;o&&"OBJECT"===o.nodeName&&(el.parentNode.replaceChild(o,el),poster&&(o.style.backgroundImage="url('"+resolveMediaPath(poster)+"')"))}})},each:function(o,cb,s){var n,l;if(!o)return 0;if(s=s||o,void 0!==o.length)for(n=0,l=o.length;n<l&&cb.call(s,o[n],n,o)!==!1;n++);else for(n in o)if(o.hasOwnProperty(n)&&cb.call(s,o[n],n,o)===!1)break;return o},extend:function(obj,ext){var i,l,name,value,args=arguments;for(i=1,l=args.length;i<l;i++){ext=args[i];for(name in ext)ext.hasOwnProperty(name)&&(value=ext[name],void 0!==value&&(obj[name]=value))}return obj},trim:function(s){return(s?""+s:"").replace(/^\s*|\s*$/g,"")},inArray:function(a,s){var i,l;if(a)for(i=0,l=a.length;i<l;i++)if(a[i]===s)return i;return-1},DOM:{get:function(s){return"string"==typeof s?document.getElementById(s):s},select:function(o,p){function inArray(a,v){var i,l;if(a)for(i=0,l=a.length;i<l;i++)if(a[i]===v)return!0;return!1}var s,parts,at,tag,cl,t=this,r=[],each=JCEMediaBox.each;return p=p||document,"*"==o?p.getElementsByTagName(o):p.querySelectorAll?p.querySelectorAll(o):(s=o.split(","),each(s,function(selectors){parts=JCEMediaBox.trim(selectors).split("."),tag=parts[0]||"*",cl=parts[1]||"",/\[(.*?)\]/.test(tag)&&(tag=tag.replace(/(.*?)\[(.*?)\]/,function(a,b,c){return at=c,b}));var elements=p.getElementsByTagName(tag);cl||at?each(elements,function(el){cl&&t.hasClass(el,cl)&&(inArray(r,el)||r.push(el)),at&&el.getAttribute(at)&&(inArray(r,el)||r.push(el))}):r=elements}),r)},hasClass:function(el,c){return new RegExp(c).test(el.className)},addClass:function(el,c){this.hasClass(el,c)||(el.className=JCEMediaBox.trim(el.className+" "+c))},removeClass:function(el,c){if(this.hasClass(el,c)){var s=el.className,re=new RegExp("(^|\\s+)"+c+"(\\s+|$)","g"),v=s.replace(re," ");v=v.replace(/^\s|\s$/g,""),el.className=v}},show:function(el){el.style.display="block"},hide:function(el){el.style.display="none"},remove:function(el,attrib){if(attrib)el.removeAttribute(attrib);else{var p=el.parentNode||document.body;p.removeChild(el)}},style:function(n,na,v){var r,s,isIE=JCEMediaBox.isIE;if(n){if(na=na.replace(/-(\D)/g,function(a,b){return b.toUpperCase()}),s=n.style,"undefined"==typeof v){if("float"==na&&(na=isIE?"styleFloat":"cssFloat"),r=s[na],document.defaultView&&!r){/float/i.test(na)&&(na="float"),na=na.replace(/[A-Z]/g,function(a){return"-"+a}).toLowerCase();try{r=document.defaultView.getComputedStyle(n,null).getPropertyValue(na)}catch(e){}}return n.currentStyle&&!r&&(r=n.currentStyle[na]),r}switch(na){case"opacity":v=parseFloat(v),isIE&&(s.filter=""===v?"":"alpha(opacity="+100*v+")",n.currentStyle&&n.currentStyle.hasLayout||(s.display="inline-block")),s[na]=v;break;case"float":na=isIE?"styleFloat":"cssFloat";break;default:v&&/(margin|padding|width|height|top|bottom|left|right)/i.test(na)&&(v=/^[\-0-9\.]+$/.test(v)?v+"px":v)}s[na]=v}},styles:function(el,props){var t=this;JCEMediaBox.each(props,function(v,s){return t.style(el,s,v)})},attribute:function(el,s,v){if("undefined"==typeof v)return"class"==s?el.className:(v=el.getAttribute(s),v&&/^on/.test(s)&&(v=v.toString(),v=v.replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/,"$1")),"hspace"==s&&v==-1&&(v=""),v);switch(""===v&&el.removeAttribute(s),s){case"style":"object"==typeof v?this.styles(el,v):el.style.cssText=v;break;case"class":el.className=v||"";break;default:el.setAttribute(s,v)}},attributes:function(el,attribs){var t=this;JCEMediaBox.each(attribs,function(v,s){t.attribute(el,s,v)})},create:function(el,attribs,html){var o=document.createElement(el);return this.attributes(o,attribs),"undefined"!=typeof html&&(o.innerHTML=html),o},add:function(n,o,a,h){return"string"==typeof o&&(a=a||{},o=this.create(o,a,h)),n.appendChild(o),o},addBefore:function(n,o,c){"undefined"==typeof c&&(c=n.firstChild),n.insertBefore(o,c)},png:function(el){var s;if("IMG"==el.nodeName)s=el.src,/\.png$/i.test(s)&&(this.attribute(el,"src",JCEMediaBox.site+"plugins/system/jcemediabox/img/blank.gif"),this.style(el,"filter","progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"')"));else if(s=this.style(el,"background-image"),/\.png/i.test(s)){var bg=/url\("(.*)"\)/.exec(s)[1];this.styles(el,{"background-image":"none",filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+bg+"', sizingMethod='image')"})}},encode:function(s){return(""+s).replace(/[<>&\"\']/g,function(c){return entities[c]||c})},decode:function(s){var el;return s=s.replace(/&lt;/g,"<").replace(/&gt;/g,">"),el=document.createElement("div"),el.innerHTML=s,el.innerHTML||s}},Event:{events:[],add:function(o,n,f,s){function _add(o,n,f){o.attachEvent?o.attachEvent("on"+n,f):o.addEventListener?o.addEventListener(n,f,!1):o["on"+n]=f}var t=this;cb=function(e){if(!t.disabled)return e=e||window.event,e&&JCEMediaBox.isIE&&(e.target||(e.target=e.srcElement||document),!e.relatedTarget&&e.fromElement&&(e.relatedTarget=e.fromElement==e.target?e.toElement:e.fromElement),JCEMediaBox.extend(e,{preventDefault:function(){this.returnValue=!1},stopPropagation:function(){this.cancelBubble=!0}})),e&&JCEMediaBox.isWebKit&&3==e.target.nodeType&&(e.target=e.target.parentNode),s?f.call(s,e):f(e)},t.events.push({obj:o,name:n,func:f,cfunc:cb,scope:s}),_add(o,n,cb)},remove:function(o,n,f){var t=this,a=t.events,s=!1;return JCEMediaBox.each(a,function(e,i){if(e.obj==o&&e.name==n&&(!f||e.func==f||e.cfunc==f))return a.splice(i,1),t._remove(o,n,e.cfunc),s=!0,!1}),s},_remove:function(o,n,f){if(o)try{o.detachEvent?o.detachEvent("on"+n,f):o.removeEventListener?o.removeEventListener(n,f,!1):o["on"+n]=null}catch(ex){}},cancel:function(e){return!!e&&(this.stop(e),this.prevent(e))},stop:function(e){return e.stopPropagation?e.stopPropagation():e.cancelBubble=!0,!1},prevent:function(e){return e.preventDefault?e.preventDefault():e.returnValue=!1,!1},destroy:function(){var t=this;JCEMediaBox.each(t.events,function(e,i){t._remove(e.obj,e.name,e.cfunc),e.obj=e.cfunc=null}),t.events=[],t=null},addUnload:function(f,s){function unload(){var o,n,li=t.unloads;if(li){for(n in li)o=li[n],o&&o.func&&o.func.call(o.scope,1);window.detachEvent?(window.detachEvent("onbeforeunload",fakeUnload),window.detachEvent("onunload",unload)):window.removeEventListener&&window.removeEventListener("unload",unload,!1),t.unloads=o=li=w=unload=0,window.CollectGarbage&&CollectGarbage()}}function fakeUnload(){function stop(){d.detachEvent("onstop",stop),unload&&unload(),d=0}var d=document;"interactive"==d.readyState&&(d&&d.attachEvent("onstop",stop),window.setTimeout(function(){d&&d.detachEvent("onstop",stop)},0))}var t=this;return f={func:f,scope:s||this},t.unloads?t.unloads.push(f):(window.attachEvent?(window.attachEvent("onunload",unload),window.attachEvent("onbeforeunload",fakeUnload)):window.addEventListener&&window.addEventListener("unload",unload,!1),t.unloads=[f]),f},removeUnload:function(f){var u=this.unloads,r=null;return JCEMediaBox.each(u,function(o,i){if(o&&o.func==f)return u.splice(i,1),r=f,!1}),r}},Dimensions:{getWidth:function(){return window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth||0},getHeight:function(){if(JCEMediaBox.isiOS||JCEMediaBox.isAndroid){var zoomLevel=document.documentElement.clientWidth/window.innerWidth;return window.innerHeight*zoomLevel}return window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight||0},getScrollHeight:function(){return document.documentElement.scrollHeight||document.body.scrollHeight||0},getScrollWidth:function(){return document.documentElement.scrollWidth||document.body.scrollWidth||0},getScrollTop:function(){return window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0},getScrollbarWidth:function(){var DOM=JCEMediaBox.DOM;if(this.scrollbarWidth)return this.scrollbarWidth;var outer=DOM.add(document.body,"div",{style:{position:"absolute",visibility:"hidden",width:200,height:200,border:0,margin:0,padding:0,overflow:"hidden"}}),inner=DOM.add(outer,"div",{style:{width:"100%",height:200,border:0,margin:0,padding:0}}),w1=parseInt(inner.offsetWidth);outer.style.overflow="scroll";var w2=parseInt(inner.offsetWidth);return w1==w2&&(w2=parseInt(outer.clientWidth)),document.body.removeChild(outer),this.scrollbarWidth=w1-w2,this.scrollbarWidth},outerWidth:function(n){var v=0,x=0;return x=n.offsetWidth,x||JCEMediaBox.each(["padding-left","padding-right","border-left","border-right","width"],function(s){v=parseFloat(JCEMediaBox.DOM.style(n,s)),v=/[0-9]/.test(v)?v:0,x+=v}),x},outerHeight:function(n){var v=0,x=0;return x=n.offsetHeight,x||JCEMediaBox.each(["padding-top","padding-bottom","border-top","border-bottom","height"],function(s){v=parseFloat(JCEMediaBox.DOM.style(n,s)),v=/[0-9]/.test(v)?v:0,x+=v}),x}},FX:{animate:function(el,props,speed,cb){var sv,DOM=JCEMediaBox.DOM,options={speed:speed||100,callback:cb||function(){}},styles={};return JCEMediaBox.each(props,function(v,s){sv=parseFloat(DOM.style(el,s)),styles[s]=[sv,v]}),new JCEMediaBox.fx(el,options).custom(styles),!0}}},JCEMediaBox.XHR=function(options,scope){this.options={async:!0,headers:{"X-Requested-With":"XMLHttpRequest",Accept:"text/javascript, text/html, application/xml, text/xml, */*"},data:null,encoding:"UTF-8",success:function(){},error:function(){}},JCEMediaBox.extend(this.options,options),this.scope=scope||this},JCEMediaBox.XHR.prototype={setTransport:function(){function get(s){var x=0;try{x=new ActiveXObject(s)}catch(ex){}return x}this.transport=window.XMLHttpRequest?new XMLHttpRequest:get("Microsoft.XMLHTTP")||get("Msxml2.XMLHTTP")},onStateChange:function(){if(4==this.transport.readyState&&this.running){if(this.running=!1,this.transport.status>=200&&this.transport.status<300){var s=this.transport.responseText,x=this.transport.responseXML;this.options.success.call(this.scope,s,x)}else this.options.error.call(this.scope,this.transport,this.options);this.transport.onreadystatechange=function(){},this.transport=null}},send:function(url){var t=this,extend=JCEMediaBox.extend;if(this.running)return this;this.running=!0,this.setTransport();var method=this.options.data?"POST":"GET",encoding=this.options.encoding?"; charset="+this.options.encoding.toUpperCase():"",contentType={"Content-type":"text/html"+encoding};this.options.data&&(contentType={"Content-type":"application/x-www-form-urlencoded"+encoding}),extend(this.options.headers,contentType),this.transport.open(method,url,this.options.async),this.transport.onreadystatechange=function(){return t.onStateChange()};for(var type in this.options.headers)try{this.transport.setRequestHeader(type,this.options.headers[type])}catch(e){}this.transport.send(this.options.data)}},JCEMediaBox.fx=function(el,options){this.element=el,this.callback=options.callback,this.speed=options.speed,this.wait=!0,this.fps=50,this.now={}},JCEMediaBox.fx.prototype={step:function(){var time=(new Date).getTime();if(time<this.time+this.speed)this.cTime=time-this.time,this.setNow();else{var t=this;this.clearTimer(),this.now=this.to,setTimeout(function(){t.callback.call(t.element,t)},10)}this.increase()},setNow:function(){var p;for(p in this.from)this.now[p]=this.compute(this.from[p],this.to[p])},compute:function(from,to){var change=to-from;return this.transition(this.cTime,from,change,this.speed)},clearTimer:function(){return clearInterval(this.timer),this.timer=null,this},start:function(from,to){var t=this;if(this.wait||this.clearTimer(),!this.timer)return this.from=from,this.to=to,this.time=(new Date).getTime(),this.timer=setInterval(function(){return t.step()},Math.round(1e3/this.fps)),this},custom:function(o){if(!this.timer||!this.wait){var property,from={},to={};for(property in o)from[property]=o[property][0],to[property]=o[property][1];return this.start(from,to)}},increase:function(){for(var p in this.now)this.setStyle(this.element,p,this.now[p])},transition:function(t,b,c,d){return-c*Math.cos(t/d*(Math.PI/2))+c+b},setStyle:function(e,p,v){JCEMediaBox.DOM.style(e,p,v)}},JCEMediaBox.ToolTip={init:function(){var t=this,theme="custom"==JCEMediaBox.options.theme?JCEMediaBox.options.themecustom:JCEMediaBox.options.theme;this.tooltiptheme="",new JCEMediaBox.XHR({success:function(text,xml){var re=/<!-- THEME START -->([\s\S]*?)<!-- THEME END -->/;re.test(text)&&(text=re.exec(text)[1]),t.tooltiptheme=text,t.create()}}).send(JCEMediaBox.site+JCEMediaBox.options.themepath+"/"+theme+"/tooltip.html")},create:function(o){function _withinElement(el,e,fn){for(var p=e.relatedTarget;p&&p!=el;)try{p=p.parentNode}catch(e){p=el}return p!=el&&fn.call(this)}var t=this,each=JCEMediaBox.each,DOM=JCEMediaBox.DOM,Event=JCEMediaBox.Event;each(DOM.select(".jcetooltip, .jce_tooltip",o),function(el){DOM.attribute(el,"data-title",el.title),DOM.remove(el,"title");var n=el;"IMG"==el.nodeName&&"jcemediabox-zoom-span"==el.parentNode.className&&(n=el.parentNode),Event.add(n,"mouseover",function(e){_withinElement(el,e,function(){return t.start(el)})}),Event.add(n,"mouseout",function(e){_withinElement(el,e,function(){return t.end(el)})}),Event.add(n,"mousemove",function(e){return t.locate(e)})})},build:function(){if(!this.toolTip){var DOM=JCEMediaBox.DOM;this.toolTip=DOM.add(document.body,"div",{style:{opacity:0},class:"jcemediabox-tooltip"},this.tooltiptheme),JCEMediaBox.isIE6&&DOM.addClass(this.toolTip,"ie6")}},start:function(el){var t=this,DOM=JCEMediaBox.DOM;if(!this.tooltiptheme)return!1;this.build();var text=DOM.attribute(el,"data-title")||"",title="";if(/::/.test(text)){var parts=text.split("::");title=JCEMediaBox.trim(parts[0]),text=JCEMediaBox.trim(parts[1])}var h="";title&&(h+="<h4>"+title+"</h4>"),text&&(h+="<p>"+text+"</p>");var tn=DOM.get("jcemediabox-tooltip-text");"undefined"==typeof tn?(this.toolTip.className="jcemediabox-tooltip-simple",this.toolTip.innerHTML=h):tn.innerHTML=h,DOM.style(t.toolTip,"visibility","visible"),JCEMediaBox.FX.animate(t.toolTip,{opacity:JCEMediaBox.options.tooltip.opacity},JCEMediaBox.options.tooltip.speed)},end:function(el){return!!this.tooltiptheme&&void JCEMediaBox.DOM.styles(this.toolTip,{visibility:"hidden",opacity:0})},locate:function(e){if(!this.tooltiptheme)return!1;this.build();var o=JCEMediaBox.options.tooltip.offsets,page={x:e.pageX||e.clientX+document.documentElement.scrollLeft,y:e.pageY||e.clientY+document.documentElement.scrollTop},tip={x:this.toolTip.offsetWidth,y:this.toolTip.offsetHeight},pos={x:page.x+o.x,y:page.y+o.y},ah=0;switch(JCEMediaBox.options.tooltip.position){case"tl":pos.x=page.x-tip.x-o.x,pos.y=page.y-tip.y-(ah+o.y);break;case"tr":pos.x=page.x+o.x,pos.y=page.y-tip.y-(ah+o.y);break;case"tc":pos.x=page.x-Math.round(tip.x/2)+o.x,pos.y=page.y-tip.y-(ah+o.y);break;case"bl":pos.x=page.x-tip.x-o.x,pos.y=page.y+Math.round(tip.y/2)-(ah+o.y);break;case"br":pos.x=page.x+o.x,pos.y=page.y+o.y;break;case"bc":pos.x=page.x-tip.x/2+o.x,pos.y=page.y+ah+o.y}JCEMediaBox.DOM.styles(this.toolTip,{top:pos.y,left:pos.x})},position:function(element){}},JCEMediaBox.Popup={addons:{flash:{},image:{},iframe:{},html:{},pdf:{}},setAddons:function(n,o){JCEMediaBox.extend(this.addons[n],o)},getAddons:function(n){return n?this.addons[n]:this.addons},getAddon:function(v,n){var r,cp=!1,each=JCEMediaBox.each;return addons=this.getAddons(n),each(this.addons,function(o,s){each(o,function(fn){r=fn.call(this,v),"undefined"!=typeof r&&(cp=r)})}),cp},cleanEvent:function(s){return s.replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/,"$1")},parseJSON:function(data){return"string"==typeof data&&data?/^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))?window.JSON&&window.JSON.parse?window.JSON.parse(data):new Function("return "+data)():void 0:null},params:function(s){function trim(s){return s=s.replace(/^\s+/,"").replace(/\s+$/,"")}var a=[],x=[],DOM=JCEMediaBox.DOM;if("string"==typeof s){if(/^\{[\w\W]+\}$/.test(s))return this.parseJSON(s);if(/\w+\[[^\]]+\]/.test(s))return s=s.replace(/([\w]+)\[([^\]]+)\](;)?/g,function(a,b,c,d){return'"'+b+'":"'+DOM.encode(trim(c))+'"'+(d?",":"")}),this.parseJSON("{"+s+"}");s.indexOf("=")!==-1&&(s.indexOf("&")!==-1?x=s.split(/&(amp;)?/g):x.push(s))}return"object"==typeof s&&s instanceof Array&&(x=s),JCEMediaBox.each(x,function(n,i){n&&(n=n.replace(/^([^\[]+)(\[|=|:)([^\]]*)(\]?)$/,function(a,b,c,d){return d?/[^0-9]/.test(d)?'"'+b+'":"'+DOM.encode(trim(d))+'"':'"'+b+'":'+parseInt(d):""}),n&&a.push(n))}),this.parseJSON("{"+a.join(",")+"}")},getCookie:function(n){var e,b,c=document.cookie,p=n+"=";if(c){if(b=c.indexOf("; "+p),b==-1){if(b=c.indexOf(p),0!=b)return null}else b+=2;return e=c.indexOf(";",b),e==-1&&(e=c.length),unescape(c.substring(b+p.length,e))}},setCookie:function(n,v,e,p,d,s){document.cookie=n+"="+escape(v)+(e?"; expires="+e.toGMTString():"")+(p?"; path="+escape(p):"")+(d?"; domain="+d:"")+(s?"; secure":"")},convertLegacy:function(){var self=this,each=JCEMediaBox.each,DOM=JCEMediaBox.DOM;each(DOM.select("a[href]"),function(el){if(/com_jce/.test(el.href)){var p,s,img,oc=DOM.attribute(el,"onclick");if(oc){s=oc.replace(/&#39;/g,"'").split("'"),p=self.params(s[1]);var img=p.img||"",title=p.title||""}img&&(/http:\/\//.test(img)||("/"==img.charAt(0)&&(img=img.substr(1)),img=JCEMediaBox.site.replace(/http:\/\/([^\/]+)/,"")+img),DOM.attributes(el,{href:img,title:title.replace(/_/," "),onclick:""}),DOM.addClass(el,"jcepopup"))}})},convertLightbox:function(){var each=JCEMediaBox.each,DOM=JCEMediaBox.DOM;each(DOM.select("a[rel*=lightbox]"),function(el){DOM.addClass(el,"jcepopup"),r=el.rel.replace(/lightbox\[?([^\]]*)\]?/,function(a,b){return b?"group["+b+"]":""}),DOM.attribute(el,"rel",r)})},convertShadowbox:function(){var each=JCEMediaBox.each,DOM=JCEMediaBox.DOM;each(DOM.select("a[rel*=shadowbox]"),function(el){DOM.addClass(el,"jcepopup"),r=el.rel.replace(/shadowbox\[?([^\]]*)\]?/,function(a,b){var attribs="",group="";return b&&(group="group["+b+"]"),/;=/.test(a)&&(attribs=a.replace(/=([^;"]+)/g,function(x,z){return"["+z+"]"})),group&&attribs?group+";"+attribs:group||attribs||""}),DOM.attribute(el,"rel",r)})},translate:function(s){return s||(s=this.popup.theme),s=s.replace(/\{#(\w+?)\}/g,function(a,b){return JCEMediaBox.options.popup.labels[b]})},styles:function(o){var x=[];return o?(JCEMediaBox.each(o.split(";"),function(s,i){s=s.replace(/(.*):(.*)/,function(a,b,c){return'"'+b+'":"'+c+'"'}),x.push(s)}),this.parseJSON("{"+x.join(",")+"}")):{}},getType:function(el){var o={},type="";return el.type&&/(director|windowsmedia|mplayer|quicktime|real|divx|flash|pdf)/.test(el.type)&&(type=/(director|windowsmedia|mplayer|quicktime|real|divx|flash|pdf)/.exec(el.type)[1]),o=this.getAddon(el.src),o&&o.type&&(type=o.type),type||el.type||"iframe"},mediatype:function(c){var ci,cb,mt;switch(c=/(director|windowsmedia|mplayer|quicktime|real|divx|flash|pdf)/.exec(c),c[1]){case"director":case"application/x-director":ci="166b1bca-3f9c-11cf-8075-444553540000",cb="http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0",mt="application/x-director";break;case"windowsmedia":case"mplayer":case"application/x-mplayer2":ci="6bf52a52-394a-11d3-b153-00c04f79faa6",cb="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701",mt="application/x-mplayer2";break;case"quicktime":case"video/quicktime":ci="02bf25d5-8c17-4b23-bc80-d3488abddc6b",cb="http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0",mt="video/quicktime";break;case"real":case"realaudio":case"audio/x-pn-realaudio-plugin":ci="cfcdaa03-8be4-11cf-b84b-0020afbbccfa",cb="",mt="audio/x-pn-realaudio-plugin";break;case"divx":case"video/divx":ci="67dabfbf-d0ab-41fa-9c46-cc0f21721616",cb="http://go.divx.com/plugin/DivXBrowserPlugin.cab",mt="video/divx";break;case"pdf":case"application/pdf":ci="ca8a9780-280d-11cf-a24d-444553540000",cb="",mt="application/pdf";break;default:case"flash":case"application/x-shockwave-flash":ci="d27cdb6e-ae6d-11cf-96b8-444553540000",cb="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,124,0",mt="application/x-shockwave-flash"}return{classid:ci,codebase:cb,mediatype:mt}},islocal:function(s){return!/^(\w+:)?\/\//.test(s)||new RegExp("^("+JCEMediaBox.site+")").test(s)},protocolRelative:function(url){if(JCEMediaBox.isIE6)return url;var local=document.location.href;return url.indexOf("https://")!==-1?url:local.indexOf("https://")!==-1?url.replace(/http(s)?:\/\//i,"//"):url},frameWidth:function(){var w=0,el=this.frame;return JCEMediaBox.each(["left","right"],function(s){w+=parseFloat(JCEMediaBox.DOM.style(el,"padding-"+s))}),parseFloat(this.frame.clientWidth-w)},frameHeight:function(){var h=0,el=this.frame,DIM=JCEMediaBox.Dimensions;return JCEMediaBox.each(["top","bottom"],function(s){h+=parseFloat(JCEMediaBox.DOM.style(el,"padding-"+s))}),h+=JCEMediaBox.isIE6||JCEMediaBox.isIE7?DIM.getScrollbarWidth():0,parseInt(DIM.getHeight())-h},width:function(){return this.frameWidth()-JCEMediaBox.Dimensions.getScrollbarWidth()},height:function(){var h=0,t=this,each=JCEMediaBox.each,DIM=JCEMediaBox.Dimensions;return each(["top","bottom"],function(s){var el=t["info-"+s];el&&(h+=parseInt(DIM.outerHeight(el)))}),this.frameHeight()-h},printPage:function(){return!1},zoom:function(el){function _buildIcon(el,zoom,child,styles){var span=DOM.add(el,"span",{class:"jcemediabox-zoom-span",style:child.style.cssText});"IMG"===child.nodeName&&child.title&&span.setAttribute("title",child.title),DOM.styles(span,styles),DOM.hasClass(el.parentNode,"wf_caption")&&(span.style.width=null,DOM.style(span,"max-width",DOM.style(el.parentNode,"max-width"))),span.style.width&&(DOM.style(span,"max-width",span.style.width),span.style.width=null),DOM.add(span,child),DOM.add(span,zoom),each(["style","align","border","hspace","vspace"],function(v,i){child.removeAttribute(v)}),DOM.addClass(zoom,"jcemediabox-zoom-image"),JCEMediaBox.isIE6&&/\.png/i.test(DOM.style(zoom,"background-image"))&&DOM.png(zoom),DOM.styles(child,{margin:0,padding:0,float:"none",border:"none"})}var self=this,DOM=JCEMediaBox.DOM,extend=JCEMediaBox.extend,each=JCEMediaBox.each,zoom=(el.childNodes,DOM.create("span"));JCEMediaBox.isIE6&&DOM.addClass(el,"ie6");var cls=DOM.attribute(el,"class");cls=cls.replace("icon-","zoom-","g"),DOM.attribute(el,"class",cls);var img=DOM.select("img",el);if(img&&img.length){var child=img[0],align=child.getAttribute("align"),vspace=child.getAttribute("vspace"),hspace=child.getAttribute("hspace"),styles={};each(["top","right","bottom","left"],function(pos){styles["margin-"+pos]=DOM.style(child,"margin-"+pos),styles["padding-"+pos]=DOM.style(child,"padding-"+pos),each(["width","style","color"],function(prop){styles["border-"+pos+"-"+prop]=DOM.style(child,"border-"+pos+"-"+prop)})}),/\w+/.test(align)&&extend(styles,{float:/left|right/.test(align)?align:"","text-align":/top|middle|bottom/.test(align)?align:""}),vspace>0&&extend(styles,{"margin-top":parseInt(vspace),"margin-bottom":parseInt(vspace)}),hspace>0&&extend(styles,{"margin-left":parseInt(hspace),"margin-right":parseInt(hspace)});var w=child.getAttribute("width"),h=child.getAttribute("height"),ws=child.style.width,rh=child.height,rw=child.width;if(!w&&!ws&&!rw)return!child.loaded&&(child.onload=function(){return child.loaded=!0,self.zoom(el)},child.onerror=function(){return!1},!1);!w&&h&&(w=h/rh*rw),w||(w=/([0-9]+)(px)?$/.test(ws)?parseFloat(ws):rw),w&&(child.setAttribute("width",w),styles.width=w),extend(styles,{"text-align":child.style.textAlign});var float=DOM.style(child,"float");"left"!==float&&"right"!==float||(styles.float=float),
_buildIcon(el,zoom,child,styles)}else DOM.addClass(zoom,"jcemediabox-zoom-link"),DOM.hasClass(el,"zoom-left")?DOM.addBefore(el,zoom):DOM.add(el,zoom),JCEMediaBox.isIE7&&DOM.style(zoom,"display","inline-block");return zoom},auto:function(){function makeID(src){var url=document.location.href,key=window.btoa(url+src);return key=key.replace(/[^\w]/g,""),key=key.substr(0,24)}var dts,key,t=this,expires=JCEMediaBox.options.popup.cookie_expiry;JCEMediaBox.each(this.popups,function(el,i){if(el.auto)if("single"==el.auto){key=el.id||makeID(el.src);var cookie=t.getCookie("jcemediabox_"+key+"_"+i);cookie||(expires&&(dts=new Date,dts.setHours(24*expires)),t.setCookie("jcemediabox_"+key+"_"+i,1,dts),t.start(el))}else"multiple"==el.auto&&t.start(el)})},init:function(){window.jcepopup=this,this.create()},getPopups:function(s,p){var selector="a.jcebox, a.jcelightbox, a.jcepopup, a[data-mediabox], area.jcebox, area.jcelightbox, area.jcepopup, area[data-mediabox]";return JCEMediaBox.DOM.select(s||selector,p)},getData:function(n){var data,DOM=JCEMediaBox.DOM,o=(JCEMediaBox.each,{}),re=/\w+\[[^\]]+\]/;if(data=n.getAttribute("data-mediabox")||n.getAttribute("data-json"),data&&"1"!=data)return n.removeAttribute("data-json"),n.removeAttribute("data-mediabox"),this.params(data);var i,attrs=n.attributes,x=0;for(i=attrs.length-1;i>=0;i--){var attrName=attrs[i].name;if(attrName&&attrName.indexOf("data-mediabox-")!==-1){var attr=attrName.replace("data-mediabox-","");o[attr]=attrs[i].value,x++}}if(x)return o;var title=DOM.attribute(n,"title"),rel=DOM.attribute(n,"rel");if(title&&re.test(title))return o=this.params(title),DOM.attribute(n,"title",o.title||""),o;if(rel&&re.test(rel)){var args=[];return rel=rel.replace(/\b((\w+)\[(.*?)\])(;?)/g,function(a,b,c){return args.push(b),""}),o=this.params(args)||{},DOM.attribute(n,"rel",rel||o.rel||""),o}return o},process:function(el){var data,DOM=JCEMediaBox.DOM,o={},group="",auto=!1,title=el.title||"",rel=el.rel||"",src=el.href;if(src=src.replace(/b(w|h)=([0-9]+)/g,function(s,k,v){return k="w"==k?"width":"height",k+"="+v}),data=this.getData(el)||{},!/\w+\[[^\]]+\]/.test(rel)){var rx="alternate|stylesheet|start|next|prev|contents|index|glossary|copyright|chapter|section|subsection|appendix|help|bookmark|nofollow|noopener|noreferrer|licence|tag|friend",lb="(lightbox([(.*?)])?)",lt="(lyte(box|frame|show)([(.*?)])?)";group=JCEMediaBox.trim(rel.replace(new RegExp("(^|\\s+)"+rx+"|"+lb+"|"+lt+"(\\s+|$)","g"),"","gi"))}return"AREA"==el.nodeName&&(data||(data=this.params(src)),group=group||"AREA_ELEMENT",data.type||(match=/\b(ajax|iframe|image|flash|director|shockwave|mplayer|windowsmedia|quicktime|realaudio|real|divx|pdf)\b/.exec(el.className))&&(data.type=match[0])),/autopopup-(single|multiple)/.test(el.className)&&(auto=/(multiple)/.test(el.className)?"multiple":"single"),auto=auto||data.autopopup||"",group=group||data.group||"",JCEMediaBox.extend(o,{src:src,title:data.title||title,group:DOM.hasClass(el,"nogroup")?"":group,type:data.type||el.type||"",params:data,auto:auto}),el.href=el.href.replace(/&type=(ajax|text\/html|text\/xml)/,""),o},create:function(elements){var t=this,each=JCEMediaBox.each,Event=JCEMediaBox.Event,DOM=JCEMediaBox.DOM,pageload=!1,auto=!1;if(elements||(pageload=!0,this.popups=[],1==JCEMediaBox.options.popup.legacy&&t.convertLegacy(),1==JCEMediaBox.options.popup.lightbox&&t.convertLightbox(),1==JCEMediaBox.options.popup.shadowbox&&t.convertShadowbox()),this.elements=elements||this.getPopups(),each(this.elements,function(el,i){if(!el.href)return!0;if(1===el.childNodes.length&&"IMG"===el.firstChild.nodeName&&DOM.addClass(el,"jcemediabox-image"),1!=JCEMediaBox.options.popup.icons||"A"!=el.nodeName||/(noicon|icon-none|noshow)/.test(el.className)||"none"==el.style.display||t.zoom(el),"_blank"===DOM.attribute(el,"target")){var rel=DOM.attribute(el,"rel")||"";rel.indexOf("noopener")===-1&&(rel+=" noopener"),rel.indexOf("noreferrer")===-1&&(rel+=" noreferrer"),DOM.attribute(el,"rel",JCEMediaBox.trim(rel))}DOM.removeClass(el,"jcelightbox"),DOM.removeClass(el,"jcebox"),DOM.addClass(el,"jcepopup");var o=t.process(el);t.popups.push(o),pageload||(i=t.popups.length-1),Event.add(el,"click",function(e){return Event.cancel(e),t.start(o,i)})}),pageload){this.popuptheme="";var theme=JCEMediaBox.options.theme;new JCEMediaBox.XHR({success:function(text,xml){var re=/<!-- THEME START -->([\s\S]*?)<!-- THEME END -->/;re.test(text)&&(text=re.exec(text)[1]),t.popuptheme=text,auto||(t.auto(),auto=!0)}}).send(JCEMediaBox.site+"plugins/system/jcemediabox/themes/"+theme+"/popup.html")}},open:function(data,title,group,type,params){var i,o={};if("string"==typeof data&&(data={src:data,title:title,group:group,type:type,params:params}),data.nodeName&&("A"==data.nodeName||"AREA"==data.nodeName)){if(i=JCEMediaBox.inArray(this.elements,data),i>=0)return this.start(this.popups[i],i);var o=this.process(data),x=this.popups.push(o);return this.start(o,x-1)}return this.start(data)},start:function(p,i){var len,n=0,items=[],each=JCEMediaBox.each;if(this.build())return p.group?(each(this.popups,function(o,x){o.group==p.group&&(len=items.push(o),i&&x==i&&(n=len-1))}),p.auto||"undefined"!=typeof i||(items.push(p),n=items.length-1)):items.push(p),this.show(items,n)},build:function(){var t=this,each=JCEMediaBox.each,DOM=JCEMediaBox.DOM,Event=JCEMediaBox.Event;if(!this.page){if(this.page=DOM.add(document.body,"div",{id:"jcemediabox-popup-page"}),JCEMediaBox.isIE6&&DOM.addClass(this.page,"ie6"),JCEMediaBox.isIE7&&DOM.addClass(this.page,"ie7"),JCEMediaBox.isiOS&&DOM.addClass(this.page,"ios"),JCEMediaBox.isAndroid&&DOM.addClass(this.page,"android"),1==JCEMediaBox.options.popup.overlay&&(this.overlay=DOM.add(this.page,"div",{id:"jcemediabox-popup-overlay",style:{opacity:0,"background-color":JCEMediaBox.options.popup.overlaycolor}})),!this.popuptheme)return!1;this.popuptheme=this.popuptheme.replace(/<!--(.*?)-->/g,""),this.popuptheme=this.translate(this.popuptheme),this.frame=DOM.add(this.page,"div",{id:"jcemediabox-popup-frame"},'<div id="jcemediabox-popup-body">'+this.popuptheme+"</div>"),each(DOM.select("*[id]",this.frame),function(el){var s=el.id.replace("jcemediabox-popup-","");t[s]=el,DOM.hide(el)}),(JCEMediaBox.isiOS||JCEMediaBox.isAndroid)&&JCEMediaBox.isWebKit&&DOM.style(this.content,"webkitOverflowScrolling","touch"),2==JCEMediaBox.options.popup.close&&Event.add(this.frame,"click",function(e){e.target&&e.target==t.frame&&t.close()}),this.closelink&&Event.add(this.closelink,"click",function(){return t.close()}),this.cancellink&&Event.add(this.cancellink,"click",function(){return t.close()}),this.next&&Event.add(this.next,"click",function(){return t.nextItem()}),this.prev&&Event.add(this.prev,"click",function(){return t.previousItem()}),this.numbers&&(this.numbers.tmpHTML=this.numbers.innerHTML),this.print&&Event.add(this.print,"click",function(){return t.printPage()}),JCEMediaBox.isIE6&&(DOM.png(this.body),each(DOM.select("*",this.body),function(el){"jcemediabox-popup-content"!=DOM.attribute(el,"id")&&DOM.png(el)}))}return!0},show:function(items,n){var DOM=JCEMediaBox.DOM,DIM=JCEMediaBox.Dimensions,top=0;return this.items=items,this.bind(!0),DOM.show(this.body),/\d/.test(this.body.style.top)||(top=(DIM.getHeight()-DIM.outerHeight(this.body))/2),DOM.style(this.body,"top",top),(JCEMediaBox.isIE6||"scroll"==JCEMediaBox.options.popup.scrolling)&&(DOM.addClass(this.page,"scrolling"),DOM.style(this.overlay,"height",DIM.getScrollHeight()),DOM.style(this.body,"top",DIM.getScrollTop()+top)),1==JCEMediaBox.options.popup.overlay&&this.overlay&&(DOM.show(this.overlay),JCEMediaBox.FX.animate(this.overlay,{opacity:JCEMediaBox.options.popup.overlayopacity},JCEMediaBox.options.popup.fadespeed)),this.change(n)},bind:function(open){var t=this,isIE6=JCEMediaBox.isIE6,each=JCEMediaBox.each,DOM=JCEMediaBox.DOM,Event=JCEMediaBox.Event;JCEMediaBox.Dimensions;isIE6&&each(DOM.select("select"),function(el){open&&(el.tmpStyle=el.style.visibility||""),el.style.visibility=open?"hidden":el.tmpStyle}),JCEMediaBox.options.popup.hideobjects&&each(DOM.select("object, embed"),function(el){"jcemediabox-popup-object"!=el.id&&(open&&(el.tmpStyle=el.style.visibility||""),el.style.visibility=open?"hidden":el.tmpStyle)});var scroll=JCEMediaBox.options.popup.scrollpopup;open?(Event.add(document,"keydown",function(e){t.listener(e)}),isIE6&&(Event.add(window,"scroll",function(e){DOM.style(t.overlay,"height",JCEMediaBox.Dimensions.getScrollHeight())}),Event.add(window,"scroll",function(e){DOM.style(t.overlay,"width",JCEMediaBox.Dimensions.getScrollWidth())}))):(!isIE6&&scroll||(Event.remove(window,"scroll"),Event.remove(window,"resize")),Event.remove(document,"keydown"))},listener:function(e){switch(e.keyCode){case 27:this.close();break;case 37:this.previousItem();break;case 39:this.nextItem()}},queue:function(n){var t=this,changed=!1;JCEMediaBox.each(["top","bottom"],function(s){var el=t["info-"+s];if(el){var v=JCEMediaBox.Dimensions.outerHeight(el),style={};style.top="top"==s?v:-v,JCEMediaBox.FX.animate(el,style,JCEMediaBox.options.popup.scalespeed,function(){changed||(changed=!0,JCEMediaBox.FX.animate(t.content,{opacity:0},JCEMediaBox.options.popup.fadespeed,function(){return t.change(n)}))})}})},nextItem:function(){if(1==this.items.length)return!1;var n=this.index+1;return!(n<0||n>=this.items.length)&&this.queue(n)},previousItem:function(){if(1==this.items.length)return!1;var n=this.index-1;return!(n<0||n>=this.items.length)&&this.queue(n)},info:function(){function processRe(h){return h=h.replace(ex,'<a href="mailto:$1" target="_blank">$1</a>'),h=h.replace(ux,'<a href="$1" target="_blank">$1</a>')}var each=JCEMediaBox.each,DOM=JCEMediaBox.DOM,Event=JCEMediaBox.Event;if(this.caption){var title=this.active.title||"",text=this.active.caption||"",h="",ex=/([-!#$%&\'\*\+\\.\/0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'\*\+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\.\/0-9=?A-Z^_`a-z{|}~]+)/gi,ux=/([a-zA-Z]{3,9}:\/\/[^\s]+)/gi;title&&(h+="<h4>"+DOM.decode(title)+"</h4>"),text&&(h+="<p>"+DOM.decode(text)+"</p>"),this.caption.innerHTML=h,""!=h&&each(DOM.select("*",this.caption),function(el){"A"!=el.nodeName&&each(el.childNodes,function(n,i){if(3==n.nodeType){var s=n.innerText||n.textContent||n.data||null;s&&/(@|:\/\/)/.test(s)&&(s=processRe(s))&&(n.parentNode.innerHTML=s)}})})}var t=this,len=this.items.length;if(this.numbers&&len>1){var html=this.numbers.tmpHTML||"{$numbers}";if(/\{\$numbers\}/.test(html)){this.numbers.innerHTML="";for(var i=0;i<len;i++){var n=i+1,title=decodeURIComponent(this.items[i].title||n),link=DOM.add(this.numbers,"a",{href:"javascript:;",title:title,class:this.index==i?"active":""},n);Event.add(link,"click",function(e){var x=parseInt(e.target.innerHTML)-1;return t.index!=x&&t.queue(x)})}}/\{\$(current|total)\}/.test(html)&&(this.numbers.innerHTML=html.replace("{$current}",this.index+1).replace("{$total}",len))}else this.numbers&&(this.numbers.innerHTML="");each(["top","bottom"],function(v,i){var el=t["info-"+v];el&&(DOM.show(el),each(DOM.select("*[id]",el),function(s){DOM.show(s)}),DOM.style(el,"visibility","hidden"))}),DOM.hide(this.next),DOM.hide(this.prev),len>1&&(this.prev&&(this.index>0?DOM.show(this.prev):DOM.hide(this.prev)),this.next&&(this.index<len-1?DOM.show(this.next):DOM.hide(this.next)))},change:function(n){function toAbsolute(url){var div=document.createElement("div");return div.innerHTML='<a href="'+url+'">x</a>',div.firstChild.href}function resolveMediaPath(s,absolute){return s&&s.indexOf("://")===-1&&"/"!==s.charAt(0)&&(s=JCEMediaBox.options.base+s),absolute?toAbsolute(s):s}var o,w,h,t=this,extend=JCEMediaBox.extend,each=JCEMediaBox.each,DOM=(JCEMediaBox.inArray,JCEMediaBox.DOM),Event=JCEMediaBox.Event,isIE=JCEMediaBox.isIE,DIM=JCEMediaBox.Dimensions,p={};if(n<0||n>=this.items.length)return!1;this.index=n,this.active={},DOM.show(this.container),this.loader&&DOM.show(this.loader),this.cancellink&&DOM.show(this.cancellink),this.object&&(this.object=null),this.content.innerHTML="",o=this.items[n],extend(p,this.getAddon(o.src,o.type)),delete o.params.src,extend(p,o.params);var width=p.width||JCEMediaBox.options.popup.width||0,height=p.height||JCEMediaBox.options.popup.height||0;width&&/%/.test(width)&&(width=DIM.getWidth()*parseInt(width)/100),height&&/%/.test(height)&&(height=DIM.getHeight()*parseInt(height)/100);var title=o.title||p.title||"",caption=p.caption||"";if(/::/.test(title)){var parts=title.split("::");title=JCEMediaBox.trim(parts[0]),caption=JCEMediaBox.trim(parts[1])}title=DOM.decode(title),caption=DOM.decode(caption);try{title=decodeURIComponent(title),caption=decodeURIComponent(caption)}catch(e){}switch(extend(this.active,{src:p.src||o.src,title:title,caption:caption,type:p.type||this.getType(o),params:p||{},width:width,height:height}),this.active.type){case"image":case"image/jpeg":case"image/png":case"image/gif":case"image/bmp":this.print&&this.options.print&&(this.print.style.visibility="visible"),this.img=new Image,this.img.onload=function(){return t.setup()},this.img.onerror=function(){return t.img.error=!0,t.setup()},this.img.src=this.active.src,isIE&&DOM.style(this.content,"background-color",DOM.style(this.content,"background-color")),p.width&&!p.height?this.active.height=0:p.height&&!p.width&&(this.active.width=0);break;case"flash":case"director":case"shockwave":case"mplayer":case"windowsmedia":case"quicktime":case"realaudio":case"real":case"divx":this.print&&(this.print.style.visibility="hidden"),p.src=this.active.src;var base=/:\/\//.test(p.src)?"":this.site;this.object="",w=this.width(),h=this.height();var mt=this.mediatype(this.active.type);"flash"==this.active.type&&(p.wmode="transparent",p.base=base),/(mplayer|windowsmedia)/i.test(this.active.type)&&(p.baseurl=base,isIE&&(p.url=p.src,delete p.src)),delete p.title,delete p.group,p.width=this.active.width||this.width(),p.height=this.active.height||this.height();var flash=/flash/i.test(this.active.type);/pdf/i.test(this.active.type);if(this.active.type="media",this.active.width=p.width,this.active.height=p.height,flash||isIE){this.object='<object id="jcemediabox-popup-object"',flash&&!isIE?this.object+=' type="'+mt.mediatype+'" data="'+p.src+'"':(this.object+=' classid="clsid:'+mt.classid+'"',mt.codebase&&(this.object+=' codebase="'+mt.codebase+'"'));for(n in p)""!==p[n]&&/^(id|name|style|width|height)$/.test(n)&&(t.object+=" "+n+'="'+decodeURIComponent(DOM.decode(p[n]))+'"',delete p[n]);delete p.type,this.object+=">";for(n in p)t.object+='<param name="'+n+'" value="'+decodeURIComponent(DOM.decode(p[n]))+'" />';this.object+="</object>"}else{this.object='<embed id="jcemediabox-popup-object" type="'+mt.mediatype+'"';for(n in p)""!==v&&(t.object+=" "+n+'="'+v+'"');this.object+="></embed>"}this.setup();break;case"video/x-flv":case"video/mp4":case"video/mpeg":case"video/ogg":case"audio/ogg":case"audio/mp3":case"video/webm":case"audio/webm":var type=this.active.type,tag=/video/.test(type)?"video":"audio",supportMap={video:{h264:["video/mp4","video/mpeg"],webm:["video/webm"],ogg:["video/ogg"]},audio:{mp3:["audio/mp3"],ogg:["audio/ogg"],webm:["audio/webm"]}},hasSupport=!1;if("video/x-flv"!==type)for(var n in supportMap[tag])supportMap[tag][n].indexOf(type)!==-1&&(hasSupport=support[tag]&&!!support[tag][n]);this.object="";var src=resolveMediaPath(this.active.src);if(p.poster&&(p.poster=resolveMediaPath(p.poster)),hasSupport){p.width=p.width||this.active.width,p.height=p.height||this.active.height,this.object+="<"+tag+' type="'+type+'" src="'+this.active.src+'"';for(n in p)""!==p[n]&&(/(loop|autoplay|controls|preload)$/.test(n)&&(t.object+=" "+n+'="'+n+'"'),/(id|style|poster|audio)$/.test(n)&&(t.object+=" "+n+'="'+decodeURIComponent(DOM.decode(p[n]))+'"'));this.object+="></"+tag+">"}else if(/(video|audio)\/(mp4|mpeg|x-flv|mp3)/.test(type)){var swf=JCEMediaBox.options.base+"plugins/system/jcemediabox/mediaplayer/mediaplayer.swf";this.object+='<object type="application/x-shockwave-flash" class="wf-mediaplayer-object" data="'+swf+'"',p.style=p.style||"";var flashvars=["file="+toAbsolute(src)];p.poster&&(p.style+=" background-image:url('"+p.poster+"')"),each(p,function(v,n){""!==v&&(n=n.toLowerCase(),"loop"!==n&&"autoplay"!==n&&"controls"!==n||flashvars.push(n+"="+!!v),"preload"===n&&flashvars.push(n+"="+v),"id"!==n&&"style"!==n||(v=decodeURIComponent(DOM.decode(v)),v=JCEMediaBox.trim(v),""!==v&&(t.object+=" "+n+'="'+v+'"')),"width"===n|"height"===n&&(t.object+=" "+n+'="'+v+'"'))}),this.object+=">",this.object+='<param name="movie" value="'+swf+'" />',this.object+='<param name="flashvars" value="'+flashvars.join("&")+'" />',this.object+='<param name="allowfullscreen" value="true" />',this.object+='<param name="wmode" value="transparent" />',this.object+='<i>Flash is required to play this video. <a href="http://get.adobe.com/flashplayer/" target="_blank">Get Adobe® Flash Player</a></i>',this.object+="</object>"}else DOM.addClass(this.content,"broken-media");this.active.type="media",this.setup();break;case"ajax":case"text/html":case"text/xml":this.print&&this.options.print&&(this.print.style.visibility="visible"),this.active.width=this.active.width||this.width(),this.active.height=this.active.height||this.height(),this.islocal(this.active.src)?(/tmpl=component/i.test(this.active.src)||(this.active.src+=/\?/.test(this.active.src)?"&tmpl=component":"?tmpl=component"),this.active.type="ajax"):(this.active.type="iframe",this.setup()),styles=extend(this.styles(p.styles),{display:"none"}),this.active.src=this.active.src.replace(/\&type=(ajax|text\/html|text\/xml)/,""),this.loader&&DOM.show(this.loader);var iframe=DOM.add(document.body,"iframe",{src:this.active.src,style:"display:none;"});Event.add(iframe,"load",function(){return t.ajax=DOM.add(t.content,"div",{id:"jcemediabox-popup-ajax",style:styles}),t.ajax.innerHTML=iframe.contentWindow.document.body.innerHTML,JCEMediaBox.isIE6&&DOM.style(t.ajax,"margin-right",JCEMediaBox.Dimensions.getScrollbarWidth()),JCEMediaBox.isIE7&&DOM.style(t.ajax,"padding-right",JCEMediaBox.Dimensions.getScrollbarWidth()),window.setTimeout(function(){DOM.remove(iframe)},10),t.create(t.getPopups("",t.content)),JCEMediaBox.ToolTip.create(t.content),t.setup()}),iframe.onerror=function(){return DOM.addClass(this.content,"broken-page"),t.setup()};break;case"iframe":case"pdf":case"video/youtube":case"video/vimeo":default:if(JCEMediaBox.isMobile&&"pdf"===this.active.type)return this.close(),window.open(this.active.src);this.print&&(this.print.style.visibility="hidden"),this.islocal(this.active.src)&&(/tmpl=component/i.test(this.active.src)||/\.pdf\b/i.test(this.active.src)||(this.active.src+=/\?/.test(this.active.src)?"&tmpl=component":"?tmpl=component")),this.active.src=this.protocolRelative(this.active.src),this.active.width=this.active.width||this.width(),this.active.height=this.active.height||this.height(),this.active.type="iframe",this.setup()}return!1},resize:function(w,h,x,y){return w>x?(h*=x/w,w=x,h>y&&(w*=y/h,h=y)):h>y&&(w*=y/h,h=y,w>x&&(h*=x/w,w=x)),w=Math.round(w),h=Math.round(h),{width:Math.round(w),height:Math.round(h)}},setup:function(){var w,h,t=this,DOM=JCEMediaBox.DOM,o=JCEMediaBox.options.popup;if(w=this.active.width,h=this.active.height,this.info(),"image"==this.active.type){t.img.error&&(w=300,h=300);var x=this.img.width,y=this.img.height;w&&!h?h=y*(w/x):!w&&h&&(w=x*(h/y)),w=w||x,h=h||y}if(1===parseInt(o.resize)||0===parseInt(o.resize)&&"fixed"==o.scrolling){var x=this.width(),y=this.height(),dim=this.resize(w,h,x,y);w=dim.width,h=dim.height}if(DOM.styles(this.content,{width:w,height:h}),DOM.hide(this.content),"image"==this.active.type&&(this.img.error?DOM.addClass(this.content,"broken-image"):this.content.innerHTML='<img id="jcemediabox-popup-img" src="'+this.active.src+'" title="'+this.active.title+'" />',JCEMediaBox.isIE)){var img=DOM.get("jcemediabox-popup-img");img&&DOM.style(img,"-ms-interpolation-mode","bicubic")}return this.animate()},showInfo:function(){var t=this,each=JCEMediaBox.each,DOM=JCEMediaBox.DOM,FX=JCEMediaBox.FX,DIM=JCEMediaBox.Dimensions,ss=(JCEMediaBox.Event,JCEMediaBox.options.popup.scalespeed),itop=(JCEMediaBox.options.popup.fadespeed,t["info-top"]);if(itop){each(DOM.select("*[id]",itop),function(el){/jcemediabox-popup-(next|prev)/.test(DOM.attribute(el,"id"))||DOM.show(el)});var h=DIM.outerHeight(itop);DOM.styles(itop,{"z-index":-1,top:h,visibility:"visible"}),FX.animate(itop,{top:0},ss)}t.closelink&&DOM.show(t.closelink);var ibottom=t["info-bottom"];if(ibottom){each(DOM.select("*[id]",ibottom),function(el){/jcemediabox-popup-(next|prev)/.test(DOM.attribute(el,"id"))||DOM.show(el)});var h=DIM.outerHeight(ibottom);DOM.styles(ibottom,{"z-index":-1,top:-h,visibility:"visible"}),FX.animate(ibottom,{top:0},ss)}},animate:function(){var t=this,each=JCEMediaBox.each,DOM=JCEMediaBox.DOM,FX=JCEMediaBox.FX,DIM=JCEMediaBox.Dimensions,ss=(JCEMediaBox.Event,JCEMediaBox.options.popup.scalespeed),fs=JCEMediaBox.options.popup.fadespeed,cw=DIM.outerWidth(this.content),ch=DIM.outerHeight(this.content),ih=0;each(["top","bottom"],function(v,i){var el=t["info-"+v];el&&(ih+=DIM.outerHeight(el))});var st="fixed"==DOM.style(this.page,"position")?0:DIM.getScrollTop(),top=st+this.frameHeight()/2-(ch+ih)/2;top<0&&(top=0),DOM.style(this.content,"opacity",0),FX.animate(this.body,{height:ch,top:top,width:cw},ss,function(){if("iframe"==t.active.type){var iframe=DOM.add(t.content,"iframe",{id:"jcemediabox-popup-iframe",frameborder:0,allowTransparency:!0,allowfullscreen:!0,scrolling:t.active.params.scrolling||"auto",width:"100%",height:"100%"});if(/\.pdf\b/.test(t.active.src))t.loader&&DOM.hide(t.loader);else{var _timer,win=iframe.contentWindow,doc=win.document;JCEMediaBox.isiOS&&JCEMediaBox.isWebKit&&(_timer=setInterval(function(){"complete"===doc.readyState&&(clearInterval(_timer),t.loader&&DOM.hide(t.loader))},1e3)),iframe.onload=function(){_timer&&clearInterval(_timer),t.loader&&DOM.hide(t.loader)}}iframe.setAttribute("src",t.active.src),t.iframe=iframe}else t.loader&&DOM.hide(t.loader),"media"==t.active.type&&t.object&&(t.content.innerHTML=t.object,/\.pdf\b/.test(t.active.src)&&JCEMediaBox.isiOS&&DOM.styles(DOM.get("jcemediabox-popup-object"),{height:"1000%",width:"150%"})),"ajax"==t.active.type&&DOM.show(t.ajax);DOM.show(t.content),t.content.focus(),"image"!=t.active.type||JCEMediaBox.isIE6?(DOM.style(t.content,"opacity",1),t.showInfo()):FX.animate(t.content,{opacity:1},fs,function(){t.showInfo()})})},close:function(keepopen){var t=this,each=JCEMediaBox.each,DOM=JCEMediaBox.DOM;JCEMediaBox.Dimensions,JCEMediaBox.FX,JCEMediaBox.options.popup.scalespeed;if(this.iframe&&DOM.attribute(this.iframe,"src",""),each(["img","object","iframe","ajax"],function(i,v){t[v]&&DOM.remove(t[v]),t[v]=null}),this.closelink&&DOM.hide(this.closelink),this.content.innerHTML="",!keepopen){each(["top","bottom"],function(v,i){var el=t["info-"+v];el&&DOM.hide(el)});for(var popups=this.getPopups();this.popups.length>popups.length;)this.popups.pop();DOM.remove(this.frame),this.overlay?JCEMediaBox.isIE6?(this.bind(),DOM.remove(this.page),this.page=null):JCEMediaBox.FX.animate(this.overlay,{opacity:0},JCEMediaBox.options.popup.fadespeed,function(){t.bind(),DOM.remove(t.page),t.page=null}):(DOM.remove(this.page),this.page=null)}return!1}}}(window),JCEMediaBox.Event.addUnload(function(){JCEMediaBox.Event.destroy()}),function(mediabox,undefined){if(mediabox!==undefined){var popup=mediabox.Popup,trim=mediabox.trim;popup.setAddons("flash",{flash:function(v){if(/\.swf\b/i.test(v))return{type:"flash"}},flv:function(v){if(/\.(flv|f4v)\b/i.test(v))return{type:"video/x-flv"}},metacafe:function(v){if(/metacafe(.+)\/(watch|fplayer)\/(.+)/.test(v)){var s=trim(v);return/\.swf/i.test(s)||("/"==s.charAt(s.length-1)&&(s=s.substring(0,s.length-1)),s+=".swf"),{width:400,height:345,type:"flash",attributes:{wmode:"opaque",src:s.replace(/watch/i,"fplayer")}}}},dailymotion:function(v){if(/dailymotion(.+)\/(swf|video)\//.test(v)){var s=trim(v);return s=s.replace(/_(.*)/,""),{width:420,height:339,type:"flash",wmode:"opaque",src:s.replace(/video/i,"swf")}}},googlevideo:function(v){if(/google(.+)\/(videoplay|googleplayer\.swf)\?docid=(.+)/.test(v))return{width:425,height:326,type:"flash",id:"VideoPlayback",wmode:"opaque",src:v.replace(/videoplay/g,"googleplayer.swf")}}}),popup.setAddons("iframe",{youtube:function(v){if(/youtu(\.)?be([^\/]+)?\/(.+)/.test(v))return{width:425,height:350,type:"iframe",src:v.replace(/youtu(\.)?be([^\/]+)?\/(.+)/,function(a,b,c,d){var k,query="";if(/watch\?/.test(d)){d=d.replace(/watch\?/,"");var args=JCEMediaBox.Popup.params(d);query+=args.v,delete args.v;for(k in args)query+=(/\?/.test(query)?"&":"?")+k+"="+args[k]}else query=d.replace(/embed\//,"");return b&&!c&&(c=".com"),/wmode/.test(query)||(query+=/\?/.test(query)?"&wmode=opaque":"?wmode=opaque"),"youtube"+c+"/embed/"+query}).replace(/\/\/youtube/i,"//www.youtube")}},vimeo:function(v){if(/vimeo\.com\/(video\/)?([0-9]+)/.test(v))return{width:400,height:225,type:"iframe",src:v.replace(/(player\.)?vimeo\.com\/(video\/)?([0-9]+)/,function(a,b,c,d){return b?a:"player.vimeo.com/video/"+d})}},twitvid:function(v){if(/twitvid(.+)\/(.+)/.test(v)){var s="http://www.twitvid.com/embed.php?guid=";return{width:480,height:360,type:"iframe",src:v.replace(/(.+)twitvid([^\/]+)\/(.+)/,function(a,b,c,d){return/embed\.php/.test(d)?a:s+d})}}},word:function(v){if(/\.(doc|docx|xls|xlsx|ppt|pptx)$/i.test(v)){var src=v;return mediabox.options.popup.google_viewer&&(/:\/\//.test(v)||(v=mediabox.site+v.replace("?tmpl=component","")),src="//docs.google.com/viewer?url="+encodeURIComponent(v)+"&embedded=true"),{type:"iframe",src:src}}}}),popup.setAddons("image",{image:function(v){if(v=v.split("?")[0],/\.(jpg|jpeg|png|gif|bmp|tif)$/i.test(v))return{type:"image"}},twitpic:function(v){if(/twitpic(.+)\/(.+)/.test(v))return{type:"image"}}}),popup.setAddons("pdf",{pdf:function(v){if(/\.(pdf)$/i.test(v)){var type="pdf",src=/\?#/.test(v)?v+"&view=fitH":v+"#view=fitH";return mediabox.options.popup.google_viewer&&(type="iframe",/:\/\//.test(v)||(v=mediabox.site+v.replace("?tmpl=component","")),src="//docs.google.com/viewer?url="+encodeURIComponent(v)+"&embedded=true"),{type:type,src:src}}}})}}(JCEMediaBox);PK��#]�)��system/highlight/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]#�K<<system/highlight/highlight.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.Highlight
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * System plugin to highlight terms.
 *
 * @since  2.5
 */
class PlgSystemHighlight extends JPlugin
{
	/**
	 * Method to catch the onAfterDispatch event.
	 *
	 * This is where we setup the click-through content highlighting for.
	 * The highlighting is done with JavaScript so we just
	 * need to check a few parameters and the JHtml behavior will do the rest.
	 *
	 * @return  boolean  True on success
	 *
	 * @since   2.5
	 */
	public function onAfterDispatch()
	{
		// Check that we are in the site application.
		if (JFactory::getApplication()->isClient('administrator'))
		{
			return true;
		}

		// Set the variables.
		$input = JFactory::getApplication()->input;
		$extension = $input->get('option', '', 'cmd');

		// Check if the highlighter is enabled.
		if (!JComponentHelper::getParams($extension)->get('highlight_terms', 1))
		{
			return true;
		}

		// Check if the highlighter should be activated in this environment.
		if ($input->get('tmpl', '', 'cmd') === 'component' || JFactory::getDocument()->getType() !== 'html')
		{
			return true;
		}

		// Get the terms to highlight from the request.
		$terms = $input->request->get('highlight', null, 'base64');
		$terms = $terms ? json_decode(base64_decode($terms)) : null;

		// Check the terms.
		if (empty($terms))
		{
			return true;
		}

		// Clean the terms array.
		$filter     = JFilterInput::getInstance();

		$cleanTerms = array();

		foreach ($terms as $term)
		{
			$cleanTerms[] = htmlspecialchars($filter->clean($term, 'string'));
		}

		// Activate the highlighter.
		JHtml::_('behavior.highlighter', $cleanTerms);

		// Adjust the component buffer.
		$doc = JFactory::getDocument();
		$buf = $doc->getBuffer('component');
		$buf = '<br id="highlighter-start" />' . $buf . '<br id="highlighter-end" />';
		$doc->setBuffer($buf, 'component');

		return true;
	}
}
PK��#];��f44system/highlight/highlight.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="system" method="upgrade">
	<name>plg_system_highlight</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see	LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_HIGHLIGHT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="highlight">highlight.php</filename>
	</files>
	<languages>
		<language tag="en-GB">language/en-GB/en-GB.plg_system_highlight.ini</language>
		<language tag="en-GB">language/en-GB/en-GB.plg_system_highlight.sys.ini</language>
	</languages>
</extension>
PK��#]�)��user/joomla/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]m�_�))user/joomla/joomla.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.joomla
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserHelper;
use Joomla\Registry\Registry;

/**
 * Joomla User plugin
 *
 * @since  1.5
 */
class PlgUserJoomla extends JPlugin
{
	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.2
	 */
	protected $db;

	/**
	 * Set as required the passwords fields when mail to user is set to No
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.2
	 */
	public function onContentPrepareForm($form, $data)
	{
		// Check we are manipulating a valid user form before modifying it.
		$name = $form->getName();

		if ($name === 'com_users.user')
		{
			// In case there is a validation error (like duplicated user), $data is an empty array on save.
			// After returning from error, $data is an array but populated
			if (!$data)
			{
				$data = JFactory::getApplication()->input->get('jform', array(), 'array');
			}

			if (is_array($data))
			{
				$data = (object) $data;
			}

			// Passwords fields are required when mail to user is set to No
			if (empty($data->id) && !$this->params->get('mail_to_user', 1))
			{
				$form->setFieldAttribute('password', 'required', 'true');
				$form->setFieldAttribute('password2', 'required', 'true');
			}
		}

		return true;
	}

	/**
	 * Remove all sessions for the user name
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$query = $this->db->getQuery(true)
			->delete($this->db->quoteName('#__session'))
			->where($this->db->quoteName('userid') . ' = ' . (int) $user['id']);

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		$query = $this->db->getQuery(true)
			->delete($this->db->quoteName('#__messages'))
			->where($this->db->quoteName('user_id_from') . ' = ' . (int) $user['id']);

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Utility method to act on a user after it has been saved.
	 *
	 * This method sends a registration email to new users created in the backend.
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the database.
	 * @param   string   $msg      Message.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		$mail_to_user = $this->params->get('mail_to_user', 1);

		if (!$isnew || !$mail_to_user)
		{
			return;
		}

		// TODO: Suck in the frontend registration emails here as well. Job for a rainy day.
		// The method check here ensures that if running as a CLI Application we don't get any errors
		if (method_exists($this->app, 'isClient') && !$this->app->isClient('administrator'))
		{
			return;
		}

		// Check if we have a sensible from email address, if not bail out as mail would not be sent anyway
		if (strpos($this->app->get('mailfrom'), '@') === false)
		{
			$this->app->enqueueMessage(Text::_('JERROR_SENDING_EMAIL'), 'warning');

			return;
		}

		$lang = Factory::getLanguage();
		$defaultLocale = $lang->getTag();

		/**
		 * Look for user language. Priority:
		 * 	1. User frontend language
		 * 	2. User backend language
		 */
		$userParams = new Registry($user['params']);
		$userLocale = $userParams->get('language', $userParams->get('admin_language', $defaultLocale));

		if ($userLocale !== $defaultLocale)
		{
			$lang->setLanguage($userLocale);
		}

		$lang->load('plg_user_joomla', JPATH_ADMINISTRATOR);

		// Compute the mail subject.
		$emailSubject = Text::sprintf(
			'PLG_USER_JOOMLA_NEW_USER_EMAIL_SUBJECT',
			$user['name'],
			$this->app->get('sitename')
		);

		// Compute the mail body.
		$emailBody = Text::sprintf(
			'PLG_USER_JOOMLA_NEW_USER_EMAIL_BODY',
			$user['name'],
			$this->app->get('sitename'),
			Uri::root(),
			$user['username'],
			$user['password_clear']
		);

		$res = Factory::getMailer()->sendMail(
			$this->app->get('mailfrom'),
			$this->app->get('fromname'),
			$user['email'],
			$emailSubject,
			$emailBody
		);

		if ($res === false)
		{
			$this->app->enqueueMessage(Text::_('JERROR_SENDING_EMAIL'), 'warning');
		}

		// Set application language back to default if we changed it
		if ($userLocale !== $defaultLocale)
		{
			$lang->setLanguage($defaultLocale);
		}
	}

	/**
	 * This method should handle any login logic and report back to the subject
	 *
	 * @param   array  $user     Holds the user data
	 * @param   array  $options  Array holding options (remember, autoregister, group)
	 *
	 * @return  boolean  True on success
	 *
	 * @since   1.5
	 */
	public function onUserLogin($user, $options = array())
	{
		$instance = $this->_getUser($user, $options);

		// If _getUser returned an error, then pass it back.
		if ($instance instanceof Exception)
		{
			return false;
		}

		// If the user is blocked, redirect with an error
		if ($instance->block == 1)
		{
			$this->app->enqueueMessage(Text::_('JERROR_NOLOGIN_BLOCKED'), 'warning');

			return false;
		}

		// Authorise the user based on the group information
		if (!isset($options['group']))
		{
			$options['group'] = 'USERS';
		}

		// Check the user can login.
		$result = $instance->authorise($options['action']);

		if (!$result)
		{
			$this->app->enqueueMessage(Text::_('JERROR_LOGIN_DENIED'), 'warning');

			return false;
		}

		// Mark the user as logged in
		$instance->guest = 0;

		$session = Factory::getSession();

		// Grab the current session ID
		$oldSessionId = $session->getId();

		// Fork the session
		$session->fork();

		$session->set('user', $instance);

		// Ensure the new session's metadata is written to the database
		$this->app->checkSession();

		// Purge the old session
		$query = $this->db->getQuery(true)
			->delete('#__session')
			->where($this->db->quoteName('session_id') . ' = ' . $this->db->quoteBinary($oldSessionId));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// The old session is already invalidated, don't let this block logging in
		}

		// Hit the user last visit field
		$instance->setLastVisit();

		// Add "user state" cookie used for reverse caching proxies like Varnish, Nginx etc.
		if ($this->app->isClient('site'))
		{
			$this->app->input->cookie->set(
				'joomla_user_state',
				'logged_in',
				0,
				$this->app->get('cookie_path', '/'),
				$this->app->get('cookie_domain', ''),
				$this->app->isHttpsForced(),
				true
			);
		}

		return true;
	}

	/**
	 * This method should handle any logout logic and report back to the subject
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (client, ...).
	 *
	 * @return  boolean  True on success
	 *
	 * @since   1.5
	 */
	public function onUserLogout($user, $options = array())
	{
		$my      = Factory::getUser();
		$session = Factory::getSession();

		// Make sure we're a valid user first
		if ($user['id'] == 0 && !$my->get('tmp_user'))
		{
			return true;
		}

		$sharedSessions = $this->app->get('shared_session', '0');

		// Check to see if we're deleting the current session
		if ($my->id == $user['id'] && ($sharedSessions || (!$sharedSessions && $options['clientid'] == $this->app->getClientId())))
		{
			// Hit the user last visit field
			$my->setLastVisit();

			// Destroy the php session for this user
			$session->destroy();
		}

		// Enable / Disable Forcing logout all users with same userid
		$forceLogout = $this->params->get('forceLogout', 1);

		if ($forceLogout)
		{
			$clientId = (!$sharedSessions) ? (int) $options['clientid'] : null;

			UserHelper::destroyUserSessions($user['id'], false, $clientId);
		}

		// Delete "user state" cookie used for reverse caching proxies like Varnish, Nginx etc.
		if ($this->app->isClient('site'))
		{
			$this->app->input->cookie->set('joomla_user_state', '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));
		}

		return true;
	}

	/**
	 * This method will return a user object
	 *
	 * If options['autoregister'] is true, if the user doesn't exist yet they will be created
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (remember, autoregister, group).
	 *
	 * @return  User
	 *
	 * @since   1.5
	 */
	protected function _getUser($user, $options = array())
	{
		$instance = User::getInstance();
		$id = (int) UserHelper::getUserId($user['username']);

		if ($id)
		{
			$instance->load($id);

			return $instance;
		}

		// TODO : move this out of the plugin
		$params = ComponentHelper::getParams('com_users');

		// Read the default user group option from com_users
		$defaultUserGroup = $params->get('new_usertype', $params->get('guest_usergroup', 1));

		$instance->id = 0;
		$instance->name = $user['fullname'];
		$instance->username = $user['username'];
		$instance->password_clear = $user['password_clear'];

		// Result should contain an email (check).
		$instance->email = $user['email'];
		$instance->groups = array($defaultUserGroup);

		// If autoregister is set let's register the user
		$autoregister = isset($options['autoregister']) ? $options['autoregister'] : $this->params->get('autoregister', 1);

		if ($autoregister)
		{
			if (!$instance->save())
			{
				JLog::add('Error in autoregistration for user ' . $user['username'] . '.', JLog::WARNING, 'error');
			}
		}
		else
		{
			// No existing user and autoregister off, this is a temporary user.
			$instance->set('tmp_user', true);
		}

		return $instance;
	}
}
PK��#]���user/joomla/joomla.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="user" method="upgrade">
	<name>plg_user_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>December 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_USER_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_user_joomla.ini</language>
		<language tag="en-GB">en-GB.plg_user_joomla.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="autoregister"
					type="radio"
					label="PLG_USER_JOOMLA_FIELD_AUTOREGISTER_LABEL"
					description="PLG_USER_JOOMLA_FIELD_AUTOREGISTER_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="mail_to_user"
					type="radio"
					label="PLG_USER_JOOMLA_FIELD_MAILTOUSER_LABEL"
					description="PLG_USER_JOOMLA_FIELD_MAILTOUSER_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="forceLogout"
					type="radio"
					label="PLG_USER_JOOMLA_FIELD_FORCELOGOUT_LABEL"
					description="PLG_USER_JOOMLA_FIELD_FORCELOGOUT_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��user/profile/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��i�;4;4user/profile/profile.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 *
 * @copyright   (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\String\PunycodeHelper;
use Joomla\Utilities\ArrayHelper;

/**
 * An example custom profile plugin.
 *
 * @since  1.6
 */
class PlgUserProfile extends JPlugin
{
	/**
	 * Date of birth.
	 *
	 * @var    string
	 * @since  3.1
	 */
	private $date = '';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Constructor
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An array that holds the plugin configuration
	 *
	 * @since   1.5
	 */
	public function __construct(& $subject, $config)
	{
		parent::__construct($subject, $config);
		FormHelper::addFieldPath(__DIR__ . '/field');
	}

	/**
	 * Runs on content preparation
	 *
	 * @param   string  $context  The context for the data
	 * @param   object  $data     An object containing the data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onContentPrepareData($context, $data)
	{
		// Check we are manipulating a valid form.
		if (!in_array($context, array('com_users.profile', 'com_users.user', 'com_users.registration', 'com_admin.profile')))
		{
			return true;
		}

		if (is_object($data))
		{
			$userId = isset($data->id) ? $data->id : 0;

			if (!isset($data->profile) && $userId > 0)
			{
				// Load the profile data from the database.
				$db = Factory::getDbo();
				$db->setQuery(
					'SELECT profile_key, profile_value FROM #__user_profiles'
						. ' WHERE user_id = ' . (int) $userId . " AND profile_key LIKE 'profile.%'"
						. ' ORDER BY ordering'
				);

				try
				{
					$results = $db->loadRowList();
				}
				catch (RuntimeException $e)
				{
					$this->_subject->setError($e->getMessage());

					return false;
				}

				// Merge the profile data.
				$data->profile = array();

				foreach ($results as $v)
				{
					$k = str_replace('profile.', '', $v[0]);
					$data->profile[$k] = json_decode($v[1], true);

					if ($data->profile[$k] === null)
					{
						$data->profile[$k] = $v[1];
					}
				}
			}

			if (!HTMLHelper::isRegistered('users.url'))
			{
				HTMLHelper::register('users.url', array(__CLASS__, 'url'));
			}

			if (!HTMLHelper::isRegistered('users.calendar'))
			{
				HTMLHelper::register('users.calendar', array(__CLASS__, 'calendar'));
			}

			if (!HTMLHelper::isRegistered('users.tos'))
			{
				HTMLHelper::register('users.tos', array(__CLASS__, 'tos'));
			}

			if (!HTMLHelper::isRegistered('users.dob'))
			{
				HTMLHelper::register('users.dob', array(__CLASS__, 'dob'));
			}
		}

		return true;
	}

	/**
	 * Returns an anchor tag generated from a given value
	 *
	 * @param   string  $value  URL to use
	 *
	 * @return  mixed|string
	 */
	public static function url($value)
	{
		if (empty($value))
		{
			return HTMLHelper::_('users.value', $value);
		}
		else
		{
			// Convert website URL to utf8 for display
			$value = PunycodeHelper::urlToUTF8(htmlspecialchars($value));

			if (strpos($value, 'http') === 0)
			{
				return '<a href="' . $value . '">' . $value . '</a>';
			}
			else
			{
				return '<a href="http://' . $value . '">' . $value . '</a>';
			}
		}
	}

	/**
	 * Returns html markup showing a date picker
	 *
	 * @param   string  $value  valid date string
	 *
	 * @return  mixed
	 */
	public static function calendar($value)
	{
		if (empty($value))
		{
			return HTMLHelper::_('users.value', $value);
		}
		else
		{
			return HTMLHelper::_('date', $value, null, null);
		}
	}

	/**
	 * Returns the date of birth formatted and calculated using server timezone.
	 *
	 * @param   string  $value  valid date string
	 *
	 * @return  mixed
	 */
	public static function dob($value)
	{
		if (!$value)
		{
			return '';
		}

		return HTMLHelper::_('date', $value, Text::_('DATE_FORMAT_LC1'), false);
	}

	/**
	 * Return the translated strings yes or no depending on the value
	 *
	 * @param   boolean  $value  input value
	 *
	 * @return  string
	 */
	public static function tos($value)
	{
		if ($value)
		{
			return Text::_('JYES');
		}
		else
		{
			return Text::_('JNO');
		}
	}

	/**
	 * Adds additional fields to the user editing form
	 *
	 * @param   Form   $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onContentPrepareForm(Form $form, $data)
	{
		// Check we are manipulating a valid form.
		$name = $form->getName();

		if (!in_array($name, array('com_admin.profile', 'com_users.user', 'com_users.profile', 'com_users.registration')))
		{
			return true;
		}

		// Add the registration fields to the form.
		Form::addFormPath(__DIR__ . '/profiles');
		$form->loadFile('profile');

		$fields = array(
			'address1',
			'address2',
			'city',
			'region',
			'country',
			'postal_code',
			'phone',
			'website',
			'favoritebook',
			'aboutme',
			'dob',
			'tos',
		);

		// Change fields description when displayed in frontend or backend profile editing
		$app = Factory::getApplication();

		if ($app->isClient('site') || $name === 'com_users.user' || $name === 'com_admin.profile')
		{
			$form->setFieldAttribute('address1', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('address2', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('city', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('region', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('country', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('postal_code', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('phone', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('website', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('favoritebook', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('aboutme', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('dob', 'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('tos', 'description', 'PLG_USER_PROFILE_FIELD_TOS_DESC_SITE', 'profile');
		}

		$tosArticle = $this->params->get('register_tos_article');
		$tosEnabled = $this->params->get('register-require_tos', 0);

		// We need to be in the registration form and field needs to be enabled
		if ($name !== 'com_users.registration' || !$tosEnabled)
		{
			// We only want the TOS in the registration form
			$form->removeField('tos', 'profile');
		}
		else
		{
			// Push the TOS article ID into the TOS field.
			$form->setFieldAttribute('tos', 'article', $tosArticle, 'profile');
		}

		foreach ($fields as $field)
		{
			// Case using the users manager in admin
			if ($name === 'com_users.user')
			{
				// Toggle whether the field is required.
				if ($this->params->get('profile-require_' . $field, 1) > 0)
				{
					$form->setFieldAttribute($field, 'required', ($this->params->get('profile-require_' . $field) == 2) ? 'required' : '', 'profile');
				}
				// Remove the field if it is disabled in registration and profile
				elseif ($this->params->get('register-require_' . $field, 1) == 0
					&& $this->params->get('profile-require_' . $field, 1) == 0)
				{
					$form->removeField($field, 'profile');
				}
			}
			// Case registration
			elseif ($name === 'com_users.registration')
			{
				// Toggle whether the field is required.
				if ($this->params->get('register-require_' . $field, 1) > 0)
				{
					$form->setFieldAttribute($field, 'required', ($this->params->get('register-require_' . $field) == 2) ? 'required' : '', 'profile');
				}
				else
				{
					$form->removeField($field, 'profile');
				}
			}
			// Case profile in site or admin
			elseif ($name === 'com_users.profile' || $name === 'com_admin.profile')
			{
				// Toggle whether the field is required.
				if ($this->params->get('profile-require_' . $field, 1) > 0)
				{
					$form->setFieldAttribute($field, 'required', ($this->params->get('profile-require_' . $field) == 2) ? 'required' : '', 'profile');
				}
				else
				{
					$form->removeField($field, 'profile');
				}
			}
		}

		// Drop the profile form entirely if there aren't any fields to display.
		$remainingfields = $form->getGroup('profile');

		if (!count($remainingfields))
		{
			$form->removeGroup('profile');
		}

		return true;
	}

	/**
	 * Method is called before user data is stored in the database
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isnew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return  boolean
	 *
	 * @since   3.1
	 * @throws  InvalidArgumentException on invalid date.
	 */
	public function onUserBeforeSave($user, $isnew, $data)
	{
		// Check that the date is valid.
		if (!empty($data['profile']['dob']))
		{
			try
			{
				$date = new Date($data['profile']['dob']);
				$this->date = $date->format('Y-m-d H:i:s');
			}
			catch (Exception $e)
			{
				// Throw an exception if date is not valid.
				throw new InvalidArgumentException(Text::_('PLG_USER_PROFILE_ERROR_INVALID_DOB'));
			}

			if (Date::getInstance('now') < $date)
			{
				// Throw an exception if dob is greater than now.
				throw new InvalidArgumentException(Text::_('PLG_USER_PROFILE_ERROR_INVALID_DOB_FUTURE_DATE'));
			}
		}

		// Check that the tos is checked if required ie only in registration from frontend.
		$task       = Factory::getApplication()->input->getCmd('task');
		$option     = Factory::getApplication()->input->getCmd('option');
		$tosArticle = $this->params->get('register_tos_article');
		$tosEnabled = ($this->params->get('register-require_tos', 0) == 2);

		// Check that the tos is checked.
		if ($task === 'register' && $tosEnabled && $tosArticle && $option === 'com_users' && !$data['profile']['tos'])
		{
			throw new InvalidArgumentException(Text::_('PLG_USER_PROFILE_FIELD_TOS_DESC_SITE'));
		}

		return true;
	}

	/**
	 * Saves user profile data
	 *
	 * @param   array    $data    entered user data
	 * @param   boolean  $isNew   true if this is a new user
	 * @param   boolean  $result  true if saving the user worked
	 * @param   string   $error   error message
	 *
	 * @return  boolean
	 */
	public function onUserAfterSave($data, $isNew, $result, $error)
	{
		$userId = ArrayHelper::getValue($data, 'id', 0, 'int');

		if ($userId && $result && isset($data['profile']) && count($data['profile']))
		{
			try
			{
				$db = Factory::getDbo();

				// Sanitize the date
				if (!empty($data['profile']['dob']))
				{
					$data['profile']['dob'] = $this->date;
				}

				$keys = array_keys($data['profile']);

				foreach ($keys as &$key)
				{
					$key = 'profile.' . $key;
					$key = $db->quote($key);
				}

				$query = $db->getQuery(true)
					->delete($db->quoteName('#__user_profiles'))
					->where($db->quoteName('user_id') . ' = ' . (int) $userId)
					->where($db->quoteName('profile_key') . ' IN (' . implode(',', $keys) . ')');
				$db->setQuery($query);
				$db->execute();

				$query = $db->getQuery(true)
					->select($db->quoteName('ordering'))
					->from($db->quoteName('#__user_profiles'))
					->where($db->quoteName('user_id') . ' = ' . (int) $userId);
				$db->setQuery($query);
				$usedOrdering = $db->loadColumn();

				$tuples = array();
				$order = 1;

				foreach ($data['profile'] as $k => $v)
				{
					while (in_array($order, $usedOrdering))
					{
						$order++;
					}

					$tuples[] = '(' . $userId . ', ' . $db->quote('profile.' . $k) . ', ' . $db->quote(json_encode($v)) . ', ' . ($order++) . ')';
				}

				$db->setQuery('INSERT INTO #__user_profiles VALUES ' . implode(', ', $tuples));
				$db->execute();
			}
			catch (RuntimeException $e)
			{
				$this->_subject->setError($e->getMessage());

				return false;
			}
		}

		return true;
	}

	/**
	 * Remove all user profile information for the given user ID
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0, 'int');

		if ($userId)
		{
			try
			{
				$db = Factory::getDbo();
				$db->setQuery(
					'DELETE FROM #__user_profiles WHERE user_id = ' . $userId
						. " AND profile_key LIKE 'profile.%'"
				);

				$db->execute();
			}
			catch (Exception $e)
			{
				$this->_subject->setError($e->getMessage());

				return false;
			}
		}

		return true;
	}
}
PK��#]̨h)x'x'user/profile/profile.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="user" method="upgrade">
	<name>plg_user_profile</name>
	<author>Joomla! Project</author>
	<creationDate>January 2008</creationDate>
	<copyright>(C) 2008 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_USER_PROFILE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="profile">profile.php</filename>
		<folder>profiles</folder>
		<folder>field</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_user_profile.ini</language>
		<language tag="en-GB">en-GB.plg_user_profile.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic" addfieldpath="/administrator/components/com_content/models/fields">
				<field
					name="register-require-user"
					type="spacer"
					label="PLG_USER_PROFILE_FIELD_NAME_REGISTER_REQUIRE_USER"
					class="text"
				/>

				<field
					name="register-require_address1"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS1_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS1_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_address2"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS2_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS2_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_city"
					type="list"
					label="PLG_USER_PROFILE_FIELD_CITY_LABEL"
					description="PLG_USER_PROFILE_FIELD_CITY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_region"
					type="list"
					label="PLG_USER_PROFILE_FIELD_REGION_LABEL"
					description="PLG_USER_PROFILE_FIELD_REGION_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_country"
					type="list"
					label="PLG_USER_PROFILE_FIELD_COUNTRY_LABEL"
					description="PLG_USER_PROFILE_FIELD_COUNTRY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_postal_code"
					type="list"
					label="PLG_USER_PROFILE_FIELD_POSTAL_CODE_LABEL"
					description="PLG_USER_PROFILE_FIELD_POSTAL_CODE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_phone"
					type="list"
					label="PLG_USER_PROFILE_FIELD_PHONE_LABEL"
					description="PLG_USER_PROFILE_FIELD_PHONE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_website"
					type="list"
					label="PLG_USER_PROFILE_FIELD_WEB_SITE_LABEL"
					description="PLG_USER_PROFILE_FIELD_WEB_SITE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_favoritebook"
					type="list"
					label="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_LABEL"
					description="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_aboutme"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ABOUT_ME_LABEL"
					description="PLG_USER_PROFILE_FIELD_ABOUT_ME_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_tos"
					type="list"
					label="PLG_USER_PROFILE_FIELD_TOS_LABEL"
					description="PLG_USER_PROFILE_FIELD_TOS_DESC"
					default="0"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="register_tos_article"
					type="modal_article"
					label="PLG_USER_PROFILE_FIELD_TOS_ARTICLE_LABEL"
					description="PLG_USER_PROFILE_FIELD_TOS_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>

				<field
					name="register-require_dob"
					type="list"
					label="PLG_USER_PROFILE_FIELD_DOB_LABEL"
					description="PLG_USER_PROFILE_FIELD_DOB_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="spacer1"
					type="spacer"
					hr="true"
				/>

				<field
					name="profile-require-user"
					type="spacer"
					label="PLG_USER_PROFILE_FIELD_NAME_PROFILE_REQUIRE_USER"
					class="text"
				/>

				<field
					name="profile-require_address1"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS1_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS1_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_address2"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS2_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS2_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_city"
					type="list"
					label="PLG_USER_PROFILE_FIELD_CITY_LABEL"
					description="PLG_USER_PROFILE_FIELD_CITY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_region"
					type="list"
					label="PLG_USER_PROFILE_FIELD_REGION_LABEL"
					description="PLG_USER_PROFILE_FIELD_REGION_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_country"
					type="list"
					label="PLG_USER_PROFILE_FIELD_COUNTRY_LABEL"
					description="PLG_USER_PROFILE_FIELD_COUNTRY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_postal_code"
					type="list"
					label="PLG_USER_PROFILE_FIELD_POSTAL_CODE_LABEL"
					description="PLG_USER_PROFILE_FIELD_POSTAL_CODE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_phone"
					type="list"
					label="PLG_USER_PROFILE_FIELD_PHONE_LABEL"
					description="PLG_USER_PROFILE_FIELD_PHONE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_website"
					type="list"
					label="PLG_USER_PROFILE_FIELD_WEB_SITE_LABEL"
					description="PLG_USER_PROFILE_FIELD_WEB_SITE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_favoritebook"
					type="list"
					label="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_LABEL"
					description="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_aboutme"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ABOUT_ME_LABEL"
					description="PLG_USER_PROFILE_FIELD_ABOUT_ME_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_dob"
					type="list"
					label="PLG_USER_PROFILE_FIELD_DOB_LABEL"
					description="PLG_USER_PROFILE_FIELD_DOB_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]!�*���user/profile/field/dob.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 *
 * @copyright   (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('calendar');

/**
 * Provides input for "Date of Birth" field
 *
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 * @since       3.3.7
 */
class JFormFieldDob extends JFormFieldCalendar
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.3.7
	 */
	protected $type = 'Dob';

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.3.7
	 */
	protected function getLabel()
	{
		$label = parent::getLabel();

		// Get the info text from the XML element, defaulting to empty.
		$text  = $this->element['info'] ? (string) $this->element['info'] : '';
		$text  = $this->translateLabel ? JText::_($text) : $text;

		if ($text)
		{
			$app    = JFactory::getApplication();
			$layout = new JLayoutFile('plugins.user.profile.fields.dob');
			$view   = $app->input->getString('view', '');

			// Only display the tip when editing profile
			if ($view === 'registration' || $view === 'profile' || $app->isClient('administrator'))
			{
				$layout = new JLayoutFile('plugins.user.profile.fields.dob');
				$info   = $layout->render(array('text' => $text));
				$label  = $info . $label;
			}
		}

		return $label;
	}
}
PK��#]*�user/profile/field/tos.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 *
 * @copyright   (C) 2012 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('radio');

/**
 * Provides input for TOS
 *
 * @since  2.5.5
 */
class JFormFieldTos extends JFormFieldRadio
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  2.5.5
	 */
	protected $type = 'Tos';

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   2.5.5
	 */
	protected function getLabel()
	{
		$label = '';

		if ($this->hidden)
		{
			return $label;
		}

		// Get the label text from the XML element, defaulting to the element name.
		$text = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];
		$text = $this->translateLabel ? JText::_($text) : $text;

		// Set required to true as this field is not displayed at all if not required.
		$this->required = true;

		// Build the class for the label.
		$class = !empty($this->description) ? 'hasPopover' : '';
		$class = $class . ' required';
		$class = !empty($this->labelClass) ? $class . ' ' . $this->labelClass : $class;

		// Add the opening label tag and main attributes attributes.
		$label .= '<label id="' . $this->id . '-lbl" for="' . $this->id . '" class="' . $class . '"';

		// If a description is specified, use it to build a tooltip.
		if (!empty($this->description))
		{
			$label .= ' title="' . htmlspecialchars(trim($text, ':'), ENT_COMPAT, 'UTF-8') . '"';
			$label .= ' data-content="' . htmlspecialchars(
				$this->translateDescription ? JText::_($this->description) : $this->description,
				ENT_COMPAT,
				'UTF-8'
			) . '"';

			if (JFactory::getLanguage()->isRtl())
			{
				$label .= ' data-placement="left"';
			}
		}

		$tosArticle = $this->element['article'] > 0 ? (int) $this->element['article'] : 0;

		if ($tosArticle)
		{
			JHtml::_('behavior.modal');
			JLoader::register('ContentHelperRoute', JPATH_BASE . '/components/com_content/helpers/route.php');

			$attribs          = array();
			$attribs['class'] = 'modal';
			$attribs['rel']   = '{handler: \'iframe\', size: {x:800, y:500}}';

			$db    = JFactory::getDbo();
			$query = $db->getQuery(true);
			$query->select('id, alias, catid, language')
				->from('#__content')
				->where('id = ' . $tosArticle);
			$db->setQuery($query);
			$article = $db->loadObject();

			if (JLanguageAssociations::isEnabled())
			{
				$tosAssociated = JLanguageAssociations::getAssociations('com_content', '#__content', 'com_content.item', $tosArticle);
			}

			$currentLang = JFactory::getLanguage()->getTag();

			if (isset($tosAssociated) && $currentLang !== $article->language && array_key_exists($currentLang, $tosAssociated))
			{
				$url = ContentHelperRoute::getArticleRoute(
					$tosAssociated[$currentLang]->id,
					$tosAssociated[$currentLang]->catid,
					$tosAssociated[$currentLang]->language
				);

				$link = JHtml::_('link', JRoute::_($url . '&tmpl=component'), $text, $attribs);
			}
			else
			{
				$slug = $article->alias ? ($article->id . ':' . $article->alias) : $article->id;
				$url  = ContentHelperRoute::getArticleRoute($slug, $article->catid, $article->language);
				$link = JHtml::_('link', JRoute::_($url . '&tmpl=component'), $text, $attribs);
			}
		}
		else
		{
			$link = $text;
		}

		// Add the label text and closing tag.
		$label .= '>' . $link . '<span class="star">&#160;*</span></label>';

		return $label;
	}
}
PK��#]�uH!user/profile/profiles/profile.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="profile">
		<fieldset
			name="profile"
			label="PLG_USER_PROFILE_SLIDER_LABEL"
		>
			<field
				name="address1"
				type="text"
				label="PLG_USER_PROFILE_FIELD_ADDRESS1_LABEL"
				description="PLG_USER_PROFILE_FIELD_ADDRESS1_DESC"
				id="address1"
				filter="string"
				size="30"
			/>

			<field
				name="address2"
				type="text"
				label="PLG_USER_PROFILE_FIELD_ADDRESS2_LABEL"
				description="PLG_USER_PROFILE_FIELD_ADDRESS2_DESC"
				id="address2"
				filter="string"
				size="30"
			/>

			<field
				name="city"
				type="text"
				label="PLG_USER_PROFILE_FIELD_CITY_LABEL"
				description="PLG_USER_PROFILE_FIELD_CITY_DESC"
				id="city"
				filter="string"
				size="30"
			/>

			<field
				name="region"
				type="text"
				label="PLG_USER_PROFILE_FIELD_REGION_LABEL"
				description="PLG_USER_PROFILE_FIELD_REGION_DESC"
				id="region"
				filter="string"
				size="30"
			/>

			<field
				name="country"
				type="text"
				label="PLG_USER_PROFILE_FIELD_COUNTRY_LABEL"
				description="PLG_USER_PROFILE_FIELD_COUNTRY_DESC"
				id="country"
				filter="string"
				size="30"
			/>

			<field
				name="postal_code"
				type="text"
				label="PLG_USER_PROFILE_FIELD_POSTAL_CODE_LABEL"
				description="PLG_USER_PROFILE_FIELD_POSTAL_CODE_DESC"
				id="postal_code"
				filter="string"
				size="30"
			/>

			<field
				name="phone"
				type="tel"
				label="PLG_USER_PROFILE_FIELD_PHONE_LABEL"
				description="PLG_USER_PROFILE_FIELD_PHONE_DESC"
				id="phone"
				filter="string"
				size="30"
			/>

			<field
				name="website"
				type="url"
				label="PLG_USER_PROFILE_FIELD_WEB_SITE_LABEL"
				description="PLG_USER_PROFILE_FIELD_WEB_SITE_DESC"
				id="website"
				filter="url"
				size="30"
				validate="url"
			/>

			<field
				name="favoritebook"
				type="text"
				label="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_LABEL"
				description="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_DESC"
				filter="string"
				size="30"
			/>

			<field
				name="aboutme"
				type="textarea"
				label="PLG_USER_PROFILE_FIELD_ABOUT_ME_LABEL"
				description="PLG_USER_PROFILE_FIELD_ABOUT_ME_DESC"
				cols="30"
				rows="5"
				filter="safehtml"
			/>

			<field
				name="dob"
				type="dob"
				label="PLG_USER_PROFILE_FIELD_DOB_LABEL"
				description="PLG_USER_PROFILE_FIELD_DOB_DESC"
				info="PLG_USER_PROFILE_SPACER_DOB"
				translateformat="true"
				showtime="false"
				filter="server_utc"
			/>

			<field
				name="tos"
				type="tos"
				label="PLG_USER_PROFILE_FIELD_TOS_LABEL"
				description="PLG_USER_PROFILE_FIELD_TOS_DESC"
				default="0"
				filter="integer"
				>
				<option value="1">PLG_USER_PROFILE_OPTION_AGREE</option>
				<option value="0">PLG_USER_PROFILE_OPTION_DO_NOT_AGREE</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]�)��user/contactcreator/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]6�^�kk&user/contactcreator/contactcreator.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="user" method="upgrade">
	<name>plg_user_contactcreator</name>
	<author>Joomla! Project</author>
	<creationDate>August 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTACTCREATOR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contactcreator">contactcreator.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_user_contactcreator.ini</language>
		<language tag="en-GB">en-GB.plg_user_contactcreator.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="autowebpage"
					type="text"
					label="PLG_CONTACTCREATOR_FIELD_AUTOMATIC_WEBPAGE_LABEL"
					description="PLG_CONTACTCREATOR_FIELD_AUTOMATIC_WEBPAGE_DESC"
					size="40"
				/>

				<field
					name="category"
					type="category"
					label="JCATEGORY"
					description="PLG_CONTACTCREATOR_FIELD_CATEGORY_DESC"
					extension="com_contact"
					filter="integer"
				/>

				<field
					name="autopublish"
					type="radio"
					label="PLG_CONTACTCREATOR_FIELD_AUTOPUBLISH_LABEL"
					description="PLG_CONTACTCREATOR_FIELD_AUTOPUBLISH_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]]��c��&user/contactcreator/contactcreator.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.contactcreator
 *
 * @copyright   (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Table\Table;
use Joomla\String\StringHelper;

/**
 * Class for Contact Creator
 *
 * A tool to automatically create and synchronise contacts with a user
 *
 * @since  1.6
 */
class PlgUserContactCreator extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Utility method to act on a user after it has been saved.
	 *
	 * This method creates a contact for the saved user
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the database.
	 * @param   string   $msg      Message.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		// If the user wasn't stored we don't resync
		if (!$success)
		{
			return false;
		}

		// If the user isn't new we don't sync
		if (!$isnew)
		{
			return false;
		}

		// Ensure the user id is really an int
		$user_id = (int) $user['id'];

		// If the user id appears invalid then bail out just in case
		if (empty($user_id))
		{
			return false;
		}

		$categoryId = $this->params->get('category', 0);

		if (empty($categoryId))
		{
			JError::raiseWarning('', Text::_('PLG_CONTACTCREATOR_ERR_NO_CATEGORY'));

			return false;
		}

		if ($contact = $this->getContactTable())
		{
			/**
			 * Try to pre-load a contact for this user. Apparently only possible if other plugin creates it
			 * Note: $user_id is cleaned above
			 */
			if (!$contact->load(array('user_id' => (int) $user_id)))
			{
				$contact->published = $this->params->get('autopublish', 0);
			}

			$contact->name     = $user['name'];
			$contact->user_id  = $user_id;
			$contact->email_to = $user['email'];
			$contact->catid    = $categoryId;
			$contact->access   = (int) Factory::getConfig()->get('access');
			$contact->language = '*';
			$contact->generateAlias();

			// Check if the contact already exists to generate new name & alias if required
			if ($contact->id == 0)
			{
				list($name, $alias) = $this->generateAliasAndName($contact->alias, $contact->name, $categoryId);

				$contact->name  = $name;
				$contact->alias = $alias;
			}

			$autowebpage = $this->params->get('autowebpage', '');

			if (!empty($autowebpage))
			{
				// Search terms
				$search_array = array('[name]', '[username]', '[userid]', '[email]');

				// Replacement terms, urlencoded
				$replace_array = array_map('urlencode', array($user['name'], $user['username'], $user['id'], $user['email']));

				// Now replace it in together
				$contact->webpage = str_replace($search_array, $replace_array, $autowebpage);
			}

			if ($contact->check() && $contact->store())
			{
				return true;
			}
		}

		JError::raiseWarning('', Text::_('PLG_CONTACTCREATOR_ERR_FAILED_CREATING_CONTACT'));

		return false;
	}

	/**
	 * Method to change the name & alias if alias is already in use
	 *
	 * @param   string   $alias       The alias.
	 * @param   string   $name        The name.
	 * @param   integer  $categoryId  Category identifier
	 *
	 * @return  array  Contains the modified title and alias.
	 *
	 * @since   3.2.3
	 */
	protected function generateAliasAndName($alias, $name, $categoryId)
	{
		$table = $this->getContactTable();

		while ($table->load(array('alias' => $alias, 'catid' => $categoryId)))
		{
			if ($name === $table->name)
			{
				$name = StringHelper::increment($name);
			}

			$alias = StringHelper::increment($alias, 'dash');
		}

		return array($name, $alias);
	}

	/**
	 * Get an instance of the contact table
	 *
	 * @return  ContactTableContact
	 *
	 * @since   3.2.3
	 */
	protected function getContactTable()
	{
		Table::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_contact/tables');

		return Table::getInstance('contact', 'ContactTable');
	}
}
PK��#]&���user/terms/terms/terms.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="terms">
		<fieldset
			name="terms"
			label="PLG_USER_TERMS_LABEL"
		>
			<field
				name="terms"
				type="terms"
				label="PLG_USER_TERMS_FIELD_LABEL"
				description="PLG_USER_TERMS_FIELD_DESC"
				default="0"
				filter="integer"
				required="true"
				>
				<option value="1">PLG_USER_TERMS_OPTION_AGREE</option>
				<option value="0">PLG_USER_TERMS_OPTION_DO_NOT_AGREE</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]�r
��user/terms/field/terms.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.terms
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;

FormHelper::loadFieldClass('radio');

/**
 * Provides input for privacyterms
 *
 * @since  3.9.0
 */
class JFormFieldterms extends JFormFieldRadio
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $type = 'terms';

	/**
	 * Method to get the field input markup.
	 *
	 * @return  string   The field input markup.
	 *
	 * @since   3.9.0
	 */
	protected function getInput()
	{
		// Display the message before the field
		echo $this->getRenderer('plugins.user.terms.message')->render($this->getLayoutData());

		return parent::getInput();
	}

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.9.0
	 */
	protected function getLabel()
	{
		if ($this->hidden)
		{
			return '';
		}

		return $this->getRenderer('plugins.user.terms.label')->render($this->getLayoutData());
	}

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.9.4
	 */
	protected function getLayoutData()
	{
		$data = parent::getLayoutData();

		$article = false;
		$termsArticle = $this->element['article'] > 0 ? (int) $this->element['article'] : 0;

		if ($termsArticle && Factory::getApplication()->isClient('site'))
		{
			$db    = Factory::getDbo();
			$query = $db->getQuery(true)
				->select($db->quoteName(array('id', 'alias', 'catid', 'language')))
				->from($db->quoteName('#__content'))
				->where($db->quoteName('id') . ' = ' . (int) $termsArticle);
			$db->setQuery($query);
			$article = $db->loadObject();

			JLoader::register('ContentHelperRoute', JPATH_BASE . '/components/com_content/helpers/route.php');

			if (Associations::isEnabled())
			{
				$termsAssociated = Associations::getAssociations('com_content', '#__content', 'com_content.item', $termsArticle);
			}

			$currentLang = Factory::getLanguage()->getTag();

			if (isset($termsAssociated) && $currentLang !== $article->language && array_key_exists($currentLang, $termsAssociated))
			{
				$article->link = ContentHelperRoute::getArticleRoute(
					$termsAssociated[$currentLang]->id,
					$termsAssociated[$currentLang]->catid,
					$termsAssociated[$currentLang]->language
				);
			}
			else
			{
				$slug = $article->alias ? ($article->id . ':' . $article->alias) : $article->id;
				$article->link = ContentHelperRoute::getArticleRoute($slug, $article->catid, $article->language);
			}
		}

		$extraData = array(
			'termsnote' => !empty($this->element['note']) ? $this->element['note'] : Text::_('PLG_USER_TERMS_NOTE_FIELD_DEFAULT'),
			'options' => $this->getOptions(),
			'value'   => (string) $this->value,
			'translateLabel' => $this->translateLabel,
			'translateDescription' => $this->translateDescription,
			'translateHint' => $this->translateHint,
			'termsArticle' => $termsArticle,
			'article' => $article,
		);

		return array_merge($data, $extraData);
	}
}
PK��#]�*����user/terms/terms.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="user" method="upgrade">
	<name>plg_user_terms</name>
	<author>Joomla! Project</author>
	<creationDate>June 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_USER_TERMS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="terms">terms.php</filename>
		<folder>terms</folder>
		<folder>field</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_user_terms.ini</language>
		<language tag="en-GB">en-GB.plg_user_terms.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic" addfieldpath="/administrator/components/com_content/models/fields">
				<field 
					name="terms_note" 
					type="textarea" 
					label="PLG_USER_TERMS_NOTE_FIELD_LABEL"
					description="PLG_USER_TERMS_NOTE_FIELD_DESC"
					hint="PLG_USER_TERMS_NOTE_FIELD_DEFAULT"
					class="span12"
					rows="7" 
					cols="20" 
					filter="html"
				/>	
				<field
					name="terms_article"
					type="modal_article"
					label="PLG_USER_TERMS_FIELD_ARTICLE_LABEL"
					description="PLG_USER_TERMS_FIELD_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�+''user/terms/terms.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.terms
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Utilities\ArrayHelper;

/**
 * An example custom terms and conditions plugin.
 *
 * @since  3.9.0
 */
class PlgUserTerms extends CMSPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * Constructor
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An array that holds the plugin configuration
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		FormHelper::addFieldPath(__DIR__ . '/field');
	}

	/**
	 * Adds additional fields to the user registration form
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm($form, $data)
	{
		if (!($form instanceof JForm))
		{
			$this->_subject->setError('JERROR_NOT_A_FORM');

			return false;
		}

		// Check we are manipulating a valid form - we only display this on user registration form.
		$name = $form->getName();

		if (!in_array($name, array('com_users.registration')))
		{
			return true;
		}

		// Add the terms and conditions fields to the form.
		Form::addFormPath(__DIR__ . '/terms');
		$form->loadFile('terms');

		$termsarticle = $this->params->get('terms_article');
		$termsnote    = $this->params->get('terms_note');

		// Push the terms and conditions article ID into the terms field.
		$form->setFieldAttribute('terms', 'article', $termsarticle, 'terms');
		$form->setFieldAttribute('terms', 'note', $termsnote, 'terms');
	}

	/**
	 * Method is called before user data is stored in the database
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isNew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 * @throws  InvalidArgumentException on missing required data.
	 */
	public function onUserBeforeSave($user, $isNew, $data)
	{
		// // Only check for front-end user registration
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0, 'int');

		// User already registered, no need to check it further
		if ($userId > 0)
		{
			return true;
		}

		// Check that the terms is checked if required ie only in registration from frontend.
		$option = $this->app->input->getCmd('option');
		$task   = $this->app->input->get->getCmd('task');
		$form   = $this->app->input->post->get('jform', array(), 'array');

		if ($option == 'com_users' && in_array($task, array('registration.register')) && empty($form['terms']['terms']))
		{
			throw new InvalidArgumentException(Text::_('PLG_USER_TERMS_FIELD_ERROR'));
		}

		return true;
	}

	/**
	 * Saves user profile data
	 *
	 * @param   array    $data    entered user data
	 * @param   boolean  $isNew   true if this is a new user
	 * @param   boolean  $result  true if saving the user worked
	 * @param   string   $error   error message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($data, $isNew, $result, $error)
	{
		if (!$isNew || !$result)
		{
			return true;
		}

		JLoader::register('ActionlogsModelActionlog', JPATH_ADMINISTRATOR . '/components/com_actionlogs/models/actionlog.php');
		$userId = ArrayHelper::getValue($data, 'id', 0, 'int');

		$message = array(
			'action'      => 'consent',
			'id'          => $userId,
			'title'       => $data['name'],
			'itemlink'    => 'index.php?option=com_users&task=user.edit&id=' . $userId,
			'userid'      => $userId,
			'username'    => $data['username'],
			'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $userId,
		);

		/* @var ActionlogsModelActionlog $model */
		$model = BaseDatabaseModel::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($message), 'PLG_USER_TERMS_LOGGING_CONSENT_TO_TERMS', 'plg_user_terms', $userId);
	}
}
PK��#]�)��user/terms/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��user/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��qmap/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��qmap/content/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]���Ȗ�qmap/content/content.phpnu�[���<?php

/**
* Qlue Sitemap
*
* @author Jon Boutell
* @package QMap
* @license GNU/GPL
* @version 1.0
*
* This component gathers information from various Joomla Components and 
* compiles them into a sitemap, supporting both an HTML view and an XML 
* format for search engines.
*
*/

defined('_JEXEC') or die('Restricted Access');

JLoader::import('joomla.plugin.plugin');

require_once JPATH_ROOT . '/components/com_content/helpers/route.php';

class plgQmapContent extends JPlugin {

	protected $items;

	protected function getLinks() {

		// Get a copy of the dbo
		$db =& JFactory::getDBO();

		// Get an empty query
		$query = $db->getQuery(true);

		// Select columns
		$query->select('id, catid, alias');

		// Select the table
		$query->from('#__content');

		// Conditionals
		$query->where('state = 1 OR state = -1 AND access = 1');

		$query->order('alias', 'asc');

		// Sets the query (doesn't run it)
		$db->setQuery($query);

		// Runs the query, gets the results, returns as an object
		$this->items = $db->loadObjectList();

		// Loop through each object and append a formatted link to it
		foreach ($this->items as $key => $item) {
			$this->items[$key]->link = JRoute::_(ContentHelperRoute::getArticleRoute($item->id, $item->catid));
		}

		return $this->items;

	}

	public function onNewSitemap($context) {

		return $this->getLinks();
	}
}

?>PK��#]]�qcqmap/content/content.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3" type="plugin" group="qmap" method="upgrade">
	<name>QMap - Content</name>
	<author>Jon Boutell</author>
	<creationDate>06/10/2014</creationDate>
	<authorEmail>support@qlue.info</authorEmail>
	<authorUrl>http://qlue.co.uk</authorUrl>
	<copyright>Copyright Info</copyright>
	<license>GNU/GPL</license>
	<version>1.0</version>
	<description></description>
	<files>
		<filename plugin="content">content.php</filename>
	</files>
</extension>PK��#]3V��;;qmap/menu/menu.phpnu�[���<?php

/**
* Qlue Sitemap
*
* @author Jon Boutell
* @package QMap
* @license GNU/GPL
* @version 1.0
*
* This component gathers information from various Joomla Components and 
* compiles them into a sitemap, supporting both an HTML view and an XML 
* format for search engines.
*
*/

defined('_JEXEC') or die('Restricted Access');

JLoader::import('joomla.plugin.plugin');

class plgQmapMenu extends JPlugin {

	protected $items;

	protected function getLinks() {

		$db =& JFactory::getDBO();

		$query = $db->getQuery(true);
		$query->select('link, alias, id');
		$query->from('#__menu');
		$query->where('parent_id > 0 AND published = 1 AND client_id = 0 AND type != "url" AND access = 1');
		$query->order('alias', 'asc');

		$db->setQuery($query);

		$this->items = $db->loadObjectList();

		foreach ($this->items as $key => $item) {
			$this->items[$key]->link = JRoute::_($item->link . '&Itemid=' . $item->id);
		}

		return $this->items;

	}

	public function onNewSitemap($context) {

		return $this->getLinks();

	}
}

?>PK��#]�l��qmap/menu/menu.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3" type="plugin" group="qmap" method="upgrade">
	<name>QMap - Menu</name>
	<author>Jon Boutell</author>
	<creationDate>06/10/2014</creationDate>
	<authorEmail>support@qlue.info</authorEmail>
	<authorUrl>http://qlue.co.uk</authorUrl>
	<copyright>Copyright Info</copyright>
	<license>GNU/GPL</license>
	<version>1.0</version>
	<description></description>
	<files>
		<filename plugin="menu">menu.php</filename>
	</files>
</extension>PK��#]�)��qmap/menu/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�		qmap/categories/categories.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3" type="plugin" group="qmap" method="upgrade">
	<name>QMap - Categories</name>
	<author>Jon Boutell</author>
	<creationDate>06/10/2014</creationDate>
	<authorEmail>support@qlue.info</authorEmail>
	<authorUrl>http://qlue.co.uk</authorUrl>
	<copyright>Copyright Info</copyright>
	<license>GNU/GPL</license>
	<version>1.0</version>
	<description></description>
	<files>
		<filename plugin="categories">categories.php</filename>
	</files>
</extension>PK��#]�
d{{qmap/categories/categories.phpnu�[���<?php

/**
* Qlue Sitemap
*
* @author Jon Boutell
* @package QMap
* @license GNU/GPL
* @version 1.0
*
* This component gathers information from various Joomla Components and 
* compiles them into a sitemap, supporting both an HTML view and an XML 
* format for search engines.
*
*/

defined('_JEXEC') or die('Restricted Access');

JLoader::import('joomla.plugin.plugin');

require_once JPATH_ROOT . '/components/com_content/helpers/route.php';

class plgQmapCategories extends JPlugin {

	protected $items;

	protected function getLinks() {

		$db =& JFactory::getDBO();

		$query = $db->getQuery(true);
		$query->select('id, alias');
		$query->from('#__categories');
		$query->where('level > 0 AND extension = "com_content" AND access = 1');
		$query->order('alias', 'asc');

		$db->setQuery($query);

		$this->items = $db->loadObjectList();

		foreach ($this->items as $key => $item) {
			$this->items[$key]->link = JRoute::_(ContentHelperRoute::getCategoryRoute($item->id));
		}

		return $this->items;

	}

	public function onNewSitemap($context) {

		return $this->getLinks();
	
	}
}

?>PK��#]�)��qmap/categories/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�w�R�	�	'fields/repeatable/params/repeatable.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="fields"
				type="subform"
				label="PLG_FIELDS_REPEATABLE_PARAMS_FIELDS_LABEL"
				description="PLG_FIELDS_REPEATABLE_PARAMS_FIELDS_DESC"
				multiple="true">
				<form>
					<fields>
						<fieldset>
							<field
								name="fieldname"
								type="text"
								label="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_NAME_LABEL"
								description="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_NAME_DESC"
								required="true"
							/>
							<field
								name="fieldtype"
								type="list"
								label="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_LABEL"
								description="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_DESC"
								>
								<option value="editor">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_EDITOR</option>
								<option value="media">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_MEDIA</option>
								<option value="number">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_NUMBER</option>
								<option value="text">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_TEXT</option>
								<option value="textarea">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_TEXTAREA</option>
							</field>
							<field
								name="fieldfilter"
								type="list"
								label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
								description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
								class="btn-group"
								validate="options"
								showon="fieldtype!:media,number"
								>
								<option value="0">JNO</option>
								<option
									showon="fieldtype:editor,text,textarea"
									value="raw">JLIB_FILTER_PARAMS_RAW</option>
								<option
									showon="fieldtype:editor,text,textarea"
									value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
								<option
									showon="fieldtype:editor,text,textarea"
									value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
								<option
									showon="fieldtype:text,textarea"
									value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
								<option
									showon="fieldtype:text,textarea"
									value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
								<option
									showon="fieldtype:text,textarea"
									value="float">JLIB_FILTER_PARAMS_FLOAT</option>
								<option
									showon="fieldtype:text,textarea"
									value="tel">JLIB_FILTER_PARAMS_TEL</option>
							</field>
						</fieldset>
					</fields>
				</form>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]N���� fields/repeatable/repeatable.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Repeatable
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

use Joomla\CMS\MVC\Model\BaseDatabaseModel;

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Repeatable plugin.
 *
 * @since  3.9.0
 */
class PlgFieldsRepeatable extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.9.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$readonly = false;

		if (!FieldsHelper::canEditFieldValue($field))
		{
			$readonly = true;
		}

		$fieldNode->setAttribute('type', 'subform');
		$fieldNode->setAttribute('multiple', 'true');
		$fieldNode->setAttribute('layout', 'joomla.form.field.subform.repeatable-table');

		// Build the form source
		$fieldsXml = new SimpleXMLElement('<form/>');
		$fields    = $fieldsXml->addChild('fields');

		// Get the form settings
		$formFields = $field->fieldparams->get('fields');

		// Add the fields to the form
		foreach ($formFields as $index => $formField)
		{
			$child = $fields->addChild('field');
			$child->addAttribute('name', $formField->fieldname);
			$child->addAttribute('type', $formField->fieldtype);
			$child->addAttribute('readonly', $readonly);

			if (isset($formField->fieldfilter))
			{
				$child->addAttribute('filter', $formField->fieldfilter);
			}
		}

		$fieldNode->setAttribute('formsource', $fieldsXml->asXML());

		// Return the node
		return $fieldNode;
	}

	/**
	 * The save event.
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $item     The article data
	 * @param   boolean  $isNew    Is new item
	 * @param   array    $data     The validated data
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentAfterSave($context, $item, $isNew, $data = array())
	{
		// Create correct context for category
		if ($context == 'com_categories.category')
		{
			$context = $item->get('extension') . '.categories';

			// Set the catid on the category to get only the fields which belong to this category
			$item->set('catid', $item->get('id'));
		}

		// Check the context
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return true;
		}

		// Compile the right context for the fields
		$context = $parts[0] . '.' . $parts[1];

		// Loading the fields
		$fields = FieldsHelper::getFields($context, $item);

		if (!$fields)
		{
			return true;
		}

		// Get the fields data
		$fieldsData = !empty($data['com_fields']) ? $data['com_fields'] : array();

		// Loading the model
		/** @var FieldsModelField $model */
		$model = BaseDatabaseModel::getInstance('Field', 'FieldsModel', array('ignore_request' => true));

		// Loop over the fields
		foreach ($fields as $field)
		{
			// Find the field of this type repeatable
			if ($field->type !== $this->_name)
			{
				continue;
			}

			// Determine the value if it is available from the data
			$value = key_exists($field->name, $fieldsData) ? $fieldsData[$field->name] : null;

			// Handle json encoded values
			if (!is_array($value))
			{
				$value = json_decode($value, true);
			}

			// Setting the value for the field and the item
			$model->setFieldValue($field->id, $item->get('id'), json_encode($value));
		}

		return true;
	}
}
PK��#]q.�)nn fields/repeatable/repeatable.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.8.0" group="fields" method="upgrade">
	<name>plg_fields_repeatable</name>
	<author>Joomla! Project</author>
	<creationDate>April 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_FIELDS_REPEATABLE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="repeatable">repeatable.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_fields_repeatable.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_fields_repeatable.sys.ini</language>
	</languages>
</extension>
PK��#]���??%fields/repeatable/tmpl/repeatable.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Repeatable
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

$fieldValue = $field->value;

if ($fieldValue === '')
{
	return;
}

// Get the values
$fieldValues = json_decode($fieldValue, true);

if (empty($fieldValues))
{
	return;
}

$html = '<ul>';

foreach ($fieldValues as $value)
{
	$html .= '<li>' . implode(', ', $value) . '</li>';
}

$html .= '</ul>';

echo $html;
PK��#]�)��fields/repeatable/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]{Rx  fields/list/list.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.List
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin', JPATH_ADMINISTRATOR);

/**
 * Fields list Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsList extends FieldsListPlugin
{
	/**
	 * Prepares the field
	 *
	 * @param   string    $context  The context.
	 * @param   stdclass  $item     The item.
	 * @param   stdclass  $field    The field.
	 *
	 * @return  object
	 *
	 * @since   3.9.2
	 */
	public function onCustomFieldsPrepareField($context, $item, $field)
	{
		// Check if the field should be processed
		if (!$this->isTypeSupported($field->type))
		{
			return;
		}

		// The field's rawvalue should be an array
		if (!is_array($field->rawvalue))
		{
			$field->rawvalue = (array) $field->rawvalue;
		}

		return parent::onCustomFieldsPrepareField($context, $item, $field);
	}
}
PK��#]�e�fields/list/list.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_list</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_LIST_XML_DESCRIPTION</description>
	<files>
		<filename plugin="list">list.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_list.ini</language>
		<language tag="en-GB">en-GB.plg_fields_list.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_LIST_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_LIST_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="options"
					type="subform"
					label="PLG_FIELDS_LIST_PARAMS_OPTIONS_LABEL"
					description="PLG_FIELDS_LIST_PARAMS_OPTIONS_DESC"
					layout="joomla.form.field.subform.repeatable-table"
					icon="list"
					multiple="true"
					>
					<form hidden="true" name="list_templates_modal" repeat="true">
						<field
							name="name"
							type="text"
							label="PLG_FIELDS_LIST_PARAMS_OPTIONS_NAME_LABEL"
							size="30"
						/>

						<field
							name="value"
							type="text"
							label="PLG_FIELDS_LIST_PARAMS_OPTIONS_VALUE_LABEL"
							size="30"
						/>
					</form>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]oƔ�##fields/list/params/list.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_LIST_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_LIST_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="options"
				type="subform"
				label="PLG_FIELDS_LIST_PARAMS_OPTIONS_LABEL"
				description="PLG_FIELDS_LIST_PARAMS_OPTIONS_DESC"
				layout="joomla.form.field.subform.repeatable-table"
				icon="list"
				multiple="true"
				>
				<form hidden="true" name="list_templates_modal" repeat="true">
					<field
						name="name"
						type="text"
						label="PLG_FIELDS_LIST_PARAMS_OPTIONS_NAME_LABEL"
						size="30"
					/>

					<field
						name="value"
						type="text"
						label="PLG_FIELDS_LIST_PARAMS_OPTIONS_VALUE_LABEL"
						size="30"
					/>
				</form>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]�)��fields/list/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�ӃZXXfields/list/tmpl/list.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.List
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$fieldValue = $field->value;

if ($fieldValue == '')
{
	return;
}

$fieldValue = (array) $fieldValue;
$texts      = array();
$options    = $this->getOptionsFromField($field);

foreach ($options as $value => $name)
{
	if (in_array((string) $value, $fieldValue))
	{
		$texts[] = JText::_($name);
	}
}


echo htmlentities(implode(', ', $texts));
PK��#]�)��fields/radio/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�%_iTTfields/radio/tmpl/radio.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Radio
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$value   = (array) $value;
$texts   = array();
$options = $this->getOptionsFromField($field);

foreach ($options as $optionValue => $optionText)
{
	if (in_array((string) $optionValue, $value))
	{
		$texts[] = JText::_($optionText);
	}
}


echo htmlentities(implode(', ', $texts));
PK��#]~щ�		fields/radio/radio.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_radio</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_RADIO_XML_DESCRIPTION</description>
	<files>
		<filename plugin="radio">radio.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_radio.ini</language>
		<language tag="en-GB">en-GB.plg_fields_radio.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="options"
					type="subform"
					label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_LABEL"
					description="PLG_FIELDS_RADIO_PARAMS_OPTIONS_DESC"
					layout="joomla.form.field.subform.repeatable-table"
					icon="list"
					multiple="true"
					>
					<form hidden="true" name="list_templates_modal" repeat="true">
						<field
							name="name"
							type="text"
							label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_NAME_LABEL"
							size="30"
						/>

						<field
							name="value"
							type="text"
							label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_VALUE_LABEL"
							size="30"
						/>
					</form>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]/P�#��fields/radio/radio.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Radio
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Radio Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsRadio extends FieldsListPlugin
{
}
PK��#]�ʗ���fields/radio/params/radio.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="options"
				type="subform"
				label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_LABEL"
				description="PLG_FIELDS_RADIO_PARAMS_OPTIONS_DESC"
				layout="joomla.form.field.subform.repeatable-table"
				icon="list"
				multiple="true"
				>
				<form hidden="true" name="list_templates_modal" repeat="true">
					<field
						name="name"
						type="text"
						label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_NAME_LABEL"
						size="30"
					/>

					<field
						name="value"
						type="text"
						label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_VALUE_LABEL"
						size="30"
					/>
				</form>
			</field>
		</fieldset>
	</fields>

	<fields name="params">
		<fieldset name="basic">
			<field
				name="class"
				type="textarea"
				label="COM_FIELDS_FIELD_CLASS_LABEL"
				description="COM_FIELDS_FIELD_CLASS_DESC"
				class="input-xxlarge"
				size="40"
				default="btn-group"
			/>
		</fieldset>
	</fields>
</form>
PK��#]�E!���fields/color/tmpl/color.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Color
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', $value);
}

echo htmlentities($value);
PK��#]1�?fields/color/color.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_color</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_COLOR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="color">color.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_color.ini</language>
		<language tag="en-GB">en-GB.plg_fields_color.sys.ini</language>
	</languages>
</extension>
PK��#]Y�		fields/color/color.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Color
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Color Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsColor extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('validate', 'color');

		return $fieldNode;
	}
}
PK��#]�)��fields/color/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]!��D!fields/integer/params/integer.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="first"
				type="number"
				label="PLG_FIELDS_INTEGER_PARAMS_FIRST_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_FIRST_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="last"
				type="number"
				label="PLG_FIELDS_INTEGER_PARAMS_LAST_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_LAST_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="step"
				type="number"
				label="PLG_FIELDS_INTEGER_PARAMS_STEP_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_STEP_DESC"
				filter="integer"
				size="5"
			/>
		</fieldset>
	</fields>
</form>
PK��#]�)��fields/integer/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]t�޽�fields/integer/tmpl/integer.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Integer
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', array_map('intval', $value));
}
else
{
	$value = (int) $value;
}

echo $value;
PK��#],q���fields/integer/integer.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Integer
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Integer Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsInteger extends FieldsPlugin
{
}
PK��#](�-ttfields/integer/integer.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_integer</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_INTEGER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="integer">integer.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_integer.ini</language>
		<language tag="en-GB">en-GB.plg_fields_integer.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="first"
					type="number"
					label="PLG_FIELDS_INTEGER_PARAMS_FIRST_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_FIRST_DESC"
					default="1"
					filter="integer"
					size="5"
				/>

				<field
					name="last"
					type="number"
					label="PLG_FIELDS_INTEGER_PARAMS_LAST_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_LAST_DESC"
					default="100"
					filter="integer"
					size="5"
				/>

				<field
					name="step"
					type="number"
					label="PLG_FIELDS_INTEGER_PARAMS_STEP_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_STEP_DESC"
					default="1"
					filter="integer"
					size="5"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��fields/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�ٸYvv%fields/checkboxes/tmpl/checkboxes.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Checkboxes
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$fieldValue = $field->value;

if ($fieldValue === '' || $fieldValue === null)
{
	return;
}

$fieldValue = (array) $fieldValue;
$texts      = array();
$options    = $this->getOptionsFromField($field);

foreach ($options as $value => $name)
{
	if (in_array((string) $value, $fieldValue))
	{
		$texts[] = JText::_($name);
	}
}

echo htmlentities(implode(', ', $texts));
PK��#]��b��'fields/checkboxes/params/checkboxes.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="options"
				type="subform"
				label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_LABEL"
				description="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_DESC"
				layout="joomla.form.field.subform.repeatable-table"
				icon="list"
				multiple="true"
				>
				<form hidden="true" name="list_templates_modal" repeat="true">
					<field
						name="name"
						type="text"
						label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_NAME_LABEL"
						size="30"
					/>

					<field
						name="value"
						type="text"
						label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_VALUE_LABEL"
						size="30"
					/>
				</form>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]��I�;; fields/checkboxes/checkboxes.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_checkboxes</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_CHECKBOXES_XML_DESCRIPTION</description>
	<files>
		<filename plugin="checkboxes">checkboxes.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_checkboxes.ini</language>
		<language tag="en-GB">en-GB.plg_fields_checkboxes.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="options"
					type="subform"
					label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_LABEL"
					description="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_DESC"
					layout="joomla.form.field.subform.repeatable-table"
					icon="list"
					multiple="true"
					>
					<form hidden="true" name="list_templates_modal" repeat="true">
						<field
							name="name"
							type="text"
							label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_NAME_LABEL"
							size="30"
						/>

						<field
							name="value"
							type="text"
							label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_VALUE_LABEL"
							size="30"
						/>
					</form>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]���� fields/checkboxes/checkboxes.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Checkboxes
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Checkboxes Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsCheckboxes extends FieldsListPlugin
{
}
PK��#]�)��fields/checkboxes/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�:W��fields/sql/sql.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_sql</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_SQL_XML_DESCRIPTION</description>
	<files>
		<filename plugin="sql">sql.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_sql.ini</language>
		<language tag="en-GB">en-GB.plg_fields_sql.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="query"
					type="textarea"
					label="PLG_FIELDS_SQL_PARAMS_QUERY_LABEL"
					description="PLG_FIELDS_SQL_PARAMS_QUERY_DESC"
					rows="10"
					filter="raw"
					required="true"
				/>

				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_SQL_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_SQL_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�>��NNfields/sql/sql.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Sql
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Sql Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsSql extends FieldsListPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('value_field', 'text');
		$fieldNode->setAttribute('key_field', 'value');

		return $fieldNode;
	}

	/**
	 * The save event.
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $item     The table
	 * @param   boolean  $isNew    Is new item
	 * @param   array    $data     The validated data
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentBeforeSave($context, $item, $isNew, $data = array())
	{
		// Only work on new SQL fields
		if ($context != 'com_fields.field' || !isset($item->type) || $item->type != 'sql')
		{
			return true;
		}

		// If we are not a super admin, don't let the user create or update a SQL field
		if (!JAccess::getAssetRules(1)->allow('core.admin', JFactory::getUser()->getAuthorisedGroups()))
		{
			$item->setError(JText::_('PLG_FIELDS_SQL_CREATE_NOT_POSSIBLE'));

			return false;
		}

		return true;
	}
}
PK��#]$צ?��fields/sql/params/sql.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="query"
				type="textarea"
				label="PLG_FIELDS_SQL_PARAMS_QUERY_LABEL"
				description="PLG_FIELDS_SQL_PARAMS_QUERY_DESC"
				filter="raw"
				rows="10"
				required="true"
			/>

			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_SQL_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_SQL_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]�)��fields/sql/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]���
��fields/sql/tmpl/sql.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Sql
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$db        = JFactory::getDbo();
$value     = (array) $value;
$condition = '';

foreach ($value as $v)
{
	if (!$v)
	{
		continue;
	}

	$condition .= ', ' . $db->q($v);
}

$query = $fieldParams->get('query', '');

// Run the query with a having condition because it supports aliases
$db->setQuery($query . ' having value in (' . trim($condition, ',') . ')');

try
{
	$items = $db->loadObjectlist();
}
catch (Exception $e)
{
	// If the query failed, we fetch all elements
	$db->setQuery($query);
	$items = $db->loadObjectlist();
}

$texts = array();

foreach ($items as $item)
{
	if (in_array($item->value, $value))
	{
		$texts[] = $item->text;
	}
}

echo htmlentities(implode(', ', $texts));
PK��#]�)��fields/imagelist/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�o�l��#fields/imagelist/tmpl/imagelist.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Imagelist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

if ($field->value == '')
{
	return;
}

$class = $fieldParams->get('image_class');

if ($class)
{
	// space before, so if no class sprintf below works
	$class = ' class="' . htmlentities($class, ENT_COMPAT, 'UTF-8', true) . '"';
}

$value  = (array) $field->value;
$buffer = '';

foreach ($value as $path)
{
	if (!$path || $path == '-1')
	{
		continue;
	}

	if ($fieldParams->get('directory', '/') !== '/')
	{
		$buffer .= sprintf('<img src="images/%s/%s"%s>',
			$fieldParams->get('directory'),
			htmlentities($path, ENT_COMPAT, 'UTF-8', true),
			$class
		);
	}
	else
	{
		$buffer .= sprintf('<img src="images/%s"%s>',
			htmlentities($path, ENT_COMPAT, 'UTF-8', true),
			$class
		);
	}
}

echo $buffer;
PK��#]�5�fields/imagelist/imagelist.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_imagelist</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_IMAGELIST_XML_DESCRIPTION</description>
	<files>
		<filename plugin="imagelist">imagelist.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_imagelist.ini</language>
		<language tag="en-GB">en-GB.plg_fields_imagelist.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="directory"
					type="folderlist"
					label="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_LABEL"
					description="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_DESC"
					directory="images"
					hide_none="true"
					hide_default="true"
					recursive="true"
					default="/"
					>
					<option value="/">/</option>
				</field>

				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="image_class"
					type="textarea"
					label="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_LABEL"
					description="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_DESC"
					size="40"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]%m�auufields/imagelist/imagelist.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Imagelist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Imagelist Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsImagelist extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('hide_default', 'true');
		$fieldNode->setAttribute('directory', '/images/' . $fieldNode->getAttribute('directory'));

		return $fieldNode;
	}
}
PK��#]�hE�		%fields/imagelist/params/imagelist.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="directory"
				type="folderlist"
				label="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_LABEL"
				description="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_DESC"
				directory="images"
				hide_none="true"
				hide_default="true"
				recursive="true"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="/">/</option>
			</field>

			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="image_class"
				type="textarea"
				label="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_LABEL"
				description="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_DESC"
				size="40"
			/>
		</fieldset>
	</fields>
</form>
PK��#]!p��!fields/mediajce/tmpl/mediajce.phpnu�[���<?php

/**
 * @package     JCE
 * @subpackage  Fields.MediaJce
 *
 * @copyright   Copyright (C) 2005 - 2023 Open Source Matters, Inc. All rights reserved.
 * @copyright   Copyright (C) 2020 - 2023 Ryan Demmer. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Path;
use Joomla\Utilities\ArrayHelper;
use Joomla\CMS\Helper\MediaHelper;

if (empty($field->value) || empty($field->value['media_src']))
{
	return;
}

$data = array(
    'media_src'         => '',
    'media_text'        => (string) $fieldParams->get('media_description', ''),
    'media_type'        => (string) $fieldParams->get('mediatype', 'embed'),
    'media_target'      => (string) $fieldParams->get('media_target', ''),
    'media_class'       => (string) $fieldParams->get('media_class', ''),
    'media_caption'     => '',
    'media_supported'   => array('img', 'video', 'audio', 'iframe', 'a')
);

foreach($field->value as $key => $value) {
	if (empty($value)) {
		continue;
	}
	
	$data[$key] = $value;
}

// convert to object
$data = (object) $data;

// convert legacy value
if (isset($data->src)) {
    $data->media_src = $data->src;
}

// clean Joomla 4 media stuff
if ($pos = strpos($data->media_src, '#')) {
    $data->media_src = substr($data->media_src, 0, $pos);
}

$allowable = array(
    'img'       => 'jpg,jpeg,png,gif',
    'audio'     => 'mp3,m4a,mp4a,ogg',
    'video'     => 'mp4,mp4v,mpeg,mov,webm',
    'iframe'    => 'doc,docx,odg,odp,ods,odt,pdf,ppt,pptx,txt,xcf,xls,xlsx,csv'
);

// get file extension to determine tag
$extension = File::getExt($data->media_src);
// lowercase
$extension = strtolower($extension);

// get tag from extension
array_walk($allowable, function ($values, $key) use ($extension, &$tag) {
    if (in_array($extension, explode(',', $values))) {
        $tag = $key;
    }
});

// reset media_type as link
if (false == in_array($tag, $data->media_supported)) {
    $data->media_type = 'link';
}

// reset tag type
if ($data->media_type == 'link') {
    $tag = 'a';
}

$attribs = array();

if ($data->media_class) {
    $data->media_class = preg_replace('#[^-\w ]#i', '', $data->media_class);
    $attribs['class'] = trim($data->media_class);
}

$text = '';

if ($data->media_text) {
    $text = htmlentities($data->media_text, ENT_COMPAT, 'UTF-8', true);
}

switch ($tag) {
    case 'a':
    default:
        $element = '<a href="%s"%s>%s</a>';
        break;
    case 'img':
        $element = '<img src="%s"%s alt="%s" />';

        $attribs['width']    = isset($data->media_width) ? $data->media_width : '';
        $attribs['height']   = isset($data->media_height) ? $data->media_height : '';
        $attribs['loading']  = 'lazy';
        break;
    case 'audio':
        $element = '<audio src="%s"%s></audio>';
        $attribs['controls'] = 'controls';

        if ($text) {
            $attribs['title'] = $text;
        }

        break;
    case 'video':
        $element = '<video src="%s"%s></video>';
        $attribs['controls'] = 'controls';

        $attribs['width']    = isset($data->media_width) ? $data->media_width : '';
        $attribs['height']   = isset($data->media_height) ? $data->media_height : '';

        if ($text) {
            $attribs['title'] = $text;
        }

        break;
    case 'iframe':
        $element = '<iframe src="%s"%s></iframe>';

        $attribs['frameborder'] = 0;
        $attribs['width']    = isset($data->media_width) ? $data->media_width : '100%';
        $attribs['height']   = isset($data->media_height) ? $data->media_height : '100%';
        $attribs['loading']  = 'lazy';

        if ($text) {
            $attribs['title'] = $text;
        }

        break;
}

if ($data->media_type == 'embed' && $data->media_caption) {
    $fig_attribs = '';
    $caption_class = (string) $fieldParams->get('media_caption_class', '');

    if ($caption_class) {
        $caption_class = preg_replace('#[^ \w-]#i', '', $caption_class);
        $fig_attribs = ' class="' . $caption_class . '"';
    }

    $element = '<figure' . $fig_attribs . '>' . $element . '<figcaption>' . htmlentities($data->media_caption, ENT_COMPAT, 'UTF-8', true) . '</figcaption></figure>';
}

$buffer = '';

// perform pcre replacement of common invalid characters
$path = preg_replace('#[\+\\\?\#%&<>"\'=\[\]\{\},;@\^\(\)£€$]#u', '', $data->media_src);

// trim
$path = trim($path);

// check for valid path after clean
if ($path) {

    // clean path
    $path = Path::clean($path);

    // create full path
    $fullpath = JPATH_SITE . '/' . trim($path, '/');

    // check path is valid
    if (is_file($fullpath)) {
        // set text as basename if not an image
        if (!$text && $data->media_type == "link") {
            $text = basename($path);

            if ($data->media_target) {
                if ($data->media_target == 'download') {
                    $attribs['download'] = $path;
                } else {
                    $attribs['target'] = $data->media_target;
                }
            }
        }

        $buffer .= sprintf(
            $element,
            htmlentities($path, ENT_COMPAT, 'UTF-8', true),
            ArrayHelper::toString($attribs),
            $text
        );
    }
}

echo $buffer;PK��#]v!ie
e
fields/mediajce/mediajce.phpnu�[���<?php
/**
 * @package     JCE
 * @subpackage  Fields.MediaJce
 *
 * @copyright   Copyright (C) 2005 - 2023 Open Source Matters, Inc. All rights reserved.
 * @copyright   Copyright (C) 2020 - 2023 Ryan Demmer. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Form\Form;

// use legacy import to support J3.9
JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

Form::addFieldPath(__DIR__ . '/fields');

/**
 * Fields MediaJce Plugin
 *
 * @since  2.6.27
 */
class PlgFieldsMediaJce extends FieldsPlugin
{    
    /**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   Form        $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, Form $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldParams = clone $this->params;
        $fieldParams->merge($field->fieldparams);

		// reset from parent
		$fieldNode->setAttribute('type', 'mediajce');

		if ((int) $fieldParams->get('extendedmedia', 0) == 1) {
			$fieldNode->setAttribute('type', 'extendedmedia');
		}

		return $fieldNode;
	}

	/**
	 * Before prepares the field value.
	 *
	 * @param   string     $context  The context.
	 * @param   \stdclass  $item     The item.
	 * @param   \stdclass  $field    The field.
	 *
	 * @return  void
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsBeforePrepareField($context, $item, $field)
	{
		// Check if the field should be processed by us
		if (!$this->isTypeSupported($field->type))
		{
			return;
		}

		// Check if the field value is an old (string) value
		$field->value = $this->checkValue($field->value);

		$fieldParams = clone $this->params;
        $fieldParams->merge($field->fieldparams);

		// if extendedmedia is disabled, use restricted media support
		if ((int) $fieldParams->get('extendedmedia', 0) == 0) {
			$field->value['media_supported'] = array('img', 'a');
		}
	}

	/**
	 * Before prepares the field value.
	 *
	 * @param   string  $value  The value to check.
	 *
	 * @return  array  The checked value
	 *
	 * @since   4.0.0
	 */
	private function checkValue($value)
	{
		json_decode($value);

		if (json_last_error() === JSON_ERROR_NONE)
		{
			return (array) json_decode($value, true);
		}

		return array('media_src' => $value, 'media_text' => '');
	}
}PK��#]wN�uxxfields/mediajce/mediajce.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.8" group="fields" method="upgrade">
	<name>plg_fields_mediajce</name>
	 <version>2.9.38</version>
  	<creationDate>27-06-2023</creationDate>
  	<author>Ryan Demmer</author>
  	<authorEmail>info@joomlacontenteditor.net</authorEmail>
  	<authorUrl>https://www.joomlacontenteditor.net</authorUrl>
  	<copyright>Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved</copyright>
  	<license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
	<description>PLG_FIELDS_MEDIAJCE_XML_DESCRIPTION</description>
	<files folder="plugins/fields/mediajce">
		<filename plugin="mediajce">mediajce.php</filename>
		<folder>fields</folder>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages folder="administrator/language/en-GB">
		<language tag="en-GB">en-GB.plg_fields_mediajce.ini</language>
		<language tag="en-GB">en-GB.plg_fields_mediajce.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<!--field
					name="extendedmedia"
					type="list"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_EXTENDEDMEDIA_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_EXTENDEDMEDIA_DESC"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
				</field-->
				<field
					name="mediatype"
					type="combo"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIATYPE_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIATYPE_DESC"
					layout="joomla.form.field.list-fancy-select"
				>
				<option value="images">images</option>
				<option value="media">media</option>
				<option value="documents">documents</option>
				<option value="files">files</option>
				</field>
				<field
					name="media_class"
					type="text"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_CLASS_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_CLASS_DESC"
				/>
				<field
					name="media_description"
					type="text"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_DESCRIPTION_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_DESCRIPTION_DESC"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��fields/mediajce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]&�Ao		#fields/mediajce/params/mediajce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
			<fieldset name="fieldparams">
				<field
					name="extendedmedia"
					type="list"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_EXTENDEDMEDIA_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_EXTENDEDMEDIA_DESC"
					default="0"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
				</field>
				
				<field
					name="mediatype"
					type="combo"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIATYPE_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIATYPE_DESC"
				>
				<option value="images">images</option>
				<option value="media">media</option>
				<option value="documents">documents</option>
				<option value="files">files</option>
				</field>
				<field
					name="media_class"
					type="text"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_CLASS_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_CLASS_DESC"
				/>
				<field
					name="media_description"
					type="text"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_DESCRIPTION_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_DESCRIPTION_DESC"
				/>

				<field
					name="media_target"
					type="list"
					default=""
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_DESC"
					showon="mediatype!:images"
				>
                    <option value=""></option>
					<option value="_blank">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_BLANK</option>
					<option value="_self">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_SELF</option>
                    <option value="_parent">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_PARENT</option>
                    <option value="_top">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_TOP</option>
					<option value="download">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_DOWNLOAD</option>
				</field>

				<field
					name="media_folder"
					type="text"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_FOLDER_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_FOLDER_DESC"
				/>

				<field
					name="media_caption_class"
					type="text"
					label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_CAPTION_CLASS_LABEL"
					description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_CAPTION_CLASS_DESC"
					showon="extendedmedia:1"
				/>
			</fieldset>
		</fields>
</form>
PK��#]����#fields/mediajce/fields/mediajce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="extendedmedia" label="">
		<field name="media_src" type="mediajce" label="PLG_FIELDS_MEDIAJCE_MEDIA_FILE_LABEL" />

		<field name="media_text" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_TEXT_LABEL" />
		<field name="media_width" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_WIDTH_LABEL" size="20" />
		<field name="media_height" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_HEIGHT_LABEL" />

		<field name="media_type" type="list" label="PLG_FIELDS_MEDIAJCE_MEDIA_TYPE_LABEL">
			<option value="embed">Embed</option>
			<option value="link">Link</option>
		</field>

		<field name="media_caption" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_CAPTION_LABEL" showon="media_type:embed" />

		<field name="media_target" type="list" default="" label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_LABEL" description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_DESC" showon="media_type:link">
			<option value=""></option>
			<option value="_blank">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_BLANK</option>
			<option value="_self">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_SELF</option>
			<option value="_parent">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_PARENT</option>
			<option value="_top">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_TOP</option>
			<option value="download">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_DOWNLOAD</option>
		</field>
	</fieldset>
</form>PK��#]뭘�!�!#fields/mediajce/fields/mediajce.phpnu�[���<?php
/**
 * @package     JCE
 * @subpackage  Fields.MediaJce
 *
 * @copyright   Copyright (C) 2005 - 2023 Open Source Matters, Inc. All rights reserved.
 * @copyright   Copyright (C) 2020 - 2023 Ryan Demmer. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\Field\MediaField;
use Joomla\CMS\Helper\MediaHelper;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\Registry\Registry;

/**
 * Provides a modal media selector field for the JCE File Browser
 *
 * @since  2.6.17
 */
class JFormFieldMediaJce extends MediaField
{
    /**
     * The form field type.
     *
     * @var    string
     */
    protected $type = 'MediaJce';

    /**
     * Layout to render
     *
     * @var    string
     * @since  3.5
     */
    protected $layout = 'joomla.form.field.media';

     /**
     * The mediatype for the form field.
     *
     * @var    string
     * @since  2.9.37
     */
    protected $mediatype = 'images';

    /**
     * Method to attach a JForm object to the field.
     *
     * @param   SimpleXMLElement  $element  The SimpleXMLElement object representing the `<field>` tag for the form field object.
     * @param   mixed             $value    The form field value to validate.
     * @param   string            $group    The field name group control value. This acts as an array container for the field.
     *                                      For example if the field has name="foo" and the group value is set to "bar" then the
     *                                      full field name would end up being "bar[foo]".
     *
     * @return  boolean  True on success.
     *
     * @see     JFormField::setup()
     */
    public function setup(SimpleXMLElement $element, $value, $group = null)
    {                
        // decode value if it is a string
        if (is_string($value)) {
            $json = json_decode($value, true);

            if ($json) {
                $value = isset($json['media_src']) ? $json['media_src'] : $value;
            }
        } elseif (is_array($value)) {
            $value = isset($value['media_src']) ? $value['media_src'] : '';
        }     
        
        $result = parent::setup($element, $value, $group);

        if ($result === true) {
            $this->mediatype = isset($this->element['mediatype']) ? (string) $this->element['mediatype'] : 'images';

            if (isset($this->types) && (bool) $this->element['converted'] === false) {
                $this->value = MediaHelper::getCleanMediaFieldValue($this->value);
            }
        }

        return $result;
    }

    /**
     * Get the data that is going to be passed to the layout
     *
     * @return  array
     */
    public function getLayoutData()
    {
        // component must be installed and enabled
        if (!ComponentHelper::isEnabled('com_jce')) {
            return parent::getLayoutData();
        }
        
        require_once JPATH_ADMINISTRATOR . '/components/com_jce/helpers/browser.php';

        $config = array(
            'element' => $this->id,
            'mediatype' => strtolower($this->mediatype),
            'converted' => (int) $this->element['converted'] ? true : false
        );

        $options = WFBrowserHelper::getMediaFieldOptions($config);

        $this->link = $options['url'];

        // Get the basic field data
        $data = parent::getLayoutData();

        // not a valid file browser link
        if (!$this->link) {
            return $data;
        }

        if ($this->element['media_folder']) {
            $this->link .= '&mediafolder=' . rawurlencode($this->element['media_folder']);
        }

        $extraData = array(
            'link'      => $this->link,
            'class'     => $this->element['class'] . ' input-medium wf-media-input wf-media-input-active'
        );
        
        if ($options['upload']) {
            $extraData['class'] .= ' wf-media-input-upload';
        }

        if ($config['converted']) {
            $extraData['class'] .= ' wf-media-input-converted';
        } else {
            $extraData['class'] .= ' wf-media-input-core';
        }

        // Joomla 4
        if (isset($this->types)) {            
            $mediaData = array(
                'imagesAllowedExt'    => '',
                'audiosAllowedExt'    => '',
                'videosAllowedExt'    => '',
                'documentsAllowedExt' => ''
            );

            $allowable = array('jpg,jpeg,png,apng,gif,webp', 'mp3,m4a,mp4a,ogg', 'mp4,mp4v,mpeg,mov,webm', 'doc,docx,odg,odp,ods,odt,pdf,ppt,pptx,txt,xcf,xls,xlsx,csv', 'zip,tar,gz');

            if (!empty($options['accept'])) {
                $accept = explode(',', $options['accept']);

                array_walk($allowable, function (&$item) use ($accept) {
                    $items = explode(',', $item);

                    $values = array_intersect($items, $accept);
                    $item   = empty($values) ? '' : implode(',', $values);
                });
            }

            $mediaMap = array('images', 'audio', 'video', 'documents', 'media', 'files');

            // find mediatype value if passed in values is an extension list, eg: pdf,docx
            if (!in_array($this->mediatype, $mediaMap)) {
                $accept = explode(',', $this->mediatype);

                $mediatypes = array();

                array_walk($allowable, function (&$item, $key) use ($accept, $mediaMap, &$mediatypes) {
                    $items  = explode(',', $item);
                    $values = array_intersect($items, $accept);

                    if (!empty($values)) {
                        $mediatypes[] = $mediaMap[$key];
                        $item = implode(',', $values);
                    }
                });

                if (count($mediatypes) == 2 && $mediatypes[0] == 'audio' && $mediatypes[1] == 'video') {
                    $this->mediatype = 'media';
                } else if (count($mediatypes) > 1) {
                    $this->mediatype = 'files';
                }
            }

            $mediaType = [0, 1, 2, 3];

            switch ($this->mediatype) {
                case 'images':
                    $mediaType = [0];
                    $mediaData['imagesAllowedExt'] = $allowable[0];
                    break;
                case 'audio':
                    $mediaType = [1];
                    $mediaData['audiosAllowedExt'] = $allowable[1];
                    break;
                case 'video':
                    $mediaType = [2];
                    $mediaData['videosAllowedExt'] = $allowable[2];
                    break;
                case 'media':
                    $mediaType = [1, 2];
                    $mediaData['audiosAllowedExt'] = $allowable[1];
                    $mediaData['videosAllowedExt'] = $allowable[2];
                    break;
                case 'documents':
                    $mediaType = [3];
                    $mediaData['documentsAllowedExt'] = $allowable[3];
                    break;
                case 'files':
                    $mediaType = [0, 1, 2, 3];

                    $mediaData = array(
                        'imagesAllowedExt'    => $allowable[0],
                        'audiosAllowedExt'    => $allowable[1],
                        'videosAllowedExt'    => $allowable[2],
                        'documentsAllowedExt' => $allowable[3]
                    );

                    break;
            }

            $mediaData['mediaTypes'] = implode(',', $mediaType);

            $extraData = array_merge($extraData, $mediaData);
        }

        return array_merge($data, $extraData);
    }

    /**
     * Method to post-process a field value.
     * Remove Joomla 4.2 Media Field parameters
     *
     * @param   mixed     $value  The optional value to use as the default for the field.
     * @param   string    $group  The optional dot-separated form group path on which to find the field.
     * @param   Registry  $input  An optional Registry object with the entire data set to filter
     *                            against the entire form.
     *
     * @return  mixed   The processed value.
     *
     * @since   2.9.31
     */
    public function postProcess($value, $group = null, Registry $input = null)
    {        
        if ((bool) $this->element['converted'] === false) {
            $value = MediaHelper::getCleanMediaFieldValue($value);
        }

        return $value;
    }
}PK��#]���� fields/mediajce/fields/media.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="extendedmedia" label="">
		<field name="media_src" type="mediajce" label="PLG_FIELDS_MEDIAJCE_MEDIA_FILE_LABEL" />

		<field name="media_text" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_TEXT_LABEL" />
		<field name="media_width" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_WIDTH_LABEL" size="20" />
		<field name="media_height" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_HEIGHT_LABEL" />

		<field name="media_type" type="list" label="PLG_FIELDS_MEDIAJCE_MEDIA_TYPE_LABEL">
			<option value="embed">Embed</option>
			<option value="link">Link</option>
		</field>

		<field name="media_caption" type="text" label="PLG_FIELDS_MEDIAJCE_MEDIA_CAPTION_LABEL" showon="media_type:embed" />

		<field name="media_target" type="list" default="" label="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_LABEL" description="PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_DESC" showon="media_type:link">
			<option value=""></option>
			<option value="_blank">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_BLANK</option>
			<option value="_self">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_SELF</option>
			<option value="_parent">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_PARENT</option>
			<option value="_top">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_TOP</option>
			<option value="download">PLG_FIELDS_MEDIAJCE_PARAMS_MEDIA_TARGET_DOWNLOAD</option>
		</field>
	</fieldset>
</form>PK��#]�&��$$(fields/mediajce/fields/extendedmedia.phpnu�[���<?php
/**
 * @package     JCE
 * @subpackage  Fields.MediaJce
 *
 * @copyright   Copyright (C) 2005 - 2023 Open Source Matters, Inc. All rights reserved.
 * @copyright   Copyright (C) 2020 - 2023 Ryan Demmer. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Form\Field;

// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects

use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\Registry\Registry;

/**
 * Extended the JCE Media Field with additional options
 *
 * @since  2.9.31
 */
class ExtendedMediaField extends FormField
{
    /**
     * The form field type.
     *
     * @var    string
     * @since  2.9.31
     */
    protected $type = 'ExtendedMedia';

    /**
     * Layout to render the form
     * @var  string
     */
    protected $layout = 'joomla.form.field.subform.default';

    /**
     * Method to attach a Form object to the field.
     *
     * @param   \SimpleXMLElement  $element  The SimpleXMLElement object representing the <field /> tag for the form field object.
     * @param   mixed              $value    The form field value to validate.
     * @param   string             $group    The field name group control value.
     *
     * @return  boolean  True on success.
     *
     * @since   2.9.31
     */
    public function setup(\SimpleXMLElement $element, $value, $group = null)
    {
        // convert array value to object
        $value = is_array($value) ? (object) $value : $value;

        // decode value if it is a string
        if (is_string($value)) {
            json_decode($value);

            // Check if value is a valid JSON string.
            if ($value !== '' && json_last_error() !== JSON_ERROR_NONE) {

                // check for valid file which indicates value string
                if (is_file(JPATH_ROOT . '/' . $value)) {
                    $value = '{"media_src":"' . $value . '","media_text":""}';
                } else {
                    $value = '';
                }
            }
        } elseif (
            !is_object($value)
            || !property_exists($value, 'media_src')
            || !property_exists($value, 'media_text')
        ) {
            return false;
        }

        if (!parent::setup($element, $value, $group)) {
            return false;
        }

        return true;
    }

    /**
     * Method to get the field input markup.
     *
     * @return  string  The field input markup.
     *
     * @since   2.7
     */
    protected function getInput()
    {
        $xml = file_get_contents(__DIR__ . '/mediajce.xml');

        $formname   = 'subform.' . str_replace(array('jform[', '[', ']'), array('', '.', ''), $this->name);
        $subForm     = Form::getInstance($formname, $xml, array('control' => $this->name));

        if (is_string($this->value)) {
            $this->value = json_decode($this->value);
        }

        // add data
        $subForm->bind($this->value);

        $exclude = array('name', 'type', 'label', 'description');

        foreach ($this->element->attributes() as $key => $value) {
            if (in_array($key, $exclude)) {
                continue;
            }

            $subForm->setFieldAttribute('media_src', $key, (string) $value);
        }

        $data = $this->getLayoutData();

        $data['forms'] = array($subForm);

        // Prepare renderer
        $renderer = $this->getRenderer($this->layout);

        // Render
        $html = $renderer->render($data);

        return $html;
    }

    /**
     * Method to post-process a field value.
     *
     * @param   mixed     $value  The optional value to use as the default for the field.
     * @param   string    $group  The optional dot-separated form group path on which to find the field.
     * @param   Registry  $input  An optional Registry object with the entire data set to filter
     *                            against the entire form.
     *
     * @return  mixed   The processed value.
     *
     * @since   2.9.31
     */
    public function postProcess($value, $group = null, Registry $input = null)
    {        
        $media = array('img', 'video', 'audio', 'iframe', 'a');
        
        $value->media_supported = array_filter($media, function ($tag) {
			$html = '<' . $tag . '></' . $tag . '>';
            
            if ($tag == 'img') {
				$html = '<' . $tag . '/>';
			}

            $html = ComponentHelper::filterText($html);

			return !empty($html);
 		});

        return $value;
    }
}
PK��#]�)��fields/usergrouplist/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]Mp^/��-fields/usergrouplist/params/usergrouplist.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]�����+fields/usergrouplist/tmpl/usergrouplist.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Usergrouplist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

JLoader::register('UsersHelper', JPATH_ADMINISTRATOR . '/components/com_users/helpers/users.php');

$value  = (array) $value;
$texts  = array();
$groups = UsersHelper::getGroups();

foreach ($groups as $group)
{
	if (in_array($group->value, $value))
	{
		$texts[] = htmlentities(trim($group->text, '- '));
	}
}

echo htmlentities(implode(', ', $texts));
PK��#]�	/^  &fields/usergrouplist/usergrouplist.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_usergrouplist</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_USERGROUPLIST_XML_DESCRIPTION</description>
	<files>
		<filename plugin="usergrouplist">usergrouplist.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_usergrouplist.ini</language>
		<language tag="en-GB">en-GB.plg_fields_usergrouplist.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�H���&fields/usergrouplist/usergrouplist.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Usergrouplist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Usergrouplist Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsUsergrouplist extends FieldsPlugin
{
}
PK��#]-�gW��fields/user/params/user.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<field
		name="default_value"
		type="user"
		label="PLG_FIELDS_USER_DEFAULT_VALUE_LABEL"
		description="PLG_FIELDS_USER_DEFAULT_VALUE_DESC"
	/>
	<fields name="params" label="COM_FIELDS_FIELD_BASIC_LABEL">
		<fieldset name="basic">
			<field
				name="show_on"
				type="hidden"
				filter="unset"
			/>
		</fieldset>
	</fields>
</form>
PK��#]ӸR�fields/user/user.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.User
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields User Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsUser extends FieldsPlugin
{

	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		if (JFactory::getApplication()->isClient('site'))
		{
			// The user field is not working on the front end
			return;
		}

		return parent::onCustomFieldsPrepareDom($field, $parent, $form);
	}
}
PK��#]�;pfields/user/user.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_user</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_USER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="user">user.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_user.ini</language>
		<language tag="en-GB">en-GB.plg_fields_user.sys.ini</language>
	</languages>
</extension>
PK��#]�)��fields/user/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��NH��fields/user/tmpl/user.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.User
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$value = (array) $value;
$texts = array();

foreach ($value as $userId)
{
	if (!$userId)
	{
		continue;
	}

	$user = JFactory::getUser($userId);

	if ($user)
	{
		// Use the Username
		$texts[] = $user->name;
		continue;
	}

	// Fallback and add the User ID if we get no JUser Object
	$texts[] = $userId;
}

echo htmlentities(implode(', ', $texts));
PK��#]N�"�hh!fields/textarea/tmpl/textarea.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Textarea
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

echo JHtml::_('content.prepare', $value);
PK��#]�����#fields/textarea/params/textarea.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="rows"
				type="number"
				label="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="cols"
				type="number"
				label="PLG_FIELDS_TEXTAREA_PARAMS_COLS_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_COLS_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="maxlength"
				type="number"
				label="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_DESC"
				filter="integer"
			/>

			<field
				name="filter"
				type="list"
				label="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_DESC"
				class="btn-group"
				validate="options"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="0">JNO</option>
				<option value="raw">JLIB_FILTER_PARAMS_RAW</option>
				<option value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
				<option value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
				<option value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
				<option value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
				<option value="float">JLIB_FILTER_PARAMS_FLOAT</option>
				<option value="tel">JLIB_FILTER_PARAMS_TEL</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]�)��fields/textarea/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]_��;		fields/textarea/textarea.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_textarea</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_TEXTAREA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="textarea">textarea.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_textarea.ini</language>
		<language tag="en-GB">en-GB.plg_fields_textarea.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="rows"
					type="number"
					label="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_DESC"
					default="10"
					filter="integer"
					size="5"
				/>

				<field
					name="cols"
					type="number"
					label="PLG_FIELDS_TEXTAREA_PARAMS_COLS_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_COLS_DESC"
					default="10"
					filter="integer"
					size="5"
				/>

				<field
					name="maxlength"
					type="number"
					label="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_DESC"
					filter="integer"
				/>

				<field
					name="filter"
					type="list"
					label="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_DESC"
					class="btn-group"
					default="JComponentHelper::filterText"
					validate="options"
					>
					<option value="0">JNO</option>
					<option value="raw">JLIB_FILTER_PARAMS_RAW</option>
					<option value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
					<option value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
					<option value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
					<option value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
					<option value="float">JLIB_FILTER_PARAMS_FLOAT</option>
					<option value="tel">JLIB_FILTER_PARAMS_TEL</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]��5��fields/textarea/textarea.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Textarea
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Textarea Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsTextarea extends FieldsPlugin
{
}
PK��#]�8���fields/media/media.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_media</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_MEDIA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="media">media.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_media.ini</language>
		<language tag="en-GB">en-GB.plg_fields_media.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="directory"
					type="folderlist"
					label="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_LABEL"
					description="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_DESC"
					directory="images"
					hide_none="true"
					recursive="true"
				/>

				<field
					name="preview"
					type="list"
					label="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_LABEL"
					description="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_DESC"
					class="btn-group"
					default="tooltip"
					>
					<option value="tooltip">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_TOOLTIP</option>
					<option value="true">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_INLINE</option>
					<option value="false">JNO</option>
				</field>

				<field
					name="image_class"
					type="textarea"
					label="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_LABEL"
					description="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_DESC"
					size="40"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]��oD��fields/media/tmpl/media.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Media
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

if ($field->value == '')
{
	return;
}

$class = $fieldParams->get('image_class');

if ($class)
{
	$class = ' class="' . htmlentities($class, ENT_COMPAT, 'UTF-8', true) . '"';
}

$value  = (array) $field->value;
$buffer = '';

foreach ($value as $path)
{
	if (!$path)
	{
		continue;
	}

	$buffer .= sprintf('<img src="%s"%s>',
		htmlentities($path, ENT_COMPAT, 'UTF-8', true),
		$class
	);
}

echo $buffer;
PK��#]@���fields/media/media.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Media
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Media Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsMedia extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('hide_default', 'true');

		return $fieldNode;
	}
}
PK��#]�)��fields/media/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]kb9���fields/media/params/media.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="directory"
				type="folderlist"
				label="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_LABEL"
				description="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_DESC"
				directory="images"
				hide_none="true"
				recursive="true"
			/>

			<field
				name="preview"
				type="list"
				label="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_LABEL"
				description="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_DESC"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="tooltip">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_TOOLTIP</option>
				<option value="true">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_INLINE</option>
				<option value="false">JNO</option>
			</field>

			<field
				name="image_class"
				type="textarea"
				label="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_LABEL"
				description="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_DESC"
				size="40"
			/>
		</fieldset>
	</fields>
</form>
PK��#]v��--fields/text/params/text.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="filter"
				type="list"
				label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
				description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
				class="btn-group"
				validate="options"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="0">JNO</option>
				<option value="raw">JLIB_FILTER_PARAMS_RAW</option>
				<option value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
				<option value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
				<option value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
				<option value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
				<option value="float">JLIB_FILTER_PARAMS_FLOAT</option>
				<option value="tel">JLIB_FILTER_PARAMS_TEL</option>
			</field>

			<field
				name="maxlength"
				type="number"
				label="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_LABEL"
				description="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_DESC"
				filter="integer"
			/>
		</fieldset>
	</fields>
</form>
PK��#]�)��fields/text/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�$`;;fields/text/text.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_text</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_TEXT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="text">text.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_text.ini</language>
		<language tag="en-GB">en-GB.plg_fields_text.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="filter"
					type="list"
					label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
					description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
					class="btn-group"
					default="JComponentHelper::filterText"
					validate="options"
					>
					<option value="0">JNO</option>
					<option value="raw">JLIB_FILTER_PARAMS_RAW</option>
					<option value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
					<option value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
					<option value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
					<option value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
					<option value="float">JLIB_FILTER_PARAMS_FLOAT</option>
					<option value="tel">JLIB_FILTER_PARAMS_TEL</option>
				</field>

				<field
					name="maxlength"
					type="number"
					label="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_LABEL"
					description="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_DESC"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�Cr��fields/text/text.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Text
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Text Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsText extends FieldsPlugin
{
}
PK��#]ϫ���fields/text/tmpl/text.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Text
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', $value);
}

echo htmlentities($value);
PK��#]3\��fields/editor/params/editor.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="buttons"
				type="list"
				label="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_LABEL"
				description="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_DESC"
				filter="integer"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="hide"
				type="plugins"
				label="PLG_FIELDS_EDITOR_PARAMS_BUTTONS_HIDE_LABEL"
				description="JGLOBAL_SELECT_SOME_OPTIONS"
				folder="editors-xtd"
				multiple="true"
			/>

			<field
				name="width"
				type="text"
				label="PLG_FIELDS_EDITOR_PARAMS_WIDTH_LABEL"
				description="PLG_FIELDS_EDITOR_PARAMS_WIDTH_DESC"
				size="5"
			/>

			<field
				name="height"
				type="text"
				label="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_LABEL"
				description="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_DESC"
				size="5"
			/>

			<field
				name="filter"
				type="list"
				label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
				description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
				class="btn-group"
				validate="options"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="0">JNO</option>
				<option value="raw">JLIB_FILTER_PARAMS_RAW</option>
				<option value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
				<option value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]����fffields/editor/tmpl/editor.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Editor
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

echo JHtml::_('content.prepare', $value);
PK��#]���
A	A	fields/editor/editor.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_editor</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_EDITOR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="editor">editor.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_editor.ini</language>
		<language tag="en-GB">en-GB.plg_fields_editor.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="buttons"
					type="radio"
					label="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="hide"
					type="plugins"
					label="PLG_FIELDS_EDITOR_PARAMS_BUTTONS_HIDE_LABEL"
					description="JGLOBAL_SELECT_SOME_OPTIONS"
					folder="editors-xtd"
					multiple="true"
				/>

				<field
					name="width"
					type="text"
					label="PLG_FIELDS_EDITOR_PARAMS_WIDTH_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_WIDTH_DESC"
					default="100%"
					size="5"
				/>

				<field
					name="height"
					type="text"
					label="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_DESC"
					default="250px"
					size="5"
				/>

				<field
					name="filter"
					type="list"
					label="PLG_FIELDS_EDITOR_PARAMS_FILTER_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_FILTER_DESC"
					class="btn-group"
					default="JComponentHelper::filterText"
					validate="options"
					>
					<option value="0">JNO</option>
					<option value="raw">JLIB_FILTER_PARAMS_RAW</option>
					<option value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
					<option value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]Ƌ�O��fields/editor/editor.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Editor
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Editor Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsEditor extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('buttons', $field->fieldparams->get('buttons', $this->params->get('buttons', 0)) ? 'true' : 'false');
		$fieldNode->setAttribute('hide', implode(',', $field->fieldparams->get('hide', array())));

		return $fieldNode;
	}
}
PK��#]�)��fields/editor/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��ZEDDfields/calendar/calendar.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_calendar</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_CALENDAR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="calendar">calendar.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_calendar.ini</language>
		<language tag="en-GB">en-GB.plg_fields_calendar.sys.ini</language>
	</languages>
</extension>
PK��#]��m��fields/calendar/calendar.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Calendar
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields Calendar Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsCalendar extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		// Set filter to user UTC
		$fieldNode->setAttribute('filter', 'USER_UTC');

		// Set field to use translated formats
		$fieldNode->setAttribute('translateformat', '1');
		$fieldNode->setAttribute('showtime', $field->fieldparams->get('showtime', 0) ? 'true' : 'false');

		return $fieldNode;
	}
}
PK��#]����#fields/calendar/params/calendar.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="showtime"
				type="radio"
				label="PLG_FIELDS_CALENDAR_PARAMS_SHOWTIME_LABEL"
				description="PLG_FIELDS_CALENDAR_PARAMS_SHOWTIME_DESC"
				class="btn-group btn-group-yesno"
				default="0"
				filter="integer"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]�ӫ�$$!fields/calendar/tmpl/calendar.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Calendar
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', $value);
}

$formatString =  $field->fieldparams->get('showtime', 0) ? 'DATE_FORMAT_LC5' : 'DATE_FORMAT_LC4';

echo htmlentities(JHtml::_('date', $value, JText::_($formatString)));
PK��#]�)��fields/calendar/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��fields/url/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�6��fields/url/url.xmlnu�[���<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0" group="fields" method="upgrade">
	<name>plg_fields_url</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_URL_XML_DESCRIPTION</description>
	<files>
		<filename plugin="url">url.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_fields_url.ini</language>
		<language tag="en-GB">en-GB.plg_fields_url.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="schemes"
					type="list"
					label="PLG_FIELDS_URL_PARAMS_SCHEMES_LABEL"
					description="PLG_FIELDS_URL_PARAMS_SCHEMES_DESC"
					multiple="true"
					>
					<option value="http">HTTP</option>
					<option value="https">HTTPS</option>
					<option value="ftp">FTP</option>
					<option value="ftps">FTPS</option>
					<option value="file">FILE</option>
					<option value="mailto">MAILTO</option>
				</field>

				<field
					name="relative"
					type="radio"
					label="PLG_FIELDS_URL_PARAMS_RELATIVE_LABEL"
					description="PLG_FIELDS_URL_PARAMS_RELATIVE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]D��ddfields/url/url.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.URL
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin', JPATH_ADMINISTRATOR);

/**
 * Fields URL Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsUrl extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm $form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('validate', 'url');

		if (! $fieldNode->getAttribute('relative'))
		{
			$fieldNode->removeAttribute('relative');
		}

		return $fieldNode;
	}
}
PK��#]`�o�ppfields/url/params/url.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="schemes"
				type="list"
				label="PLG_FIELDS_URL_PARAMS_SCHEMES_LABEL"
				description="PLG_FIELDS_URL_PARAMS_SCHEMES_DESC"
				multiple="true"
				>
				<option value="http">HTTP</option>
				<option value="https">HTTPS</option>
				<option value="ftp">FTP</option>
				<option value="ftps">FTPS</option>
				<option value="file">FILE</option>
				<option value="mailto">MAILTO</option>
			</field>

			<field
				name="relative"
				type="list"
				label="PLG_FIELDS_URL_PARAMS_RELATIVE_LABEL"
				description="PLG_FIELDS_URL_PARAMS_RELATIVE_DESC"
				filter="integer"
				>
				<option value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
PK��#]z��""fields/url/tmpl/url.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.URL
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$attributes = '';

if (!JUri::isInternal($value))
{
	$attributes = ' rel="nofollow noopener noreferrer" target="_blank"';
}

echo sprintf('<a href="%s"%s>%s</a>',
	htmlspecialchars($value),
	$attributes,
	htmlspecialchars($value)
);
PK��#]�)��	.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��editors-xtd/module/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]����editors-xtd/module/module.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_module</name>
	<author>Joomla! Project</author>
	<creationDate>October 2015</creationDate>
	<copyright>(C) 2015 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.5.0</version>
	<description>PLG_MODULE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="module">module.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_module.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_module.sys.ini</language>
	</languages>
</extension>
PK��#]�C���editors-xtd/module/module.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.module
 *
 * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Module button
 *
 * @since  3.5
 */
class PlgButtonModule extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.5
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   3.5
	 */
	public function onDisplay($name)
	{
		/*
		 * Use the built-in element view to select the module.
		 * Currently uses blank class.
		 */
		$user  = JFactory::getUser();

		if ($user->authorise('core.create', 'com_modules')
			|| $user->authorise('core.edit', 'com_modules')
			|| $user->authorise('core.edit.own', 'com_modules'))
		{
			$link = 'index.php?option=com_modules&amp;view=modules&amp;layout=modal&amp;tmpl=component&amp;editor='
					. $name . '&amp;' . JSession::getFormToken() . '=1';

			$button          = new JObject;
			$button->modal   = true;
			$button->class   = 'btn';
			$button->link    = $link;
			$button->text    = JText::_('PLG_MODULE_BUTTON_MODULE');
			$button->name    = 'file-add';
			$button->options = "{handler: 'iframe', size: {x: 800, y: 500}}";

			return $button;
		}
	}
}
PK��#]�)��editors-xtd/article/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�k\�editors-xtd/article/article.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_article</name>
	<author>Joomla! Project</author>
	<creationDate>October 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_ARTICLE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="article">article.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_article.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_article.sys.ini</language>
	</languages>
</extension>
PK��#]�"EOOeditors-xtd/article/article.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.article
 *
 * @copyright   (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Article button
 *
 * @since  1.5
 */
class PlgButtonArticle extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   1.5
	 */
	public function onDisplay($name)
	{
		$input = JFactory::getApplication()->input;
		$user  = JFactory::getUser();

		// Can create in any category (component permission) or at least in one category
		$canCreateRecords = $user->authorise('core.create', 'com_content')
			|| count($user->getAuthorisedCategories('com_content', 'core.create')) > 0;

		// Instead of checking edit on all records, we can use **same** check as the form editing view
		$values = (array) JFactory::getApplication()->getUserState('com_content.edit.article.id');
		$isEditingRecords = count($values);

		// This ACL check is probably a double-check (form view already performed checks)
		$hasAccess = $canCreateRecords || $isEditingRecords;
		if (!$hasAccess)
		{
			return;
		}

		$link = 'index.php?option=com_content&amp;view=articles&amp;layout=modal&amp;tmpl=component&amp;'
			. JSession::getFormToken() . '=1&amp;editor=' . $name;

		$button = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    = JText::_('PLG_ARTICLE_BUTTON_ARTICLE');
		$button->name    = 'file-add';
		$button->options = "{handler: 'iframe', size: {x: 800, y: 500}}";

		return $button;
	}
}
PK��#]|�/4}}editors-xtd/image/image.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.image
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Image buton
 *
 * @since  1.5
 */
class PlgButtonImage extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button.
	 *
	 * @param   string   $name    The name of the button to display.
	 * @param   string   $asset   The name of the asset being edited.
	 * @param   integer  $author  The id of the author owning the asset being edited.
	 *
	 * @return  JObject  The button options as JObject or false if not allowed
	 *
	 * @since   1.5
	 */
	public function onDisplay($name, $asset, $author)
	{
		$app       = JFactory::getApplication();
		$user      = JFactory::getUser();
		$extension = $app->input->get('option');

		// For categories we check the extension (ex: component.section)
		if ($extension === 'com_categories')
		{
			$parts     = explode('.', $app->input->get('extension', 'com_content'));
			$extension = $parts[0];
		}

		$asset = $asset !== '' ? $asset : $extension;

		if ($user->authorise('core.edit', $asset)
			|| $user->authorise('core.create', $asset)
			|| (count($user->getAuthorisedCategories($asset, 'core.create')) > 0)
			|| ($user->authorise('core.edit.own', $asset) && $author === $user->id)
			|| (count($user->getAuthorisedCategories($extension, 'core.edit')) > 0)
			|| (count($user->getAuthorisedCategories($extension, 'core.edit.own')) > 0 && $author === $user->id))
		{
			$link = 'index.php?option=com_media&amp;view=images&amp;tmpl=component&amp;e_name=' . $name . '&amp;asset=' . $asset . '&amp;author=' . $author;

			$button = new JObject;
			$button->modal   = true;
			$button->class   = 'btn';
			$button->link    = $link;
			$button->text    = JText::_('PLG_IMAGE_BUTTON_IMAGE');
			$button->name    = 'pictures';
			$button->options = "{handler: 'iframe', size: {x: 800, y: 500}}";

			return $button;
		}

		return false;
	}
}
PK��#]�)��editors-xtd/image/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�6�editors-xtd/image/image.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_image</name>
	<author>Joomla! Project</author>
	<creationDate>August 2004</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_IMAGE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="image">image.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_image.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_image.sys.ini</language>
	</languages>
</extension>
PK��#]�RL$$editors-xtd/contact/contact.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_contact</name>
	<author>Joomla! Project</author>
	<creationDate>October 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_EDITORS-XTD_CONTACT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contact">contact.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_contact.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_contact.sys.ini</language>
	</languages>
</extension>
PK��#]�)��editors-xtd/contact/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]K����editors-xtd/contact/contact.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.contact
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Contact button
 *
 * @since  3.7.0
 */
class PlgButtonContact extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   3.7.0
	 */
	public function onDisplay($name)
	{
		$user  = JFactory::getUser();

		if ($user->authorise('core.create', 'com_contact')
			|| $user->authorise('core.edit', 'com_contact')
			|| $user->authorise('core.edit.own', 'com_contact'))
		{
			// The URL for the contacts list
			$link = 'index.php?option=com_contact&amp;view=contacts&amp;layout=modal&amp;tmpl=component&amp;'
				. JSession::getFormToken() . '=1&amp;editor=' . $name;

			$button          = new JObject;
			$button->modal   = true;
			$button->class   = 'btn';
			$button->link    = $link;
			$button->text    = JText::_('PLG_EDITORS-XTD_CONTACT_BUTTON_CONTACT');
			$button->name    = 'address';
			$button->options = "{handler: 'iframe', size: {x: 800, y: 500}}";

			return $button;
		}
	}
}
PK��#]�)��editors-xtd/readmore/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]���GG!editors-xtd/readmore/readmore.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.readmore
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Readmore button
 *
 * @since  1.5
 */
class PlgButtonReadmore extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Readmore button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   1.5
	 */
	public function onDisplay($name)
	{
		JHtml::_('script', 'com_content/admin-article-readmore.min.js', array('version' => 'auto', 'relative' => true));

		// Pass some data to javascript
		JFactory::getDocument()->addScriptOptions(
			'xtd-readmore',
			array(
				'editor' => $this->_subject->getContent($name),
				'exists' => JText::_('PLG_READMORE_ALREADY_EXISTS', true),
			)
		);

		$button = new JObject;
		$button->modal   = false;
		$button->class   = 'btn';
		$button->onclick = 'insertReadmore(\'' . $name . '\');return false;';
		$button->text    = JText::_('PLG_READMORE_BUTTON_READMORE');
		$button->name    = 'arrow-down';
		$button->link    = '#';

		return $button;
	}
}
PK��#]��bi!editors-xtd/readmore/readmore.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_readmore</name>
	<author>Joomla! Project</author>
	<creationDate>March 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_READMORE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="readmore">readmore.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_readmore.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_readmore.sys.ini</language>
	</languages>
</extension>
PK��#]<^�I..#editors-xtd/pagebreak/pagebreak.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_pagebreak</name>
	<author>Joomla! Project</author>
	<creationDate>August 2004</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_EDITORSXTD_PAGEBREAK_XML_DESCRIPTION</description>
	<files>
		<filename plugin="pagebreak">pagebreak.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_pagebreak.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_pagebreak.sys.ini</language>
	</languages>
</extension>
PK��#]Rk����#editors-xtd/pagebreak/pagebreak.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.pagebreak
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Pagebreak button
 *
 * @since  1.5
 */
class PlgButtonPagebreak extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   1.5
	 */
	public function onDisplay($name)
	{
		$input = JFactory::getApplication()->input;
		$user  = JFactory::getUser();

		// Can create in any category (component permission) or at least in one category
		$canCreateRecords = $user->authorise('core.create', 'com_content')
			|| count($user->getAuthorisedCategories('com_content', 'core.create')) > 0;

		// Instead of checking edit on all records, we can use **same** check as the form editing view
		$values = (array) JFactory::getApplication()->getUserState('com_content.edit.article.id');
		$isEditingRecords = count($values);

		// This ACL check is probably a double-check (form view already performed checks)
		$hasAccess = $canCreateRecords || $isEditingRecords;
		if (!$hasAccess)
		{
			return;
		}

		JFactory::getDocument()->addScriptOptions('xtd-pagebreak', array('editor' => $name));
		$link = 'index.php?option=com_content&amp;view=article&amp;layout=pagebreak&amp;tmpl=component&amp;e_name=' . $name;

		$button          = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    = JText::_('PLG_EDITORSXTD_PAGEBREAK_BUTTON_PAGEBREAK');
		$button->name    = 'copy';
		$button->options = "{handler: 'iframe', size: {x: 500, y: 300}}";

		return $button;
	}
}
PK��#]�)��editors-xtd/pagebreak/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��editors-xtd/menu/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��=editors-xtd/menu/menu.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_menu</name>
	<author>Joomla! Project</author>
	<creationDate>August 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_EDITORS-XTD_MENU_XML_DESCRIPTION</description>
	<files>
		<filename plugin="menu">menu.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_menu.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_menu.sys.ini</language>
	</languages>
</extension>
PK��#]�䮉XXeditors-xtd/menu/menu.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.menu
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor menu button
 *
 * @since  3.7.0
 */
class PlgButtonMenu extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @since  3.7.0
	 * @return array
	 */
	public function onDisplay($name)
	{
		/*
		 * Use the built-in element view to select the menu item.
		 * Currently uses blank class.
		 */
		$user  = JFactory::getUser();

		if ($user->authorise('core.create', 'com_menus')
			|| $user->authorise('core.edit', 'com_menus'))
		{
		$link = 'index.php?option=com_menus&amp;view=items&amp;layout=modal&amp;tmpl=component&amp;'
			. JSession::getFormToken() . '=1&amp;editor=' . $name;

		$button          = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    = JText::_('PLG_EDITORS-XTD_MENU_BUTTON_MENU');
		$button->name    = 'share-alt';
		$button->options = "{handler: 'iframe', size: {x: 800, y: 500}}";

		return $button;
		}
	}
}
PK��#]�)��editors-xtd/fields/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]����editors-xtd/fields/fields.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.fields
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Fields button
 *
 * @since  3.7.0
 */
class PlgButtonFields extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since  3.7.0
	 */
	public function onDisplay($name)
	{
		// Check if com_fields is enabled
		if (!JComponentHelper::isEnabled('com_fields'))
		{
			return;
		}

		// Register FieldsHelper
		JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');

		// Guess the field context based on view.
		$jinput = JFactory::getApplication()->input;
		$context = $jinput->get('option') . '.' . $jinput->get('view');

		// Validate context.
		$context = implode('.', FieldsHelper::extract($context));
		if (!FieldsHelper::getFields($context))
		{
			return;
		}

		$link = 'index.php?option=com_fields&amp;view=fields&amp;layout=modal&amp;tmpl=component&amp;context='
			. $context . '&amp;editor=' . $name . '&amp;' . JSession::getFormToken() . '=1';

		$button          = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    = JText::_('PLG_EDITORS-XTD_FIELDS_BUTTON_FIELD');
		$button->name    = 'puzzle';
		$button->options = "{handler: 'iframe', size: {x: 800, y: 500}}";

		return $button;
	}
}
PK��#]�4yleditors-xtd/fields/fields.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin" group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_fields</name>
	<author>Joomla! Project</author>
	<creationDate>February 2017</creationDate>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_EDITORS-XTD_FIELDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="fields">fields.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors-xtd_fields.ini</language>
		<language tag="en-GB">en-GB.plg_editors-xtd_fields.sys.ini</language>
	</languages>
</extension>
PK��#]�)��editors-xtd/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�8���search/tags/tags.phpnu�[���<?php

/**
 * @package     Joomla.Plugin
 * @subpackage  Search.tags
 *
 * @copyright   (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

/**
 * Tags search plugin.
 *
 * @since  3.3
 */
class PlgSearchTags extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.3
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   3.3
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'tags' => 'PLG_SEARCH_TAGS_TAGS'
		);

		return $areas;
	}

	/**
	 * Search content (tags).
	 *
	 * The SQL must return the following fields that are used in a common display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values: exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values: newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   string  $areas     An array if the search is to be restricted to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   3.3
	 */
	public function onContentSearch($text, $phrase = '', $ordering = '', $areas = null)
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true);
		$app   = JFactory::getApplication();
		$user  = JFactory::getUser();
		$lang  = JFactory::getLanguage();

		$section = JText::_('PLG_SEARCH_TAGS_TAGS');
		$limit   = $this->params->def('search_limit', 50);

		if (is_array($areas) && !array_intersect($areas, array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		$text = $db->quote('%' . $db->escape($text, true) . '%', false);

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.title ASC';
				break;

			case 'newest':
				$order = 'a.created_time DESC';
				break;

			case 'oldest':
				$order = 'a.created_time ASC';
				break;

			case 'popular':
			default:
				$order = 'a.title DESC';
		}

		$query->select('a.id, a.title, a.alias, a.note, a.published, a.access'
			. ', a.checked_out, a.checked_out_time, a.created_user_id'
			. ', a.path, a.parent_id, a.level, a.lft, a.rgt'
			. ', a.language, a.created_time AS created, a.description');

		$case_when_item_alias  = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias', '!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id                  = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$query->from('#__tags AS a');
		$query->where('a.alias <> ' . $db->quote('root'));

		$query->where('(a.title LIKE ' . $text . ' OR a.alias LIKE ' . $text . ')');

		$query->where($db->qn('a.published') . ' = 1');

		if (!$user->authorise('core.admin'))
		{
			$groups = implode(',', $user->getAuthorisedViewLevels());
			$query->where('a.access IN (' . $groups . ')');
		}

		if ($app->isClient('site') && JLanguageMultilang::isEnabled())
		{
			$tag = JFactory::getLanguage()->getTag();
			$query->where('a.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')');
		}

		$query->order($order);

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
		}

		if ($rows)
		{
			JLoader::register('TagsHelperRoute', JPATH_SITE . '/components/com_tags/helpers/route.php');

			foreach ($rows as $key => $row)
			{
				$rows[$key]->href       = TagsHelperRoute::getTagRoute($row->slug);
				$rows[$key]->text       = ($row->description !== '' ? $row->description : $row->title);
				$rows[$key]->text      .= $row->note;
				$rows[$key]->section    = $section;
				$rows[$key]->created    = $row->created;
				$rows[$key]->browsernav = 0;
			}
		}

		if (!$this->params->get('show_tagged_items', 0))
		{
			return $rows;
		}
		else
		{
			$final_items = $rows;
			JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_tags/models');
			$tag_model = JModelLegacy::getInstance('Tag', 'TagsModel');
			$tag_model->getState();

			foreach ($rows as $key => $row)
			{
				$tag_model->setState('tag.id', $row->id);
				$tagged_items = $tag_model->getItems();

				if ($tagged_items)
				{
					foreach ($tagged_items as $k => $item)
					{
						// For 3rd party extensions we need to load the component strings from its sys.ini file
						$parts = explode('.', $item->type_alias);
						$comp = array_shift($parts);
						$lang->load($comp, JPATH_SITE, null, false, true)
						|| $lang->load($comp, JPATH_SITE . '/components/' . $comp, null, false, true);

						// Making up the type string
						$type = implode('_', $parts);
						$type = $comp . '_CONTENT_TYPE_' . $type;

						$new_item        = new stdClass;
						$new_item->href  = $item->link;
						$new_item->title = $item->core_title;
						$new_item->text  = $item->core_body;

						if ($lang->hasKey($type))
						{
							$new_item->section = JText::sprintf('PLG_SEARCH_TAGS_ITEM_TAGGED_WITH', JText::_($type), $row->title);
						}
						else
						{
							$new_item->section = JText::sprintf('PLG_SEARCH_TAGS_ITEM_TAGGED_WITH', $item->content_type_title, $row->title);
						}

						$new_item->created    = $item->displayDate;
						$new_item->browsernav = 0;
						$final_items[]        = $new_item;
					}
				}
			}

			return $final_items;
		}
	}
}
PK��#]�$?B��search/tags/tags.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="search" method="upgrade">
	<name>plg_search_tags</name>
	<author>Joomla! Project</author>
	<creationDate>March 2014</creationDate>
	<copyright>(C) 2014 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_TAGS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="tags">tags.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_search_tags.ini</language>
		<language tag="en-GB">en-GB.plg_search_tags.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="show_tagged_items"
					type="radio"
					label="PLG_SEARCH_TAGS_FIELD_SHOW_TAGGED_ITEMS_LABEL"
					description="PLG_SEARCH_TAGS_FIELD_SHOW_TAGGED_ITEMS_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��search/tags/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]6\}��� search/categories/categories.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="search" method="upgrade">
	<name>plg_search_categories</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_CATEGORIES_XML_DESCRIPTION</description>
	<files>
		<filename plugin="categories">categories.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_search_categories.ini</language>
		<language tag="en-GB">en-GB.plg_search_categories.sys.ini</language>
	</languages>
	<config>
		<fields name="params">

			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="JFIELD_PLG_SEARCH_ALL_LABEL"
					description="JFIELD_PLG_SEARCH_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="JFIELD_PLG_SEARCH_ARCHIVED_LABEL"
					description="JFIELD_PLG_SEARCH_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>

		</fields>
	</config>
</extension>
PK��#]�i��� search/categories/categories.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.categories
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php');

/**
 * Categories search plugin.
 *
 * @since  1.6
 */
class PlgSearchCategories extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'categories' => 'PLG_SEARCH_CATEGORIES_CATEGORIES'
		);

		return $areas;
	}

	/**
	 * Search content (categories).
	 *
	 * The SQL must return the following fields that are used in a common display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values: exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values: newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   mixed   $areas     An array if the search is to be restricted to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering = '', $areas = null)
	{
		$db = JFactory::getDbo();
		$user = JFactory::getUser();
		$app = JFactory::getApplication();
		$groups = implode(',', $user->getAuthorisedViewLevels());
		$searchText = $text;

		if (is_array($areas) && !array_intersect($areas, array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit = $this->params->def('search_limit', 50);
		$state = array();

		if ($sContent)
		{
			$state[] = 1;
		}

		if ($sArchived)
		{
			$state[] = 2;
		}

		if (empty($state))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		/* TODO: The $where variable does not seem to be used at all
		switch ($phrase)
		{
			case 'exact':
				$text = $db->quote('%' . $db->escape($text, true) . '%', false);
				$wheres2 = array();
				$wheres2[] = 'a.title LIKE ' . $text;
				$wheres2[] = 'a.description LIKE ' . $text;
				$where = '(' . implode(') OR (', $wheres2) . ')';
				break;

			case 'any':
			case 'all';
			default:
				$words = explode(' ', $text);
				$wheres = array();
				foreach ($words as $word)
				{
					$word = $db->quote('%' . $db->escape($word, true) . '%', false);
					$wheres2 = array();
					$wheres2[] = 'a.title LIKE ' . $word;
					$wheres2[] = 'a.description LIKE ' . $word;
					$wheres[] = implode(' OR ', $wheres2);
				}
				$where = '(' . implode(($phrase == 'all' ? ') AND (' : ') OR ('), $wheres) . ')';
				break;
		}
		*/

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.title ASC';
				break;

			case 'category':
			case 'popular':
			case 'newest':
			case 'oldest':
			default:
				$order = 'a.title DESC';
		}

		$text = $db->quote('%' . $db->escape($text, true) . '%', false);
		$query = $db->getQuery(true);

		// SQLSRV changes.
		$case_when = ' CASE WHEN ';
		$case_when .= $query->charLength('a.alias', '!=', '0');
		$case_when .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when .= ' ELSE ';
		$case_when .= $a_id . ' END as slug';
		$query->select('a.title, a.description AS text, a.created_time AS created, \'2\' AS browsernav, a.id AS catid, ' . $case_when)
			->from('#__categories AS a')
			->where(
				'(a.title LIKE ' . $text . ' OR a.description LIKE ' . $text . ') AND a.published IN (' . implode(',', $state) . ') AND a.extension = '
				. $db->quote('com_content') . 'AND a.access IN (' . $groups . ')'
			)
			->group('a.id, a.title, a.description, a.alias, a.created_time')
			->order($order);

		if ($app->isClient('site') && JLanguageMultilang::isEnabled())
		{
			$query->where('a.language in (' . $db->quote(JFactory::getLanguage()->getTag()) . ',' . $db->quote('*') . ')');
		}

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
		}

		$return = array();

		if ($rows)
		{
			foreach ($rows as $i => $row)
			{
				if (searchHelper::checkNoHtml($row, $searchText, array('name', 'title', 'text')))
				{
					$row->href = ContentHelperRoute::getCategoryRoute($row->slug);
					$row->section = JText::_('JCATEGORY');

					$return[] = $row;
				}
			}
		}

		return $return;
	}
}
PK��#]�)��search/categories/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]	�~�44search/content/content.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.content
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Content search plugin.
 *
 * @since  1.6
 */
class PlgSearchContent extends JPlugin
{
	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'content' => 'JGLOBAL_ARTICLES'
		);

		return $areas;
	}

	/**
	 * Search content (articles).
	 * The SQL must return the following fields that are used in a common display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values: exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values: newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   mixed   $areas     An array if the search it to be restricted to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering = '', $areas = null)
	{
		$db         = JFactory::getDbo();
		$serverType = $db->getServerType();
		$app        = JFactory::getApplication();
		$user       = JFactory::getUser();
		$groups     = implode(',', $user->getAuthorisedViewLevels());
		$tag        = JFactory::getLanguage()->getTag();

		JLoader::register('ContentHelperRoute', JPATH_SITE . '/components/com_content/helpers/route.php');
		JLoader::register('SearchHelper', JPATH_ADMINISTRATOR . '/components/com_search/helpers/search.php');

		$searchText = $text;

		if (is_array($areas) && !array_intersect($areas, array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent  = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit     = $this->params->def('search_limit', 50);

		$nullDate  = $db->getNullDate();
		$date      = JFactory::getDate();
		$now       = $date->toSql();

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		switch ($phrase)
		{
			case 'exact':
				$text      = $db->quote('%' . $db->escape($text, true) . '%', false);
				$wheres2   = array();
				$wheres2[] = 'a.title LIKE ' . $text;
				$wheres2[] = 'a.introtext LIKE ' . $text;
				$wheres2[] = 'a.fulltext LIKE ' . $text;
				$wheres2[] = 'a.metakey LIKE ' . $text;
				$wheres2[] = 'a.metadesc LIKE ' . $text;

				$relevance[] = ' CASE WHEN ' . $wheres2[0] . ' THEN 5 ELSE 0 END ';

				// Join over Fields.
				$subQuery = $db->getQuery(true);
				$subQuery->select("cfv.item_id")
					->from("#__fields_values AS cfv")
					->join('LEFT', '#__fields AS f ON f.id = cfv.field_id')
					->where('(f.context IS NULL OR f.context = ' . $db->q('com_content.article') . ')')
					->where('(f.state IS NULL OR f.state = 1)')
					->where('(f.access IS NULL OR f.access IN (' . $groups . '))')
					->where('cfv.value LIKE ' . $text);

				// Filter by language.
				if ($app->isClient('site') && JLanguageMultilang::isEnabled())
				{
					$subQuery->where('(f.language IS NULL OR f.language in (' . $db->quote($tag) . ',' . $db->quote('*') . '))');
				}

				if ($serverType == "mysql")
				{
					/* This generates a dependent sub-query so do no use in MySQL prior to version 6.0 !
					* $wheres2[] = 'a.id IN( '. (string) $subQuery.')';
					*/

					$db->setQuery($subQuery);
					$fieldids = $db->loadColumn();

					if (count($fieldids))
					{
						$wheres2[] = 'a.id IN(' . implode(",", $fieldids) . ')';
					}
				}
				else
				{
					$wheres2[] = $subQuery->castAsChar('a.id') . ' IN( ' . (string) $subQuery . ')';
				}

				$where = '(' . implode(') OR (', $wheres2) . ')';
				break;

			case 'all':
			case 'any':
			default:
				$words = explode(' ', $text);
				$wheres = array();
				$cfwhere = array();

				foreach ($words as $word)
				{
					$word      = $db->quote('%' . $db->escape($word, true) . '%', false);
					$wheres2   = array();
					$wheres2[] = 'LOWER(a.title) LIKE LOWER(' . $word . ')';
					$wheres2[] = 'LOWER(a.introtext) LIKE LOWER(' . $word . ')';
					$wheres2[] = 'LOWER(a.fulltext) LIKE LOWER(' . $word . ')';
					$wheres2[] = 'LOWER(a.metakey) LIKE LOWER(' . $word . ')';
					$wheres2[] = 'LOWER(a.metadesc) LIKE LOWER(' . $word . ')';

					$relevance[] = ' CASE WHEN ' . $wheres2[0] . ' THEN 5 ELSE 0 END ';

					if ($phrase === 'all')
					{
						// Join over Fields.
						$subQuery = $db->getQuery(true);
						$subQuery->select("cfv.item_id")
							->from("#__fields_values AS cfv")
							->join('LEFT', '#__fields AS f ON f.id = cfv.field_id')
							->where('(f.context IS NULL OR f.context = ' . $db->q('com_content.article') . ')')
							->where('(f.state IS NULL OR f.state = 1)')
							->where('(f.access IS NULL OR f.access IN (' . $groups . '))')
							->where('LOWER(cfv.value) LIKE LOWER(' . $word . ')');

						// Filter by language.
						if ($app->isClient('site') && JLanguageMultilang::isEnabled())
						{
							$subQuery->where('(f.language IS NULL OR f.language in (' . $db->quote($tag) . ',' . $db->quote('*') . '))');
						}

						if ($serverType == "mysql")
						{
							$db->setQuery($subQuery);
							$fieldids = $db->loadColumn();

							if (count($fieldids))
							{
								$wheres2[] = 'a.id IN(' . implode(",", $fieldids) . ')';
							}
						}
						else
						{
							$wheres2[] = $subQuery->castAsChar('a.id') . ' IN( ' . (string) $subQuery . ')';
						}
					}
					else
					{
						$cfwhere[] = 'LOWER(cfv.value) LIKE LOWER(' . $word . ')';
					}

					$wheres[] = implode(' OR ', $wheres2);
				}

				if ($phrase === 'any')
				{
					// Join over Fields.
					$subQuery = $db->getQuery(true);
					$subQuery->select("cfv.item_id")
						->from("#__fields_values AS cfv")
						->join('LEFT', '#__fields AS f ON f.id = cfv.field_id')
						->where('(f.context IS NULL OR f.context = ' . $db->q('com_content.article') . ')')
						->where('(f.state IS NULL OR f.state = 1)')
						->where('(f.access IS NULL OR f.access IN (' . $groups . '))')
						->where('(' . implode(($phrase === 'all' ? ') AND (' : ') OR ('), $cfwhere) . ')');

					// Filter by language.
					if ($app->isClient('site') && JLanguageMultilang::isEnabled())
					{
						$subQuery->where('(f.language IS NULL OR f.language in (' . $db->quote($tag) . ',' . $db->quote('*') . '))');
					}

					if ($serverType == "mysql")
					{
						$db->setQuery($subQuery);
						$fieldids = $db->loadColumn();

						if (count($fieldids))
						{
							$wheres[] = 'a.id IN(' . implode(",", $fieldids) . ')';
						}
					}
					else
					{
						$wheres[] = $subQuery->castAsChar('a.id') . ' IN( ' . (string) $subQuery . ')';
					}
				}

				$where = '(' . implode(($phrase === 'all' ? ') AND (' : ') OR ('), $wheres) . ')';
				break;
		}

		switch ($ordering)
		{
			case 'oldest':
				$order = 'a.created ASC';
				break;

			case 'popular':
				$order = 'a.hits DESC';
				break;

			case 'alpha':
				$order = 'a.title ASC';
				break;

			case 'category':
				$order = 'c.title ASC, a.title ASC';
				break;

			case 'newest':
			default:
				$order = 'a.created DESC';
				break;
		}

		$rows = array();
		$query = $db->getQuery(true);

		// Search articles.
		if ($sContent && $limit > 0)
		{
			$query->clear();

			// SQLSRV changes.
			$case_when  = ' CASE WHEN ';
			$case_when .= $query->charLength('a.alias', '!=', '0');
			$case_when .= ' THEN ';
			$a_id       = $query->castAsChar('a.id');
			$case_when .= $query->concatenate(array($a_id, 'a.alias'), ':');
			$case_when .= ' ELSE ';
			$case_when .= $a_id . ' END as slug';

			$case_when1  = ' CASE WHEN ';
			$case_when1 .= $query->charLength('c.alias', '!=', '0');
			$case_when1 .= ' THEN ';
			$c_id        = $query->castAsChar('c.id');
			$case_when1 .= $query->concatenate(array($c_id, 'c.alias'), ':');
			$case_when1 .= ' ELSE ';
			$case_when1 .= $c_id . ' END as catslug';

			if (!empty($relevance))
			{
				$query->select(implode(' + ', $relevance) . ' AS relevance');
				$order = ' relevance DESC, ' . $order;
			}

			$query->select('a.title AS title, a.metadesc, a.metakey, a.created AS created, a.language, a.catid')
				->select($query->concatenate(array('a.introtext', 'a.fulltext')) . ' AS text')
				->select('c.title AS section, ' . $case_when . ',' . $case_when1 . ', ' . '\'2\' AS browsernav')
				->from('#__content AS a')
				->join('INNER', '#__categories AS c ON c.id=a.catid')
				->where(
					'(' . $where . ') AND a.state=1 AND c.published = 1 AND a.access IN (' . $groups . ') '
						. 'AND c.access IN (' . $groups . ')'
						. 'AND (a.publish_up = ' . $db->quote($nullDate) . ' OR a.publish_up <= ' . $db->quote($now) . ') '
						. 'AND (a.publish_down = ' . $db->quote($nullDate) . ' OR a.publish_down >= ' . $db->quote($now) . ')'
				)
				->group('a.id, a.title, a.metadesc, a.metakey, a.created, a.language, a.catid, a.introtext, a.fulltext, c.title, a.alias, c.alias, c.id')
				->order($order);

			// Filter by language.
			if ($app->isClient('site') && JLanguageMultilang::isEnabled())
			{
				$query->where('a.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')')
					->where('c.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')');
			}

			$db->setQuery($query, 0, $limit);

			try
			{
				$list = $db->loadObjectList();
			}
			catch (RuntimeException $e)
			{
				$list = array();
				JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
			}

			$limit -= count($list);

			if (isset($list))
			{
				foreach ($list as $key => $item)
				{
					$list[$key]->href = ContentHelperRoute::getArticleRoute($item->slug, $item->catid, $item->language);
				}
			}

			$rows[] = $list;
		}

		// Search archived content.
		if ($sArchived && $limit > 0)
		{
			$query->clear();

			// SQLSRV changes.
			$case_when  = ' CASE WHEN ';
			$case_when .= $query->charLength('a.alias', '!=', '0');
			$case_when .= ' THEN ';
			$a_id       = $query->castAsChar('a.id');
			$case_when .= $query->concatenate(array($a_id, 'a.alias'), ':');
			$case_when .= ' ELSE ';
			$case_when .= $a_id . ' END as slug';

			$case_when1  = ' CASE WHEN ';
			$case_when1 .= $query->charLength('c.alias', '!=', '0');
			$case_when1 .= ' THEN ';
			$c_id        = $query->castAsChar('c.id');
			$case_when1 .= $query->concatenate(array($c_id, 'c.alias'), ':');
			$case_when1 .= ' ELSE ';
			$case_when1 .= $c_id . ' END as catslug';

			if (!empty($relevance))
			{
				$query->select(implode(' + ', $relevance) . ' AS relevance');
				$order = ' relevance DESC, ' . $order;
			}

			$query->select('a.title AS title, a.metadesc, a.metakey, a.created AS created, a.language, a.catid')
				->select($query->concatenate(array('a.introtext', 'a.fulltext')) . ' AS text')
				->select('c.title AS section, ' . $case_when . ',' . $case_when1 . ', ' . '\'2\' AS browsernav')
				->from('#__content AS a')
				->join('INNER', '#__categories AS c ON c.id=a.catid AND c.access IN (' . $groups . ')')
				->where(
					'(' . $where . ') AND a.state = 2 AND c.published = 1 AND a.access IN (' . $groups
						. ') AND c.access IN (' . $groups . ') '
						. 'AND (a.publish_up = ' . $db->quote($nullDate) . ' OR a.publish_up <= ' . $db->quote($now) . ') '
						. 'AND (a.publish_down = ' . $db->quote($nullDate) . ' OR a.publish_down >= ' . $db->quote($now) . ')'
				)
				->order($order);

			// Join over Fields is no longer needed

			// Filter by language.
			if ($app->isClient('site') && JLanguageMultilang::isEnabled())
			{
				$query->where('a.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')')
					->where('c.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')');
			}

			$db->setQuery($query, 0, $limit);

			try
			{
				$list3 = $db->loadObjectList();
			}
			catch (RuntimeException $e)
			{
				$list3 = array();
				JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
			}

			if (isset($list3))
			{
				foreach ($list3 as $key => $item)
				{
					$list3[$key]->href = ContentHelperRoute::getArticleRoute($item->slug, $item->catid, $item->language);
				}
			}

			$rows[] = $list3;
		}

		$results = array();

		if (count($rows))
		{
			foreach ($rows as $row)
			{
				$new_row = array();

				foreach ($row as $article)
				{
					// Not efficient to get these ONE article at a TIME
					// Lookup field values so they can be checked, GROUP_CONCAT would work in above queries, but isn't supported by non-MySQL DBs.
					$query = $db->getQuery(true);
					$query->select('fv.value')
						->from('#__fields_values as fv')
						->join('left', '#__fields as f on fv.field_id = f.id')
						->where('f.context = ' . $db->quote('com_content.article'))
						->where('fv.item_id = ' . $db->quote((int) $article->slug));
					$db->setQuery($query);
					$article->jcfields = implode(',', $db->loadColumn());

					if (SearchHelper::checkNoHtml($article, $searchText, array('text', 'title', 'jcfields', 'metadesc', 'metakey')))
					{
						$new_row[] = $article;
					}
				}

				$results = array_merge($results, (array) $new_row);
			}
		}

		return $results;
	}

}
PK��#]��ֆ��search/content/content.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="search" method="upgrade">
	<name>plg_search_content</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_CONTENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="content">content.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_search_content.ini</language>
		<language tag="en-GB">en-GB.plg_search_content.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="PLG_SEARCH_CONTENT_FIELD_SEARCHLIMIT_LABEL"
					description="PLG_SEARCH_CONTENT_FIELD_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="PLG_SEARCH_CONTENT_FIELD_CONTENT_LABEL"
					description="PLG_SEARCH_CONTENT_FIELD_CONTENT_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="PLG_SEARCH_CONTENT_FIELD_ARCHIVED_LABEL"
					description="PLG_SEARCH_CONTENT_FIELD_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>

		</fields>
	</config>
</extension>
PK��#]�)��search/content/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��search/newsfeeds/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]T��search/newsfeeds/newsfeeds.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="search" method="upgrade">
	<name>plg_search_newsfeeds</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_NEWSFEEDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="newsfeeds">newsfeeds.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_search_newsfeeds.ini</language>
		<language tag="en-GB">en-GB.plg_search_newsfeeds.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="JFIELD_PLG_SEARCH_ALL_LABEL"
					description="JFIELD_PLG_SEARCH_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="JFIELD_PLG_SEARCH_ARCHIVED_LABEL"
					description="JFIELD_PLG_SEARCH_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]*o�search/newsfeeds/newsfeeds.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.newsfeeds
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Newsfeeds search plugin.
 *
 * @since  1.6
 */
class PlgSearchNewsfeeds extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'newsfeeds' => 'PLG_SEARCH_NEWSFEEDS_NEWSFEEDS'
		);

		return $areas;
	}

	/**
	 * Search content (newsfeeds).
	 *
	 * The SQL must return the following fields that are used in a common display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values: exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values: newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   mixed   $areas     An array if the search it to be restricted to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering = '', $areas = null)
	{
		$db = JFactory::getDbo();
		$app = JFactory::getApplication();
		$user = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());

		if (is_array($areas) && !array_intersect($areas, array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit = $this->params->def('search_limit', 50);
		$state = array();

		if ($sContent)
		{
			$state[] = 1;
		}

		if ($sArchived)
		{
			$state[] = 2;
		}

		if (empty($state))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		switch ($phrase)
		{
			case 'exact':
				$text = $db->quote('%' . $db->escape($text, true) . '%', false);
				$wheres2 = array();
				$wheres2[] = 'a.name LIKE ' . $text;
				$wheres2[] = 'a.link LIKE ' . $text;
				$where = '(' . implode(') OR (', $wheres2) . ')';
				break;

			case 'all':
			case 'any':
			default:
				$words = explode(' ', $text);
				$wheres = array();

				foreach ($words as $word)
				{
					$word = $db->quote('%' . $db->escape($word, true) . '%', false);
					$wheres2 = array();
					$wheres2[] = 'a.name LIKE ' . $word;
					$wheres2[] = 'a.link LIKE ' . $word;
					$wheres[] = implode(' OR ', $wheres2);
				}

				$where = '(' . implode(($phrase === 'all' ? ') AND (' : ') OR ('), $wheres) . ')';
				break;
		}

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.name ASC';
				break;

			case 'category':
				$order = 'c.title ASC, a.name ASC';
				break;

			case 'oldest':
			case 'popular':
			case 'newest':
			default:
				$order = 'a.name ASC';
		}

		$searchNewsfeeds = JText::_('PLG_SEARCH_NEWSFEEDS_NEWSFEEDS');

		$query = $db->getQuery(true);

		// SQLSRV changes.
		$case_when  = ' CASE WHEN ';
		$case_when .= $query->charLength('a.alias', '!=', '0');
		$case_when .= ' THEN ';
		$a_id       = $query->castAsChar('a.id');
		$case_when .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when .= ' ELSE ';
		$case_when .= $a_id . ' END as slug';

		$case_when1  = ' CASE WHEN ';
		$case_when1 .= $query->charLength('c.alias', '!=', '0');
		$case_when1 .= ' THEN ';
		$c_id        = $query->castAsChar('c.id');
		$case_when1 .= $query->concatenate(array($c_id, 'c.alias'), ':');
		$case_when1 .= ' ELSE ';
		$case_when1 .= $c_id . ' END as catslug';

		$query->select('a.name AS title, \'\' AS created, a.link AS text, ' . $case_when . ',' . $case_when1)
			->select($query->concatenate(array($db->quote($searchNewsfeeds), 'c.title'), ' / ') . ' AS section')
			->select('\'1\' AS browsernav')
			->from('#__newsfeeds AS a')
			->join('INNER', '#__categories as c ON c.id = a.catid')
			->where('(' . $where . ') AND a.published IN (' . implode(',', $state) . ') AND c.published = 1 AND c.access IN (' . $groups . ')')
			->order($order);

		// Filter by language.
		if ($app->isClient('site') && JLanguageMultilang::isEnabled())
		{
			$tag = JFactory::getLanguage()->getTag();
			$query->where('a.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')')
				->where('c.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')');
		}

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
		}

		if ($rows)
		{
			foreach ($rows as $key => $row)
			{
				$rows[$key]->href = 'index.php?option=com_newsfeeds&view=newsfeed&catid=' . $row->catslug . '&id=' . $row->slug;
			}
		}

		return $rows;
	}
}
PK��#]�)��search/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��search/contacts/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]f ����search/contacts/contacts.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="search" method="upgrade">
	<name>plg_search_contacts</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_CONTACTS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contacts">contacts.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_search_contacts.ini</language>
		<language tag="en-GB">en-GB.plg_search_contacts.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="JFIELD_PLG_SEARCH_ALL_LABEL"
					description="JFIELD_PLG_SEARCH_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="JFIELD_PLG_SEARCH_ARCHIVED_LABEL"
					description="JFIELD_PLG_SEARCH_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�"(�77search/contacts/contacts.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.contacts
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Contacts search plugin.
 *
 * @since  1.6
 */
class PlgSearchContacts extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'contacts' => 'PLG_SEARCH_CONTACTS_CONTACTS'
		);

		return $areas;
	}

	/**
	 * Search content (contacts).
	 *
	 * The SQL must return the following fields that are used in a common display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values: exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values: newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   string  $areas     An array if the search is to be restricted to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering = '', $areas = null)
	{
		JLoader::register('ContactHelperRoute', JPATH_SITE . '/components/com_contact/helpers/route.php');

		$db     = JFactory::getDbo();
		$app    = JFactory::getApplication();
		$user   = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());

		if (is_array($areas) && !array_intersect($areas, array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent  = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit     = $this->params->def('search_limit', 50);
		$state     = array();

		if ($sContent)
		{
			$state[] = 1;
		}

		if ($sArchived)
		{
			$state[] = 2;
		}

		if (empty($state))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		$section = JText::_('PLG_SEARCH_CONTACTS_CONTACTS');

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.name ASC';
				break;

			case 'category':
				$order = 'c.title ASC, a.name ASC';
				break;

			case 'popular':
			case 'newest':
			case 'oldest':
			default:
				$order = 'a.name DESC';
		}

		$text = $db->quote('%' . $db->escape($text, true) . '%', false);

		$query = $db->getQuery(true);

		// SQLSRV changes.
		$case_when  = ' CASE WHEN ';
		$case_when .= $query->charLength('a.alias', '!=', '0');
		$case_when .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when .= $query->concatenate(array($a_id, 'a.alias'), ':');
		$case_when .= ' ELSE ';
		$case_when .= $a_id . ' END as slug';

		$case_when1  = ' CASE WHEN ';
		$case_when1 .= $query->charLength('c.alias', '!=', '0');
		$case_when1 .= ' THEN ';
		$c_id        = $query->castAsChar('c.id');
		$case_when1 .= $query->concatenate(array($c_id, 'c.alias'), ':');
		$case_when1 .= ' ELSE ';
		$case_when1 .= $c_id . ' END as catslug';

		$query->select(
			'a.name AS title, \'\' AS created, a.con_position, a.misc, '
				. $case_when . ',' . $case_when1 . ', '
				. $query->concatenate(array('a.name', 'a.con_position', 'a.misc'), ',') . ' AS text,'
				. $query->concatenate(array($db->quote($section), 'c.title'), ' / ') . ' AS section,'
				. '\'2\' AS browsernav'
		);
		$query->from('#__contact_details AS a')
			->join('INNER', '#__categories AS c ON c.id = a.catid')
			->where(
				'(a.name LIKE ' . $text . ' OR a.misc LIKE ' . $text . ' OR a.con_position LIKE ' . $text
					. ' OR a.address LIKE ' . $text . ' OR a.suburb LIKE ' . $text . ' OR a.state LIKE ' . $text
					. ' OR a.country LIKE ' . $text . ' OR a.postcode LIKE ' . $text . ' OR a.telephone LIKE ' . $text
					. ' OR a.fax LIKE ' . $text . ') AND a.published IN (' . implode(',', $state) . ') AND c.published=1 '
					. ' AND a.access IN (' . $groups . ') AND c.access IN (' . $groups . ')'
			)
			->order($order);

		// Filter by language.
		if ($app->isClient('site') && JLanguageMultilang::isEnabled())
		{
			$tag = JFactory::getLanguage()->getTag();
			$query->where('a.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')')
				->where('c.language in (' . $db->quote($tag) . ',' . $db->quote('*') . ')');
		}

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');
		}

		if ($rows)
		{
			foreach ($rows as $key => $row)
			{
				$rows[$key]->href  = ContactHelperRoute::getContactRoute($row->slug, $row->catslug);
				$rows[$key]->text  = $row->title;
				$rows[$key]->text .= $row->con_position ? ', ' . $row->con_position : '';
				$rows[$key]->text .= $row->misc ? ', ' . $row->misc : '';
			}
		}

		return $rows;
	}
}
PK��#]�)��privacy/actionlogs/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�����!privacy/actionlogs/actionlogs.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.actionlogs
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR . '/components/com_actionlogs/helpers/actionlogs.php');
JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla actionlogs data
 *
 * @since  3.9.0
 */
class PlgPrivacyActionlogs extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core actionlog data
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser $user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domain = $this->createDomain('user_action_logs', 'joomla_user_action_logs_data');

		$query = $this->db->getQuery(true)
			->select('a.*, u.name')
			->from('#__action_logs AS a')
			->innerJoin('#__users AS u ON a.user_id = u.id')
			->where($this->db->quoteName('a.user_id') . ' = ' . (int) $user->id);

		$this->db->setQuery($query);

		$data = $this->db->loadObjectList();

		if (!count($data))
		{
			return array();
		}

		$data    = ActionlogsHelper::getCsvData($data);
		$isFirst = true;

		foreach ($data as $item)
		{
			if ($isFirst)
			{
				$isFirst = false;

				continue;
			}

			$domain->addItem($this->createItemFromArray($item));
		}

		return array($domain);
	}
}
PK��#]�N��!privacy/actionlogs/actionlogs.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="privacy" method="upgrade">
	<name>plg_privacy_actionlogs</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_ACTIONLOGS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="actionlogs">actionlogs.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_privacy_actionlogs.ini</language>
		<language tag="en-GB">en-GB.plg_privacy_actionlogs.sys.ini</language>
	</languages>
</extension>
PK��#]�)��privacy/message/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��E�%%privacy/message/message.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.message
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user messages
 *
 * @since  3.9.0
 */
class PlgPrivacyMessage extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user message
	 *
	 * This event will collect data for the message table
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser $user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domain = $this->createDomain('user_messages', 'joomla_user_messages_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__messages'))
			->where($this->db->quoteName('user_id_from') . ' = ' . (int) $user->id)
			->orWhere($this->db->quoteName('user_id_to') . ' = ' . (int) $user->id)
			->order($this->db->quoteName('date_time') . ' ASC');

		$items = $this->db->setQuery($query)->loadAssocList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item));
		}

		return array($domain);
	}
}
PK��#]����

privacy/message/message.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="privacy" method="upgrade">
	<name>plg_privacy_message</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_MESSAGE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="message">message.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_privacy_message.ini</language>
		<language tag="en-GB">en-GB.plg_privacy_message.sys.ini</language>
	</languages>
</extension>
PK��#]�)��privacy/user/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]r9GGprivacy/user/user.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.user
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\User\UserHelper;
use Joomla\Utilities\ArrayHelper;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/plugin.php');
JLoader::register('PrivacyRemovalStatus', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/removal/status.php');

/**
 * Privacy plugin managing Joomla user data
 *
 * @since  3.9.0
 */
class PlgPrivacyUser extends PrivacyPlugin
{
	/**
	 * Performs validation to determine if the data associated with a remove information request can be processed
	 *
	 * This event will not allow a super user account to be removed
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  PrivacyRemovalStatus
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCanRemoveData(PrivacyTableRequest $request, JUser $user = null)
	{
		$status = new PrivacyRemovalStatus;

		if (!$user)
		{
			return $status;
		}

		if ($user->authorise('core.admin'))
		{
			$status->canRemove = false;
			$status->reason    = JText::_('PLG_PRIVACY_USER_ERROR_CANNOT_REMOVE_SUPER_USER');
		}

		return $status;
	}

	/**
	 * Processes an export request for Joomla core user data
	 *
	 * This event will collect data for the following core tables:
	 *
	 * - #__users (excluding the password, otpKey, and otep columns)
	 * - #__user_notes
	 * - #__user_profiles
	 * - User custom fields
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser $user = null)
	{
		if (!$user)
		{
			return array();
		}

		/** @var JTableUser $userTable */
		$userTable = JUser::getTable();
		$userTable->load($user->id);

		$domains = array();
		$domains[] = $this->createUserDomain($userTable);
		$domains[] = $this->createNotesDomain($userTable);
		$domains[] = $this->createProfileDomain($userTable);
		$domains[] = $this->createCustomFieldsDomain('com_users.user', array($userTable));

		return $domains;
	}

	/**
	 * Removes the data associated with a remove information request
	 *
	 * This event will pseudoanonymise the user account
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyRemoveData(PrivacyTableRequest $request, JUser $user = null)
	{
		// This plugin only processes data for registered user accounts
		if (!$user)
		{
			return;
		}

		$pseudoanonymisedData = array(
			'name'      => 'User ID ' . $user->id,
			'username'  => bin2hex(random_bytes(12)),
			'email'     => 'UserID' . $user->id . 'removed@email.invalid',
			'block'     => true,
		);

		$user->bind($pseudoanonymisedData);

		$user->save();

		// Destroy all sessions for the user account
		UserHelper::destroyUserSessions($user->id);
	}

	/**
	 * Create the domain for the user notes data
	 *
	 * @param   JTableUser  $user  The JTableUser object to process
	 *
	 * @return  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	private function createNotesDomain(JTableUser $user)
	{
		$domain = $this->createDomain('user_notes', 'joomla_user_notes_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__user_notes'))
			->where($this->db->quoteName('user_id') . ' = ' . $this->db->quote($user->id));

		$items = $this->db->setQuery($query)->loadAssocList();

		// Remove user ID columns
		foreach (array('user_id', 'created_user_id', 'modified_user_id') as $column)
		{
			$items = ArrayHelper::dropColumn($items, $column);
		}

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item, $item['id']));
		}

		return $domain;
	}

	/**
	 * Create the domain for the user profile data
	 *
	 * @param   JTableUser  $user  The JTableUser object to process
	 *
	 * @return  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	private function createProfileDomain(JTableUser $user)
	{
		$domain = $this->createDomain('user_profile', 'joomla_user_profile_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__user_profiles'))
			->where($this->db->quoteName('user_id') . ' = ' . $this->db->quote($user->id))
			->order($this->db->quoteName('ordering') . ' ASC');

		$items = $this->db->setQuery($query)->loadAssocList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item));
		}

		return $domain;
	}

	/**
	 * Create the domain for the user record
	 *
	 * @param   JTableUser  $user  The JTableUser object to process
	 *
	 * @return  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	private function createUserDomain(JTableUser $user)
	{
		$domain = $this->createDomain('users', 'joomla_users_data');
		$domain->addItem($this->createItemForUserTable($user));

		return $domain;
	}

	/**
	 * Create an item object for a JTableUser object
	 *
	 * @param   JTableUser  $user  The JTableUser object to convert
	 *
	 * @return  PrivacyExportItem
	 *
	 * @since   3.9.0
	 */
	private function createItemForUserTable(JTableUser $user)
	{
		$data    = array();
		$exclude = array('password', 'otpKey', 'otep');

		foreach (array_keys($user->getFields()) as $fieldName)
		{
			if (!in_array($fieldName, $exclude))
			{
				$data[$fieldName] = $user->$fieldName;
			}
		}

		return $this->createItemFromArray($data, $user->id);
	}
}
PK��#]H׾��privacy/user/user.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="privacy" method="upgrade">
	<name>plg_privacy_user</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_USER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="user">user.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_privacy_user.ini</language>
		<language tag="en-GB">en-GB.plg_privacy_user.sys.ini</language>
	</languages>
</extension>
PK��#]��

privacy/content/content.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="privacy" method="upgrade">
	<name>plg_privacy_content</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_CONTENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="content">content.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_privacy_content.ini</language>
		<language tag="en-GB">en-GB.plg_privacy_content.sys.ini</language>
	</languages>
</extension>
PK��#]��.H��privacy/content/content.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.content
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user content data
 *
 * @since  3.9.0
 */
class PlgPrivacyContent extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user content data
	 *
	 * This event will collect data for the content core table
	 *
	 * - Content custom fields
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser $user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domains   = array();
		$domain    = $this->createDomain('user_content', 'joomla_user_content_data');
		$domains[] = $domain;

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__content'))
			->where($this->db->quoteName('created_by') . ' = ' . (int) $user->id)
			->order($this->db->quoteName('ordering') . ' ASC');

		$items = $this->db->setQuery($query)->loadObjectList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray((array) $item));
		}

		$domains[] = $this->createCustomFieldsDomain('com_content.article', $items);

		return $domains;
	}
}
PK��#]�)��privacy/content/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��privacy/consents/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��privacy/consents/consents.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="privacy" method="upgrade">
	<name>plg_privacy_consents</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_CONSENTS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="consents">consents.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_privacy_consents.ini</language>
		<language tag="en-GB">en-GB.plg_privacy_consents.sys.ini</language>
	</languages>
</extension>
PK��#]G�����privacy/consents/consents.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.consents
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user consent data
 *
 * @since  3.9.0
 */
class PlgPrivacyConsents extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user consent data
	 *
	 * This event will collect data for the core `#__privacy_consents` table
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser $user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domain    = $this->createDomain('consents', 'joomla_consent_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__privacy_consents'))
			->where($this->db->quoteName('user_id') . ' = ' . (int) $user->id)
			->order($this->db->quoteName('created') . ' ASC');

		$items = $this->db->setQuery($query)->loadAssocList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item));
		}

		return array($domain);
	}
}
PK��#]�)��privacy/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��privacy/contact/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�(�r//privacy/contact/contact.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.contact
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR . '/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user contact data
 *
 * @since  3.9.0
 */
class PlgPrivacyContact extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user contact data
	 *
	 * This event will collect data for the contact core tables:
	 *
	 * - Contact custom fields
	 *
	 * @param   PrivacyTableRequest  $request  The request record being processed
	 * @param   JUser                $user     The user account associated with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser $user = null)
	{
		if (!$user && !$request->email)
		{
			return array();
		}

		$domains   = array();
		$domain    = $this->createDomain('user_contact', 'joomla_user_contact_data');
		$domains[] = $domain;

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__contact_details'))
			->order($this->db->quoteName('ordering') . ' ASC');

		if ($user)
		{
			$query->where($this->db->quoteName('user_id') . ' = ' . (int) $user->id);
		}
		else
		{
			$query->where($this->db->quoteName('email_to') . ' = ' . $this->db->quote($request->email));
		}

		$items = $this->db->setQuery($query)->loadObjectList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray((array) $item));
		}

		$domains[] = $this->createCustomFieldsDomain('com_contact.contact', $items);

		return $domains;
	}
}
PK��#]�L�0

privacy/contact/contact.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="privacy" method="upgrade">
	<name>plg_privacy_contact</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_CONTACT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contact">contact.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_privacy_contact.ini</language>
		<language tag="en-GB">en-GB.plg_privacy_contact.sys.ini</language>
	</languages>
</extension>
PK��#]�)��editors/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]6����#editors/tinymce/form/setoptions.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<form>
    <field
        name="access"
        type="usergrouplist"
        label="PLG_TINY_FIELD_SETACCESS_LABEL"
        description="PLG_TINY_FIELD_SETACCESS_DESC"
        multiple="true"
        class="access-select"
        labelclass="label label-success"
    />

    <field
        name="skins"
        type="note"
        label="PLG_TINY_FIELD_SKIN_INFO_LABEL"
        description="PLG_TINY_FIELD_SKIN_INFO_DESC"
    />

    <field
        name="skin"
        type="skins"
        label="PLG_TINY_FIELD_SKIN_LABEL"
        description="PLG_TINY_FIELD_SKIN_DESC"
    />

    <field
        name="skin_admin"
        type="skins"
        label="PLG_TINY_FIELD_SKIN_ADMIN_LABEL"
        description="PLG_TINY_FIELD_SKIN_ADMIN_DESC"
    />

    <field
        name="mobile"
        type="radio"
        label="PLG_TINY_FIELD_MOBILE_LABEL"
        description="PLG_TINY_FIELD_MOBILE_DESC"
        class="btn-group btn-group-yesno"
        default="0"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="drag_drop"
        type="radio"
        label="PLG_TINY_FIELD_DRAG_DROP_LABEL"
        description="PLG_TINY_FIELD_DRAG_DROP_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="path"
        type="uploaddirs"
        label="PLG_TINY_FIELD_CUSTOM_PATH_LABEL"
        description="PLG_TINY_FIELD_CUSTOM_PATH_DESC"
        class="input-xxlarge"
        showon="drag_drop:1"
    />

    <field
        name="entity_encoding"
        type="list"
        label="PLG_TINY_FIELD_ENCODING_LABEL"
        description="PLG_TINY_FIELD_ENCODING_DESC"
        default="raw"
        >
        <option value="named">PLG_TINY_FIELD_VALUE_NAMED</option>
        <option value="numeric">PLG_TINY_FIELD_VALUE_NUMERIC</option>
        <option value="raw">PLG_TINY_FIELD_VALUE_RAW</option>
    </field>

    <field
        name="lang_mode"
        type="radio"
        label="PLG_TINY_FIELD_LANGSELECT_LABEL"
        description="PLG_TINY_FIELD_LANGSELECT_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="lang_code"
        type="filelist"
        label="PLG_TINY_FIELD_LANGCODE_LABEL"
        description="PLG_TINY_FIELD_LANGCODE_DESC"
        class="inputbox"
        stripext="1"
        directory="media/editors/tinymce/langs/"
        hide_none="1"
        default="en"
        hide_default="1"
        filter="\.js$"
        size="10"
        showon="lang_mode:0"
    />

    <field
        name="text_direction"
        type="list"
        label="PLG_TINY_FIELD_DIRECTION_LABEL"
        description="PLG_TINY_FIELD_DIRECTION_DESC"
        default="ltr"
        >
        <option value="ltr">PLG_TINY_FIELD_VALUE_LTR</option>
        <option value="rtl">PLG_TINY_FIELD_VALUE_RTL</option>
    </field>

    <field
        name="content_css"
        type="radio"
        label="PLG_TINY_FIELD_CSS_LABEL"
        description="PLG_TINY_FIELD_CSS_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="content_css_custom"
        type="text"
        label="PLG_TINY_FIELD_CUSTOM_CSS_LABEL"
        description="PLG_TINY_FIELD_CUSTOM_CSS_DESC"
        class="input-xxlarge"
    />

    <field
        name="relative_urls"
        type="list"
        label="PLG_TINY_FIELD_URLS_LABEL"
        description="PLG_TINY_FIELD_URLS_DESC"
        default="1"
        >
        <option value="0">PLG_TINY_FIELD_VALUE_ABSOLUTE</option>
        <option value="1">PLG_TINY_FIELD_VALUE_RELATIVE</option>
    </field>

    <field
        name="newlines"
        type="list"
        label="PLG_TINY_FIELD_NEWLINES_LABEL"
        description="PLG_TINY_FIELD_NEWLINES_DESC"
        default="0"
        >
        <option value="1">PLG_TINY_FIELD_VALUE_BR</option>
        <option value="0">PLG_TINY_FIELD_VALUE_P</option>
    </field>

    <field
        name="use_config_textfilters"
        type="radio"
        label="PLG_TINY_CONFIG_TEXTFILTER_ACL_LABEL"
        description="PLG_TINY_CONFIG_TEXTFILTER_ACL_DESC"
        class="btn-group btn-group-yesno"
        default="0"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="invalid_elements"
        type="text"
        label="PLG_TINY_FIELD_PROHIBITED_LABEL"
        description="PLG_TINY_FIELD_PROHIBITED_DESC"
        showon="use_config_textfilters:0"
        default="script,applet,iframe"
        class="input-xxlarge"
    />

    <field
        name="valid_elements"
        type="text"
        label="PLG_TINY_FIELD_VALIDELEMENTS_LABEL"
        description="PLG_TINY_FIELD_VALIDELEMENTS_DESC"
        showon="use_config_textfilters:0"
        class="input-xxlarge"
    />

    <field
        name="extended_elements"
        type="text"
        label="PLG_TINY_FIELD_ELEMENTS_LABEL"
        description="PLG_TINY_FIELD_ELEMENTS_DESC"
        showon="use_config_textfilters:0"
        class="input-xxlarge"
    />

    <!-- Extra plugins -->
    <field
        name="resizing"
        type="radio"
        label="PLG_TINY_FIELD_RESIZING_LABEL"
        description="PLG_TINY_FIELD_RESIZING_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="resize_horizontal"
        type="radio"
        label="PLG_TINY_FIELD_RESIZE_HORIZONTAL_LABEL"
        description="PLG_TINY_FIELD_RESIZE_HORIZONTAL_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        showon="resizing:1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="element_path"
        type="radio"
        label="PLG_TINY_FIELD_PATH_LABEL"
        description="PLG_TINY_FIELD_PATH_DESC"
        class="btn-group btn-group-yesno"
        default="0"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="wordcount"
        type="radio"
        label="PLG_TINY_FIELD_WORDCOUNT_LABEL"
        description="PLG_TINY_FIELD_WORDCOUNT_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="image_advtab"
        type="radio"
        label="PLG_TINY_FIELD_ADVIMAGE_LABEL"
        description="PLG_TINY_FIELD_ADVIMAGE_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="advlist"
        type="radio"
        label="PLG_TINY_FIELD_ADVLIST_LABEL"
        description="PLG_TINY_FIELD_ADVLIST_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="contextmenu"
        type="radio"
        label="PLG_TINY_FIELD_CONTEXTMENU_LABEL"
        description="PLG_TINY_FIELD_CONTEXTMENU_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="custom_plugin"
        type="text"
        label="PLG_TINY_FIELD_CUSTOMPLUGIN_LABEL"
        description="PLG_TINY_FIELD_CUSTOMPLUGIN_DESC"
        class="input-xxlarge"
    />

    <field
        name="custom_button"
        type="text"
        label="PLG_TINY_FIELD_CUSTOMBUTTON_LABEL"
        description="PLG_TINY_FIELD_CUSTOMBUTTON_DESC"
        class="input-xxlarge"
    />
</form>PK��#]X�ʬ��editors/tinymce/field/skins.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

jimport('joomla.form.helper');

JFormHelper::loadFieldClass('list');

/**
 * Generates the list of options for available skins.
 *
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 * @since       3.4
 */
class JFormFieldSkins extends JFormFieldList
{
	protected $type = 'skins';

	/**
	 * Method to get the skins options.
	 *
	 * @return  array  The skins option objects.
	 *
	 * @since   3.4
	 */
	public function getOptions()
	{
		$options = array();

		$directories = glob(JPATH_ROOT . '/media/editors/tinymce/skins' . '/*', GLOB_ONLYDIR);

		for ($i = 0, $iMax = count($directories); $i < $iMax; ++$i)
		{
			$dir = basename($directories[$i]);
			$options[] = JHtml::_('select.option', $i, $dir);
		}

		$options = array_merge(parent::getOptions(), $options);

		return $options;
	}

	/**
	 * Method to get the field input markup for the list of skins.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   3.4
	 */
	protected function getInput()
	{
		$html = array();

		// Get the field options.
		$options = (array) $this->getOptions();

		// Create a regular list.
		$html[] = JHtml::_('select.genericlist', $options, $this->name, '', 'value', 'text', $this->value, $this->id);

		return implode($html);
	}
}
PK��#]w��--(editors/tinymce/field/tinymcebuilder.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Form Field class for the TinyMCE editor.
 *
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 * @since       3.7.0
 */
class JFormFieldTinymceBuilder extends JFormField
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.7.0
	 */
	protected $type = 'tinymcebuilder';

	/**
	 * Name of the layout being used to render the field
	 *
	 * @var    string
	 * @since  3.7.0
	 */
	protected $layout = 'plugins.editors.tinymce.field.tinymcebuilder';

	/**
	 * The prepared layout data
	 *
	 * @var    array
	 * @since  3.7.0
	 */
	protected $layoutData = array();

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since  3.7.0
	 */
	protected function getLayoutData()
	{
		if (!empty($this->layoutData))
		{
			return $this->layoutData;
		}

		$data       = parent::getLayoutData();
		$paramsAll  = (object) $this->form->getValue('params');
		$setsAmount = empty($paramsAll->sets_amount) ? 3 : $paramsAll->sets_amount;

		if (empty($data['value']))
		{
			$data['value'] = array();
		}

		// Get the plugin
		require_once JPATH_PLUGINS . '/editors/tinymce/tinymce.php';

		$menus = array(
			'edit'   => array('label' => 'Edit'),
			'insert' => array('label' => 'Insert'),
			'view'   => array('label' => 'View'),
			'format' => array('label' => 'Format'),
			'table'  => array('label' => 'Table'),
			'tools'  => array('label' => 'Tools'),
		);

		$data['menus']         = $menus;
		$data['menubarSource'] = array_keys($menus);
		$data['buttons']       = PlgEditorTinymce::getKnownButtons();
		$data['buttonsSource'] = array_keys($data['buttons']);
		$data['toolbarPreset'] = PlgEditorTinymce::getToolbarPreset();
		$data['setsAmount']    = $setsAmount;

		// Get array of sets names
		for ($i = 0; $i < $setsAmount; $i++)
		{
			$data['setsNames'][$i] = JText::sprintf('PLG_TINY_SET_TITLE', $i);
		}

		// Prepare the forms for each set
		$setsForms  = array();
		$formsource = JPATH_PLUGINS . '/editors/tinymce/form/setoptions.xml';

		// Preload an old params for B/C
		$setParams = new stdClass;
		if (!empty($paramsAll->html_width) && empty($paramsAll->configuration['setoptions']))
		{
			$plugin = JPluginHelper::getPlugin('editors', 'tinymce');

			JFactory::getApplication()->enqueueMessage(JText::sprintf('PLG_TINY_LEGACY_WARNING', '#'), 'warning');

			if (is_object($plugin) && !empty($plugin->params))
			{
				$setParams = (object) json_decode($plugin->params);
			}
		}

		// Collect already used groups
		$groupsInUse = array();

		// Prepare the Set forms, for the set options
		foreach (array_keys($data['setsNames']) as $num)
		{
			$formname = 'set.form.' . $num;
			$control  = $this->name . '[setoptions][' . $num . ']';

			$setsForms[$num] = JForm::getInstance($formname, $formsource, array('control' => $control));

			// Check whether we already have saved values or it first time or even old params
			if (empty($this->value['setoptions'][$num]))
			{
				$formValues = $setParams;

				/*
				 * Predefine group:
				 * Set 0: for Administrator, Editor, Super Users (4,7,8)
				 * Set 1: for Registered, Manager (2,6), all else are public
				 */
				$formValues->access = !$num ? array(4,7,8) : ($num === 1 ? array(2,6) : array());

				// Assign Public to the new Set, but only when it not in use already
				if (empty($formValues->access) && !in_array(1, $groupsInUse))
				{
					$formValues->access = array(1);
				}
			}
			else
			{
				$formValues = (object) $this->value['setoptions'][$num];
			}

			// Collect already used groups
			if (!empty($formValues->access))
			{
				$groupsInUse = array_merge($groupsInUse, $formValues->access);
			}

			// Bind the values
			$setsForms[$num]->bind($formValues);
		}

		krsort($data['setsNames']);

		$data['setsForms'] = $setsForms;

		// Check for TinyMCE language file
		$language      = JFactory::getLanguage();
		$languageFile1 = 'media/editors/tinymce/langs/' . $language->getTag() . '.js';
		$languageFile2 = 'media/editors/tinymce/langs/' . substr($language->getTag(), 0, strpos($language->getTag(), '-')) . '.js';

		$data['languageFile'] = '';

		if (file_exists(JPATH_ROOT . '/' . $languageFile1))
		{
			$data['languageFile'] = $languageFile1;
		}
		elseif (file_exists(JPATH_ROOT . '/' . $languageFile2))
		{
			$data['languageFile'] = $languageFile2;
		}

		$this->layoutData = $data;

		return $data;
	}

}
PK��#]���h	h	$editors/tinymce/field/uploaddirs.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

jimport('joomla.form.helper');

JFormHelper::loadFieldClass('folderlist');

/**
 * Generates the list of directories  available for drag and drop upload.
 *
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 * @since       3.7.0
 */
class JFormFieldUploaddirs extends JFormFieldFolderList
{
	protected $type = 'uploaddirs';

	/**
	 * Method to attach a JForm object to the field.
	 *
	 * @param   SimpleXMLElement  $element  The SimpleXMLElement object representing the `<field>` tag for the form field object.
	 * @param   mixed             $value    The form field value to validate.
	 * @param   string            $group    The field name group control value. This acts as an array container for the field.
	 *                                      For example if the field has name="foo" and the group value is set to "bar" then the
	 *                                      full field name would end up being "bar[foo]".
	 *
	 * @return  boolean  True on success.
	 *
	 * @see     JFormField::setup()
	 * @since   3.7.0
	 */
	public function setup(SimpleXMLElement $element, $value, $group = null)
	{
		$return = parent::setup($element, $value, $group);

		// Get the path in which to search for file options.
		$this->directory   = JComponentHelper::getParams('com_media')->get('image_path');
		$this->recursive   = true;
		$this->hideDefault = true;

		return $return;
	}

	/**
	 * Method to get the directories options.
	 *
	 * @return  array  The dirs option objects.
	 *
	 * @since   3.7.0
	 */
	public function getOptions()
	{
		return parent::getOptions();
	}

	/**
	 * Method to get the field input markup for the list of directories.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   3.7.0
	 */
	protected function getInput()
	{
		$html = array();

		// Get the field options.
		$options = (array) $this->getOptions();

		// Reset the non selected value to null
		if ($options[0]->value === '-1')
		{
			$options[0]->value = '';
		}

		// Create a regular list.
		$html[] = JHtml::_('select.genericlist', $options, $this->name, '', 'value', 'text', $this->value, $this->id);

		return implode($html);
	}
}
PK��#]��G~�~�editors/tinymce/tinymce.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\HTML\HTMLHelper;

/**
 * TinyMCE Editor Plugin
 *
 * @since  1.5
 */
class PlgEditorTinymce extends JPlugin
{
	/**
	 * Base path for editor files
	 *
	 * @since  3.5
	 */
	protected $_basePath = 'media/editors/tinymce';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Loads the application object
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app = null;

	/**
	 * Initialises the Editor.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onInit()
	{
		JHtml::_('behavior.core');
		JHtml::_('behavior.polyfill', array('event'), 'lt IE 9');
		JHtml::_('script', $this->_basePath . '/tinymce.min.js', array('version' => 'auto'));
		JHtml::_('script', 'editors/tinymce/tinymce.min.js', array('version' => 'auto', 'relative' => true));
	}

	/**
	 * TinyMCE WYSIWYG Editor - get the editor content
	 *
	 * @param   string  $id  The name of the editor
	 *
	 * @since   1.5
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onGetContent($id)
	{
		return 'Joomla.editors.instances[' . json_encode($id) . '].getValue();';
	}

	/**
	 * TinyMCE WYSIWYG Editor - set the editor content
	 *
	 * @param   string  $id    The name of the editor
	 * @param   string  $html  The html to place in the editor
	 *
	 * @since   1.5
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSetContent($id, $html)
	{
		return 'Joomla.editors.instances[' . json_encode($id) . '].setValue(' . json_encode($html) . ');';
	}

	/**
	 * TinyMCE WYSIWYG Editor - copy editor content to form field
	 *
	 * @param   string  $id  The name of the editor
	 *
	 * @since   1.5
	 *
	 * @return  void
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSave($id)
	{
	}

	/**
	 * Inserts html code into the editor
	 *
	 * @param   string  $name  The name of the editor
	 *
	 * @since   1.5
	 *
	 * @return  string
	 *
	 * @deprecated 3.5 tinyMCE (API v4) will get the content automatically from the text area
	 */
	public function onGetInsertMethod($name)
	{
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The name of the editor area.
	 * @param   string   $content  The content of the field.
	 * @param   string   $width    The width of the editor area.
	 * @param   string   $height   The height of the editor area.
	 * @param   int      $col      The number of columns for the editor area.
	 * @param   int      $row      The number of rows for the editor area.
	 * @param   boolean  $buttons  True and the editor buttons will be displayed.
	 * @param   string   $id       An optional ID for the textarea. If not supplied the name is used.
	 * @param   string   $asset    The object asset
	 * @param   object   $author   The author.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string
	 */
	public function onDisplay(
		$name, $content, $width, $height, $col, $row, $buttons = true, $id = null, $asset = null, $author = null, $params = array())
	{
		$app = JFactory::getApplication();

		// Check for old params for B/C
		$config_warn_count = $app->getUserState('plg_editors_tinymce.config_legacy_warn_count', 0);

		if ($this->params->exists('mode') && $this->params->exists('alignment'))
		{
			if ($app->isClient('administrator') && $config_warn_count < 2)
			{
				$link = JRoute::_('index.php?option=com_plugins&task=plugin.edit&extension_id=' . $this->getPluginId());
				$app->enqueueMessage(JText::sprintf('PLG_TINY_LEGACY_WARNING', $link), 'warning');
				$app->setUserState('plg_editors_tinymce.config_legacy_warn_count', ++$config_warn_count);
			}

			return $this->onDisplayLegacy($name, $content, $width, $height, $col, $row, $buttons, $id, $asset, $author, $params);
		}

		if (empty($id))
		{
			$id = $name;
		}

		$id            = preg_replace('/(\s|[^A-Za-z0-9_])+/', '_', $id);
		$nameGroup     = explode('[', preg_replace('/\[\]|\]/', '', $name));
		$fieldName     = end($nameGroup);
		$scriptOptions = array();

		// Check for existing options
		$doc     = JFactory::getDocument();
		$options = $doc->getScriptOptions('plg_editor_tinymce');

		// Only add "px" to width and height if they are not given as a percentage
		if (is_numeric($width))
		{
			$width .= 'px';
		}

		if (is_numeric($height))
		{
			$height .= 'px';
		}

		// Data object for the layout
		$textarea = new stdClass;
		$textarea->name    = $name;
		$textarea->id      = $id;
		$textarea->class   = 'mce_editable joomla-editor-tinymce';
		$textarea->cols    = $col;
		$textarea->rows    = $row;
		$textarea->width   = $width;
		$textarea->height  = $height;
		$textarea->content = $content;

		// Set editor to readonly mode
		$textarea->readonly = !empty($params['readonly']);

		// Render Editor markup
		$editor = '<div class="js-editor-tinymce">';
		$editor .= JLayoutHelper::render('joomla.tinymce.textarea', $textarea);
		$editor .= $this->_toogleButton($id);
		$editor .= '</div>';

		// Prepare the instance specific options, actually the ext-buttons
		if (empty($options['tinyMCE'][$fieldName]['joomlaExtButtons']))
		{
			$btns = $this->tinyButtons($id, $buttons);

			if (!empty($btns['names']))
			{
				JHtml::_('script', 'editors/tinymce/tiny-close.min.js', array('version' => 'auto', 'relative' => true), array('defer' => 'defer'));
			}

			// Set editor to readonly mode
			if (!empty($params['readonly']))
			{
				$options['tinyMCE'][$fieldName]['readonly'] = 1;
			}

			$options['tinyMCE'][$fieldName]['joomlaMergeDefaults'] = true;
			$options['tinyMCE'][$fieldName]['joomlaExtButtons']    = $btns;

			$doc->addScriptOptions('plg_editor_tinymce', $options, false);
		}

		// Setup Default (common) options for the Editor script

		// Check whether we already have them
		if (!empty($options['tinyMCE']['default']))
		{
			return $editor;
		}

		$user     = JFactory::getUser();
		$language = JFactory::getLanguage();
		$theme    = 'modern';
		$ugroups  = array_combine($user->getAuthorisedGroups(), $user->getAuthorisedGroups());

		// Prepare the parameters
		$levelParams      = new Joomla\Registry\Registry;
		$extraOptions     = new stdClass;
		$toolbarParams    = new stdClass;
		$extraOptionsAll  = $this->params->get('configuration.setoptions', array());
		$toolbarParamsAll = $this->params->get('configuration.toolbars', array());

		// Get configuration depend from User group
		foreach ($extraOptionsAll as $set => $val)
		{
			$val->access = empty($val->access) ? array() : $val->access;

			// Check whether User in one of allowed group
			foreach ($val->access as $group)
			{
				if (isset($ugroups[$group]))
				{
					$extraOptions  = $val;
					$toolbarParams = $toolbarParamsAll->$set;
				}
			}
		}

		// Merge the params
		$levelParams->loadObject($toolbarParams);
		$levelParams->loadObject($extraOptions);

		// List the skins
		$skindirs = glob(JPATH_ROOT . '/media/editors/tinymce/skins' . '/*', GLOB_ONLYDIR);

		// Set the selected skin
		$skin = 'lightgray';
		$side = $app->isClient('administrator') ? 'skin_admin' : 'skin';

		if ((int) $levelParams->get($side, 0) < count($skindirs))
		{
			$skin = basename($skindirs[(int) $levelParams->get($side, 0)]);
		}

		$langMode   = $levelParams->get('lang_mode', 1);
		$langPrefix = $levelParams->get('lang_code', 'en');

		if ($langMode)
		{
			if (file_exists(JPATH_ROOT . '/media/editors/tinymce/langs/' . $language->getTag() . '.js'))
			{
				$langPrefix = $language->getTag();
			}
			elseif (file_exists(JPATH_ROOT . '/media/editors/tinymce/langs/' . substr($language->getTag(), 0, strpos($language->getTag(), '-')) . '.js'))
			{
				$langPrefix = substr($language->getTag(), 0, strpos($language->getTag(), '-'));
			}
			else
			{
				$langPrefix = 'en';
			}
		}

		$text_direction = 'ltr';

		if ($language->isRtl())
		{
			$text_direction = 'rtl';
		}

		$use_content_css    = $levelParams->get('content_css', 1);
		$content_css_custom = $levelParams->get('content_css_custom', '');

		/*
		 * Lets get the default template for the site application
		 */
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('template')
			->from('#__template_styles')
			->where('client_id=0 AND home=' . $db->quote('1'));

		$db->setQuery($query);

		try
		{
			$template = $db->loadResult();
		}
		catch (RuntimeException $e)
		{
			$app->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');

			return '';
		}

		$content_css    = null;
		$templates_path = JPATH_SITE . '/templates';

		// Loading of css file for 'styles' dropdown
		if ($content_css_custom)
		{
			// If URL, just pass it to $content_css
			if (strpos($content_css_custom, 'http') !== false)
			{
				$content_css = $content_css_custom;
			}

			// If it is not a URL, assume it is a file name in the current template folder
			else
			{
				$content_css = JUri::root(true) . '/templates/' . $template . '/css/' . $content_css_custom;

				// Issue warning notice if the file is not found (but pass name to $content_css anyway to avoid TinyMCE error
				if (!file_exists($templates_path . '/' . $template . '/css/' . $content_css_custom))
				{
					$msg = sprintf(JText::_('PLG_TINY_ERR_CUSTOMCSSFILENOTPRESENT'), $content_css_custom);
					JLog::add($msg, JLog::WARNING, 'jerror');
				}
			}
		}
		else
		{
			// Process when use_content_css is Yes and no custom file given
			if ($use_content_css)
			{
				// First check templates folder for default template
				// if no editor.css file in templates folder, check system template folder
				if (!file_exists($templates_path . '/' . $template . '/css/editor.css'))
				{
					// If no editor.css file in system folder, show alert
					if (!file_exists($templates_path . '/system/css/editor.css'))
					{
						JLog::add(JText::_('PLG_TINY_ERR_EDITORCSSFILENOTPRESENT'), JLog::WARNING, 'jerror');
					}
					else
					{
						$content_css = JUri::root(true) . '/templates/system/css/editor.css';
					}
				}
				else
				{
					$content_css = JUri::root(true) . '/templates/' . $template . '/css/editor.css';
				}
			}
		}

		$ignore_filter = false;

		// Text filtering
		if ($levelParams->get('use_config_textfilters', 0))
		{
			// Use filters from com_config
			$filter = static::getGlobalFilters();

			$ignore_filter = $filter === false;

			$tagBlacklist  = !empty($filter->tagBlacklist) ? $filter->tagBlacklist : array();
			$attrBlacklist = !empty($filter->attrBlacklist) ? $filter->attrBlacklist : array();
			$tagArray      = !empty($filter->tagArray) ? $filter->tagArray : array();
			$attrArray     = !empty($filter->attrArray) ? $filter->attrArray : array();

			$invalid_elements  = implode(',', array_merge($tagBlacklist, $attrBlacklist, $tagArray, $attrArray));

			// Valid elements are all whitelist entries in com_config, which are now missing in the tagBlacklist
			$default_filter = JFilterInput::getInstance();
			$valid_elements = implode(',', array_diff($default_filter->tagBlacklist, $tagBlacklist));

			$extended_elements = '';
		}
		else
		{
			// Use filters from TinyMCE params
			$invalid_elements  = trim($levelParams->get('invalid_elements', 'script,applet,iframe'));
			$extended_elements = trim($levelParams->get('extended_elements', ''));
			$valid_elements    = trim($levelParams->get('valid_elements', ''));
		}

		$html_height = $this->params->get('html_height', '550');
		$html_width  = $this->params->get('html_width', '');

		if ($html_width == 750)
		{
			$html_width = '';
		}

		// The param is true for vertical resizing only, false or both
		$resizing          = (bool) $levelParams->get('resizing', true);
		$resize_horizontal = (bool) $levelParams->get('resize_horizontal', true);

		if ($resizing && $resize_horizontal)
		{
			$resizing = 'both';
		}

		// Set of always available plugins
		$plugins  = array(
			'autolink',
			'lists',
			'colorpicker',
			'importcss',
		);

		// Allowed elements
		$elements = array(
			'hr[id|title|alt|class|width|size|noshade]',
		);

		if ($extended_elements)
		{
			$elements = array_merge($elements, explode(',', $extended_elements));
		}

		// Prepare the toolbar/menubar
		$knownButtons = static::getKnownButtons();

		// Check if there no value at all
		if (!$levelParams->get('menu') && !$levelParams->get('toolbar1') && !$levelParams->get('toolbar2'))
		{
			// Get from preset
			$presets = static::getToolbarPreset();

			/*
			 * Predefine group as:
			 * Set 0: for Administrator, Editor, Super Users (4,7,8)
			 * Set 1: for Registered, Manager (2,6), all else are public
			 */
			switch (true)
			{
				case isset($ugroups[4]) || isset($ugroups[7]) || isset($ugroups[8]):
					$preset = $presets['advanced'];
					break;

				case isset($ugroups[2]) || isset($ugroups[6]):
					$preset = $presets['medium'];
					break;

				default:
					$preset = $presets['simple'];
			}

			$levelParams->loadArray($preset);
		}

		$menubar  = (array) $levelParams->get('menu', array());
		$toolbar1 = (array) $levelParams->get('toolbar1', array());
		$toolbar2 = (array) $levelParams->get('toolbar2', array());

		// Make an easy way to check which button is enabled
		$allButtons = array_merge($toolbar1, $toolbar2);
		$allButtons = array_combine($allButtons, $allButtons);

		// Check for button-specific plugins
		foreach ($allButtons as $btnName)
		{
			if (!empty($knownButtons[$btnName]['plugin']))
			{
				$plugins[] = $knownButtons[$btnName]['plugin'];
			}
		}

		// Template
		$templates = array();

		if (!empty($allButtons['template']))
		{
			// Note this check for the template_list.js file will be removed in Joomla 4.0
			if (is_file(JPATH_ROOT . '/media/editors/tinymce/templates/template_list.js'))
			{
				// If using the legacy file we need to include and input the files the new way
				$str = file_get_contents(JPATH_ROOT . '/media/editors/tinymce/templates/template_list.js');

				// Find from one [ to the last ]
				$matches = array();
				preg_match_all('/\[.*\]/', $str, $matches);

				// Set variables
				foreach ($matches['0'] as $match)
				{
					$values = array();
					preg_match_all('/\".*\"/', $match, $values);
					$result       = trim($values['0']['0'], '"');
					$final_result = explode(',', $result);

					$templates[] = array(
						'title' => trim($final_result['0'], ' " '),
						'description' => trim($final_result['2'], ' " '),
						'url' => JUri::root(true) . '/' . trim($final_result['1'], ' " '),
					);
				}

			}
			else
			{
				foreach (glob(JPATH_ROOT . '/media/editors/tinymce/templates/*.html') as $filename)
				{
					$filename = basename($filename, '.html');

					if ($filename !== 'index')
					{
						$lang        = JFactory::getLanguage();
						$title       = $filename;
						$description = ' ';

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_TITLE'))
						{
							$title = JText::_('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_TITLE');
						}

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_DESC'))
						{
							$description = JText::_('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_DESC');
						}

						$templates[] = array(
							'title' => $title,
							'description' => $description,
							'url' => JUri::root(true) . '/media/editors/tinymce/templates/' . $filename . '.html',
						);
					}
				}
			}
		}

		// Check for extra plugins, from the setoptions form
		foreach (array('wordcount' => 1, 'advlist' => 1, 'autosave' => 1, 'contextmenu' => 1) as $pName => $def)
		{
			if ($levelParams->get($pName, $def))
			{
				$plugins[] = $pName;
			}
		}

		// User custom plugins and buttons
		$custom_plugin = trim($levelParams->get('custom_plugin', ''));
		$custom_button = trim($levelParams->get('custom_button', ''));

		if ($custom_plugin)
		{
			$separator = strpos($custom_plugin, ',') !== false ? ',' : ' ';
			$plugins   = array_merge($plugins, explode($separator, $custom_plugin));
		}

		if ($custom_button)
		{
			$separator = strpos($custom_button, ',') !== false ? ',' : ' ';
			$toolbar1  = array_merge($toolbar1, explode($separator, $custom_button));
		}

		// Drag and drop Images
		$allowImgPaste = false;
		$dragdrop      = $levelParams->get('drag_drop', 1);

		if ($dragdrop && $user->authorise('core.create', 'com_media'))
		{
			$externalPlugins['jdragdrop'] = HTMLHelper::_(
					'script',
					'editors/tinymce/plugins/dragdrop/plugin.min.js',
					array('relative' => true, 'version' => 'auto', 'pathOnly' => true)
				);
			$allowImgPaste = true;
			$isSubDir      = '';
			$session       = JFactory::getSession();
			$uploadUrl     = JUri::base() . 'index.php?option=com_media&task=file.upload&tmpl=component&'
				. $session->getName() . '=' . $session->getId()
				. '&' . JSession::getFormToken() . '=1'
				. '&asset=image&format=json';

			if ($app->isClient('site'))
			{
				$uploadUrl = htmlentities($uploadUrl, 0, 'UTF-8', false);
			}

			// Is Joomla installed in subdirectory
			if (JUri::root(true) !== '/')
			{
				$isSubDir = JUri::root(true);
			}

			JText::script('PLG_TINY_ERR_UNSUPPORTEDBROWSER');

			$scriptOptions['setCustomDir']    = $isSubDir;
			$scriptOptions['mediaUploadPath'] = $levelParams->get('path', '');
			$scriptOptions['uploadUri']       = $uploadUrl;
		}

		// Build the final options set
		$scriptOptions = array_merge(
			$scriptOptions,
			array(
			'suffix'  => '.min',
			'baseURL' => JUri::root(true) . '/media/editors/tinymce',
			'directionality' => $text_direction,
			'language' => $langPrefix,
			'autosave_restore_when_empty' => false,
			'skin'   => $skin,
			'theme'  => $theme,
			'schema' => 'html5',

			// Toolbars
			'menubar'  => empty($menubar)  ? false : implode(' ', array_unique($menubar)),
			'toolbar1' => empty($toolbar1) ? null  : implode(' ', $toolbar1),
			'toolbar2' => empty($toolbar2) ? null  : implode(' ', $toolbar2),

			'plugins'  => implode(',', array_unique($plugins)),

			// Cleanup/Output
			'inline_styles'    => true,
			'gecko_spellcheck' => true,
			'entity_encoding'  => $levelParams->get('entity_encoding', 'raw'),
			'verify_html'      => !$ignore_filter,

			'valid_elements'          => $valid_elements,
			'extended_valid_elements' => implode(',', $elements),
			'invalid_elements'        => $invalid_elements,

			// URL
			'relative_urls'      => (bool) $levelParams->get('relative_urls', true),
			'remove_script_host' => false,

			// Layout
			'content_css'        => $content_css,
			'document_base_url'  => JUri::root(true) . '/',
			'paste_data_images'  => $allowImgPaste,
			'importcss_append'   => true,
			'image_title'        => true,
			'height'             => $html_height,
			'width'              => $html_width,
			'resize'             => $resizing,
			'templates'          => $templates,
			'image_advtab'       => (bool) $levelParams->get('image_advtab', false),
			'external_plugins'   => empty($externalPlugins) ? null  : $externalPlugins,
			'contextmenu'        => (bool) $levelParams->get('contextmenu', true) ? null : false,
			'elementpath'        => (bool) $levelParams->get('element_path', true),
		)
		);

		if ($levelParams->get('newlines'))
		{
			// Break
			$scriptOptions['force_br_newlines'] = true;
			$scriptOptions['force_p_newlines']  = false;
			$scriptOptions['forced_root_block'] = '';
		}
		else
		{
			// Paragraph
			$scriptOptions['force_br_newlines'] = false;
			$scriptOptions['force_p_newlines']  = true;
			$scriptOptions['forced_root_block'] = 'p';
		}

		$scriptOptions['rel_list'] = array(
			array('title' => 'None', 'value' => ''),
			array('title' => 'Alternate', 'value' => 'alternate'),
			array('title' => 'Author', 'value' => 'author'),
			array('title' => 'Bookmark', 'value' => 'bookmark'),
			array('title' => 'Help', 'value' => 'help'),
			array('title' => 'License', 'value' => 'license'),
			array('title' => 'Lightbox', 'value' => 'lightbox'),
			array('title' => 'Next', 'value' => 'next'),
			array('title' => 'No Follow', 'value' => 'nofollow'),
			array('title' => 'No Referrer', 'value' => 'noreferrer'),
			array('title' => 'Prefetch', 'value' => 'prefetch'),
			array('title' => 'Prev', 'value' => 'prev'),
			array('title' => 'Search', 'value' => 'search'),
			array('title' => 'Tag', 'value' => 'tag'),
		);

		/**
		 * Shrink the buttons if not on a mobile or if mobile view is off.
		 * If mobile view is on force into simple mode and enlarge the buttons
		 **/
		if (!$this->app->client->mobile)
		{
			$scriptOptions['toolbar_items_size'] = 'small';
		}
		elseif ($levelParams->get('mobile', 0))
		{
			$scriptOptions['menubar'] = false;
			unset($scriptOptions['toolbar2']);
		}

		$options['tinyMCE']['default'] = $scriptOptions;

		$doc->addStyleDeclaration('.mce-in { padding: 5px 10px !important;}');
		$doc->addScriptOptions('plg_editor_tinymce', $options);

		return $editor;
	}

	/**
	 * Get the toggle editor button
	 *
	 * @param   string  $name  Editor name
	 *
	 * @return  string
	 */
	private function _toogleButton($name)
	{
		return JLayoutHelper::render('joomla.tinymce.togglebutton', $name);
	}

	/**
	 * Get the XTD buttons and render them inside tinyMCE
	 *
	 * @param   string  $name      the id of the editor field
	 * @param   string  $excluded  the buttons that should be hidden
	 *
	 * @return array
	 */
	private function tinyButtons($name, $excluded)
	{
		// Get the available buttons
		$buttons = $this->_subject->getButtons($name, $excluded);

		// Init the arrays for the buttons
		$tinyBtns  = array();
		$btnsNames = array();

		// Build the script
		foreach ($buttons as $i => $button)
		{
			if ($button->get('name'))
			{
				// Set some vars
				$name    = 'button-' . $i . str_replace(' ', '', $button->get('text'));
				$title   = $button->get('text');
				$onclick = $button->get('onclick') ?: null;
				$options = $button->get('options');
				$icon    = $button->get('name');

				if ($button->get('link') !== '#')
				{
					$href = JUri::base() . $button->get('link');
				}
				else
				{
					$href = null;
				}

				// We do some hack here to set the correct icon for 3PD buttons
				$icon = 'none icon-' . $icon;

				$tempConstructor = array();

				// Now we can built the script
				$tempConstructor[] = '!(function(){';

				// Get the modal width/height
				if ($options && is_scalar($options))
				{
					$tempConstructor[] = 'var getBtnOptions=new Function("return ' . addslashes($options) . '"),';
					$tempConstructor[] = 'btnOptions=getBtnOptions(),';
					$tempConstructor[] = 'modalWidth=btnOptions.size&&btnOptions.size.x?btnOptions.size.x:null,';
					$tempConstructor[] = 'modalHeight=btnOptions.size&&btnOptions.size.y?btnOptions.size.y:null;';
				}
				else
				{
					$tempConstructor[] = 'var btnOptions={},modalWidth=null,modalHeight=null;';
				}

				// Now we can built the script
				// AddButton starts here
				$tempConstructor[] = 'editor.addButton("' . $name . '",{';
				$tempConstructor[] = 'text:"' . $title . '",';
				$tempConstructor[] = 'title:"' . $title . '",';
				$tempConstructor[] = 'icon:"' . $icon . '",';

				// Onclick starts here
				$tempConstructor[] = 'onclick:function(){';

				if ($href || $button->get('modal'))
				{
					// TinyMCE standard modal options
					$tempConstructor[] = 'var modalOptions={';
					$tempConstructor[] = 'title:"' . $title . '",';
					$tempConstructor[] = 'url:"' . $href . '",';
					$tempConstructor[] = 'buttons:[{text: "Close",onclick:"close"}]';
					$tempConstructor[] = '};';

					// Set width/height
					$tempConstructor[] = 'if(modalWidth){modalOptions.width=modalWidth;}';
					$tempConstructor[] = 'if(modalHeight){modalOptions.height = modalHeight;}';
					$tempConstructor[] = 'var win=editor.windowManager.open(modalOptions);';

					if (JFactory::getApplication()->client->mobile)
					{
						$tempConstructor[] = 'win.fullscreen(true);';
					}

					if ($onclick && ($button->get('modal') || $href))
					{
						// Adds callback for close button
						$tempConstructor[] = $onclick . ';';
					}
				}
				else
				{
					// Adds callback for the button, eg: readmore
					$tempConstructor[] = $onclick . ';';
				}

				// Onclick ends here
				$tempConstructor[] = '}';

				// AddButton ends here
				$tempConstructor[] = '});';

				// IIFE ends here
				$tempConstructor[] = '})();';

				// The array with the toolbar buttons
				$btnsNames[] = $name . ' | ';

				// The array with code for each button
				$tinyBtns[] = implode('', $tempConstructor);
			}
		}

		return array(
				'names'  => $btnsNames,
				'script' => $tinyBtns
		);
	}

	/**
	 * Get the global text filters to arbitrary text as per settings for current user groups
	 *
	 * @return  JFilterInput
	 *
	 * @since   3.6
	 */
	protected static function getGlobalFilters()
	{
		// Filter settings
		$config     = JComponentHelper::getParams('com_config');
		$user       = JFactory::getUser();
		$userGroups = JAccess::getGroupsByUser($user->get('id'));

		$filters = $config->get('filters');

		$blackListTags       = array();
		$blackListAttributes = array();

		$customListTags       = array();
		$customListAttributes = array();

		$whiteListTags       = array();
		$whiteListAttributes = array();

		$whiteList  = false;
		$blackList  = false;
		$customList = false;
		$unfiltered = false;

		// Cycle through each of the user groups the user is in.
		// Remember they are included in the public group as well.
		foreach ($userGroups as $groupId)
		{
			// May have added a group but not saved the filters.
			if (!isset($filters->$groupId))
			{
				continue;
			}

			// Each group the user is in could have different filtering properties.
			$filterData = $filters->$groupId;
			$filterType = strtoupper($filterData->filter_type);

			if ($filterType === 'NH')
			{
				// Maximum HTML filtering.
			}
			elseif ($filterType === 'NONE')
			{
				// No HTML filtering.
				$unfiltered = true;
			}
			else
			{
				// Blacklist or whitelist.
				// Preprocess the tags and attributes.
				$tags           = explode(',', $filterData->filter_tags);
				$attributes     = explode(',', $filterData->filter_attributes);
				$tempTags       = array();
				$tempAttributes = array();

				foreach ($tags as $tag)
				{
					$tag = trim($tag);

					if ($tag)
					{
						$tempTags[] = $tag;
					}
				}

				foreach ($attributes as $attribute)
				{
					$attribute = trim($attribute);

					if ($attribute)
					{
						$tempAttributes[] = $attribute;
					}
				}

				// Collect the blacklist or whitelist tags and attributes.
				// Each list is cummulative.
				if ($filterType === 'BL')
				{
					$blackList           = true;
					$blackListTags       = array_merge($blackListTags, $tempTags);
					$blackListAttributes = array_merge($blackListAttributes, $tempAttributes);
				}
				elseif ($filterType === 'CBL')
				{
					// Only set to true if Tags or Attributes were added
					if ($tempTags || $tempAttributes)
					{
						$customList           = true;
						$customListTags       = array_merge($customListTags, $tempTags);
						$customListAttributes = array_merge($customListAttributes, $tempAttributes);
					}
				}
				elseif ($filterType === 'WL')
				{
					$whiteList           = true;
					$whiteListTags       = array_merge($whiteListTags, $tempTags);
					$whiteListAttributes = array_merge($whiteListAttributes, $tempAttributes);
				}
			}
		}

		// Remove duplicates before processing (because the blacklist uses both sets of arrays).
		$blackListTags        = array_unique($blackListTags);
		$blackListAttributes  = array_unique($blackListAttributes);
		$customListTags       = array_unique($customListTags);
		$customListAttributes = array_unique($customListAttributes);
		$whiteListTags        = array_unique($whiteListTags);
		$whiteListAttributes  = array_unique($whiteListAttributes);

		// Unfiltered assumes first priority.
		if ($unfiltered)
		{
			// Dont apply filtering.
			return false;
		}
		else
		{
			// Custom blacklist precedes Default blacklist
			if ($customList)
			{
				$filter = JFilterInput::getInstance(array(), array(), 1, 1);

				// Override filter's default blacklist tags and attributes
				if ($customListTags)
				{
					$filter->tagBlacklist = $customListTags;
				}

				if ($customListAttributes)
				{
					$filter->attrBlacklist = $customListAttributes;
				}
			}
			// Blacklists take second precedence.
			elseif ($blackList)
			{
				// Remove the white-listed tags and attributes from the black-list.
				$blackListTags       = array_diff($blackListTags, $whiteListTags);
				$blackListAttributes = array_diff($blackListAttributes, $whiteListAttributes);

				$filter = JFilterInput::getInstance($blackListTags, $blackListAttributes, 1, 1);

				// Remove whitelisted tags from filter's default blacklist
				if ($whiteListTags)
				{
					$filter->tagBlacklist = array_diff($filter->tagBlacklist, $whiteListTags);
				}

				// Remove whitelisted attributes from filter's default blacklist
				if ($whiteListAttributes)
				{
					$filter->attrBlacklist = array_diff($filter->attrBlacklist, $whiteListAttributes);
				}
			}
			// Whitelists take third precedence.
			elseif ($whiteList)
			{
				// Turn off XSS auto clean
				$filter = JFilterInput::getInstance($whiteListTags, $whiteListAttributes, 0, 0, 0);
			}
			// No HTML takes last place.
			else
			{
				$filter = JFilterInput::getInstance();
			}

			return $filter;
		}
	}

	/**
	 * Return list of known TinyMCE buttons
	 *
	 * @return array
	 *
	 * @since 3.7.0
	 */
	public static function getKnownButtons()
	{
		// See https://www.tinymce.com/docs/demo/full-featured/
		// And https://www.tinymce.com/docs/plugins/
		$buttons = array(

			// General buttons
			'|'              => array('label' => JText::_('PLG_TINY_TOOLBAR_BUTTON_SEPARATOR'), 'text' => '|'),

			'undo'           => array('label' => 'Undo'),
			'redo'           => array('label' => 'Redo'),

			'bold'           => array('label' => 'Bold'),
			'italic'         => array('label' => 'Italic'),
			'underline'      => array('label' => 'Underline'),
			'strikethrough'  => array('label' => 'Strikethrough'),
			'styleselect'    => array('label' => JText::_('PLG_TINY_TOOLBAR_BUTTON_STYLESELECT'), 'text' => 'Formats'),
			'formatselect'   => array('label' => JText::_('PLG_TINY_TOOLBAR_BUTTON_FORMATSELECT'), 'text' => 'Paragraph'),
			'fontselect'     => array('label' => JText::_('PLG_TINY_TOOLBAR_BUTTON_FONTSELECT'), 'text' => 'Font Family'),
			'fontsizeselect' => array('label' => JText::_('PLG_TINY_TOOLBAR_BUTTON_FONTSIZESELECT'), 'text' => 'Font Sizes'),

			'alignleft'     => array('label' => 'Align left'),
			'aligncenter'   => array('label' => 'Align center'),
			'alignright'    => array('label' => 'Align right'),
			'alignjustify'  => array('label' => 'Justify'),

			'outdent'       => array('label' => 'Decrease indent'),
			'indent'        => array('label' => 'Increase indent'),

			'bullist'       => array('label' => 'Bullet list'),
			'numlist'       => array('label' => 'Numbered list'),

			'link'          => array('label' => 'Insert/edit link', 'plugin' => 'link'),
			'unlink'        => array('label' => 'Remove link', 'plugin' => 'link'),

			'subscript'     => array('label' => 'Subscript'),
			'superscript'   => array('label' => 'Superscript'),
			'blockquote'    => array('label' => 'Blockquote'),

			'cut'           => array('label' => 'Cut'),
			'copy'          => array('label' => 'Copy'),
			'paste'         => array('label' => 'Paste', 'plugin' => 'paste'),
			'pastetext'     => array('label' => 'Paste as text', 'plugin' => 'paste'),
			'removeformat'  => array('label' => 'Clear formatting'),

			// Buttons from the plugins
			'forecolor'      => array('label' => 'Text color', 'plugin' => 'textcolor'),
			'backcolor'      => array('label' => 'Background color', 'plugin' => 'textcolor'),
			'anchor'         => array('label' => 'Anchor', 'plugin' => 'anchor'),
			'hr'             => array('label' => 'Horizontal line', 'plugin' => 'hr'),
			'ltr'            => array('label' => 'Left to right', 'plugin' => 'directionality'),
			'rtl'            => array('label' => 'Right to left', 'plugin' => 'directionality'),
			'code'           => array('label' => 'Source code', 'plugin' => 'code'),
			'codesample'     => array('label' => 'Insert/Edit code sample', 'plugin' => 'codesample'),
			'table'          => array('label' => 'Table', 'plugin' => 'table'),
			'charmap'        => array('label' => 'Special character', 'plugin' => 'charmap'),
			'visualchars'    => array('label' => 'Show invisible characters', 'plugin' => 'visualchars'),
			'visualblocks'   => array('label' => 'Show blocks', 'plugin' => 'visualblocks'),
			'nonbreaking'    => array('label' => 'Nonbreaking space', 'plugin' => 'nonbreaking'),
			'emoticons'      => array('label' => 'Emoticons', 'plugin' => 'emoticons'),
			'image'          => array('label' => 'Insert/edit image', 'plugin' => 'image'),
			'media'          => array('label' => 'Insert/edit video', 'plugin' => 'media'),
			'pagebreak'      => array('label' => 'Page break', 'plugin' => 'pagebreak'),
			'print'          => array('label' => 'Print', 'plugin' => 'print'),
			'preview'        => array('label' => 'Preview', 'plugin' => 'preview'),
			'fullscreen'     => array('label' => 'Fullscreen', 'plugin' => 'fullscreen'),
			'template'       => array('label' => 'Insert template', 'plugin' => 'template'),
			'searchreplace'  => array('label' => 'Find and replace', 'plugin' => 'searchreplace'),
			'insertdatetime' => array('label' => 'Insert date/time', 'plugin' => 'insertdatetime'),
			// 'spellchecker'   => array('label' => 'Spellcheck', 'plugin' => 'spellchecker'),
		);

		return $buttons;
	}

	/**
	 * Return toolbar presets
	 *
	 * @return array
	 *
	 * @since 3.7.0
	 */
	public static function getToolbarPreset()
	{
		$preset = array();

		$preset['simple'] = array(
			'menu' => array(),
			'toolbar1' => array(
				'bold', 'underline', 'strikethrough', '|',
				'undo', 'redo', '|',
				'bullist', 'numlist', '|',
				'pastetext'
			),
			'toolbar2' => array(),
		);

		$preset['medium'] = array(
			'menu' => array('edit', 'insert', 'view', 'format', 'table', 'tools'),
			'toolbar1' => array(
				'bold', 'italic', 'underline', 'strikethrough', '|',
				'alignleft', 'aligncenter', 'alignright', 'alignjustify', '|',
				'formatselect', '|',
				'bullist', 'numlist', '|',
				'outdent', 'indent', '|',
				'undo', 'redo', '|',
				'link', 'unlink', 'anchor', 'code', '|',
				'hr', 'table', '|',
				'subscript', 'superscript', '|',
				'charmap', 'pastetext' , 'preview'
			),
			'toolbar2' => array(),
		);

		$preset['advanced'] = array(
			'menu'     => array('edit', 'insert', 'view', 'format', 'table', 'tools'),
			'toolbar1' => array(
				'bold', 'italic', 'underline', 'strikethrough', '|',
				'alignleft', 'aligncenter', 'alignright', 'alignjustify', '|',
				'styleselect', '|',
				'formatselect', 'fontselect', 'fontsizeselect', '|',
				'searchreplace', '|',
				'bullist', 'numlist', '|',
				'outdent', 'indent', '|',
				'undo', 'redo', '|',
				'link', 'unlink', 'anchor', 'image', '|',
				'code', '|',
				'forecolor', 'backcolor', '|',
				'fullscreen', '|',
				'table', '|',
				'subscript', 'superscript', '|',
				'charmap', 'emoticons', 'media', 'hr', 'ltr', 'rtl', '|',
				'cut', 'copy', 'paste', 'pastetext', '|',
				'visualchars', 'visualblocks', 'nonbreaking', 'blockquote', 'template', '|',
				'print', 'preview', 'codesample', 'insertdatetime', 'removeformat',
			),
			'toolbar2' => array(),
		);

		return $preset;
	}

	/**
	 * Gets the plugin extension id.
	 *
	 * @return  int  The plugin id.
	 *
	 * @since   3.7.0
	 */
	private function getPluginId()
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
					->select($db->quoteName('extension_id'))
					->from($db->quoteName('#__extensions'))
					->where($db->quoteName('folder') . ' = ' . $db->quote($this->_type))
					->where($db->quoteName('element') . ' = ' . $db->quote($this->_name));
		$db->setQuery($query);

		return (int) $db->loadResult();
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The name of the editor area.
	 * @param   string   $content  The content of the field.
	 * @param   string   $width    The width of the editor area.
	 * @param   string   $height   The height of the editor area.
	 * @param   int      $col      The number of columns for the editor area.
	 * @param   int      $row      The number of rows for the editor area.
	 * @param   boolean  $buttons  True and the editor buttons will be displayed.
	 * @param   string   $id       An optional ID for the textarea. If not supplied the name is used.
	 * @param   string   $asset    The object asset
	 * @param   object   $author   The author.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string
	 *
	 * @since  3.7.0
	 *
	 * @deprecated 4.0
	 */
	private function onDisplayLegacy(
		$name, $content, $width, $height, $col, $row, $buttons = true, $id = null, $asset = null, $author = null, $params = array())
	{
		if (empty($id))
		{
			$id = $name;
		}

		$id            = preg_replace('/(\s|[^A-Za-z0-9_])+/', '_', $id);
		$nameGroup     = explode('[', preg_replace('/\[\]|\]/', '', $name));
		$fieldName     = end($nameGroup);
		$scriptOptions = array();

		// Check for existing options
		$doc     = JFactory::getDocument();
		$options = $doc->getScriptOptions('plg_editor_tinymce');

		// Only add "px" to width and height if they are not given as a percentage
		if (is_numeric($width))
		{
			$width .= 'px';
		}

		if (is_numeric($height))
		{
			$height .= 'px';
		}

		// Data object for the layout
		$textarea = new stdClass;
		$textarea->name    = $name;
		$textarea->id      = $id;
		$textarea->class   = 'mce_editable joomla-editor-tinymce';
		$textarea->cols    = $col;
		$textarea->rows    = $row;
		$textarea->width   = $width;
		$textarea->height  = $height;
		$textarea->content = $content;

		// Set editor to readonly mode
		$textarea->readonly = !empty($params['readonly']);

		// Render Editor markup
		$editor = '<div class="editor js-editor-tinymce">';
		$editor .= JLayoutHelper::render('joomla.tinymce.textarea', $textarea);
		$editor .= $this->_toogleButton($id);
		$editor .= '</div>';

		// Prepare instance specific options, actually the ext-buttons
		if (empty($options['tinyMCE'][$fieldName]['joomlaExtButtons']))
		{
			$btns = $this->tinyButtons($id, $buttons);

			if (!empty($btns['names']))
			{
				JHtml::_('script', 'editors/tinymce/tiny-close.min.js', array('version' => 'auto', 'relative' => true), array('defer' => 'defer'));
			}

			// Set editor to readonly mode
			if (!empty($params['readonly']))
			{
				$options['tinyMCE'][$fieldName]['readonly'] = 1;
			}

			$options['tinyMCE'][$fieldName]['joomlaMergeDefaults'] = true;
			$options['tinyMCE'][$fieldName]['joomlaExtButtons']    = $btns;

			$doc->addScriptOptions('plg_editor_tinymce', $options, false);
		}

		// Setup Default options for the Editor script

		// Check whether we already have them
		if (!empty($options['tinyMCE']['default']))
		{
			return $editor;
		}

		$app      = JFactory::getApplication();
		$user     = JFactory::getUser();
		$language = JFactory::getLanguage();
		$mode     = (int) $this->params->get('mode', 1);
		$theme    = 'modern';

		// List the skins
		$skindirs = glob(JPATH_ROOT . '/media/editors/tinymce/skins' . '/*', GLOB_ONLYDIR);


		// Set the selected skin
		$skin = 'lightgray';
		$side = $app->isClient('administrator') ? 'skin_admin' : 'skin';

		if ((int) $this->params->get($side, 0) < count($skindirs))
		{
			$skin = basename($skindirs[(int) $this->params->get($side, 0)]);
		}

		$langMode        = $this->params->get('lang_mode', 0);
		$langPrefix      = $this->params->get('lang_code', 'en');

		if ($langMode)
		{
			if (file_exists(JPATH_ROOT . "/media/editors/tinymce/langs/" . $language->getTag() . ".js"))
			{
				$langPrefix = $language->getTag();
			}
			elseif (file_exists(JPATH_ROOT . "/media/editors/tinymce/langs/" . substr($language->getTag(), 0, strpos($language->getTag(), '-')) . ".js"))
			{
				$langPrefix = substr($language->getTag(), 0, strpos($language->getTag(), '-'));
			}
			else
			{
				$langPrefix = "en";
			}
		}

		$text_direction = 'ltr';

		if ($language->isRtl())
		{
			$text_direction = 'rtl';
		}

		$use_content_css    = $this->params->get('content_css', 1);
		$content_css_custom = $this->params->get('content_css_custom', '');

		/*
		 * Lets get the default template for the site application
		 */
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
					->select('template')
					->from('#__template_styles')
					->where('client_id=0 AND home=' . $db->quote('1'));

		$db->setQuery($query);

		try
		{
			$template = $db->loadResult();
		}
		catch (RuntimeException $e)
		{
			$app->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error');

			return;
		}

		$content_css    = null;
		$templates_path = JPATH_SITE . '/templates';

		// Loading of css file for 'styles' dropdown
		if ($content_css_custom)
		{
			// If URL, just pass it to $content_css
			if (strpos($content_css_custom, 'http') !== false)
			{
				$content_css = $content_css_custom;
			}

			// If it is not a URL, assume it is a file name in the current template folder
			else
			{
				$content_css = JUri::root(true) . '/templates/' . $template . '/css/' . $content_css_custom;

				// Issue warning notice if the file is not found (but pass name to $content_css anyway to avoid TinyMCE error
				if (!file_exists($templates_path . '/' . $template . '/css/' . $content_css_custom))
				{
					$msg = sprintf(JText::_('PLG_TINY_ERR_CUSTOMCSSFILENOTPRESENT'), $content_css_custom);
					JLog::add($msg, JLog::WARNING, 'jerror');
				}
			}
		}
		else
		{
			// Process when use_content_css is Yes and no custom file given
			if ($use_content_css)
			{
				// First check templates folder for default template
				// if no editor.css file in templates folder, check system template folder
				if (!file_exists($templates_path . '/' . $template . '/css/editor.css'))
				{
					// If no editor.css file in system folder, show alert
					if (!file_exists($templates_path . '/system/css/editor.css'))
					{
						JLog::add(JText::_('PLG_TINY_ERR_EDITORCSSFILENOTPRESENT'), JLog::WARNING, 'jerror');
					}
					else
					{
						$content_css = JUri::root(true) . '/templates/system/css/editor.css';
					}
				}
				else
				{
					$content_css = JUri::root(true) . '/templates/' . $template . '/css/editor.css';
				}
			}
		}

		$ignore_filter = false;

		// Text filtering
		if ($this->params->get('use_config_textfilters', 0))
		{
			// Use filters from com_config
			$filter = static::getGlobalFilters();

			$ignore_filter = $filter === false;

			$tagBlacklist  = !empty($filter->tagBlacklist) ? $filter->tagBlacklist : array();
			$attrBlacklist = !empty($filter->attrBlacklist) ? $filter->attrBlacklist : array();
			$tagArray      = !empty($filter->tagArray) ? $filter->tagArray : array();
			$attrArray     = !empty($filter->attrArray) ? $filter->attrArray : array();

			$invalid_elements  = implode(',', array_merge($tagBlacklist, $attrBlacklist, $tagArray, $attrArray));

			// Valid elements are all whitelist entries in com_config, which are now missing in the tagBlacklist
			$default_filter = JFilterInput::getInstance();
			$valid_elements =	implode(',', array_diff($default_filter->tagBlacklist, $tagBlacklist));

			$extended_elements = '';
		}
		else
		{
			// Use filters from TinyMCE params
			$invalid_elements  = $this->params->get('invalid_elements', 'script,applet,iframe');
			$extended_elements = $this->params->get('extended_elements', '');
			$valid_elements    = $this->params->get('valid_elements', '');
		}

		// Advanced Options
		$access = $user->getAuthorisedViewLevels();

		// Flip for performance, so we can direct check for the key isset($access[$key])
		$access = array_flip($access);

		$html_height = $this->params->get('html_height', '550');
		$html_width  = $this->params->get('html_width', '');

		if ($html_width == 750)
		{
			$html_width = '';
		}

		// Image advanced options
		$image_advtab = $this->params->get('image_advtab', true);

		if (isset($access[$image_advtab]))
		{
			$image_advtab = true;
		}
		else
		{
			$image_advtab = false;
		}

		// The param is true for vertical resizing only, false or both
		$resizing          = $this->params->get('resizing', '1');
		$resize_horizontal = $this->params->get('resize_horizontal', '1');

		if ($resizing || $resizing == 'true')
		{
			if ($resize_horizontal || $resize_horizontal == 'true')
			{
				$resizing = 'both';
			}
			else
			{
				$resizing = true;
			}
		}
		else
		{
			$resizing = false;
		}

		$toolbar1_add   = array();
		$toolbar2_add   = array();
		$toolbar3_add   = array();
		$toolbar4_add   = array();
		$elements       = array();
		$plugins        = array(
			'autolink',
			'lists',
			'image',
			'charmap',
			'print',
			'preview',
			'anchor',
			'pagebreak',
			'code',
			'save',
			'textcolor',
			'colorpicker',
			'importcss');
		$toolbar1_add[] = 'bold';
		$toolbar1_add[] = 'italic';
		$toolbar1_add[] = 'underline';
		$toolbar1_add[] = 'strikethrough';

		// Alignment buttons
		$alignment = $this->params->get('alignment', 1);

		if (isset($access[$alignment]))
		{
			$toolbar1_add[] = '|';
			$toolbar1_add[] = 'alignleft';
			$toolbar1_add[] = 'aligncenter';
			$toolbar1_add[] = 'alignright';
			$toolbar1_add[] = 'alignjustify';
		}

		$toolbar1_add[] = '|';
		$toolbar1_add[] = 'styleselect';
		$toolbar1_add[] = '|';
		$toolbar1_add[] = 'formatselect';

		// Fonts
		$fonts = $this->params->get('fonts', 1);

		if (isset($access[$fonts]))
		{
			$toolbar1_add[] = 'fontselect';
			$toolbar1_add[] = 'fontsizeselect';
		}

		// Search & replace
		$searchreplace = $this->params->get('searchreplace', 1);

		if (isset($access[$searchreplace]))
		{
			$plugins[]      = 'searchreplace';
			$toolbar2_add[] = 'searchreplace';
		}

		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'bullist';
		$toolbar2_add[] = 'numlist';
		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'outdent';
		$toolbar2_add[] = 'indent';
		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'undo';
		$toolbar2_add[] = 'redo';
		$toolbar2_add[] = '|';

		// Insert date and/or time plugin
		$insertdate = $this->params->get('insertdate', 1);

		if (isset($access[$insertdate]))
		{
			$plugins[]      = 'insertdatetime';
			$toolbar4_add[] = 'inserttime';
		}

		// Link plugin
		$link = $this->params->get('link', 1);

		if (isset($access[$link]))
		{
			$plugins[]      = 'link';
			$toolbar2_add[] = 'link';
			$toolbar2_add[] = 'unlink';
		}

		$toolbar2_add[] = 'anchor';
		$toolbar2_add[] = 'image';
		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'code';

		// Colors
		$colors = $this->params->get('colors', 1);

		if (isset($access[$colors]))
		{
			$toolbar2_add[] = '|';
			$toolbar2_add[] = 'forecolor,backcolor';
		}

		// Fullscreen
		$fullscreen = $this->params->get('fullscreen', 1);

		if (isset($access[$fullscreen]))
		{
			$plugins[]      = 'fullscreen';
			$toolbar2_add[] = '|';
			$toolbar2_add[] = 'fullscreen';
		}

		// Table
		$table = $this->params->get('table', 1);

		if (isset($access[$table]))
		{
			$plugins[]      = 'table';
			$toolbar3_add[] = 'table';
			$toolbar3_add[] = '|';
		}

		$toolbar3_add[] = 'subscript';
		$toolbar3_add[] = 'superscript';
		$toolbar3_add[] = '|';
		$toolbar3_add[] = 'charmap';

		// Emotions
		$smilies = $this->params->get('smilies', 1);

		if (isset($access[$smilies]))
		{
			$plugins[]      = 'emoticons';
			$toolbar3_add[] = 'emoticons';
		}

		// Media plugin
		$media = $this->params->get('media', 1);

		if (isset($access[$media]))
		{
			$plugins[]      = 'media';
			$toolbar3_add[] = 'media';
		}

		// Horizontal line
		$hr = $this->params->get('hr', 1);

		if (isset($access[$hr]))
		{
			$plugins[]      = 'hr';
			$elements[]     = 'hr[id|title|alt|class|width|size|noshade]';
			$toolbar3_add[] = 'hr';
		}
		else
		{
			$elements[] = 'hr[id|class|title|alt]';
		}

		// RTL/LTR buttons
		$directionality = $this->params->get('directionality', 1);

		if (isset($access[$directionality]))
		{
			$plugins[]      = 'directionality';
			$toolbar3_add[] = 'ltr rtl';
		}

		if ($extended_elements != "")
		{
			$elements = explode(',', $extended_elements);
		}

		$toolbar4_add[] = 'cut';
		$toolbar4_add[] = 'copy';

		// Paste
		$paste = $this->params->get('paste', 1);

		if (isset($access[$paste]))
		{
			$plugins[]      = 'paste';
			$toolbar4_add[] = 'paste';
		}

		$toolbar4_add[] = '|';

		// Visualchars
		$visualchars = $this->params->get('visualchars', 1);

		if (isset($access[$visualchars]))
		{
			$plugins[]      = 'visualchars';
			$toolbar4_add[] = 'visualchars';
		}

		// Visualblocks
		$visualblocks = $this->params->get('visualblocks', 1);

		if (isset($access[$visualblocks]))
		{
			$plugins[]      = 'visualblocks';
			$toolbar4_add[] = 'visualblocks';
		}

		// Non-breaking
		$nonbreaking = $this->params->get('nonbreaking', 1);

		if (isset($access[$nonbreaking]))
		{
			$plugins[]      = 'nonbreaking';
			$toolbar4_add[] = 'nonbreaking';
		}

		// Blockquote
		$blockquote = $this->params->get('blockquote', 1);

		if (isset($access[$blockquote]))
		{
			$toolbar4_add[] = 'blockquote';
		}

		// Template
		$template = $this->params->get('template', 1);
		$templates = array();

		if (isset($access[$template]))
		{
			$plugins[]      = 'template';
			$toolbar4_add[] = 'template';

			// Note this check for the template_list.js file will be removed in Joomla 4.0
			if (is_file(JPATH_ROOT . "/media/editors/tinymce/templates/template_list.js"))
			{
				// If using the legacy file we need to include and input the files the new way
				$str = file_get_contents(JPATH_ROOT . "/media/editors/tinymce/templates/template_list.js");

				// Find from one [ to the last ]
				$matches = array();
				preg_match_all('/\[.*\]/', $str, $matches);

				// Set variables
				foreach ($matches['0'] as $match)
				{
					$values = array();
					preg_match_all('/\".*\"/', $match, $values);
					$result       = trim($values["0"]["0"], '"');
					$final_result = explode(',', $result);

					$templates[] = array(
						'title' => trim($final_result['0'], ' " '),
						'description' => trim($final_result['2'], ' " '),
						'url' => JUri::root(true) . '/' . trim($final_result['1'], ' " '),
					);
				}

			}
			else
			{
				foreach (glob(JPATH_ROOT . '/media/editors/tinymce/templates/*.html') as $filename)
				{
					$filename = basename($filename, '.html');

					if ($filename !== 'index')
					{
						$lang        = JFactory::getLanguage();
						$title       = $filename;
						$description = ' ';

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_TITLE'))
						{
							$title = JText::_('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_TITLE');
						}

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_DESC'))
						{
							$description = JText::_('PLG_TINY_TEMPLATE_' . strtoupper($filename) . '_DESC');
						}

						$templates[] = array(
							'title' => $title,
							'description' => $description,
							'url' => JUri::root(true) . '/media/editors/tinymce/templates/' . $filename . '.html',
						);
					}
				}
			}
		}

		// Print
		$print = $this->params->get('print', 1);

		if (isset($access[$print]))
		{
			$plugins[]      = 'print';
			$toolbar4_add[] = '|';
			$toolbar4_add[] = 'print';
			$toolbar4_add[] = 'preview';
		}

		// Spellchecker
		$spell = $this->params->get('spell', 0);

		if (isset($access[$spell]))
		{
			$plugins[]      = 'spellchecker';
			$toolbar4_add[] = '|';
			$toolbar4_add[] = 'spellchecker';
		}

		// Wordcount
		$wordcount = $this->params->get('wordcount', 1);

		if (isset($access[$wordcount]))
		{
			$plugins[] = 'wordcount';
		}

		// Advlist
		$advlist = $this->params->get('advlist', 1);

		if (isset($access[$advlist]))
		{
			$plugins[] = 'advlist';
		}

		// Codesample
		$advlist = $this->params->get('code_sample', 1);

		if (isset($access[$advlist]))
		{
			$plugins[]      = 'codesample';
			$toolbar4_add[] = 'codesample';
		}

		// Autosave
		$autosave = $this->params->get('autosave', 1);

		if (isset($access[$autosave]))
		{
			$plugins[] = 'autosave';
		}

		// Context menu
		$contextmenu = $this->params->get('contextmenu', 1);

		if (isset($access[$contextmenu]))
		{
			$plugins[] = 'contextmenu';
		}

		$custom_plugin = $this->params->get('custom_plugin', '');

		if ($custom_plugin != "")
		{
			$plugins[] = $custom_plugin;
		}

		$custom_button = $this->params->get('custom_button', '');

		if ($custom_button != "")
		{
			$toolbar4_add[] = $custom_button;
		}

		// Drag and drop Images
		$externalPlugins = array();
		$allowImgPaste   = false;
		$dragdrop        = $this->params->get('drag_drop', 1);

		if ($dragdrop && $user->authorise('core.create', 'com_media'))
		{
			$allowImgPaste = true;
			$isSubDir      = '';
			$session       = JFactory::getSession();
			$uploadUrl     = JUri::base() . 'index.php?option=com_media&task=file.upload&tmpl=component&'
								. $session->getName() . '=' . $session->getId()
								. '&' . JSession::getFormToken() . '=1'
								. '&asset=image&format=json';

			if ($app->isClient('site'))
			{
				$uploadUrl = htmlentities($uploadUrl, 0, 'UTF-8', false);
			}

			// Is Joomla installed in subdirectory
			if (JUri::root(true) != '/')
			{
				$isSubDir = JUri::root(true);
			}

			JText::script('PLG_TINY_ERR_UNSUPPORTEDBROWSER');

			$scriptOptions['setCustomDir']    = $isSubDir;
			$scriptOptions['mediaUploadPath'] = $this->params->get('path', '');
			$scriptOptions['uploadUri']       = $uploadUrl;

			$externalPlugins = array(
				array(
					'jdragdrop' => HTMLHelper::_(
						'script',
						'editors/tinymce/plugins/dragdrop/plugin.min.js',
						array('relative' => true, 'version' => 'auto', 'pathOnly' => true)
					),
				),
			);
		}

		// Prepare config variables
		$plugins  = implode(',', $plugins);
		$elements = implode(',', $elements);

		// Prepare config variables
		$toolbar1 = implode(' ', $toolbar1_add) . ' | '
					. implode(' ', $toolbar2_add) . ' | '
					. implode(' ', $toolbar3_add) . ' | '
					. implode(' ', $toolbar4_add);

		// See if mobileVersion is activated
		$mobileVersion = $this->params->get('mobile', 0);

		$scriptOptions = array_merge(
			$scriptOptions,
			array(
			'suffix'  => '.min',
			'baseURL' => JUri::root(true) . '/media/editors/tinymce',
			'directionality' => $text_direction,
			'language' => $langPrefix,
			'autosave_restore_when_empty' => false,
			'skin'   => $skin,
			'theme'  => $theme,
			'schema' => 'html5',

			// Cleanup/Output
			'inline_styles'    => true,
			'gecko_spellcheck' => true,
			'entity_encoding'  => $this->params->get('entity_encoding', 'raw'),
			'verify_html'      => !$ignore_filter,

			// URL
			'relative_urls'      => (bool) $this->params->get('relative_urls', true),
			'remove_script_host' => false,

			// Layout
			'content_css'        => $content_css,
			'document_base_url'  => JUri::root(true) . '/',
			'paste_data_images'  => $allowImgPaste,
			'externalPlugins'    => json_encode($externalPlugins),
		)
		);

		if ($this->params->get('newlines'))
		{
			// Break
			$scriptOptions['force_br_newlines'] = true;
			$scriptOptions['force_p_newlines']  = false;
			$scriptOptions['forced_root_block'] = '';
		}
		else
		{
			// Paragraph
			$scriptOptions['force_br_newlines'] = false;
			$scriptOptions['force_p_newlines']  = true;
			$scriptOptions['forced_root_block'] = 'p';
		}

		/**
		 * Shrink the buttons if not on a mobile or if mobile view is off.
		 * If mobile view is on force into simple mode and enlarge the buttons
		 **/
		if (!$this->app->client->mobile)
		{
			$scriptOptions['toolbar_items_size'] = 'small';
		}
		elseif ($mobileVersion)
		{
			$mode = 0;
		}

		switch ($mode)
		{
			case 0: /* Simple mode*/
				$scriptOptions['menubar']  = false;
				$scriptOptions['toolbar1'] = 'bold italic underline strikethrough | undo redo | bullist numlist | code';
				$scriptOptions['plugins']  = ' code';

				break;

			case 1:
			default: /* Advanced mode*/
				$toolbar1 = "bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | formatselect | bullist numlist "
							. "| outdent indent | undo redo | link unlink anchor code | hr table | subscript superscript | charmap";

				$scriptOptions['valid_elements'] = $valid_elements;
				$scriptOptions['extended_valid_elements'] = $elements;
				$scriptOptions['invalid_elements'] = $invalid_elements;
				$scriptOptions['plugins']  = 'table link code hr charmap autolink lists importcss ';
				$scriptOptions['toolbar1'] = $toolbar1;
				$scriptOptions['removed_menuitems'] = 'newdocument';
				$scriptOptions['importcss_append']  = true;
				$scriptOptions['height'] = $html_height;
				$scriptOptions['width']  = $html_width;
				$scriptOptions['resize'] = $resizing;

				break;

			case 2: /* Extended mode*/
				$scriptOptions['valid_elements'] = $valid_elements;
				$scriptOptions['extended_valid_elements'] = $elements;
				$scriptOptions['invalid_elements'] = $invalid_elements;
				$scriptOptions['plugins']  = $plugins;
				$scriptOptions['toolbar1'] = $toolbar1;
				$scriptOptions['removed_menuitems'] = 'newdocument';
				$scriptOptions['rel_list'] = array(
					array('title' => 'None', 'value' => ''),
					array('title' => 'Alternate', 'value' => 'alternate'),
					array('title' => 'Author', 'value' => 'author'),
					array('title' => 'Bookmark', 'value' => 'bookmark'),
					array('title' => 'Help', 'value' => 'help'),
					array('title' => 'License', 'value' => 'license'),
					array('title' => 'Lightbox', 'value' => 'lightbox'),
					array('title' => 'Next', 'value' => 'next'),
					array('title' => 'No Follow', 'value' => 'nofollow'),
					array('title' => 'No Referrer', 'value' => 'noreferrer'),
					array('title' => 'Prefetch', 'value' => 'prefetch'),
					array('title' => 'Prev', 'value' => 'prev'),
					array('title' => 'Search', 'value' => 'search'),
					array('title' => 'Tag', 'value' => 'tag'),
				);
				$scriptOptions['importcss_append'] = true;
				$scriptOptions['image_advtab']     = $image_advtab;
				$scriptOptions['height']    = $html_height;
				$scriptOptions['width']     = $html_width;
				$scriptOptions['resize']    = $resizing;
				$scriptOptions['templates'] = $templates;

				break;
		}

		$options['tinyMCE']['default'] = $scriptOptions;

		$doc->addStyleDeclaration(".mce-in { padding: 5px 10px !important;}");
		$doc->addScriptOptions('plg_editor_tinymce', $options);

		return $editor;
	}
}
PK��#]�)��editors/tinymce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�o�c��editors/tinymce/tinymce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin" group="editors" method="upgrade">
	<name>plg_editors_tinymce</name>
	<version>4.5.12</version>
	<creationDate>2005-2020</creationDate>
	<author>Tiny Technologies, Inc</author>
	<authorEmail>N/A</authorEmail>
	<authorUrl>https://www.tiny.cloud</authorUrl>
	<copyright>Tiny Technologies, Inc</copyright>
	<license>LGPL</license>
	<description>PLG_TINY_XML_DESCRIPTION</description>
	<files>
		<filename plugin="tinymce">tinymce.php</filename>
		<folder>fields</folder>
		<folder>form</folder>
	</files>
	<media destination="editors" folder="media">
		<folder>tinymce</folder>
	</media>
	<languages>
		<language tag="en-GB">en-GB.plg_editors_tinymce.ini</language>
		<language tag="en-GB">en-GB.plg_editors_tinymce.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
				       name="configuration"
				       type="tinymcebuilder"
				       hiddenLabel="true"
				 />
			</fieldset>

			<fieldset name="advanced" label="PLG_TINY_FIELD_LABEL_ADVANCEDPARAMS">
				<field
					name="sets_amount"
					type="number"
					label="PLG_TINY_FIELD_NUMBER_OF_SETS_LABEL"
					description="PLG_TINY_FIELD_NUMBER_OF_SETS_DESC"
					filter="int"
					validate="number"
					min="3"
					default="3"
				/>

				<field
					name="html_height"
					type="text"
					label="PLG_TINY_FIELD_HTMLHEIGHT_LABEL"
					description="PLG_TINY_FIELD_HTMLHEIGHT_DESC"
					default="550px"
				/>

				<field
					name="html_width"
					type="text"
					label="PLG_TINY_FIELD_HTMLWIDTH_LABEL"
					description="PLG_TINY_FIELD_HTMLWIDTH_DESC"
					default=""
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]� 8y;);)!editors/codemirror/codemirror.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

/**
 * CodeMirror Editor Plugin.
 *
 * @since  1.6
 */
class PlgEditorCodemirror extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded automatically.
	 *
	 * @var    boolean
	 * @since  3.1.4
	 */
	protected $autoloadLanguage = true;

	/**
	 * Mapping of syntax to CodeMirror modes.
	 *
	 * @var array
	 */
	protected $modeAlias = array();

	/**
	 * Initialises the Editor.
	 *
	 * @return  void
	 */
	public function onInit()
	{
		static $done = false;

		// Do this only once.
		if ($done)
		{
			return;
		}

		$done = true;

		// Most likely need this later
		$doc = JFactory::getDocument();

		// Codemirror shall have its own group of plugins to modify and extend its behavior
		JPluginHelper::importPlugin('editors_codemirror');
		$dispatcher	= JEventDispatcher::getInstance();

		// At this point, params can be modified by a plugin before going to the layout renderer.
		$dispatcher->trigger('onCodeMirrorBeforeInit', array(&$this->params));

		$displayData = (object) array('params'  => $this->params);

		// We need to do output buffering here because layouts may actually 'echo' things which we do not want.
		ob_start();
		JLayoutHelper::render('editors.codemirror.init', $displayData, __DIR__ . '/layouts');
		ob_end_clean();

		$font = $this->params->get('fontFamily', '0');
		$fontInfo = $this->getFontInfo($font);

		if (isset($fontInfo))
		{
			if (isset($fontInfo->url))
			{
				$doc->addStyleSheet($fontInfo->url);
			}

			if (isset($fontInfo->css))
			{
				$displayData->fontFamily = $fontInfo->css . '!important';
			}
		}

		// We need to do output buffering here because layouts may actually 'echo' things which we do not want.
		ob_start();
		JLayoutHelper::render('editors.codemirror.styles', $displayData, __DIR__ . '/layouts');
		ob_end_clean();

		$dispatcher->trigger('onCodeMirrorAfterInit', array(&$this->params));
	}

	/**
	 * Copy editor content to form field.
	 *
	 * @param   string  $id  The id of the editor field.
	 *
	 * @return  string  Javascript
	 *
	 * @deprecated 4.0 Code executes directly on submit
	 */
	public function onSave($id)
	{
		return sprintf('document.getElementById(%1$s).value = Joomla.editors.instances[%1$s].getValue();', json_encode((string) $id));
	}

	/**
	 * Get the editor content.
	 *
	 * @param   string  $id  The id of the editor field.
	 *
	 * @return  string  Javascript
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onGetContent($id)
	{
		return sprintf('Joomla.editors.instances[%1$s].getValue();', json_encode((string) $id));
	}

	/**
	 * Set the editor content.
	 *
	 * @param   string  $id       The id of the editor field.
	 * @param   string  $content  The content to set.
	 *
	 * @return  string  Javascript
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSetContent($id, $content)
	{
		return sprintf('Joomla.editors.instances[%1$s].setValue(%2$s);', json_encode((string) $id), json_encode((string) $content));
	}

	/**
	 * Adds the editor specific insert method.
	 *
	 * @return  void
	 *
	 * @deprecated 4.0 Code is loaded in the init script
	 */
	public function onGetInsertMethod()
	{
		static $done = false;

		// Do this only once.
		if ($done)
		{
			return true;
		}

		$done = true;

		JFactory::getDocument()->addScriptDeclaration("
		;function jInsertEditorText(text, editor) { Joomla.editors.instances[editor].replaceSelection(text); }
		");

		return true;
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The control name.
	 * @param   string   $content  The contents of the text area.
	 * @param   string   $width    The width of the text area (px or %).
	 * @param   string   $height   The height of the text area (px or %).
	 * @param   int      $col      The number of columns for the textarea.
	 * @param   int      $row      The number of rows for the textarea.
	 * @param   boolean  $buttons  True and the editor buttons will be displayed.
	 * @param   string   $id       An optional ID for the textarea (note: since 1.6). If not supplied the name is used.
	 * @param   string   $asset    Not used.
	 * @param   object   $author   Not used.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string  HTML
	 */
	public function onDisplay(
		$name, $content, $width, $height, $col, $row, $buttons = true, $id = null, $asset = null, $author = null, $params = array())
	{
		// True if a CodeMirror already has autofocus. Prevent multiple autofocuses.
		static $autofocused;

		$id = empty($id) ? $name : $id;

		// Must pass the field id to the buttons in this editor.
		$buttons = $this->displayButtons($id, $buttons, $asset, $author);

		// Only add "px" to width and height if they are not given as a percentage.
		$width .= is_numeric($width) ? 'px' : '';
		$height .= is_numeric($height) ? 'px' : '';

		// Options for the CodeMirror constructor.
		$options = new stdClass;

		// Is field readonly?
		if (!empty($params['readonly']))
		{
			$options->readOnly = 'nocursor';
		}

		// Should we focus on the editor on load?
		if (!$autofocused)
		{
			$options->autofocus = isset($params['autofocus']) ? (bool) $params['autofocus'] : false;
			$autofocused = $options->autofocus;
		}

		$options->lineWrapping = (boolean) $this->params->get('lineWrapping', 1);

		// Add styling to the active line.
		$options->styleActiveLine = (boolean) $this->params->get('activeLine', 1);

		// Do we highlight selection matches?
		if ($this->params->get('selectionMatches', 1))
		{
			$options->highlightSelectionMatches = array(
					'showToken' => true,
					'annotateScrollbar' => true,
				);
		}

		// Do we use line numbering?
		if ($options->lineNumbers = (boolean) $this->params->get('lineNumbers', 1))
		{
			$options->gutters[] = 'CodeMirror-linenumbers';
		}

		// Do we use code folding?
		if ($options->foldGutter = (boolean) $this->params->get('codeFolding', 1))
		{
			$options->gutters[] = 'CodeMirror-foldgutter';
		}

		// Do we use a marker gutter?
		if ($options->markerGutter = (boolean) $this->params->get('markerGutter', $this->params->get('marker-gutter', 1)))
		{
			$options->gutters[] = 'CodeMirror-markergutter';
		}

		// Load the syntax mode.
		$syntax = !empty($params['syntax'])
			? $params['syntax']
			: $this->params->get('syntax', 'html');
		$options->mode = isset($this->modeAlias[$syntax]) ? $this->modeAlias[$syntax] : $syntax;

		// Load the theme if specified.
		if ($theme = $this->params->get('theme'))
		{
			$options->theme = $theme;
			JHtml::_('stylesheet', $this->params->get('basePath', 'media/editors/codemirror/') . 'theme/' . $theme . '.css', array('version' => 'auto'));
		}

		// Special options for tagged modes (xml/html).
		if (in_array($options->mode, array('xml', 'html', 'php')))
		{
			// Autogenerate closing tags (html/xml only).
			$options->autoCloseTags = (boolean) $this->params->get('autoCloseTags', 1);

			// Highlight the matching tag when the cursor is in a tag (html/xml only).
			$options->matchTags = (boolean) $this->params->get('matchTags', 1);
		}

		// Special options for non-tagged modes.
		if (!in_array($options->mode, array('xml', 'html')))
		{
			// Autogenerate closing brackets.
			$options->autoCloseBrackets = (boolean) $this->params->get('autoCloseBrackets', 1);

			// Highlight the matching bracket.
			$options->matchBrackets = (boolean) $this->params->get('matchBrackets', 1);
		}

		$options->scrollbarStyle = $this->params->get('scrollbarStyle', 'native');

		// KeyMap settings.
		$options->keyMap = $this->params->get('keyMap', false);

		// Support for older settings.
		if ($options->keyMap === false)
		{
			$options->keyMap = $this->params->get('vimKeyBinding', 0) ? 'vim' : 'default';
		}

		if ($options->keyMap && $options->keyMap != 'default')
		{
			$this->loadKeyMap($options->keyMap);
		}

		$displayData = (object) array(
				'options' => $options,
				'params'  => $this->params,
				'name'    => $name,
				'id'      => $id,
				'cols'    => $col,
				'rows'    => $row,
				'content' => $content,
				'buttons' => $buttons
			);

		$dispatcher = JEventDispatcher::getInstance();

		// At this point, displayData can be modified by a plugin before going to the layout renderer.
		$results = $dispatcher->trigger('onCodeMirrorBeforeDisplay', array(&$displayData));

		$results[] = JLayoutHelper::render('editors.codemirror.element', $displayData, __DIR__ . '/layouts', array('debug' => JDEBUG));

		foreach ($dispatcher->trigger('onCodeMirrorAfterDisplay', array(&$displayData)) as $result)
		{
			$results[] = $result;
		}

		return implode("\n", $results);
	}

	/**
	 * Displays the editor buttons.
	 *
	 * @param   string  $name     Button name.
	 * @param   mixed   $buttons  [array with button objects | boolean true to display buttons]
	 * @param   mixed   $asset    Unused.
	 * @param   mixed   $author   Unused.
	 *
	 * @return  string  HTML
	 */
	protected function displayButtons($name, $buttons, $asset, $author)
	{
		$return = '';

		$args = array(
			'name'  => $name,
			'event' => 'onGetInsertMethod'
		);

		$results = (array) $this->update($args);

		if ($results)
		{
			foreach ($results as $result)
			{
				if (is_string($result) && trim($result))
				{
					$return .= $result;
				}
			}
		}

		if (is_array($buttons) || (is_bool($buttons) && $buttons))
		{
			$buttons = $this->_subject->getButtons($name, $buttons, $asset, $author);

			$return .= JLayoutHelper::render('joomla.editors.buttons', $buttons);
		}

		return $return;
	}

	/**
	 * Gets font info from the json data file
	 *
	 * @param   string  $font  A key from the $fonts array.
	 *
	 * @return  object
	 */
	protected function getFontInfo($font)
	{
		static $fonts;

		if (!$fonts)
		{
			$fonts = json_decode(file_get_contents(__DIR__ . '/fonts.json'), true);
		}

		return isset($fonts[$font]) ? (object) $fonts[$font] : null;
	}

	/**
	 * Loads a keyMap file
	 *
	 * @param   string  $keyMap  The name of a keyMap file to load.
	 *
	 * @return  void
	 */
	protected function loadKeyMap($keyMap)
	{
		$basePath = $this->params->get('basePath', 'media/editors/codemirror/');
		$ext = JDEBUG ? '.js' : '.min.js';
		JHtml::_('script', $basePath . 'keymap/' . $keyMap . $ext, array('version' => 'auto'));
	}
}
PK��#]�W"�)�)!editors/codemirror/codemirror.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin" group="editors" method="upgrade">
	<name>plg_editors_codemirror</name>
	<version>5.60.0</version>
	<creationDate>28 March 2011</creationDate>
	<author>Marijn Haverbeke</author>
	<authorEmail>marijnh@gmail.com</authorEmail>
	<authorUrl>https://codemirror.net/</authorUrl>
	<copyright>Copyright (C) 2014 - 2021 by Marijn Haverbeke &lt;marijnh@gmail.com&gt; and others</copyright>
	<license>MIT license: https://codemirror.net/LICENSE</license>
	<description>PLG_CODEMIRROR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="codemirror">codemirror.php</filename>
		<filename>styles.css</filename>
		<filename>styles.min.css</filename>
		<filename>fonts.json</filename>
		<filename>fonts.php</filename>
	</files>

	<languages>
		<language tag="en-GB">en-GB.plg_editors_codemirror.ini</language>
		<language tag="en-GB">en-GB.plg_editors_codemirror.sys.ini</language>
	</languages>

	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="lineNumbers"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_LINENUMBERS_LABEL"
					description="PLG_CODEMIRROR_FIELD_LINENUMBERS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="codeFolding"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_CODEFOLDING_LABEL"
					description="PLG_CODEMIRROR_FIELD_CODEFOLDING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="markerGutter"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_MARKERGUTTER_LABEL"
					description="PLG_CODEMIRROR_FIELD_MARKERGUTTER_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="lineWrapping"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_LINEWRAPPING_LABEL"
					description="PLG_CODEMIRROR_FIELD_LINEWRAPPING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="activeLine"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_ACTIVELINE_LABEL"
					description="PLG_CODEMIRROR_FIELD_ACTIVELINE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="selectionMatches"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_SELECTIONMATCHES_LABEL"
					description="PLG_CODEMIRROR_FIELD_SELECTIONMATCHES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="matchTags"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_MATCHTAGS_LABEL"
					description="PLG_CODEMIRROR_FIELD_MATCHTAGS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="matchBrackets"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_MATCHBRACKETS_LABEL"
					description="PLG_CODEMIRROR_FIELD_MATCHBRACKETS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="autoCloseTags"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_AUTOCLOSETAGS_LABEL"
					description="PLG_CODEMIRROR_FIELD_AUTOCLOSETAGS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="autoCloseBrackets"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_AUTOCLOSEBRACKET_LABEL"
					description="PLG_CODEMIRROR_FIELD_AUTOCLOSEBRACKET_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="keyMap"
					type="list"
					label="PLG_CODEMIRROR_FIELD_KEYMAP_LABEL"
					description="PLG_CODEMIRROR_FIELD_KEYMAP_DESC"
					default=""
					>
					<option value="">JDEFAULT</option>
					<option value="emacs">PLG_CODEMIRROR_FIELD_KEYMAP_EMACS</option>
					<option value="sublime">PLG_CODEMIRROR_FIELD_KEYMAP_SUBLIME</option>
					<option value="vim">PLG_CODEMIRROR_FIELD_KEYMAP_VIM</option>
				</field>

				<field
					name="fullScreen"
					type="list"
					label="PLG_CODEMIRROR_FIELD_FULLSCREEN_LABEL"
					description="PLG_CODEMIRROR_FIELD_FULLSCREEN_DESC"
					default="F10"
					>
					<option value="F1">F1</option>
					<option value="F2">F2</option>
					<option value="F3">F3</option>
					<option value="F4">F4</option>
					<option value="F5">F5</option>
					<option value="F6">F6</option>
					<option value="F7">F7</option>
					<option value="F8">F8</option>
					<option value="F9">F9</option>
					<option value="F10">F10</option>
					<option value="F11">F11</option>
					<option value="F12">F12</option>
				</field>

				<field
					name="fullScreenMod"
					type="checkboxes"
					label="PLG_CODEMIRROR_FIELD_FULLSCREEN_MOD_LABEL"
					description="PLG_CODEMIRROR_FIELD_FULLSCREEN_MOD_DESC"
					>
					<option value="Shift">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_SHIFT</option>
					<option value="Cmd">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_CMD</option>
					<option value="Ctrl">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_CTRL</option>
					<option value="Alt">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_ALT</option>
				</field>

				<field
					name="basePath"
					type="hidden"
					default="media/editors/codemirror/"
				/>

				<field
					name="modePath"
					type="hidden"
					default="media/editors/codemirror/mode/%N/%N"
				/>
			</fieldset>

			<fieldset name="appearance" label="PLG_CODEMIRROR_FIELDSET_APPEARANCE_OPTIONS_LABEL" addfieldpath="plugins/editors/codemirror">
				<field
					name="theme"
					type="filelist"
					label="PLG_CODEMIRROR_FIELD_THEME_LABEL"
					description="PLG_CODEMIRROR_FIELD_THEME_DESC"
					default=""
					filter="\.css$"
					stripext="true"
					hide_none="true"
					hide_default="false"
					directory="media/editors/codemirror/theme"
				/>

				<field
					name="activeLineColor"
					type="color"
					label="PLG_CODEMIRROR_FIELD_ACTIVELINE_COLOR_LABEL"
					description="PLG_CODEMIRROR_FIELD_ACTIVELINE_COLOR_DESC"
					default="#a4c2eb"
					filter="color"
				/>

				<field
					name="highlightMatchColor"
					type="color"
					label="PLG_CODEMIRROR_FIELD_HIGHLIGHT_MATCH_COLOR_LABEL"
					description="PLG_CODEMIRROR_FIELD_HIGHLIGHT_MATCH_COLOR_DESC"
					default="#fa542f"
					filter="color"
				/>

				<field
					name="fontFamily"
					type="fonts"
					label="PLG_CODEMIRROR_FIELD_FONT_FAMILY_LABEL"
					description="PLG_CODEMIRROR_FIELD_FONT_FAMILY_DESC"
					default="0"
					>
					<option value="0">PLG_CODEMIRROR_FIELD_VALUE_FONT_FAMILY_DEFAULT</option>
				</field>

				<field
					name="fontSize"
					type="integer"
					label="PLG_CODEMIRROR_FIELD_FONT_SIZE_LABEL"
					description="PLG_CODEMIRROR_FIELD_FONT_SIZE_DESC"
					first="6"
					last="16"
					step="1"
					default="13"
					filter="integer"
				/>

				<field
					name="lineHeight"
					type="list"
					label="PLG_CODEMIRROR_FIELD_LINE_HEIGHT_LABEL"
					description="PLG_CODEMIRROR_FIELD_LINE_HEIGHT_DESC"
					default="1.2"
					filter="float"
					>
					<option value="1">1</option>
					<option value="1.1">1.1</option>
					<option value="1.2">1.2</option>
					<option value="1.3">1.3</option>
					<option value="1.4">1.4</option>
					<option value="1.5">1.5</option>
					<option value="1.6">1.6</option>
					<option value="1.7">1.7</option>
					<option value="1.8">1.8</option>
					<option value="1.9">1.9</option>
					<option value="2">2</option>
				</field>

				<field
					name="scrollbarStyle"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_LABEL"
					description="PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_DESC"
					class="btn-group btn-group-yesno"
					default="native"
					>
					<option value="native">PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_DEFAULT</option>
					<option value="simple">PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_SIMPLE</option>
					<option value="overlay">PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_OVERLAY</option>
				</field>

				<field
					name="preview"
					type="editor"
					label="PLG_CODEMIRROR_FIELD_PREVIEW_LABEL"
					description="PLG_CODEMIRROR_FIELD_PREVIEW_DESC"
					editor="codemirror"
					filter="unset"
					buttons="false"
					>
					<default>
<![CDATA[
<script type="text/javascript">
	jQuery(function ($) {
		$('.hello').html('Hello World');
	});
</script>

<style type="text/css">
	h1 {
		background-clip: border-box;
		background-color: #cacaff;
		background-image: linear-gradient(45deg, transparent 0px, transparent 30px, #ababff 30px, #ababff 60px, transparent 60px);
		background-repeat: repeat-x;
		background-size: 90px 100%;
		border: 1px solid #8989ff;
		border-radius: 10px;
		color: #333;
		padding: 0 15px;
	}
</style>

<div>
	<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam a ornare lectus, quis semper urna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus interdum metus id elit rutrum sollicitudin. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam in fermentum risus, id facilisis nulla. Phasellus gravida erat sed ullamcorper accumsan. Donec blandit sem eget sem congue, a varius sapien semper.</p>
	<p>Integer euismod tempor convallis. Nullam porttitor et ex ac fringilla. Quisque facilisis est ac erat condimentum malesuada. Aenean commodo quam odio, tincidunt ultricies mauris suscipit et.</p>

	<ul>
		<li>Vivamus ultrices ligula a odio lacinia pellentesque.</li>
		<li>Curabitur iaculis arcu pharetra, mollis turpis id, commodo erat.</li>
		<li>Etiam consequat enim quis faucibus interdum.</li>
		<li>Morbi in ipsum pulvinar, eleifend lorem sit amet, euismod magna.</li>
		<li>Donec consectetur lacus vitae eros euismod porta.</li>
	</ul>
</div>
]]>
					</default>
				</field>

			</fieldset>
		</fields>
	</config>
</extension>
PK��#]���--editors/codemirror/fonts.jsonnu�[���{
	"anonymous_pro": {
		"name": "Anonymous Pro",
		"url": "https://fonts.googleapis.com/css?family=Anonymous+Pro",
		"css": "'Anonymous Pro', monospace"
	},
	"cousine": {
		"name": "Cousine",
		"url": "https://fonts.googleapis.com/css?family=Cousine",
		"css": "Cousine, monospace"
	},
	"cutive_mono": {
		"name": "Cutive Mono",
		"url": "https://fonts.googleapis.com/css?family=Cutive+Mono",
		"css": "'Cutive Mono', monospace"
	},
	"droid_sans_mono": {
		"name": "Droid Sans Mono",
		"url": "https://fonts.googleapis.com/css?family=Droid+Sans+Mono",
		"css": "'Droid Sans Mono', monospace"
	},
	"fira_mono": {
		"name": "Fira Mono",
		"url": "https://fonts.googleapis.com/css?family=Fira+Mono",
		"css": "'Fira Mono', monospace"
	},
	"ibm_plex_mono": {
		"name": "IBM Plex Mono",
		"url": "https://fonts.googleapis.com/css?family=IBM+Plex+Mono",
		"css": "'IBM Plex Mono', monospace;"
	},
	"inconsolata": {
		"name": "Inconsolata",
		"url": "https://fonts.googleapis.com/css?family=Inconsolata",
		"css": "Inconsolata, monospace"
	},
	"lekton": {
		"name": "Lekton",
		"url": "https://fonts.googleapis.com/css?family=Lekton",
		"css": "Lekton, monospace"
	},
	"nanum_gothic_coding": {
		"name": "Nanum Gothic Coding",
		"url": "https://fonts.googleapis.com/css?family=Nanum+Gothic+Coding",
		"css": "'Nanum Gothic Coding', monospace"
	},
	"nova_mono": {
		"name": "Nova Mono",
		"url": "https://fonts.googleapis.com/css?family=Nova+Mono",
		"css": "'Nova Mono', monospace"
	},
	"overpass_mono": {
		"name": "Overpass Mono",
		"url": "https://fonts.googleapis.com/css?family=Overpass+Mono",
		"css": "'Overpass Mono', monospace"
	},
	"oxygen_mono": {
		"name": "Oxygen Mono",
		"url": "https://fonts.googleapis.com/css?family=Oxygen+Mono",
		"css": "'Oxygen Mono', monospace"
	},
	"press_start_2p": {
		"name": "Press Start 2P",
		"url": "https://fonts.googleapis.com/css?family=Press+Start+2P",
		"css": "'Press Start 2P', monospace"
	},
	"pt_mono": {
		"name": "PT Mono",
		"url": "https://fonts.googleapis.com/css?family=PT+Mono",
		"css": "'PT Mono', monospace"
	},
	"roboto_mono": {
		"name": "Roboto Mono",
		"url": "https://fonts.googleapis.com/css?family=Roboto+Mono",
		"css": "'Roboto Mono', monospace"
	},
	"rubik_mono_one": {
		"name": "Rubik Mono One",
		"url": "https://fonts.googleapis.com/css?family=Rubik+Mono+One",
		"css": "'Rubik Mono One', monospace"
	},
	"share_tech_mono": {
		"name": "Share Tech Mono",
		"url": "https://fonts.googleapis.com/css?family=Share+Tech+Mono",
		"css": "'Share Tech Mono', monospace"
	},
	"source_code_pro": {
		"name": "Source Code Pro",
		"url": "https://fonts.googleapis.com/css?family=Source+Code+Pro",
		"css": "'Source Code Pro', monospace"
	},
	"space_mono": {
		"name": "Space Mono",
		"url": "https://fonts.googleapis.com/css?family=Space+Mono",
		"css": "'Space Mono', monospace"
	},
	"ubuntu_mono": {
		"name": "Ubuntu Mono",
		"url": "https://fonts.googleapis.com/css?family=Ubuntu+Mono",
		"css": "'Ubuntu Mono', monospace"
	},
	"vt323": {
		"name": "VT323",
		"url": "https://fonts.googleapis.com/css?family=VT323",
		"css": "'VT323', monospace"
	}
}
PK��#]�1nB	B	8editors/codemirror/layouts/editors/codemirror/styles.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

$params     = $displayData->params;
$fontFamily = isset($displayData->fontFamily) ? $displayData->fontFamily : 'monospace';
$fontSize   = $params->get('fontSize', 13) . 'px;';
$lineHeight = $params->get('lineHeight', 1.2) . 'em;';

// Set the active line color.
$color           = $params->get('activeLineColor', '#a4c2eb');
$r               = hexdec($color[1] . $color[2]);
$g               = hexdec($color[3] . $color[4]);
$b               = hexdec($color[5] . $color[6]);
$activeLineColor = 'rgba(' . $r . ', ' . $g . ', ' . $b . ', .5)';

// Set the color for matched tags.
$color               = $params->get('highlightMatchColor', '#fa542f');
$r                   = hexdec($color[1] . $color[2]);
$g                   = hexdec($color[3] . $color[4]);
$b                   = hexdec($color[5] . $color[6]);
$highlightMatchColor = 'rgba(' . $r . ', ' . $g . ', ' . $b . ', .5)';

JFactory::getDocument()->addStyleDeclaration(
<<<CSS
		.CodeMirror
		{
			font-family: $fontFamily;
			font-size: $fontSize;
			line-height: $lineHeight;
			border: 1px solid #ccc;
		}
		/* In order to hid the Joomla menu */
		.CodeMirror-fullscreen
		{
			z-index: 1040;
		}
		/* Make the fold marker a little more visible/nice */
		.CodeMirror-foldmarker
		{
			background: rgb(255, 128, 0);
			background: rgba(255, 128, 0, .5);
			box-shadow: inset 0 0 2px rgba(255, 255, 255, .5);
			font-family: serif;
			font-size: 90%;
			border-radius: 1em;
			padding: 0 1em;
			vertical-align: middle;
			color: white;
			text-shadow: none;
		}
		.CodeMirror-foldgutter, .CodeMirror-markergutter { width: 1.2em; text-align: center; }
		.CodeMirror-markergutter { cursor: pointer; }
		.CodeMirror-markergutter-mark { cursor: pointer; text-align: center; }
		.CodeMirror-markergutter-mark:after { content: "\25CF"; }
		.CodeMirror-activeline-background { background: $activeLineColor; }
		.CodeMirror-matchingtag { background: $highlightMatchColor; }
		.cm-matchhighlight {background-color: $highlightMatchColor; }
		.CodeMirror-selection-highlight-scrollbar {background-color: $highlightMatchColor; }
CSS
);
PK��#]GL:**9editors/codemirror/layouts/editors/codemirror/element.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

$options  = $displayData->options;
$params   = $displayData->params;
$name     = $displayData->name;
$id       = $displayData->id;
$cols     = $displayData->cols;
$rows     = $displayData->rows;
$content  = $displayData->content;
$buttons  = $displayData->buttons;
$modifier = $params->get('fullScreenMod', array()) ? implode(' + ', $params->get('fullScreenMod', array())) . ' + ' : '';

?>

<p class="label">
    <?php echo JText::sprintf('PLG_CODEMIRROR_TOGGLE_FULL_SCREEN', $modifier, $params->get('fullScreen', 'F10')); ?>
</p>

<?php
	echo '<textarea class="codemirror-source" name="', $name,
		'" id="', $id,
		'" cols="', $cols,
		'" rows="', $rows,
		'" data-options="', htmlspecialchars(json_encode($options)),
		'">', $content, '</textarea>';
?>

<?php echo $buttons; ?>
PK��#]��'d��6editors/codemirror/layouts/editors/codemirror/init.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2015 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

$params   = $displayData->params;
$basePath = $params->get('basePath', 'media/editors/codemirror/');
$modePath = $params->get('modePath', 'media/editors/codemirror/mode/%N/%N');
$extJS    = JDEBUG ? '.js' : '.min.js';
$extCSS   = JDEBUG ? '.css' : '.min.css';

JHtml::_('script', $basePath . 'lib/codemirror' . $extJS, array('version' => 'auto'));
JHtml::_('script', $basePath . 'lib/addons' . $extJS, array('version' => 'auto'));
JHtml::_('stylesheet', $basePath . 'lib/codemirror' . $extCSS, array('version' => 'auto'));
JHtml::_('stylesheet', $basePath . 'lib/addons' . $extCSS, array('version' => 'auto'));

$fskeys          = $params->get('fullScreenMod', array());
$fskeys[]        = $params->get('fullScreen', 'F10');
$fullScreenCombo = implode('-', $fskeys);
$fsCombo         = json_encode($fullScreenCombo);
$modPath         = json_encode(JUri::root(true) . '/' . $modePath . $extJS);
JFactory::getDocument()->addScriptDeclaration(
<<<JS
		;(function (cm, $) {
			cm.commands.toggleFullScreen = function (cm) {
				cm.setOption('fullScreen', !cm.getOption('fullScreen'));
			};
			cm.commands.closeFullScreen = function (cm) {
				cm.getOption('fullScreen') && cm.setOption('fullScreen', false);
			};

			cm.keyMap.default['Ctrl-Q'] = 'toggleFullScreen';
			cm.keyMap.default[$fsCombo] = 'toggleFullScreen';
			cm.keyMap.default['Esc'] = 'closeFullScreen';
			// For mode autoloading.
			cm.modeURL = $modPath;
			// Fire this function any time an editor is created.
			cm.defineInitHook(function (editor)
			{
				// Try to set up the mode
				var mode = cm.findModeByMIME(editor.options.mode || '') ||
							cm.findModeByName(editor.options.mode || '') ||
							cm.findModeByExtension(editor.options.mode || '');

				cm.autoLoadMode(editor, mode ? mode.mode : editor.options.mode);

				if (mode && mode.mime)
				{
					editor.setOption('mode', mode.mime);
				}

				// Handle gutter clicks (place or remove a marker).
				editor.on('gutterClick', function (ed, n, gutter) {
					if (gutter != 'CodeMirror-markergutter') { return; }
					var info = ed.lineInfo(n),
						hasMarker = !!info.gutterMarkers && !!info.gutterMarkers['CodeMirror-markergutter'];
					ed.setGutterMarker(n, 'CodeMirror-markergutter', hasMarker ? null : makeMarker());
				});

				// jQuery's ready function.
				$(function () {
					// Some browsers do something weird with the fieldset which doesn't work well with CodeMirror. Fix it.
					$(editor.getWrapperElement()).parent('fieldset').css('min-width', 0);
					// Listen for Bootstrap's 'shown' event. If this editor was in a hidden element when created, it may need to be refreshed.
					$(document.body).on('shown shown.bs.tab shown.bs.modal', function () { editor.refresh(); });
				});
			});

			function makeMarker()
			{
				var marker = document.createElement('div');
				marker.className = 'CodeMirror-markergutter-mark';
				return marker;
			}

			// Initialize any CodeMirrors on page load and when a subform is added
			$(function ($) {
				initCodeMirror();
				$('body').on('subform-row-add', initCodeMirror);
			});

			function initCodeMirror(event, container)
			{
				container = container || document;
				$(container).find('textarea.codemirror-source').each(function () {
					var input = $(this).removeClass('codemirror-source');
					var id = input.prop('id');

					Joomla.editors.instances[id] = cm.fromTextArea(this, input.data('options'));
				});
			}

		}(CodeMirror, jQuery));
JS
);
PK��#]�)��editors/codemirror/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]>MDDeditors/codemirror/fonts.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

JFormHelper::loadFieldClass('list');

/**
 * Supports an HTML select list of fonts
 *
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 * @since       3.4
 */
class JFormFieldFonts extends JFormFieldList
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.4
	 */
	protected $type = 'Fonts';

	/**
	 * Method to get the list of fonts field options.
	 *
	 * @return  array  The field option objects.
	 *
	 * @since   3.4
	 */
	protected function getOptions()
	{
		$fonts = json_decode(file_get_contents(__DIR__ . '/fonts.json'));
		$options = array();

		foreach ($fonts as $key => $info)
		{
			$options[] = JHtml::_('select.option', $key, $info->name);
		}

		// Merge any additional options in the XML definition.
		return array_merge(parent::getOptions(), $options);
	}
}
PK��#]{,t���'editors/jce/layouts/editor/textarea.phpnu�[���<?php
/**
 * @package     JCE
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_BASE') or die;

$data = $displayData;

?>
<textarea
	spellcheck="false"
	autocomplete="off"
	name="<?php echo $data->name; ?>"
	id="<?php echo $data->id; ?>"
	cols="<?php echo $data->cols; ?>"
	rows="<?php echo $data->rows; ?>"
	style="width: <?php echo $data->width; ?>; height: <?php echo $data->height; ?>;"
	class="<?php echo empty($data->class) ? 'mce_editable' : $data->class; ?>"
><?php echo $data->content; ?></textarea>
PK��#]�)��editors/jce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�yq�//editors/jce/jce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="editors" method="upgrade">
    <name>plg_editors_jce</name>
    <version>2.9.38</version>
    <creationDate>27-06-2023</creationDate>
    <author>Ryan Demmer</author>
    <authorEmail>info@joomlacontenteditor.net</authorEmail>
    <authorUrl>http://www.joomlacontenteditor.net</authorUrl>
    <copyright>Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved</copyright>
    <license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
    <description>WF_EDITOR_PLUGIN_DESC</description>
    <files folder="plugins/editors/jce">
        <file plugin="jce">jce.php</file>
        <folder>layouts</folder>
    </files>

    <!-- Media -->
    <media folder="media/jce" destination="jce">
        <folder>icons</folder>
    </media>

    <languages folder="administrator/language/en-GB">
        <language tag="en-GB">en-GB.plg_editors_jce.ini</language>
        <language tag="en-GB">en-GB.plg_editors_jce.sys.ini</language>
    </languages>
</extension>
PK��#]@���%�%editors/jce/jce.phpnu�[���<?php

/**
 * @copyright     Copyright (c) 2009-2022 Ryan Demmer. All rights reserved
 * @license       GNU/GPL 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * JCE is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses
 */
// Do not allow direct access
defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Layout\LayoutHelper;

/**
 * JCE WYSIWYG Editor Plugin.
 *
 * @since 1.5
 */
class plgEditorJCE extends CMSPlugin
{
    protected static $instances = array();
    
    /**
     * Constructor.
     *
     * @param object $subject The object to observe
     * @param array  $config  An array that holds the plugin configuration
     *
     * @since       1.5
     */
    public function __construct(&$subject, $config)
    {        
        parent::__construct($subject, $config);
    }

    protected function getEditorInstance()
    {        
        // pass config to WFEditor
        $config = array(
            'profile_id' => $this->params->get('profile_id', 0),
            'plugin' => $this->params->get('plugin', '')
        );

        $signature = md5(serialize($config));

        if (empty(self::$instances[$signature])) {
            // load base file
            require_once JPATH_ADMINISTRATOR . '/components/com_jce/includes/base.php';

            // create editor
            self::$instances[$signature] = new WFEditor($config);
        }

        return self::$instances[$signature];
    }

    /**
     * Method to handle the onInit event.
     *  - Initializes the JCE WYSIWYG Editor.
     *
     * @param   $toString Return javascript and css as a string
     *
     * @return string JavaScript Initialization string
     *
     * @since   1.5
     */
    public function onInit()
    {
        if (!ComponentHelper::isEnabled('com_jce')) {
            return false;
        }
        
        $language = Factory::getLanguage();
        $document = Factory::getDocument();

        $language->load('plg_editors_jce', JPATH_ADMINISTRATOR);
        $language->load('com_jce', JPATH_ADMINISTRATOR);

        $editor = $this->getEditorInstance();
        $editor->init();

        foreach ($editor->getScripts() as $script) {
            $document->addScript($script);
        }

        foreach ($editor->getStyleSheets() as $style) {
            $document->addStylesheet($style);
        }

        $document->addScriptDeclaration(implode("\n", $editor->getScriptDeclaration()));
    }

    /**
     * JCE WYSIWYG Editor - get the editor content.
     *
     * @vars string   The name of the editor
     */
    public function onGetContent($editor)
    {
        return $this->onSave($editor);
    }

    /**
     * JCE WYSIWYG Editor - set the editor content.
     *
     * @vars string   The name of the editor
     */
    public function onSetContent($editor, $html)
    {
        return "WFEditor.setContent('" . $editor . "','" . $html . "');";
    }

    /**
     * JCE WYSIWYG Editor - copy editor content to form field.
     *
     * @vars string   The name of the editor
     */
    public function onSave($editor)
    {
        return "WFEditor.getContent('" . $editor . "');";
    }

    /**
     * JCE WYSIWYG Editor - Display the editor area.
     *
     * @param   string   $name     The name of the editor area.
     * @param   string   $content  The content of the field.
     * @param   string   $width    The width of the editor area.
     * @param   string   $height   The height of the editor area.
     * @param   int      $col      The number of columns for the editor area.
     * @param   int      $row      The number of rows for the editor area.
     * @param   boolean  $buttons  True and the editor buttons will be displayed.
     * @param   string   $id       An optional ID for the textarea. If not supplied the name is used.
     * @param   string   $asset    The object asset
     * @param   object   $author   The author.
     * @param   array    $params   Associative array of editor parameters.
     *
     * @return  string
     */
    public function onDisplay($name, $content, $width, $height, $col, $row, $buttons = true, $id = null, $asset = null, $author = null, $params = array())
    {
        if (empty($id)) {
            $id = $name;
        }

        // Only add "px" to width and height if they are not given as a percentage
        if (is_numeric($width)) {
            $width .= 'px';
        }

        if (is_numeric($height)) {
            $height .= 'px';
        }

        if (empty($id)) {
            $id = $name;
        }

        // Data object for the layout
        $textarea = new stdClass;
        $textarea->name = $name;
        $textarea->id = $id;
        $textarea->class = 'mce_editable wf-editor';
        $textarea->cols = $col;
        $textarea->rows = $row;
        $textarea->width = $width;
        $textarea->height = $height;
        $textarea->content = $content;

        $classes = version_compare(JVERSION, '4', 'ge') ? ' mb-2 joomla4' : '';

        // Render Editor markup
        $html = '<div class="editor wf-editor-container' . $classes . '">';
        $html .= '<div class="wf-editor-header"></div>';
        $html .= LayoutHelper::render('editor.textarea', $textarea, __DIR__ . '/layouts');
        $html .= '</div>';

        if (!ComponentHelper::isEnabled('com_jce')) {
            return $html;
        }

        $editor = $this->getEditorInstance();

        // no profile assigned or available
        if (!$editor->hasProfile()) {
            return $html;
        }

        if (!$editor->hasPlugin('joomla')) {            
            if ((bool) $editor->getParam('editor.xtd_buttons', 1)) {                
                $html .= $this->displayButtons($id, $buttons, $asset, $author);
            }
        } else {
            $list = $this->getXtdButtonsList($id, $buttons, $asset, $author);

            if (!empty($list)) {
                $options = array(
                    'joomla_xtd_buttons' => array_values($list)
                );

                Factory::getDocument()->addScriptOptions('plg_editor_jce', $options, true);
            }

            // render empty container for dynamic buttons
            $html .= LayoutHelper::render('joomla.editors.buttons', array());
        }

        return $html;
    }

    public function onGetInsertMethod($name)
    {
    }

    private function getXtdButtonsList($name, $buttons, $asset, $author)
    {
        $list = array();

        $excluded = array('readmore', 'pagebreak', 'image');

        if (!is_array($buttons)) {
            $buttons = !$buttons ? false : $excluded;
        } else {
            $buttons = array_merge($buttons, $excluded);
        }

        $buttons = $this->getXtdButtons($name, $buttons, $asset, $author);

        if (!empty($buttons)) {
            foreach ($buttons as $i => $button) {
                if ($button->get('name')) {
                    // Set some vars
                    $icon = 'none icon-' . $button->get('icon', $button->get('name'));

                    $name = 'button-' . $i . '-' . str_replace(' ', '-', $button->get('text'));
                    $title = $button->get('text');
                    $onclick = $button->get('onclick', '');

                    if ($button->get('link') !== '#') {
                        $href = JUri::base() . $button->get('link');
                    } else {
                        $href = '';
                    }

                    $id = $button->get('name');

                    $list[$id] = array(
                        'name' => $name,
                        'title' => $title,
                        'icon' => $icon,
                        'href' => $href,
                        'onclick' => $onclick,
                        'svg' => $button->get('iconSVG'),
                        'options' => $button->get('options', array())
                    );
                }
            }
        }

        return $list;
    }

    private function getXtdButtons($name, $buttons, $asset, $author)
    {
        $xtdbuttons = array();
        if (is_array($buttons) || (is_bool($buttons) && $buttons)) {
            $buttonsEvent = new Joomla\Event\Event(
                'getButtons',
                [
                    'editor' => $name,
                    'buttons' => $buttons,
                ]
            );
            if (method_exists($this, 'getDispatcher')) {
                $buttonsResult = $this->getDispatcher()->dispatch('getButtons', $buttonsEvent);
                $xtdbuttons = $buttonsResult['result'];
            } else {
                $xtdbuttons = $this->_subject->getButtons($name, $buttons, $asset, $author);
            }
        }
        return $xtdbuttons;
    }

    private function displayButtons($name, $buttons, $asset, $author)
    {
        $buttons = $this->getXtdButtons($name, $buttons, $asset, $author);

        if (!empty($buttons)) {
            // fix some legacy buttons
            array_walk($buttons, function ($button) {
                $cls = $button->get('class', '');
                if (empty($cls) || strpos($cls, 'btn') === false) {
                    $cls .= ' btn';
                    $button->set('class', trim($cls));
                }
            });

            return LayoutHelper::render('joomla.editors.buttons', $buttons);
        }
    }
}
PK��#]B�C_uueditors/none/none.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.none
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plain Textarea Editor Plugin
 *
 * @since  1.5
 */
class PlgEditorNone extends JPlugin
{
	/**
	 * Method to handle the onInitEditor event.
	 *  - Initialises the Editor
	 *
	 * @return  void
	 *
	 * @since 1.5
	 */
	public function onInit()
	{
		JHtml::_('script', 'editors/none/none.min.js', array('version' => 'auto', 'relative' => true));
	}

	/**
	 * Copy editor content to form field.
	 *
	 * Not applicable in this editor.
	 *
	 * @param   string  $editor  the editor id
	 *
	 * @return  void
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSave($editor)
	{
	}

	/**
	 * Get the editor content.
	 *
	 * @param   string  $id  The id of the editor field.
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onGetContent($id)
	{
		return 'Joomla.editors.instances[' . json_encode($id) . '].getValue();';
	}

	/**
	 * Set the editor content.
	 *
	 * @param   string  $id    The id of the editor field.
	 * @param   string  $html  The content to set.
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSetContent($id, $html)
	{
		return 'Joomla.editors.instances[' . json_encode($id) . '].setValue(' . json_encode($html) . ');';
	}

	/**
	 * Inserts html code into the editor
	 *
	 * @param   string  $id  The id of the editor field
	 *
	 * @return  void
	 *
	 * @deprecated 4.0
	 */
	public function onGetInsertMethod($id)
	{
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The control name.
	 * @param   string   $content  The contents of the text area.
	 * @param   string   $width    The width of the text area (px or %).
	 * @param   string   $height   The height of the text area (px or %).
	 * @param   integer  $col      The number of columns for the textarea.
	 * @param   integer  $row      The number of rows for the textarea.
	 * @param   boolean  $buttons  True and the editor buttons will be displayed.
	 * @param   string   $id       An optional ID for the textarea (note: since 1.6). If not supplied the name is used.
	 * @param   string   $asset    The object asset
	 * @param   object   $author   The author.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string
	 */
	public function onDisplay($name, $content, $width, $height, $col, $row, $buttons = true,
		$id = null, $asset = null, $author = null, $params = array())
	{
		if (empty($id))
		{
			$id = $name;
		}

		// Only add "px" to width and height if they are not given as a percentage
		if (is_numeric($width))
		{
			$width .= 'px';
		}

		if (is_numeric($height))
		{
			$height .= 'px';
		}

		$readonly = !empty($params['readonly']) ? ' readonly disabled' : '';

		$editor = '<div class="js-editor-none">'
			. '<textarea name="' . $name . '" id="' . $id . '" cols="' . $col . '" rows="' . $row
			. '" style="width: ' . $width . '; height: ' . $height . ';"' . $readonly . '>' . $content . '</textarea>'
			. $this->_displayButtons($id, $buttons, $asset, $author)
			. '</div>';

		return $editor;
	}

	/**
	 * Displays the editor buttons.
	 *
	 * @param   string  $name     The control name.
	 * @param   mixed   $buttons  [array with button objects | boolean true to display buttons]
	 * @param   string  $asset    The object asset
	 * @param   object  $author   The author.
	 *
	 * @return  void|string HTML
	 */
	public function _displayButtons($name, $buttons, $asset, $author)
	{
		if (is_array($buttons) || (is_bool($buttons) && $buttons))
		{
			$buttons = $this->_subject->getButtons($name, $buttons, $asset, $author);

			return JLayoutHelper::render('joomla.editors.buttons', $buttons);
		}
	}
}
PK��#]�)��editors/none/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]3�8b��editors/none/none.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="editors" method="upgrade">
	<name>plg_editors_none</name>
	<version>3.0.0</version>
	<creationDate>September 2005</creationDate>
	<author>Joomla! Project</author>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<description>PLG_NONE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="none">none.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_editors_none.ini</language>
		<language tag="en-GB">en-GB.plg_editors_none.sys.ini</language>
	</languages>
</extension>
PK��#]00cFJ!J!!twofactorauth/yubikey/yubikey.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.yubikey
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! Two Factor Authentication using Yubikey Plugin
 *
 * @since  3.2
 */
class PlgTwofactorauthYubikey extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded automatically.
	 *
	 * @var    boolean
	 * @since  3.2
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method name
	 *
	 * @var    string
	 * @since  3.2
	 */
	protected $methodName = 'yubikey';

	/**
	 * This method returns the identification object for this two factor
	 * authentication plugin.
	 *
	 * @return  stdClass  An object with public properties method and title
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorIdentify()
	{
		$section         = (int) $this->params->get('section', 3);
		$current_section = 0;

		try
		{
			$app = JFactory::getApplication();

			if ($app->isClient('administrator'))
			{
				$current_section = 2;
			}
			elseif ($app->isClient('site'))
			{
				$current_section = 1;
			}
		}
		catch (Exception $exc)
		{
			$current_section = 0;
		}

		if (!($current_section & $section))
		{
			return false;
		}

		return (object) array(
			'method' => $this->methodName,
			'title'  => JText::_('PLG_TWOFACTORAUTH_YUBIKEY_METHOD_TITLE'),
		);
	}

	/**
	 * Shows the configuration page for this two factor authentication method.
	 *
	 * @param   object   $otpConfig  The two factor auth configuration object
	 * @param   integer  $userId     The numeric user ID of the user whose form we'll display
	 *
	 * @return  boolean|string  False if the method is not ours, the HTML of the configuration page otherwise
	 *
	 * @see     UsersModelUser::getOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorShowConfiguration($otpConfig, $userId = null)
	{
		if ($otpConfig->method === $this->methodName)
		{
			// This method is already activated. Reuse the same Yubikey ID.
			$yubikey = $otpConfig->config['yubikey'];
		}
		else
		{
			// This methods is not activated yet. We'll need a Yubikey TOTP to setup this Yubikey.
			$yubikey = '';
		}

		// Is this a new TOTP setup? If so, we'll have to show the code validation field.
		$new_totp    = $otpConfig->method !== $this->methodName;

		// Start output buffering
		@ob_start();

		// Include the form.php from a template override. If none is found use the default.
		$path = FOFPlatform::getInstance()->getTemplateOverridePath('plg_twofactorauth_yubikey', true);

		JLoader::import('joomla.filesystem.file');

		if (JFile::exists($path . '/form.php'))
		{
			include_once $path . '/form.php';
		}
		else
		{
			include_once __DIR__ . '/tmpl/form.php';
		}

		// Stop output buffering and get the form contents
		$html = @ob_get_clean();

		// Return the form contents
		return array(
			'method' => $this->methodName,
			'form'   => $html,
		);
	}

	/**
	 * The save handler of the two factor configuration method's configuration
	 * page.
	 *
	 * @param   string  $method  The two factor auth method for which we'll show the config page
	 *
	 * @return  boolean|stdClass  False if the method doesn't match or we have an error, OTP config object if it succeeds
	 *
	 * @see     UsersModelUser::setOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorApplyConfiguration($method)
	{
		if ($method !== $this->methodName)
		{
			return false;
		}

		// Get a reference to the input data object
		$input = JFactory::getApplication()->input;

		// Load raw data
		$rawData = $input->get('jform', array(), 'array');

		if (!isset($rawData['twofactor']['yubikey']))
		{
			return false;
		}

		$data = $rawData['twofactor']['yubikey'];

		// Warn if the securitycode is empty
		if (array_key_exists('securitycode', $data) && empty($data['securitycode']))
		{
			try
			{
				JFactory::getApplication()->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_YUBIKEY_ERR_VALIDATIONFAILED'), 'error');
			}
			catch (Exception $exc)
			{
				// This only happens when we are in a CLI application. We cannot
				// enqueue a message, so just do nothing.
			}

			return false;
		}

		// Validate the Yubikey OTP
		$check = $this->validateYubikeyOtp($data['securitycode']);

		if (!$check)
		{
			JFactory::getApplication()->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_YUBIKEY_ERR_VALIDATIONFAILED'), 'error');

			// Check failed. Do not change two factor authentication settings.
			return false;
		}

		// Remove the last 32 digits and store the rest in the user configuration parameters
		$yubikey      = substr($data['securitycode'], 0, -32);

		// Check succeeded; return an OTP configuration object
		$otpConfig    = (object) array(
			'method'  => $this->methodName,
			'config'  => array(
				'yubikey' => $yubikey
			),
			'otep'    => array()
		);

		return $otpConfig;
	}

	/**
	 * This method should handle any two factor authentication and report back
	 * to the subject.
	 *
	 * @param   array  $credentials  Array holding the user credentials
	 * @param   array  $options      Array of extra options
	 *
	 * @return  boolean  True if the user is authorised with this two-factor authentication method
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorAuthenticate($credentials, $options)
	{
		// Get the OTP configuration object
		$otpConfig = $options['otp_config'];

		// Make sure it's an object
		if (empty($otpConfig) || !is_object($otpConfig))
		{
			return false;
		}

		// Check if we have the correct method
		if ($otpConfig->method !== $this->methodName)
		{
			return false;
		}

		// Check if there is a security code
		if (empty($credentials['secretkey']))
		{
			return false;
		}

		// Check if the Yubikey starts with the configured Yubikey user string
		$yubikey_valid = $otpConfig->config['yubikey'];
		$yubikey       = substr($credentials['secretkey'], 0, -32);

		$check = $yubikey === $yubikey_valid;

		if ($check)
		{
			$check = $this->validateYubikeyOtp($credentials['secretkey']);
		}

		return $check;
	}

	/**
	 * Validates a Yubikey OTP against the Yubikey servers
	 *
	 * @param   string  $otp  The OTP generated by your Yubikey
	 *
	 * @return  boolean  True if it's a valid OTP
	 *
	 * @since   3.2
	 */
	public function validateYubikeyOtp($otp)
	{
		$server_queue = array(
			'api.yubico.com',
			'api2.yubico.com',
			'api3.yubico.com',
			'api4.yubico.com',
			'api5.yubico.com',
		);

		shuffle($server_queue);

		$gotResponse = false;
		$check       = false;

		$token = JSession::getFormToken();
		$nonce = md5($token . uniqid(mt_rand()));

		while (!$gotResponse && !empty($server_queue))
		{
			$server = array_shift($server_queue);
			$uri    = new JUri('https://' . $server . '/wsapi/2.0/verify');

			// I don't see where this ID is used?
			$uri->setVar('id', 1);

			// The OTP we read from the user
			$uri->setVar('otp', $otp);

			// This prevents a REPLAYED_OTP status of the token doesn't change
			// after a user submits an invalid OTP
			$uri->setVar('nonce', $nonce);

			// Minimum service level required: 50% (at least 50% of the YubiCloud
			// servers must reply positively for the OTP to validate)
			$uri->setVar('sl', 50);

			// Timeou waiting for YubiCloud servers to reply: 5 seconds.
			$uri->setVar('timeout', 5);

			try
			{
				$http     = JHttpFactory::getHttp();
				$response = $http->get($uri->toString(), null, 6);

				if (!empty($response))
				{
					$gotResponse = true;
				}
				else
				{
					continue;
				}
			}
			catch (Exception $exc)
			{
				// No response, continue with the next server
				continue;
			}
		}

		// No server replied; we can't validate this OTP
		if (!$gotResponse)
		{
			return false;
		}

		// Parse response
		$lines = explode("\n", $response->body);
		$data  = array();

		foreach ($lines as $line)
		{
			$line  = trim($line);
			$parts = explode('=', $line, 2);

			if (count($parts) < 2)
			{
				continue;
			}

			$data[$parts[0]] = $parts[1];
		}

		// Validate the response - We need an OK message reply
		if ($data['status'] !== 'OK')
		{
			return false;
		}

		// Validate the response - We need a confidence level over 50%
		if ($data['sl'] < 50)
		{
			return false;
		}

		// Validate the response - The OTP must match
		if ($data['otp'] !== $otp)
		{
			return false;
		}

		// Validate the response - The token must match
		if ($data['nonce'] !== $nonce)
		{
			return false;
		}

		return true;
	}
}
PK��#]�Q�ee#twofactorauth/yubikey/tmpl/form.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.yubikey.tmpl
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;
?>
<div class="well">
	<?php echo JText::_('PLG_TWOFACTORAUTH_YUBIKEY_INTRO') ?>
</div>

<?php if ($new_totp): ?>
<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_YUBIKEY_STEP1_HEAD') ?>
	</legend>

	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_YUBIKEY_STEP1_TEXT') ?>
	</p>

	<div class="control-group">
		<label class="control-label" for="yubikeysecuritycode">
			<?php echo JText::_('PLG_TWOFACTORAUTH_YUBIKEY_SECURITYCODE') ?>
		</label>
		<div class="controls">
			<input type="text" class="input-medium" name="jform[twofactor][yubikey][securitycode]" id="yubikeysecuritycode" autocomplete="0">
		</div>
	</div>
</fieldset>
<?php else: ?>
<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_RESET_HEAD') ?>
	</legend>

	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_RESET_TEXT') ?>
	</p>
</fieldset>
<?php endif; ?>
PK��#]�Stt!twofactorauth/yubikey/yubikey.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="twofactorauth" method="upgrade">
	<name>plg_twofactorauth_yubikey</name>
	<author>Joomla! Project</author>
	<creationDate>September 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.2.0</version>
	<description>PLG_TWOFACTORAUTH_YUBIKEY_XML_DESCRIPTION</description>
	<files>
		<filename plugin="yubikey">yubikey.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_twofactorauth_yubikey.ini</language>
		<language tag="en-GB">en-GB.plg_twofactorauth_yubikey.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="section"
					type="radio"
					label="PLG_TWOFACTORAUTH_YUBIKEY_SECTION_LABEL"
					description="PLG_TWOFACTORAUTH_YUBIKEY_SECTION_DESC"
					default="3"
					filter="integer"
					class="btn-group"
					>
					<option value="1">PLG_TWOFACTORAUTH_YUBIKEY_SECTION_SITE</option>
					<option value="2">PLG_TWOFACTORAUTH_YUBIKEY_SECTION_ADMIN</option>
					<option value="3">PLG_TWOFACTORAUTH_YUBIKEY_SECTION_BOTH</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��twofactorauth/yubikey/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��twofactorauth/totp/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]���!!twofactorauth/totp/totp.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.totp
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! Two Factor Authentication using Google Authenticator TOTP Plugin
 *
 * @since  3.2
 */
class PlgTwofactorauthTotp extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded automatically.
	 *
	 * @var    boolean
	 * @since  3.2
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method name
	 *
	 * @var    string
	 * @since  3.2
	 */
	protected $methodName = 'totp';

	/**
	 * This method returns the identification object for this two factor
	 * authentication plugin.
	 *
	 * @return  stdClass  An object with public properties method and title
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorIdentify()
	{
		$section = (int) $this->params->get('section', 3);

		$current_section = 0;

		try
		{
			$app = JFactory::getApplication();

			if ($app->isClient('administrator'))
			{
				$current_section = 2;
			}
			elseif ($app->isClient('site'))
			{
				$current_section = 1;
			}
		}
		catch (Exception $exc)
		{
			$current_section = 0;
		}

		if (!($current_section & $section))
		{
			return false;
		}

		return (object) array(
			'method' => $this->methodName,
			'title'  => JText::_('PLG_TWOFACTORAUTH_TOTP_METHOD_TITLE')
		);
	}

	/**
	 * Shows the configuration page for this two factor authentication method.
	 *
	 * @param   object   $otpConfig  The two factor auth configuration object
	 * @param   integer  $userId     The numeric user ID of the user whose form we'll display
	 *
	 * @return  boolean|string  False if the method is not ours, the HTML of the configuration page otherwise
	 *
	 * @see     UsersModelUser::getOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorShowConfiguration($otpConfig, $userId = null)
	{
		// Create a new TOTP class with Google Authenticator compatible settings
		$totp = new FOFEncryptTotp(30, 6, 10);

		if ($otpConfig->method === $this->methodName)
		{
			// This method is already activated. Reuse the same secret key.
			$secret = $otpConfig->config['code'];
		}
		else
		{
			// This methods is not activated yet. Create a new secret key.
			$secret = $totp->generateSecret();
		}

		// These are used by Google Authenticator to tell accounts apart
		$username = JFactory::getUser($userId)->username;
		$hostname = JUri::getInstance()->getHost();

		// This is the URL to the QR code for Google Authenticator
		$url = sprintf("otpauth://totp/%s@%s?secret=%s", $username, $hostname, $secret);

		// Is this a new TOTP setup? If so, we'll have to show the code validation field.
		$new_totp = $otpConfig->method !== 'totp';

		// Start output buffering
		@ob_start();

		// Include the form.php from a template override. If none is found use the default.
		$path = FOFPlatform::getInstance()->getTemplateOverridePath('plg_twofactorauth_totp', true);

		JLoader::import('joomla.filesystem.file');

		if (JFile::exists($path . '/form.php'))
		{
			include_once $path . '/form.php';
		}
		else
		{
			include_once __DIR__ . '/tmpl/form.php';
		}

		// Stop output buffering and get the form contents
		$html = @ob_get_clean();

		// Return the form contents
		return array(
			'method' => $this->methodName,
			'form'   => $html
		);
	}

	/**
	 * The save handler of the two factor configuration method's configuration
	 * page.
	 *
	 * @param   string  $method  The two factor auth method for which we'll show the config page
	 *
	 * @return  boolean|stdClass  False if the method doesn't match or we have an error, OTP config object if it succeeds
	 *
	 * @see     UsersModelUser::setOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorApplyConfiguration($method)
	{
		if ($method !== $this->methodName)
		{
			return false;
		}

		// Get a reference to the input data object
		$input = JFactory::getApplication()->input;

		// Load raw data
		$rawData = $input->get('jform', array(), 'array');

		if (!isset($rawData['twofactor']['totp']))
		{
			return false;
		}

		$data = $rawData['twofactor']['totp'];

		// Warn if the securitycode is empty
		if (array_key_exists('securitycode', $data) && empty($data['securitycode']))
		{
			try
			{
				$app = JFactory::getApplication();
				$app->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_TOTP_ERR_VALIDATIONFAILED'), 'error');
			}
			catch (Exception $exc)
			{
				// This only happens when we are in a CLI application. We cannot
				// enqueue a message, so just do nothing.
			}

			return false;
		}

		// Create a new TOTP class with Google Authenticator compatible settings
		$totp = new FOFEncryptTotp(30, 6, 10);

		// Check the security code entered by the user (exact time slot match)
		$code = $totp->getCode($data['key']);
		$check = $code === $data['securitycode'];

		/*
		 * If the check fails, test the previous 30 second slot. This allow the
		 * user to enter the security code when it's becoming red in Google
		 * Authenticator app (reaching the end of its 30 second lifetime)
		 */
		if (!$check)
		{
			$time = time() - 30;
			$code = $totp->getCode($data['key'], $time);
			$check = $code === $data['securitycode'];
		}

		/*
		 * If the check fails, test the next 30 second slot. This allows some
		 * time drift between the authentication device and the server
		 */
		if (!$check)
		{
			$time = time() + 30;
			$code = $totp->getCode($data['key'], $time);
			$check = $code === $data['securitycode'];
		}

		if (!$check)
		{
			// Check failed. Do not change two factor authentication settings.
			return false;
		}

		// Check succeeded; return an OTP configuration object
		$otpConfig = (object) array(
			'method'   => 'totp',
			'config'   => array(
				'code' => $data['key']
			),
			'otep'     => array()
		);

		return $otpConfig;
	}

	/**
	 * This method should handle any two factor authentication and report back
	 * to the subject.
	 *
	 * @param   array  $credentials  Array holding the user credentials
	 * @param   array  $options      Array of extra options
	 *
	 * @return  boolean  True if the user is authorised with this two-factor authentication method
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorAuthenticate($credentials, $options)
	{
		// Get the OTP configuration object
		$otpConfig = $options['otp_config'];

		// Make sure it's an object
		if (empty($otpConfig) || !is_object($otpConfig))
		{
			return false;
		}

		// Check if we have the correct method
		if ($otpConfig->method !== $this->methodName)
		{
			return false;
		}

		// Check if there is a security code
		if (empty($credentials['secretkey']))
		{
			return false;
		}

		// Create a new TOTP class with Google Authenticator compatible settings
		$totp = new FOFEncryptTotp(30, 6, 10);

		// Check the code
		$code = $totp->getCode($otpConfig->config['code']);
		$check = $code === $credentials['secretkey'];

		/*
		 * If the check fails, test the previous 30 second slot. This allow the
		 * user to enter the security code when it's becoming red in Google
		 * Authenticator app (reaching the end of its 30 second lifetime)
		 */
		if (!$check)
		{
			$time = time() - 30;
			$code = $totp->getCode($otpConfig->config['code'], $time);
			$check = $code === $credentials['secretkey'];
		}

		/*
		 * If the check fails, test the next 30 second slot. This allows some
		 * time drift between the authentication device and the server
		 */
		if (!$check)
		{
			$time = time() + 30;
			$code = $totp->getCode($otpConfig->config['code'], $time);
			$check = $code === $credentials['secretkey'];
		}

		return $check;
	}
}
PK��#]�^*UU*twofactorauth/totp/postinstall/actions.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.totp
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 *
 * This file contains the functions used by the com_postinstall code to deliver
 * the necessary post-installation messages concerning the activation of the
 * two-factor authentication code.
 */

/**
 * Checks if the plugin is enabled. If not it returns true, meaning that the
 * message concerning two factor authentication should be displayed.
 *
 * @return  integer
 *
 * @since   3.2
 */
function twofactorauth_postinstall_condition()
{
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->select('*')
		->from($db->qn('#__extensions'))
		->where($db->qn('type') . ' = ' . $db->q('plugin'))
		->where($db->qn('enabled') . ' = 1')
		->where($db->qn('folder') . ' = ' . $db->q('twofactorauth'));
	$db->setQuery($query);
	$enabled_plugins = $db->loadObjectList();

	return count($enabled_plugins) === 0;
}

/**
 * Enables the two factor authentication plugin and redirects the user to their
 * user profile page so that they can enable two factor authentication on their
 * account.
 *
 * @return  void
 *
 * @since   3.2
 */
function twofactorauth_postinstall_action()
{
	// Enable the plugin
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->update($db->qn('#__extensions'))
		->set($db->qn('enabled') . ' = 1')
		->where($db->qn('type') . ' = ' . $db->q('plugin'))
		->where($db->qn('folder') . ' = ' . $db->q('twofactorauth'));
	$db->setQuery($query);
	$db->execute();

	// Clean cache.
	JFactory::getCache()->clean('com_plugins');

	// Redirect the user to their profile editor page
	$url = 'index.php?option=com_users&task=user.edit&id=' . JFactory::getUser()->id;
	JFactory::getApplication()->redirect($url);
}
PK��#]�E�\ootwofactorauth/totp/totp.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="twofactorauth" method="upgrade">
	<name>plg_twofactorauth_totp</name>
	<author>Joomla! Project</author>
	<creationDate>August 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.2.0</version>
	<description>PLG_TWOFACTORAUTH_TOTP_XML_DESCRIPTION</description>
	<files>
		<filename plugin="totp">totp.php</filename>
		<folder>postinstall</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_twofactorauth_totp.ini</language>
		<language tag="en-GB">en-GB.plg_twofactorauth_totp.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="section"
					type="radio"
					label="PLG_TWOFACTORAUTH_TOTP_SECTION_LABEL"
					description="PLG_TWOFACTORAUTH_TOTP_SECTION_DESC"
					default="3"
					filter="integer"
					class="btn-group"
					>
					<option value="1">PLG_TWOFACTORAUTH_TOTP_SECTION_SITE</option>
					<option value="2">PLG_TWOFACTORAUTH_TOTP_SECTION_ADMIN</option>
					<option value="3">PLG_TWOFACTORAUTH_TOTP_SECTION_BOTH</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�/�d�� twofactorauth/totp/tmpl/form.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.totp.tmpl
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Factory;

HTMLHelper::_('script', 'plg_twofactorauth_totp/qrcode.min.js', array('version' => 'auto', 'relative' => true));

$js = "
(function(document)
{
	document.addEventListener('DOMContentLoaded', function()
	{
		var qr = qrcode(0, 'H');
		qr.addData('" . $url . "');
		qr.make();

		document.getElementById('totp-qrcode').innerHTML = qr.createImgTag(4);
	});
})(document);
";

Factory::getDocument()->addScriptDeclaration($js);
?>
<input type="hidden" name="jform[twofactor][totp][key]" value="<?php echo $secret ?>" />

<div class="well">
	<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_INTRO') ?>
</div>

<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_HEAD') ?>
	</legend>
	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_TEXT') ?>
	</p>
	<ul>
		<li>
			<a href="<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM1_LINK') ?>" target="_blank" rel="noopener noreferrer">
				<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM1') ?>
			</a>
		</li>
		<li>
			<a href="<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM2_LINK') ?>" target="_blank" rel="noopener noreferrer">
				<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM2') ?>
			</a>
		</li>
	</ul>
	<div class="alert">
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_WARN') ?>
	</div>
</fieldset>

<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_HEAD') ?>
	</legend>

	<div class="span6">
		<p>
			<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_TEXT') ?>
		</p>
		<table class="table table-striped">
			<tr>
				<td>
					<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_ACCOUNT') ?>
				</td>
				<td>
					<?php echo $username ?>@<?php echo $hostname ?>
				</td>
			</tr>
			<tr>
				<td>
					<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_KEY') ?>
				</td>
				<td>
					<?php echo $secret ?>
				</td>
			</tr>
		</table>
	</div>

	<div class="span6">
		<p>
			<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_ALTTEXT') ?>
			<br />
			<div id="totp-qrcode"></div>
		</p>
	</div>

	<div class="clearfix"></div>

	<div class="alert alert-info">
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_RESET') ?>
	</div>
</fieldset>

<?php if ($new_totp): ?>
<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP3_HEAD') ?>
	</legend>
	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP3_TEXT') ?>
	</p>
	<div class="control-group">
		<label class="control-label" for="totpsecuritycode">
			<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP3_SECURITYCODE') ?>
		</label>
		<div class="controls">
			<input type="text" class="input-small" name="jform[twofactor][totp][securitycode]" id="totpsecuritycode" autocomplete="0">
		</div>
	</div>
</fieldset>
<?php endif; ?>
PK��#]�)��twofactorauth/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��#quickicon/extensionupdate/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]J�Ƶuu-quickicon/extensionupdate/extensionupdate.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="quickicon" method="upgrade">
	<name>plg_quickicon_extensionupdate</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_QUICKICON_EXTENSIONUPDATE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="extensionupdate">extensionupdate.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_quickicon_extensionupdate.ini</language>
		<language tag="en-GB">en-GB.plg_quickicon_extensionupdate.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field 
					name="context"
					type="text"
					label="PLG_QUICKICON_EXTENSIONUPDATE_GROUP_LABEL"
					description="PLG_QUICKICON_EXTENSIONUPDATE_GROUP_DESC"
					default="mod_quickicon"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]��Mq
q
-quickicon/extensionupdate/extensionupdate.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.Extensionupdate
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! update notification plugin
 *
 * @since  2.5
 */
class PlgQuickiconExtensionupdate extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Returns an icon definition for an icon which looks for extensions updates
	 * via AJAX and displays a notification when such updates are found.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array  A list of icon definition associative arrays, consisting of the
	 *                 keys link, image, text and access.
	 *
	 * @since   2.5
	 */
	public function onGetIcons($context)
	{
		if ($context !== $this->params->get('context', 'mod_quickicon') || !JFactory::getUser()->authorise('core.manage', 'com_installer'))
		{
			return;
		}

		JHtml::_('jquery.framework');

		$token    = JSession::getFormToken() . '=' . 1;
		$url      = JUri::base() . 'index.php?option=com_installer&view=update&task=update.find&' . $token;
		$ajax_url = JUri::base() . 'index.php?option=com_installer&view=update&task=update.ajax&' . $token;
		$script   = array();
		$script[] = 'var plg_quickicon_extensionupdate_url = \'' . $url . '\';';
		$script[] = 'var plg_quickicon_extensionupdate_ajax_url = \'' . $ajax_url . '\';';
		$script[] = 'var plg_quickicon_extensionupdate_text = {'
			. '"UPTODATE" : "' . JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPTODATE', true) . '",'
			. '"UPDATEFOUND": "' . JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPDATEFOUND', true) . '",'
			. '"UPDATEFOUND_MESSAGE": "' . JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPDATEFOUND_MESSAGE', true) . '",'
			. '"UPDATEFOUND_BUTTON": "' . JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPDATEFOUND_BUTTON', true) . '",'
			. '"ERROR": "' . JText::_('PLG_QUICKICON_EXTENSIONUPDATE_ERROR', true) . '",'
			. '};';
		JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));
		JHtml::_('script', 'plg_quickicon_extensionupdate/extensionupdatecheck.js', array('version' => 'auto', 'relative' => true));

		return array(
			array(
				'link'  => 'index.php?option=com_installer&view=update&task=update.find&' . $token,
				'image' => 'asterisk',
				'icon'  => 'header/icon-48-extension.png',
				'text'  => JText::_('PLG_QUICKICON_EXTENSIONUPDATE_CHECKING'),
				'id'    => 'plg_quickicon_extensionupdate',
				'group' => 'MOD_QUICKICON_MAINTENANCE'
			)
		);
	}
}
PK��#]�;��!quickicon/akeebabackup/script.phpnu�[���<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

use FOF40\InstallScript\Plugin;

defined('_JEXEC') || die;

// Load FOF if not already loaded
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
	throw new RuntimeException('This extension requires FOF 4.');
}

class plgQuickiconAkeebabackupInstallerScript extends Plugin
{
}
PK��#]L�J���!quickicon/akeebabackup/index.htmlnu�[���<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<html><head><title></title></head><body></body></html>PK��#]|��N!quickicon/akeebabackup/web.confignu�[���<?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>PK��#]�)�� quickicon/akeebabackup/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]Q6Q��'quickicon/akeebabackup/akeebabackup.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<extension version="2.5" type="plugin" group="quickicon" method="upgrade">
    <name>plg_quickicon_akeebabackup</name>
    <author>Nicholas K. Dionysopoulos</author>
    <authorEmail>nicholas@akeeba.com</authorEmail>
    <authorUrl>https://www.akeeba.com</authorUrl>
    <copyright>Copyright (c)2006-2023 Nicholas K. Dionysopoulos</copyright>
    <license>GNU General Public License version 3, or later</license>
    <creationDate>2023-02-08</creationDate>
    <version>8.2.7</version>
    <description>PLG_QUICKICON_AKEEBABACKUP_XML_DESCRIPTION</description>
    <files>
        <filename plugin="akeebabackup">akeebabackup.php</filename>
        <filename>index.html</filename>
        <filename>.htaccess</filename>
        <filename>web.config</filename>
    </files>
    <languages folder="language">
        <language tag="en-GB">en-GB/en-GB.plg_quickicon_akeebabackup.ini</language>
        <language tag="en-GB">en-GB/en-GB.plg_quickicon_akeebabackup.sys.ini</language>
    </languages>
    <config addfieldpath="/administrator/components/com_akeeba/fields">
        <fields name="params">
            <fieldset name="basic">
                <field name="enablewarning"
					   type="fancyradio"
					   label="PLG_QUICKICON_AKEEBABACKUP_LBL_WARNINGS"
                       description="PLG_QUICKICON_AKEEBABACKUP_DESC_WARNINGS"
					   default="1"
                       class="btn-group btn-group-yesno"
				>
                    <option value="0">JNO</option>
                    <option value="1">JYES</option>
                </field>

                <field name="warnfailed"
                       type="fancyradio"
                       label="PLG_QUICKICON_AKEEBABACKUP_LBL_WARNFAILED"
                       description="PLG_QUICKICON_AKEEBABACKUP_DESC_WARNFAILED"
					   default="1"
                       class="btn-group btn-group-yesno"
                       showon="enablewarning:1"
                >
                    <option value="0">JNO</option>
                    <option value="1">JYES</option>
                </field>

                <field name="maxbackupperiod"
					   type="number"
					   label="PLG_QUICKICON_AKEEBABACKUP_LBL_PERIOD"
                       description="PLG_QUICKICON_AKEEBABACKUP_DESC_PERIOD"
					   min="1"
					   max="87600"
					   step="1"
					   default="24"/>


                <field name="profileid"
					   type="backupprofiles"
					   default="1"
                       label="PLG_QUICKICON_AKEEBABACKUP_PROFILE_LABEL"
					   class="advancedSelect"
                       description="PLG_QUICKICON_AKEEBABACKUP_PROFILE_DESC"
                />
            </fieldset>
        </fields>
    </config>

    <scriptfile>script.php</scriptfile>
</extension>PK��#]b�d�3�3'quickicon/akeebabackup/akeebabackup.phpnu�[���<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

// Old PHP version detected. EJECT! EJECT! EJECT!
if (!version_compare(PHP_VERSION, '7.2.0', '>='))
{
	return;
}

// Make sure Akeeba Backup is installed
if (!file_exists(JPATH_ADMINISTRATOR . '/components/com_akeeba'))
{
	return;
}

use Akeeba\Backup\Admin\Model\Statistics;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use FOF40\Container\Container;
use FOF40\Date\Date;
use FOF40\JoomlaAbstraction\CacheCleaner;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Uri\Uri;

// Deactivate self
$db    = JFactory::getDbo();
$query = $db->getQuery(true)
	->update($db->qn('#__extensions'))
	->set($db->qn('enabled') . ' = ' . $db->q('0'))
	->where($db->qn('element') . ' = ' . $db->q('akeebabackup'))
	->where($db->qn('folder') . ' = ' . $db->q('quickicon'));
$db->setQuery($query);
$db->execute();

// Load FOF if not already loaded
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
	return;
}

CacheCleaner::clearPluginsCache();

// Timezone fix; avoids errors printed out by PHP 5.3.3+ (thanks Yannick!)
if (function_exists('date_default_timezone_get') && function_exists('date_default_timezone_set'))
{
	if (function_exists('error_reporting'))
	{
		$oldLevel = error_reporting(0);
	}
	$serverTimezone = @date_default_timezone_get();
	if (empty($serverTimezone) || !is_string($serverTimezone))
	{
		$serverTimezone = 'UTC';
	}
	if (function_exists('error_reporting'))
	{
		error_reporting($oldLevel);
	}
	@date_default_timezone_set($serverTimezone);
}
/*
 * Hopefully, if we are still here, the site is running on at least PHP5. This means that
 * including the Akeeba Backup factory class will not throw a White Screen of Death, locking
 * the administrator out of the back-end.
 */

// Make sure Akeeba Backup is installed, or quit
$akeeba_installed = @file_exists(JPATH_ADMINISTRATOR . '/components/com_akeeba/BackupEngine/Factory.php');

if (!$akeeba_installed)
{
	return;
}

// Make sure Akeeba Backup is enabled
if (!ComponentHelper::isEnabled('com_akeeba'))
{
	return;
}

// Joomla! 1.6 or later - check ACLs (and not display when the site is bricked,
// hopefully resulting in no stupid emails from users who think that somehow
// Akeeba Backup crashed their site). It also not displays the button to people
// who are not authorised to take backups - which makes perfect sense!
$continueLoadingIcon = true;
$user                = JFactory::getUser();

if (!$user->authorise('akeeba.backup', 'com_akeeba'))
{
	$continueLoadingIcon = false;
}

// Do we really, REALLY have Akeeba Engine?
if ($continueLoadingIcon)
{
	if (!defined('AKEEBAENGINE'))
	{
		define('AKEEBAENGINE', 1); // Required for accessing Akeeba Engine's factory class
	}
	try
	{
		@include_once JPATH_ADMINISTRATOR . '/components/com_akeeba/BackupEngine/Factory.php';
		if (!class_exists('\Akeeba\Engine\Factory', false))
		{
			$continueLoadingIcon = false;
		}
	}
	catch (Exception $e)
	{
		$continueLoadingIcon = false;
	}
}

// Enable self if we have to bail out
if (!$continueLoadingIcon)
{
	$db    = JFactory::getDbo();
	$query = $db->getQuery(true)
		->update($db->qn('#__extensions'))
		->set($db->qn('enabled') . ' = ' . $db->q('1'))
		->where($db->qn('element') . ' = ' . $db->q('akeebabackup'))
		->where($db->qn('folder') . ' = ' . $db->q('quickicon'));
	$db->setQuery($query);
	$db->execute();

	CacheCleaner::clearPluginsCache();

	return;
}
unset($continueLoadingIcon);

/**
 * Akeeba Backup Notification plugin
 */
class plgQuickiconAkeebabackup extends CMSPlugin
{
	/**
	 * Constructor
	 *
	 * @param   object  $subject  The object to observe
	 * @param   array   $config   An array that holds the plugin configuration
	 *
	 * @since       2.5
	 */
	public function __construct(&$subject, $config)
	{
		/**
		 * I know that this piece of code cannot possibly be executed since I have already returned BEFORE declaring
		 * the class when eAccelerator is detected. However, eAccelerator is being dumb. It will return above BUT it
		 * will also declare the class EVEN THOUGH according to how PHP works this part of the code should be
		 * unreachable o_O Therefore I have to define this constant and exit the constructor when we have already
		 * determined that this class MUST NOT be defined.
		 */
		if (defined('AKEEBA_EACCELERATOR_IS_SO_BORKED_IT_DOES_NOT_EVEN_RETURN'))
		{
			return;
		}

		parent::__construct($subject, $config);
		$this->loadLanguage();
	}

	/**
	 * This method is called when the Quick Icons module is constructing its set
	 * of icons. You can return an array which defines a single icon and it will
	 * be rendered right after the stock Quick Icons.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array|null A list of icon definition associative arrays, consisting of the
	 *                 keys link, image, text and access.
	 *
	 * @throws  Exception
	 */
	public function onGetIcons($context)
	{
		$container           = Container::getInstance('com_akeeba');
		$user                = $container->platform->getUser();
		$j4WarningJavascript = false;

		if (!$user->authorise('akeeba.backup', 'com_akeeba'))
		{
			return null;
		}

		/**
		 * The context in which quickicons appear. There's a reason this is hardcoded now.
		 *
		 * Joomla 3. This is always mod_quickicon. Grouping is defined by the 'group' key of the returned array. This is
		 * the sane way I personally wrote this feature when I contributed it to Joomla! 1.7. The whole point of the
		 * 'context' was that you could have **extension specific** quick icon plugins. Think about how JCE shows icons
		 * in its control panel. The incoming context determines which plugins to load, the returned group key
		 * determines how the icons are grouped in the context.
		 *
		 * Joomla 4. The context defines the quick icon grouping. The 'group' key of the returned array is ignored. All
		 * quick icon plugins which respond to the 'mod_quickicon' context are shown in the "Third party" backend
		 * module. This is a nonsensical change.
		 *
		 * Unfortunately, this means that I have to remove the user-defined context option. The reason is that Joomla
		 * renders plugin options based on a static XML file which is common for J3 and J4. However, the context has a
		 * different meaning and requires a different setting for J3 and J4. I have to take the flexibility away from
		 * the user and force a default context in J4 which puts our icon in Update Checks.
		 *
		 * Yes, I know that the Update Checks module is, at the very least, mislabeled. There are of course the updates
		 * to Joomla and extensions but also privacy requests and overrides, the latter two not being updates in any
		 * conceivable form and in any possible universe. Since this backend module is supposed to have everything I am
		 * going to throw my backup check in there. At least my plugin shows "backup up-to-date" or "update needed"
		 * which actually makes it FAR MORE RELEVANT in an "updates" area on the page than the friggin' privacy
		 * requests!
		 */
		$configuredContext = version_compare(JVERSION, '3.999.999', 'gt') ? 'update_quickicon' : 'mod_quickicon';

		/**/
		if (
			$context != $configuredContext
			|| !JFactory::getUser()->authorise('core.manage', 'com_installer')
		)
		{
			return null;
		}
		/**/

		// Necessary defines for Akeeba Engine
		if (!defined('AKEEBAENGINE'))
		{
			define('AKEEBAENGINE', 1);
			define('AKEEBAROOT', $container->backEndPath . '/BackupEngine');
			define('ALICEROOT', $container->backEndPath . '/AliceEngine');

			// Make sure we have a profile set throughout the component's lifetime
			$profile_id = $container->platform->getSessionVar('profile', null, 'akeeba');

			if (is_null($profile_id))
			{
				$container->platform->setSessionVar('profile', 1, 'akeeba');
			}

			// Load Akeeba Engine
			require_once $container->backEndPath . '/BackupEngine/Factory.php';
		}

		Platform::addPlatform('joomla3x', JPATH_ADMINISTRATOR . '/components/com_akeeba/BackupPlatform/Joomla3x');

		$url = Uri::base();
		$url = rtrim($url, '/');

		$profileId = (int) $this->params->get('profileid', 1);
		$token     = $container->platform->getToken(true);

		if ($profileId <= 0)
		{
			$profileId = 1;
		}

		$isJoomla4 = version_compare(JVERSION, '3.999.999', 'gt');

		$ret = [
			'link'  => 'index.php?option=com_akeeba&view=Backup&autostart=1&returnurl=' . base64_encode($url) . '&profileid=' . $profileId . "&$token=1",
			'image' => 'akeeba-black',
			'text'  => Text::_('PLG_QUICKICON_AKEEBABACKUP_OK'),
			'id'    => 'plg_quickicon_akeebabackup',
			'group' => 'MOD_QUICKICON_MAINTENANCE',
		];

		if ($isJoomla4)
		{
			$ret['image'] = 'fa fa-akeeba-black';
		}

		if ($this->params->get('enablewarning', 0) == 0)
		{
			// Process warnings
			$warning = false;

			$aeconfig = Factory::getConfiguration();
			Platform::getInstance()->load_configuration(1);

			// Get latest non-SRP backup ID
			$filters  = [
				[
					'field'   => 'tag',
					'operand' => '<>',
					'value'   => 'restorepoint',
				],
			];
			$ordering = [
				'by'    => 'backupstart',
				'order' => 'DESC',
			];

			/** @var Statistics $model */
			$model = $container->factory->model('Statistics')->tmpInstance();
			$list  = $model->getStatisticsListWithMeta(false, $filters, $ordering);

			if (!empty($list))
			{
				$record = (object) array_shift($list);
			}
			else
			{
				$record = null;
			}

			// Process "failed backup" warnings, if specified
			if ($this->params->get('warnfailed', 0) == 0)
			{
				if (!is_null($record))
				{
					$warning = (($record->status == 'fail') || ($record->status == 'run'));
				}
			}

			// Process "stale backup" warnings, if specified
			if (is_null($record))
			{
				$warning = true;
			}
			else
			{
				$maxperiod        = $this->params->get('maxbackupperiod', 24);
				$lastBackupRaw    = $record->backupstart;
				$lastBackupObject = new Date($lastBackupRaw);
				$lastBackup       = $lastBackupObject->toUnix();
				$maxBackup        = time() - $maxperiod * 3600;
				if (!$warning)
				{
					$warning = ($lastBackup < $maxBackup);
				}
			}

			if ($warning)
			{
				$ret['image'] = 'akeeba-red';
				$ret['text']  = Text::_('PLG_QUICKICON_AKEEBABACKUP_BACKUPREQUIRED');

				if ($isJoomla4)
				{
					/**
					 * Joomla! 4 is dumb. Quickicons cannot have a class. However, Joomla! itself uses a class on the icon
					 * container to tell users when the update status is OK or there are updates required. Therefore we will
					 * have to use some Javascript to achieve the same result. Grrrr...
					 */
					$j4WarningJavascript = true;
					$ret['image']        = 'fa fa-akeeba-red';
				}
				else
				{
					$ret['text'] = '<span class="badge badge-important">' . $ret['text'] . '</span>';
				}
			}
		}

		$inlineCSS = <<< CSS
@font-face
{
	font-family: "Akeeba Products for Quickicons";
	font-style: normal;
	font-weight: normal;
	src: url("../media/com_akeeba/fonts/akeeba/Akeeba-Products.woff") format("woff"); 
}

[class*=fa-akeeba-]:before
{
  display: inline-block;
  font-family: 'Akeeba Products for Quickicons';
  font-style: normal;
  font-weight: normal;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  position: relative;
  -moz-osx-font-smoothing: grayscale;
}

span.fa-akeeba-black:before,
div.fa-akeeba-black:before
{
  color: var(--success);
  background: transparent;
}

span.fa-akeeba-red:before,
div.fa-akeeba-red:before
{
  color: var(--danger);
  background: transparent;
}

span[class*=fa-akeeba]:before,
div[class*=fa-akeeba]:before
{
	content: 'B';
}

.icon-akeeba-black {
	background-image: url("../media/com_akeeba/icons/akeebabackup-16-black.png");
	width: 16px;
	height: 16px;
}

.icon-akeeba-red {
	background-image: url("../media/com_akeeba/icons/akeebabackup-16-red.png");
	width: 16px;
	height: 16px;
}

.quick-icons .nav-list [class^="icon-akeeba-"], .quick-icons .nav-list [class*=" icon-akeeba-"] {
	margin-right: 7px;
}

.quick-icons .nav-list [class^="icon-akeeba-red"], .quick-icons .nav-list [class*=" icon-akeeba-red"] {
	margin-bottom: -4px;
}
CSS;

		JFactory::getApplication()->getDocument()->addStyleDeclaration($inlineCSS);

		if ($isJoomla4)
		{
			$myClass  = $j4WarningJavascript ? 'danger' : 'success';
			$inlineJS = <<< JS
// ; Defense against third party broken Javascript
document.addEventListener('DOMContentLoaded', function() {
	document.getElementById('plg_quickicon_akeebabackup').className = 'pulse $myClass';
});

JS;

			JFactory::getApplication()->getDocument()->addScriptDeclaration($inlineJS);
		}

		// Re-enable self
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
			->update($db->qn('#__extensions'))
			->set($db->qn('enabled') . ' = ' . $db->q('1'))
			->where($db->qn('element') . ' = ' . $db->q('akeebabackup'))
			->where($db->qn('folder') . ' = ' . $db->q('quickicon'));
		$db->setQuery($query);
		$db->execute();

		CacheCleaner::clearPluginsCache();

		return [$ret];
	}
}
PK��#]�)��quickicon/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��quickicon/jce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]'�n
��quickicon/jce/jce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="quickicon" method="upgrade">
	<name>plg_quickicon_jce</name>
	<version>2.9.38</version>
    <creationDate>27-06-2023</creationDate>
    <author>Ryan Demmer</author>
    <authorEmail>info@joomlacontenteditor.net</authorEmail>
    <authorUrl>http://www.joomlacontenteditor.net</authorUrl>
    <copyright>Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved</copyright>
    <license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
	<description>PLG_QUICKICON_JCE_XML_DESCRIPTION</description>
	<files folder="plugins/quickicon/jce">
		<filename plugin="jce">jce.php</filename>
	</files>
	<languages folder="administrator/language/en-GB">
      <language tag="en-GB">en-GB.plg_quickicon_jce.ini</language>
      <language tag="en-GB">en-GB.plg_quickicon_jce.sys.ini</language>
  </languages>
</extension>
PK��#]+E���quickicon/jce/jce.phpnu�[���<?php

/**
 * @copyright 	Copyright (c) 2009-2022 Ryan Demmer. All rights reserved
 * @license   	GNU/GPL 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * JCE is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses
 */
defined('_JEXEC') or die;

/**
 * JCE File Browser Quick Icon plugin.
 *
 * @since		2.1
 */
class plgQuickiconJce extends JPlugin
{
    public function __construct(&$subject, $config)
    {
        parent::__construct($subject, $config);

        $app = JFactory::getApplication();

        // only in Admin and only if the component is enabled
        if ($app->getClientId() !== 1 || JComponentHelper::getComponent('com_jce', true)->enabled === false) {
            return;
        }

        $this->loadLanguage();
    }

    public function onGetIcons($context)
    {
        if ($context != $this->params->get('context', 'mod_quickicon')) {
            return;
        }

        $user = JFactory::getUser();

        if (!$user->authorise('jce.browser', 'com_jce')) {
            return;
        }

        $language = JFactory::getLanguage();
        $language->load('com_jce', JPATH_ADMINISTRATOR);

        return array(array(
            'link'      => 'index.php?option=com_jce&view=browser',
            'image'     => 'picture fa fa-image',
            'access'    => array('jce.browser', 'com_jce'),
            'text'      => JText::_('PLG_QUICKICON_JCE_TITLE'),
            'id'        => 'plg_quickicon_jce',
        ));
    }
}
PK��#]�)��#quickicon/phpversioncheck/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]���mII-quickicon/phpversioncheck/phpversioncheck.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin" group="quickicon" method="upgrade">
	<name>plg_quickicon_phpversioncheck</name>
	<author>Joomla! Project</author>
	<creationDate>August 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_QUICKICON_PHPVERSIONCHECK_XML_DESCRIPTION</description>
	<files>
		<filename plugin="phpversioncheck">phpversioncheck.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_quickicon_phpversioncheck.ini</language>
		<language tag="en-GB">en-GB.plg_quickicon_phpversioncheck.sys.ini</language>
	</languages>
</extension>
PK��#]�����-quickicon/phpversioncheck/phpversioncheck.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.phpversioncheck
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plugin to check the PHP version and display a warning about its support status
 *
 * @since  3.7.0
 */
class PlgQuickiconPhpVersionCheck extends JPlugin
{
	/**
	 * Constant representing the active PHP version being fully supported
	 *
	 * @var    integer
	 * @since  3.7.0
	 */
	const PHP_SUPPORTED = 0;

	/**
	 * Constant representing the active PHP version receiving security support only
	 *
	 * @var    integer
	 * @since  3.7.0
	 */
	const PHP_SECURITY_ONLY = 1;

	/**
	 * Constant representing the active PHP version being unsupported
	 *
	 * @var    integer
	 * @since  3.7.0
	 */
	const PHP_UNSUPPORTED = 2;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.7.0
	 */
	protected $app;

	/**
	 * Load plugin language files automatically
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Check the PHP version after the admin component has been dispatched.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  void
	 *
	 * @since   3.7.0
	 */
	public function onGetIcons($context)
	{
		if (!$this->shouldDisplayMessage())
		{
			return;
		}

		$supportStatus = $this->getPhpSupport();

		if ($supportStatus['status'] !== self::PHP_SUPPORTED)
		{
			// Enqueue the notification message; set a warning if receiving security support or "error" if unsupported
			switch ($supportStatus['status'])
			{
				case self::PHP_SECURITY_ONLY:
					$this->app->enqueueMessage($supportStatus['message'], 'warning');

					break;

				case self::PHP_UNSUPPORTED:
					$this->app->enqueueMessage($supportStatus['message'], 'error');

					break;
			}
		}
	}

	/**
	 * Gets PHP support status.
	 *
	 * @return  array  Array of PHP support data
	 *
	 * @since   3.7.0
	 * @note    The dates used in this method should correspond to the dates given on PHP.net
	 * @link    https://www.php.net/supported-versions.php
	 * @link    https://www.php.net/eol.php
	 */
	private function getPhpSupport()
	{
		$phpSupportData = array(
			'5.3' => array(
				'security' => '2013-07-11',
				'eos'      => '2014-08-14',
			),
			'5.4' => array(
				'security' => '2014-09-14',
				'eos'      => '2015-09-14',
			),
			'5.5' => array(
				'security' => '2015-07-10',
				'eos'      => '2016-07-21',
			),
			'5.6' => array(
				'security' => '2017-01-19',
				'eos'      => '2018-12-31',
			),
			'7.0' => array(
				'security' => '2017-12-03',
				'eos'      => '2018-12-03',
			),
			'7.1' => array(
				'security' => '2018-12-01',
				'eos'      => '2019-12-01',
			),
			'7.2' => array(
				'security' => '2019-11-30',
				'eos'      => '2020-11-30',
			),
			'7.3' => array(
				'security' => '2020-12-06',
				'eos'      => '2021-12-06',
			),
			'7.4' => array(
				'security' => '2021-11-28',
				'eos'      => '2022-11-28',
			),
			'8.0' => array(
				'security' => '2022-11-26',
				'eos'      => '2023-11-26',
			),
			'8.1' => array(
				'security' => '2023-11-25',
				'eos'      => '2024-11-25',
			),
		);

		// Fill our return array with default values
		$supportStatus = array(
			'status'  => self::PHP_SUPPORTED,
			'message' => null,
		);

		// Check the PHP version's support status using the minor version
		$activePhpVersion = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;

		// Do we have the PHP version's data?
		if (isset($phpSupportData[$activePhpVersion]))
		{
			// First check if the version has reached end of support
			$today           = new JDate;
			$phpEndOfSupport = new JDate($phpSupportData[$activePhpVersion]['eos']);

			if ($phpNotSupported = $today > $phpEndOfSupport)
			{
				/*
				 * Find the oldest PHP version still supported that is newer than the current version,
				 * this is our recommendation for users on unsupported platforms
				 */
				foreach ($phpSupportData as $version => $versionData)
				{
					$versionEndOfSupport = new JDate($versionData['eos']);

					if (version_compare($version, $activePhpVersion, 'ge') && ($today < $versionEndOfSupport))
					{
						$supportStatus['status']  = self::PHP_UNSUPPORTED;
						$supportStatus['message'] = JText::sprintf(
							'PLG_QUICKICON_PHPVERSIONCHECK_UNSUPPORTED',
							PHP_VERSION,
							$version,
							$versionEndOfSupport->format(JText::_('DATE_FORMAT_LC4'))
						);

						return $supportStatus;
					}
				}

				// PHP version is not supported and we don't know of any supported versions.
				$supportStatus['status']  = self::PHP_UNSUPPORTED;
				$supportStatus['message'] = JText::sprintf('PLG_QUICKICON_PHPVERSIONCHECK_UNSUPPORTED_JOOMLA_OUTDATED', PHP_VERSION);

				return $supportStatus;
			}

			// If the version is still supported, check if it has reached eol minus 3 month
			$securityWarningDate = clone $phpEndOfSupport;
			$securityWarningDate->sub(new DateInterval('P3M'));

			if (!$phpNotSupported && $today > $securityWarningDate)
			{
				$supportStatus['status']  = self::PHP_SECURITY_ONLY;
				$supportStatus['message'] = JText::sprintf(
					'PLG_QUICKICON_PHPVERSIONCHECK_SECURITY_ONLY', PHP_VERSION, $phpEndOfSupport->format(JText::_('DATE_FORMAT_LC4'))
				);
			}
		}

		return $supportStatus;
	}

	/**
	 * Determines if the message should be displayed
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	private function shouldDisplayMessage()
	{
		// Only on admin app
		if (!$this->app->isClient('administrator'))
		{
			return false;
		}

		// Only if authenticated
		if (JFactory::getUser()->guest)
		{
			return false;
		}

		// Only on HTML documents
		if ($this->app->getDocument()->getType() !== 'html')
		{
			return false;
		}

		// Only on full page requests
		if ($this->app->input->getCmd('tmpl', 'index') === 'component')
		{
			return false;
		}

		// Only to com_cpanel
		if ($this->app->input->get('option') !== 'com_cpanel')
		{
			return false;
		}

		return true;
	}
}
PK��#]�.U9��quickicon/eos310/eos310.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.10" type="plugin" group="quickicon" method="upgrade">
	<name>plg_quickicon_eos310</name>
	<author>Joomla! Project</author>
	<creationDate>June 2021</creationDate>
	<copyright>(C) 2021 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.10.0</version>
	<description>PLG_QUICKICON_EOS310_XML_DESCRIPTION</description>
	<files>
		<filename plugin="eos310">eos310.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_quickicon_eos310.ini</language>
		<language tag="en-GB">en-GB.plg_quickicon_eos310.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="last_snoozed_id"
					type="hidden"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]-&\�**quickicon/eos310/eos310.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.eos310
 *
 * @copyright   (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;

/**
 * Joomla! end of support notification plugin
 *
 * @since  3.10.0
 */
class PlgQuickiconEos310 extends CMSPlugin
{
	/**
	 * The EOS date for 3.10
	 *
	 * @var    string
	 * @since  3.10.0
	 */
	const EOS_DATE = '2023-08-17';

	/**
	 * Application object
	 *
	 * @var    CMSApplication
	 * @since  3.10.0
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    DatabaseDriver
	 * @since  3.10.0
	 */
	protected $db;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.10.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Holding the current valid message to be shown
	 *
	 * @var    boolean
	 * @since  3.10.0
	 */
	private $currentMessage = false;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of configuration settings.
	 *
	 * @since   3.10.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$diff           = Factory::getDate()->diff(Factory::getDate(static::EOS_DATE));
		$monthsUntilEOS = floor($diff->days / 30.417);

		$this->currentMessage = $this->getMessageInfo($monthsUntilEOS, $diff->invert);
	}

	/**
	 * Check and show the the alert and quickicon message
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array|void  A list of icon definition associative arrays, consisting of the
	 *			keys link, image, text and access, or void.
	 *
	 * @since   3.10.0
	 */
	public function onGetIcons($context)
	{
		if (!$this->shouldDisplayMessage())
		{
			return;
		}

		// No messages yet
		if (!$this->currentMessage)
		{
			return;
		}

		// Show this only when not snoozed
		if ($this->params->get('last_snoozed_id', 0) < $this->currentMessage['id'])
		{
			// Load the snooze scripts.
			HTMLHelper::_('jquery.framework');
			HTMLHelper::_('script', 'plg_quickicon_eos310/snooze.js', array('version' => 'auto', 'relative' => true));

			// Build the  message to be displayed in the cpanel
			$messageText = Text::sprintf(
				$this->currentMessage['messageText'],
				HTMLHelper::_('date', static::EOS_DATE, Text::_('DATE_FORMAT_LC3')),
				$this->currentMessage['messageLink']
			);

			if ($this->currentMessage['snoozable'])
			{
				$messageText .=
					'<p><button class="btn btn-warning eosnotify-snooze-btn" type="button">' .
					Text::_('PLG_QUICKICON_EOS310_SNOOZE_BUTTON') .
					'</button></p>';
			}

			$this->app->enqueueMessage(
				$messageText,
				$this->currentMessage['messageType']
			);
		}

		// The message as quickicon
		$messageTextQuickIcon = Text::sprintf(
			$this->currentMessage['quickiconText'],
			HTMLHelper::_(
				'date',
				static::EOS_DATE,
				Text::_('DATE_FORMAT_LC3')
			)
		);

		// The message as quickicon
		return array(array(
			'link'   => $this->currentMessage['messageLink'],
			'target' => '_blank',
			'rel'    => 'noopener noreferrer',
			'image'  => $this->currentMessage['image'],
			'text'   => $messageTextQuickIcon,
			'id'	 => 'plg_quickicon_eos310',
			'group'  => $this->currentMessage['groupText'],
		));
	}

	/**
	 * User hit the snooze button
	 *
	 * @return  void
	 *
	 * @since   3.10.0
	 *
	 * @throws  JAccessExceptionNotallowed  If user is not allowed.
	 */
	public function onAjaxSnoozeEOS()
	{
		// No messages yet so nothing to snooze
		if (!$this->currentMessage)
		{
			return;
		}

		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new JAccessExceptionNotallowed(Text::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
		}

		// Make sure only snoozable messages can be snoozed
		if ($this->currentMessage['snoozable'])
		{
			$this->params->set('last_snoozed_id', $this->currentMessage['id']);

			$this->saveParams();
		}
	}

	/**
	 * Return the texts to be displayed based on the time until we reach EOS
	 *
	 * @param   integer  $monthsUntilEOS  The months until we reach EOS
	 * @param   integer  $inverted        Have we surpassed the EOS date
	 *
	 * @return  array|bool  An array with the message to be displayed or false
	 *
	 * @since   3.10.0
	 */
	private function getMessageInfo($monthsUntilEOS, $inverted)
	{
		// The EOS date has passed - Support has ended
		if ($inverted === 1)
		{
			return array(
				'id'            => 5,
				'messageText'   => 'PLG_QUICKICON_EOS310_MESSAGE_ERROR_SUPPORT_ENDED',
				'quickiconText' => 'PLG_QUICKICON_EOS310_MESSAGE_ERROR_SUPPORT_ENDED_SHORT',
				'messageType'   => 'error',
				'image'         => 'minus-circle',
				'messageLink'   => 'https://docs.joomla.org/Special:MyLanguage/Planning_for_Mini-Migration_-_Joomla_3.10.x_to_4.x',
				'groupText'     => 'PLG_QUICKICON_EOS310_GROUPNAME_EOS',
				'snoozable'     => false,
			);
		}

		// The security support is ending in 6 months
		if ($monthsUntilEOS < 6)
		{
			return array(
				'id'            => 4,
				'messageText'   => 'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SUPPORT_ENDING',
				'quickiconText' => 'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SUPPORT_ENDING_SHORT',
				'messageType'   => 'warning',
				'image'         => 'warning-circle',
				'messageLink'   => 'https://docs.joomla.org/Special:MyLanguage/Planning_for_Mini-Migration_-_Joomla_3.10.x_to_4.x',
				'groupText'     => 'PLG_QUICKICON_EOS310_GROUPNAME_WARNING',
				'snoozable'     => true,
			);
		}

		// We are in security only mode now, 12 month to go from now on
		if ($monthsUntilEOS < 12)
		{
			return array(
				'id'            => 3,
				'messageText'   => 'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SECURITY_ONLY',
				'quickiconText' => 'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SECURITY_ONLY_SHORT',
				'messageType'   => 'warning',
				'image'         => 'warning-circle',
				'messageLink'   => 'https://docs.joomla.org/Special:MyLanguage/Planning_for_Mini-Migration_-_Joomla_3.10.x_to_4.x',
				'groupText'     => 'PLG_QUICKICON_EOS310_GROUPNAME_WARNING',
				'snoozable'     => true,
			);
		}

		// We still have 16 month to go, lets remind our users about the pre upgrade checker
		if ($monthsUntilEOS < 16)
		{
			return array(
				'id'            => 2,
				'messageText'   => 'PLG_QUICKICON_EOS310_MESSAGE_INFO_02',
				'quickiconText' => 'PLG_QUICKICON_EOS310_MESSAGE_INFO_02_SHORT',
				'messageType'   => 'info',
				'image'         => 'info-circle',
				'messageLink'   => 'https://docs.joomla.org/Special:MyLanguage/Pre-Update_Check',
				'groupText'     => 'PLG_QUICKICON_EOS310_GROUPNAME_INFO',
				'snoozable'     => true,
			);
		}

		// Lets start our messages 2 month after the initial release, still 22 month to go
		if ($monthsUntilEOS < 22)
		{
			return array(
				'id'            => 1,
				'messageText'   => 'PLG_QUICKICON_EOS310_MESSAGE_INFO_01',
				'quickiconText' => 'PLG_QUICKICON_EOS310_MESSAGE_INFO_01_SHORT',
				'messageType'   => 'info',
				'image'         => 'info-circle',
				'messageLink'   => 'https://www.joomla.org/4/#features',
				'groupText'     => 'PLG_QUICKICON_EOS310_GROUPNAME_INFO',
				'snoozable'     => true,
			);
		}

		return false;
	}

	/**
	 * Determines if the message and quickicon should be displayed
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function shouldDisplayMessage()
	{
		// Only on admin app
		if (!$this->app->isClient('administrator'))
		{
			return false;
		}

		// Only if authenticated
		if (Factory::getUser()->guest)
		{
			return false;
		}

		// Only on HTML documents
		if ($this->app->getDocument()->getType() !== 'html')
		{
			return false;
		}

		// Only on full page requests
		if ($this->app->input->getCmd('tmpl', 'index') === 'component')
		{
			return false;
		}

		// Only to com_cpanel
		if ($this->app->input->get('option') !== 'com_cpanel')
		{
			return false;
		}

		// Don't show anything in 4.0
		if (version_compare(JVERSION, '4.0', '>='))
		{
			return false;
		}

		return true;
	}

	/**
	 * Check valid AJAX request
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function isAjaxRequest()
	{
		return strtolower($this->app->input->server->get('HTTP_X_REQUESTED_WITH', '')) === 'xmlhttprequest';
	}

	/**
	 * Check if current user is allowed to send the data
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function isAllowedUser()
	{
		return Factory::getUser()->authorise('core.login.admin');
	}

	/**
	 * Save the plugin parameters
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function saveParams()
	{
		$query = $this->db->getQuery(true)
			->update($this->db->quoteName('#__extensions'))
			->set($this->db->quoteName('params') . ' = ' . $this->db->quote($this->params->toString('JSON')))
			->where($this->db->quoteName('type') . ' = ' . $this->db->quote('plugin'))
			->where($this->db->quoteName('folder') . ' = ' . $this->db->quote('quickicon'))
			->where($this->db->quoteName('element') . ' = ' . $this->db->quote('eos310'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race condition
			$this->db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue execution
			return false;
		}

		try
		{
			// Update the plugin parameters
			$result = $this->db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$this->db->unlockTables();

			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$this->db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		return $result;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.10.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1))
	{
		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'	=> $client_id ? JPATH_ADMINISTRATOR . '/cache' : $this->app->get('cache_path', JPATH_SITE . '/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
PK��#]�)��quickicon/eos310/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)�� quickicon/privacycheck/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��f55'quickicon/privacycheck/privacycheck.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin" group="quickicon" method="upgrade">
	<name>plg_quickicon_privacycheck</name>
	<author>Joomla! Project</author>
	<creationDate>June 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_QUICKICON_PRIVACYCHECK_XML_DESCRIPTION</description>
	<files>
		<filename plugin="privacycheck">privacycheck.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_quickicon_privacycheck.ini</language>
		<language tag="en-GB">en-GB.plg_quickicon_privacycheck.sys.ini</language>
	</languages>
</extension>
PK��#]�w	ڔ	�	'quickicon/privacycheck/privacycheck.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.privacycheck
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;

/**
 * Plugin to check privacy requests older than 14 days
 *
 * @since  3.9.0
 */
class PlgQuickiconPrivacyCheck extends JPlugin
{
	/**
	 * Load plugin language files automatically
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Check privacy requests older than 14 days.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array   A list of icon definition associative arrays
	 *
	 * @since   3.9.0
	 */
	public function onGetIcons($context)
	{
		if ($context !== $this->params->get('context', 'mod_quickicon') || !Factory::getUser()->authorise('core.admin'))
		{
			return;
		}

		JHtml::_('jquery.framework');

		$token    = Session::getFormToken() . '=' . 1;
		$privacy  = 'index.php?option=com_privacy';

		$options  = array(
			'plg_quickicon_privacycheck_url'      => Uri::base() . $privacy . '&view=requests&filter[status]=1&list[fullordering]=a.requested_at ASC',
			'plg_quickicon_privacycheck_ajax_url' => Uri::base() . $privacy . '&task=getNumberUrgentRequests&' . $token,
			'plg_quickicon_privacycheck_text'     => array(
				"NOREQUEST"            => Text::_('PLG_QUICKICON_PRIVACYCHECK_NOREQUEST'),
				"REQUESTFOUND"         => Text::_('PLG_QUICKICON_PRIVACYCHECK_REQUESTFOUND'),
				"REQUESTFOUND_MESSAGE" => Text::_('PLG_QUICKICON_PRIVACYCHECK_REQUESTFOUND_MESSAGE'),
				"REQUESTFOUND_BUTTON"  => Text::_('PLG_QUICKICON_PRIVACYCHECK_REQUESTFOUND_BUTTON'),
				"ERROR"                => Text::_('PLG_QUICKICON_PRIVACYCHECK_ERROR'),
			)
		);

		Factory::getDocument()->addScriptOptions('js-privacy-check', $options);

		JHtml::_('script', 'plg_quickicon_privacycheck/privacycheck.js', array('version' => 'auto', 'relative' => true));

		return array(
			array(
				'link'  => $privacy . '&view=requests&filter[status]=1&list[fullordering]=a.requested_at ASC',
				'image' => 'users',
				'icon'  => 'header/icon-48-user.png',
				'text'  => Text::_('PLG_QUICKICON_PRIVACYCHECK_CHECKING'),
				'id'    => 'plg_quickicon_privacycheck',
				'group' => 'MOD_QUICKICON_USERS'
			)
		);
	}
}
PK��#]�)�� quickicon/joomlaupdate/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]"[؋\\'quickicon/joomlaupdate/joomlaupdate.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="quickicon" method="upgrade">
	<name>plg_quickicon_joomlaupdate</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_QUICKICON_JOOMLAUPDATE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomlaupdate">joomlaupdate.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_quickicon_joomlaupdate.ini</language>
		<language tag="en-GB">en-GB.plg_quickicon_joomlaupdate.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="context"
					type="text"
					label="PLG_QUICKICON_JOOMLAUPDATE_GROUP_LABEL"
					description="PLG_QUICKICON_JOOMLAUPDATE_GROUP_DESC"
					default="mod_quickicon"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]���NN'quickicon/joomlaupdate/joomlaupdate.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.Joomlaupdate
 *
 * @copyright   (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! update notification plugin
 *
 * @since  2.5
 */
class PlgQuickiconJoomlaupdate extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * This method is called when the Quick Icons module is constructing its set
	 * of icons. You can return an array which defines a single icon and it will
	 * be rendered right after the stock Quick Icons.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array  A list of icon definition associative arrays, consisting of the
	 *                 keys link, image, text and access.
	 *
	 * @since   2.5
	 */
	public function onGetIcons($context)
	{
		if ($context !== $this->params->get('context', 'mod_quickicon') || !JFactory::getUser()->authorise('core.manage', 'com_joomlaupdate'))
		{
			return;
		}

		JHtml::_('jquery.framework');

		$currentTemplate = JFactory::getApplication()->getTemplate();

		$url      = JUri::base() . 'index.php?option=com_joomlaupdate';
		$ajaxUrl  = JUri::base() . 'index.php?option=com_joomlaupdate&task=update.ajax&' . JSession::getFormToken() . '=1';
		$script   = array();
		$script[] = 'var plg_quickicon_joomlaupdate_url = \'' . $url . '\';';
		$script[] = 'var plg_quickicon_joomlaupdate_ajax_url = \'' . $ajaxUrl . '\';';
		$script[] = 'var plg_quickicon_jupdatecheck_jversion = \'' . JVERSION . '\'';
		$script[] = 'var plg_quickicon_joomlaupdate_text = {'
			. '"UPTODATE" : "' . JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPTODATE', true) . '",'
			. '"UPDATEFOUND": "' . JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND', true) . '",'
			. '"UPDATEFOUND_MESSAGE": "' . JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND_MESSAGE', true) . '",'
			. '"UPDATEFOUND_BUTTON": "' . JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND_BUTTON', true) . '",'
			. '"ERROR": "' . JText::_('PLG_QUICKICON_JOOMLAUPDATE_ERROR', true) . '",'
			. '};';
		$script[] = 'var plg_quickicon_joomlaupdate_img = {'
			. '"UPTODATE" : "' . JUri::base(true) . '/templates/' . $currentTemplate . '/images/header/icon-48-jupdate-uptodate.png",'
			. '"UPDATEFOUND": "' . JUri::base(true) . '/templates/' . $currentTemplate . '/images/header/icon-48-jupdate-updatefound.png",'
			. '"ERROR": "' . JUri::base(true) . '/templates/' . $currentTemplate . '/images/header/icon-48-deny.png",'
			. '};';
		JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));
		JHtml::_('script', 'plg_quickicon_joomlaupdate/jupdatecheck.js', array('version' => 'auto', 'relative' => true));

		return array(
			array(
				'link' => 'index.php?option=com_joomlaupdate',
				'image' => 'joomla',
				'icon' => 'header/icon-48-download.png',
				'text' => JText::_('PLG_QUICKICON_JOOMLAUPDATE_CHECKING'),
				'id' => 'plg_quickicon_joomlaupdate',
				'group' => 'MOD_QUICKICON_MAINTENANCE'
			)
		);
	}
}
PK��#]�V�
index.htmlnu�[���<!DOCTYPE html><title></title>
PK��#]�)��#installer/folderinstaller/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�a���*installer/folderinstaller/tmpl/default.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.folderinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');

$app = JFactory::getApplication('administrator');

JFactory::getDocument()->addScriptDeclaration('
	Joomla.submitbuttonfolder = function()
	{
		var form = document.getElementById("adminForm");

		// do field validation 
		if (form.install_directory.value == "")
		{
			alert("' . JText::_('PLG_INSTALLER_FOLDERINSTALLER_NO_INSTALL_PATH', true) . '");
		}
		else
		{
			JoomlaInstaller.showLoading();
			form.installtype.value = "folder"
			form.submit();
		}
	};
');
?>
<legend><?php echo JText::_('PLG_INSTALLER_FOLDERINSTALLER_TEXT'); ?></legend>
<div class="control-group">
	<label for="install_directory" class="control-label"><?php echo JText::_('PLG_INSTALLER_FOLDERINSTALLER_TEXT'); ?></label>
	<div class="controls">
		<input type="text" id="install_directory" name="install_directory" class="span5 input_box" size="70"
			value="<?php echo $app->input->get('install_directory', $app->get('tmp_path')); ?>" />
	</div>
</div>
<div class="form-actions">
	<input type="button" class="btn btn-primary" id="installbutton_directory"
		value="<?php echo JText::_('PLG_INSTALLER_FOLDERINSTALLER_BUTTON'); ?>" onclick="Joomla.submitbuttonfolder()" />
</div>
PK��#]�?>>-installer/folderinstaller/folderinstaller.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin" group="installer">
	<name>PLG_INSTALLER_FOLDERINSTALLER</name>
	<author>Joomla! Project</author>
	<creationDate>May 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.6.0</version>
	<description>PLG_INSTALLER_FOLDERINSTALLER_PLUGIN_XML_DESCRIPTION</description>

	<files>
		<filename plugin="folderinstaller">folderinstaller.php</filename>
	</files>

	<languages>
		<language tag="en-GB">en-GB.plg_installer_folderinstaller.ini</language>
		<language tag="en-GB">en-GB.plg_installer_folderinstaller.sys.ini</language>
	</languages>
</extension>
PK��#]�#���-installer/folderinstaller/folderinstaller.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.folderInstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

/**
 * FolderInstaller Plugin.
 *
 * @since  3.6.0
 */
class PlgInstallerFolderInstaller extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.6.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Textfield or Form of the Plugin.
	 *
	 * @return  array  Returns an array with the tab information
	 *
	 * @since   3.6.0
	 */
	public function onInstallerAddInstallationTab()
	{
		$tab            = array();
		$tab['name']    = 'folder';
		$tab['label']   = JText::_('PLG_INSTALLER_FOLDERINSTALLER_TEXT');

		// Render the input
		ob_start();
		include JPluginHelper::getLayoutPath('installer', 'folderinstaller');
		$tab['content'] = ob_get_clean();

		return $tab;
	}
}
PK��#]�)��installer/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��installer/rsform/rsform.phpnu�[���<?php
/**
* @package RSForm! Pro
* @copyright (C) 2015 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

defined('_JEXEC') or die;

class plgInstallerRSForm extends JPlugin
{
	public function onInstallerBeforePackageDownload(&$url, &$headers)
	{
		$uri 	= JUri::getInstance($url);
		$parts 	= explode('/', $uri->getPath());
		
		if ($uri->getHost() == 'www.rsjoomla.com' && (in_array('com_rsform', $parts) || in_array('plg_rsform_plugins', $parts))) {
			if (!file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/config.php')) {
				return;
			}
			
			if (!file_exists(JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/version.php')) {
				return;
			}
			
			// Load our config
			require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/config.php';
			
			// Load our version
			require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/version.php';
			
			// Load language
			JFactory::getLanguage()->load('plg_installer_rsform');
			
			// Get the version
			$version = new RSFormProVersion;
			
			// Get the update code
			$code = RSFormProConfig::getInstance()->get('global.register.code');
			
			// No code added
			if (!strlen($code)) {
				JFactory::getApplication()->enqueueMessage(JText::_('PLG_INSTALLER_RSFORM_MISSING_UPDATE_CODE'), 'warning');
				return;
			}
			
			// Code length is incorrect
			if (strlen($code) != 20) {
				JFactory::getApplication()->enqueueMessage(JText::_('PLG_INSTALLER_RSFORM_INCORRECT_CODE'), 'warning');
				return;
			}
			
			// Compute the update hash			
			$uri->setVar('hash', md5($code.$version->key));
			$uri->setVar('domain', JUri::getInstance()->getHost());
			$uri->setVar('code', $code);
			$url = $uri->toString();
		}
	}
}
PK��#]?��installer/rsform/rsform.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="installer" method="upgrade">
	<name>plg_installer_rsform</name>
	<creationDate>July 2015</creationDate>
	<author>RSJoomla!</author>
	<authorEmail>support@rsjoomla.com</authorEmail>
	<authorUrl>https://www.rsjoomla.com</authorUrl>
	<copyright>(c) 2015 www.rsjoomla.com</copyright>
	<license>http://www.gnu.org/copyleft/gpl.html GNU/GPL</license> 
	<version>1.0.0</version>
	<description>PLG_INSTALLER_RSFORM_XML_DESCRIPTION</description>

	<updateservers>
        <server type="extension" priority="1" name="Installer - RSForm! Pro">https://www.rsjoomla.com/updates/com_rsform/Other/plg_installer.xml</server>
    </updateservers>

	<files>
		<filename plugin="rsform">rsform.php</filename>
		<filename>index.html</filename>
	</files>
	<languages folder="language">
		<language tag="en-GB">en-GB/en-GB.plg_installer_rsform.ini</language>
		<language tag="en-GB">en-GB/en-GB.plg_installer_rsform.sys.ini</language>
	</languages>
</extension>PK��#]�)��installer/rsform/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]��ĸ88installer/rsform/index.htmlnu�[���<html><head><title></title></head><body></body></html>
PK��#]i���yy'installer/webinstaller/tmpl/default.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.webinstaller
 *
 * @copyright   Copyright (C) 2013 - 2019 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;

/** @var PlgInstallerWebinstaller $this */

$installfrom = $this->getInstallFrom();

?>

<div id="jed-container" class="tab-pane">
	<div class="well" id="web-loader">
		<h2><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_LOADING'); ?></h2>
	</div>
	<div class="alert alert-error" id="web-loader-error" style="display:none">
		<a class="close" data-dismiss="alert">×</a><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_LOADING_ERROR'); ?>
	</div>
</div>

<fieldset class="uploadform" id="uploadform-web" style="display:none" dir="ltr">
	<div class="control-group">
		<strong><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_CONFIRM'); ?></strong><br />
		<span id="uploadform-web-name-label"><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_CONFIRM_NAME'); ?>:</span> <span id="uploadform-web-name"></span><br />
		<?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_CONFIRM_URL'); ?>: <span id="uploadform-web-url"></span>
	</div>
	<div class="form-actions">
		<input type="button" class="btn btn-primary" value="<?php echo Text::_('COM_INSTALLER_INSTALL_BUTTON'); ?>" onclick="Joomla.submitbutton<?php echo $installfrom != '' ? 4 : 5; ?>()" />
		<input type="button" class="btn btn-secondary" value="<?php echo Text::_('JCANCEL'); ?>" onclick="Joomla.installfromwebcancel()" />
	</div>
</fieldset>
PK��#])�H]��&installer/webinstaller/tmpl/hathor.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.webinstaller
 *
 * @copyright   Copyright (C) 2013 - 2019 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;

/** @var PlgInstallerWebinstaller $this */

$installfrom = $this->getInstallFrom();

?>

<div class="clr"></div>
<fieldset class="uploadform">
	<legend><?php echo Text::_('COM_INSTALLER_INSTALL_FROM_WEB', true); ?></legend>
	<div id="jed-container"<?php echo $dir; ?>>
		<div id="mywebinstaller" style="display:none">
			<a href="#"><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_LOAD_APPS'); ?></a>
		</div>
		<div class="well" id="web-loader" style="display:none">
			<h2><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_LOADING'); ?></h2>
		</div>
		<div class="alert alert-error" id="web-loader-error" style="display:none">
			<a class="close" data-dismiss="alert">×</a><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_LOADING_ERROR'); ?>
		</div>
	</div>
	<fieldset class="uploadform" id="uploadform-web" style="display:none" dir="ltr">
		<div class="control-group">
			<strong><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_CONFIRM'); ?></strong><br />
			<span id="uploadform-web-name-label"><?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_CONFIRM_NAME'); ?>:</span> <span id="uploadform-web-name"></span><br />
			<?php echo Text::_('COM_INSTALLER_WEBINSTALLER_INSTALL_WEB_CONFIRM_URL'); ?>: <span id="uploadform-web-url"></span>
		</div>
		<div class="form-actions">
			<input type="button" class="btn btn-primary" value="<?php echo Text::_('COM_INSTALLER_INSTALL_BUTTON'); ?>" onclick="Joomla.submitbutton<?php echo $installfrom != '' ? 4 : 5; ?>()" />
			<input type="button" class="btn btn-secondary" value="<?php echo Text::_('JCANCEL'); ?>" onclick="Joomla.installfromwebcancel()" />
		</div>
	</fieldset>
</fieldset>
PK��#]�)�� installer/webinstaller/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]O�,,.installer/webinstaller/webinstaller.script.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.webinstaller
 *
 * @copyright   Copyright (C) 2013 - 2019 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('_JEXEC') or die;

// If the minimum PHP version constant hasn't been defined (really old Joomla version), set it now
if (!defined('JOOMLA_MINIMUM_PHP'))
{
	// Minimum as of Joomla! 3.3
	define('JOOMLA_MINIMUM_PHP', '5.3.10');
}

// Stub the JInstallerScript class for older versions to perform the minimum required checks
if (!class_exists('JInstallerScript'))
{
	/**
	 * Base install script for use by extensions providing helper methods for common behaviours.
	 *
	 * @since  3.6
	 */
	class JInstallerScript
	{
		/**
		 * Minimum PHP version required to install the extension
		 *
		 * @var    string
		 * @since  3.6
		 */
		protected $minimumPhp;

		/**
		 * Minimum Joomla! version required to install the extension
		 *
		 * @var    string
		 * @since  3.6
		 */
		protected $minimumJoomla;

		/**
		 * Function called before extension installation/update/removal procedure commences
		 *
		 * @param   string             $type    The type of change (install, update or discover_install, not uninstall)
		 * @param   JInstallerAdapter  $parent  The class calling this method
		 *
		 * @return  boolean  True on success
		 *
		 * @since   3.6
		 */
		public function preflight($type, $parent)
		{
			// Check for the minimum PHP version before continuing
			if (!empty($this->minimumPhp) && version_compare(PHP_VERSION, $this->minimumPhp, '<'))
			{
				JLog::add(JText::sprintf('JLIB_INSTALLER_MINIMUM_PHP', $this->minimumPhp), JLog::WARNING, 'jerror');

				return false;
			}

			// Check for the minimum Joomla version before continuing
			if (!empty($this->minimumJoomla) && version_compare(JVERSION, $this->minimumJoomla, '<'))
			{
				JLog::add(JText::sprintf('JLIB_INSTALLER_MINIMUM_JOOMLA', $this->minimumJoomla), JLog::WARNING, 'jerror');

				return false;
			}

			// Theoretically we should not reach this line in this stub because triggering it means we aren't matching the minimum Joomla version
			return true;
		}
	}
}

/**
 * Support for the "Install from Web" tab
 *
 * @since  1.0
 */
class plginstallerwebinstallerInstallerScript extends JInstallerScript
{
	/**
	 * A list of files to be deleted
	 *
	 * @var    array
	 * @since  2.0
	 */
	protected $deleteFiles = array(
		'/plugins/installer/webinstaller/css/client.css',
		'/plugins/installer/webinstaller/css/client.min.css',
		'/plugins/installer/webinstaller/css/index.html',
		'/plugins/installer/webinstaller/index.html',
		'/plugins/installer/webinstaller/js/client.js',
		'/plugins/installer/webinstaller/js/client.min.js',
	);

	/**
	 * A list of folders to be deleted
	 *
	 * @var    array
	 * @since  2.0
	 */
	protected $deleteFolders = array(
		'/plugins/installer/webinstaller/css',
		'/plugins/installer/webinstaller/js',
	);

	/**
	 * Minimum PHP version required to install the extension
	 *
	 * @var    string
	 * @since  2.0
	 */
	protected $minimumPhp = JOOMLA_MINIMUM_PHP;

	/**
	 * Minimum Joomla! version required to install the extension
	 *
	 * @var    string
	 * @since  2.0
	 */
	protected $minimumJoomla = '3.9';

	/**
	 * Function called before extension installation/update/removal procedure commences
	 *
	 * @param   string             $type    The type of change (install, update or discover_install, not uninstall)
	 * @param   JInstallerAdapter  $parent  The class calling this method
	 *
	 * @return  boolean  True on success
	 *
	 * @since   3.6
	 */
	public function preflight($type, $parent)
	{
		if (!parent::preflight($type, $parent))
		{
			return false;
		}

		// Disallow installs on 4.0 as the plugin is part of core
		if (version_compare(JVERSION, '4.0', '>='))
		{
			JLog::add(JText::_('PLG_INSTALLER_WEBINSTALLER_ERROR_PLUGIN_INCLUDED_IN_CORE'), JLog::WARNING, 'jerror');

			return false;
		}

		return true;
	}

	/**
	 * Function called after extension installation/update/removal procedure commences
	 *
	 * @param   string            $route    The action being performed
	 * @param   JInstallerPlugin  $adapter  The class calling this method
	 *
	 * @return  void
	 *
	 * @since   1.0
	 */
	public function postflight($route, $adapter)
	{
		// When initially installing the plugin, enable it as well
		if ($route === 'install')
		{
			try
			{
				$db = JFactory::getDbo();
				$db->setQuery(
					$db->getQuery(true)
						->update($db->quoteName('#__extensions'))
						->set($db->quoteName('enabled') . ' = 1')
						->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
						->where($db->quoteName('element') . ' = ' . $db->quote('webinstaller'))
				)->execute();
			}
			catch (RuntimeException $e)
			{
				// Don't let this fatal out the install process, proceed as normal from here
			}
		}
	}
}
PK��#]�a�'installer/webinstaller/webinstaller.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin" group="installer" method="upgrade">
	<name>plg_installer_webinstaller</name>
	<author>Joomla! Project</author>
	<creationDate>28 April 2017</creationDate>
	<copyright>Copyright (C) 2013 - 2019 Open Source Matters. All rights reserved.</copyright>
	<license>http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>2.1.2</version>
	<description>PLG_INSTALLER_WEBINSTALLER_XML_DESCRIPTION</description>
	<files>
		<folder>tmpl</folder>
		<filename plugin="webinstaller">webinstaller.php</filename>
	</files>
	<media destination="plg_installer_webinstaller" folder="media">
		<folder>css</folder>
		<folder>js</folder>
	</media>
	<scriptfile>webinstaller.script.php</scriptfile>
	<updateservers>
		<server type="extension" priority="1" name="WebInstaller Update Site">https://appscdn.joomla.org/webapps/jedapps/webinstaller.xml</server>
	</updateservers>
</extension>
PK��#]u�d��'installer/webinstaller/webinstaller.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.webinstaller
 *
 * @copyright   Copyright (C) 2013 - 2019 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('_JEXEC') or die;

use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Rule\UrlRule;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Installer\Installer;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Version;

/**
 * Support for the "Install from Web" tab
 *
 * @since  1.0
 */
class PlgInstallerWebinstaller extends CMSPlugin
{
	/**
	 * The URL for the remote server.
	 *
	 * @var    string
	 * @since  2.0
	 */
	const REMOTE_URL = 'https://appscdn.joomla.org/webapps/';

	/**
	 * The application object.
	 *
	 * @var    CMSApplication
	 * @since  2.0
	 */
	protected $app;

	/**
	 * Affects constructor behavior. If true, language files will be loaded automatically.
	 *
	 * @var    boolean
	 * @since  2.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Flag tracking whether the Hathor admin template is in use
	 *
	 * @var    boolean|null
	 * @since  1.0
	 * @deprecated  Removed when the plugin is merged to 4.0
	 */
	private $_hathor = null;

	/**
	 * The URL to install from
	 *
	 * @var    string|null
	 * @since  1.0
	 */
	private $installfrom = null;

	/**
	 * Event listener for the `onInstallerBeforeDisplay` event.
	 *
	 * @param   boolean  $showJedAndWebInstaller  Flag indicating the install from web prompt should be displayed
	 *
	 * @return  void
	 *
	 * @since   1.0
	 * @deprecated  Removed when the plugin is merged to 4.0
	 */
	public function onInstallerBeforeDisplay(&$showJedAndWebInstaller)
	{
		$showJedAndWebInstaller = false;
	}

	/**
	 * Event listener for the `onInstallerAddInstallationTab` event.
	 *
	 * @return  array  Returns an array with the tab information
	 *
	 * @since   2.0
	 */
	public function onInstallerAddInstallationTab()
	{
		$tab = array(
			'name'  => 'web',
			'label' => Text::_('COM_INSTALLER_INSTALL_FROM_WEB'),
		);

		// Render the input
		ob_start();
		include PluginHelper::getLayoutPath('installer', 'webinstaller', $this->isHathor() ? 'hathor' : 'default');
		$tab['content'] = ob_get_clean();

		return $tab;
	}

	/**
	 * Event listener for the `onBeforeCompileHead` event.
	 *
	 * @return  void
	 *
	 * @since   2.0
	 * @deprecated  Removed when the plugin is merged to 4.0
	 * @note        This is required to ensure the plugin JS is appended after the tabs are initialized,
	 *              logic would otherwise be in the `onInstallerAddInstallationTab` listener
	 */
	public function onBeforeCompileHead()
	{
		$installfrom = $this->getInstallFrom();

		// Push language strings to the JavaScript store
		Text::script('COM_INSTALLER_MSG_INSTALL_ENTER_A_URL');
		Text::script('COM_INSTALLER_WEBINSTALLER_INSTALL_OBSOLETE');
		Text::script('COM_INSTALLER_WEBINSTALLER_INSTALL_UPDATE_AVAILABLE');
		Text::script('JLIB_INSTALLER_UPDATE');
		Text::script('PLG_INSTALLER_WEBINSTALLER_CANNOT_INSTALL_EXTENSION_IN_PLUGIN');
		Text::script('PLG_INSTALLER_WEBINSTALLER_REDIRECT_TO_EXTERNAL_SITE_TO_INSTALL');

		HTMLHelper::_('bootstrap.framework');
		HTMLHelper::_('script', 'plg_installer_webinstaller/client.min.js', array('version' => 'auto', 'relative' => true));
		HTMLHelper::_('stylesheet', 'plg_installer_webinstaller/client.min.css', array('version' => 'auto', 'relative' => true));

		$devLevel = Version::PATCH_VERSION;
		$extraVer = Version::EXTRA_VERSION;

		if (!empty($extraVer))
		{
			$devLevel .= '-' . $extraVer;
		}

		$installer = new Installer;
		$manifest  = $installer->isManifest(__DIR__ . '/webinstaller.xml');

		$doc = Factory::getDocument();

		$doc->addScriptOptions(
			'plg_installer_webinstaller',
			array(
				'base_url'        => addslashes(self::REMOTE_URL),
				'installat_url'   => base64_encode(Uri::current() . '?option=com_installer&view=install'),
				'installfrom_url' => addslashes($installfrom),
				'product'         => base64_encode(Version::PRODUCT),
				'release'         => base64_encode(Version::MAJOR_VERSION . '.' . Version::MINOR_VERSION),
				'dev_level'       => base64_encode($devLevel),
				'installfromon'   => $installfrom ? 1 : 0,
				'language'        => base64_encode(Factory::getLanguage()->getTag()),
				// The below options are deprecated and removed when the plugin is merged to 4.0
				'is_hathor'       => $this->isHathor() ? 1 : 0,
				'pv'              => base64_encode($manifest->version),
			)
		);

		$javascript = <<<JS
jQuery(document).ready(function () {
    var ifwOptions = Joomla.getOptions('plg_installer_webinstaller', {});
    var ifwLink = jQuery('#myTabTabs').find('li a[href="#web"]');
    var ifwRelativeSelector = 'li';

	if (ifwOptions.is_hathor) {
		jQuery('#mywebinstaller').show();
		ifwLink = jQuery('#mywebinstaller').find('a');
		ifwRelativeSelector = 'a';
	}

	if (ifwOptions.installfromon) {
		ifwLink.click();
	}

	if (!ifwOptions.is_hathor && ifwLink.closest('li').hasClass('active')) {
		if (!Joomla.apps.loaded) {
			Joomla.apps.initialize();
		}
	}

	ifwLink.closest(ifwRelativeSelector).click(function (event) {
		if (!Joomla.apps.loaded) {
			Joomla.apps.initialize();
		}
	});

	if (ifwOptions.installfrom_url !== '') {
	    ifwLink.closest(ifwRelativeSelector).click();
	}

	ifwLink.on('shown', function (e) {
		if (!Joomla.apps.loaded) {
			Joomla.apps.initialize();
		}
	});
});

		
JS;
		$doc->addScriptDeclaration($javascript);
	}

	/**
	 * Internal check to determine if the Hathor admin template is in use
	 *
	 * @return  boolean
	 *
	 * @since   1.0
	 * @deprecated  Removed when the plugin is merged to 4.0
	 */
	private function isHathor()
	{
		if (is_null($this->_hathor))
		{
			$this->_hathor = strtolower($this->app->getTemplate()) === 'hathor';
		}

		return $this->_hathor;
	}

	/**
	 * Get the install from URL
	 *
	 * @return  string
	 *
	 * @since   1.0
	 */
	private function getInstallFrom()
	{
		if ($this->installfrom === null)
		{
			$installfrom = base64_decode($this->app->input->getBase64('installfrom', ''));

			$field = new SimpleXMLElement('<field></field>');
			$rule  = new UrlRule;

			if ($rule->test($field, $installfrom) && preg_match('/\.xml\s*$/', $installfrom))
			{
				$update = new Update;
				$update->loadFromXML($installfrom);
				$package_url = trim($update->get('downloadurl', false)->_data);

				if ($package_url)
				{
					$installfrom = $package_url;
				}
			}

			$this->installfrom = $installfrom;
		}

		return $this->installfrom;
	}
}
PK��#]�)��installer/jce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]X	�`��installer/jce/jce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="installer" method="upgrade">
	<name>plg_installer_jce</name>
	<version>2.9.38</version>
  <creationDate>27-06-2023</creationDate>
  <author>Ryan Demmer</author>
  <authorEmail>info@joomlacontenteditor.net</authorEmail>
  <authorUrl>http://www.joomlacontenteditor.net</authorUrl>
  <copyright>Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved</copyright>
  <license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
	<description>PLG_INSTALLER_JCE_XML_DESCRIPTION</description>
	<files folder="plugins/installer/jce">
		<filename plugin="jce">jce.php</filename>
	</files>
	<languages folder="administrator/language/en-GB">
      <language tag="en-GB">en-GB.plg_installer_jce.ini</language>
      <language tag="en-GB">en-GB.plg_installer_jce.sys.ini</language>
  </languages>
</extension>
PK��#]�dd�T
T
installer/jce/jce.phpnu�[���<?php
/**
 *  @copyright Copyright (c)2016 - 2020 Ryan Demmer
 *  @license GNU General Public License version 2, or later
 */
defined('_JEXEC') or die;

/**
 * Handle commercial extension update authorization.
 *
 * @since       2.6
 */
class plgInstallerJce extends JPlugin
{    
    /**
     * Handle adding credentials to package download request.
     *
     * @param string $url     url from which package is going to be downloaded
     * @param array  $headers headers to be sent along the download request (key => value format)
     *
     * @return bool true if credentials have been added to request or not our business, false otherwise (credentials not set by user)
     *
     * @since   3.0
     */
    public function onInstallerBeforePackageDownload(&$url, &$headers)
    {
        $app = JFactory::getApplication();

        $uri = JUri::getInstance($url);
        $host = $uri->getHost();

        if ($host !== 'www.joomlacontenteditor.net') {
            return true;
        }

        // Get the subscription key
        JLoader::import('joomla.application.component.helper');
        $component = JComponentHelper::getComponent('com_jce');

        // load plugin language for warning messages
        JFactory::getLanguage()->load('plg_installer_jce', JPATH_ADMINISTRATOR);

        // check if the key has already been set via the dlid field
        $dlid = $uri->getVar('key', '');

        // check the component params, fallback to the dlid
        $key = $component->params->get('updates_key', $dlid);

        // if no key is set...
        if (empty($key)) {
            // if we are attempting to update JCE Pro, display a notice message
            if (strpos($url, 'pkg_jce_pro') !== false) {
                $app->enqueueMessage(JText::_('PLG_INSTALLER_JCE_KEY_WARNING'), 'notice');
            }

            return true;
        }

        // Append the subscription key to the download URL
        $uri->setVar('key', $key);

        // create the url string
        $url = $uri->toString();

        // check validity of the key and display a message if it is invalid / expired
        try
        {
            $tmpUri = clone $uri;

            $tmpUri->setVar('task', 'update.validate');
            $tmpUri->delVar('file');
            $tmpUrl = $tmpUri->toString();
            $response = JHttpFactory::getHttp()->get($tmpUrl, array());
        } catch (RuntimeException $exception) {}

        // invalid key, display a notice message
        if (403 == $response->code) {
            $app->enqueueMessage(JText::_('PLG_INSTALLER_JCE_KEY_INVALID'), 'notice');
        }

        return true;
    }
}
PK��#],�/���'installer/urlinstaller/urlinstaller.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.urlinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

/**
 * UrlFolderInstaller Plugin.
 *
 * @since  3.6.0
 */
class PlgInstallerUrlInstaller extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.6.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Textfield or Form of the Plugin.
	 *
	 * @return  array  Returns an array with the tab information
	 *
	 * @since   3.6.0
	 */
	public function onInstallerAddInstallationTab()
	{
		$tab            = array();
		$tab['name']    = 'url';
		$tab['label']   = JText::_('PLG_INSTALLER_URLINSTALLER_TEXT');

		// Render the input
		ob_start();
		include JPluginHelper::getLayoutPath('installer', 'urlinstaller');
		$tab['content'] = ob_get_clean();

		return $tab;
	}
}
PK��#]d�,,'installer/urlinstaller/urlinstaller.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin" group="installer">
	<name>PLG_INSTALLER_URLINSTALLER</name>
	<author>Joomla! Project</author>
	<creationDate>May 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.6.0</version>
	<description>PLG_INSTALLER_URLINSTALLER_PLUGIN_XML_DESCRIPTION</description>

	<files>
		<filename plugin="urlinstaller">urlinstaller.php</filename>
	</files>

	<languages>
		<language tag="en-GB">en-GB.plg_installer_urlinstaller.ini</language>
		<language tag="en-GB">en-GB.plg_installer_urlinstaller.sys.ini</language>
	</languages>
</extension>
PK��#]�)haa'installer/urlinstaller/tmpl/default.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.urlinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');

JFactory::getDocument()->addScriptDeclaration('
	Joomla.submitbuttonurl = function()
	{
		var form = document.getElementById("adminForm");

		JoomlaInstaller.showLoading();
		form.installtype.value = "url"
		form.submit();
	};
');
?>
<legend><?php echo JText::_('PLG_INSTALLER_URLINSTALLER_TEXT'); ?></legend>
<div class="control-group">
	<label for="install_url" class="control-label"><?php echo JText::_('PLG_INSTALLER_URLINSTALLER_TEXT'); ?></label>
	<div class="controls">
		<input type="text" id="install_url" name="install_url" class="span5 input_box" size="70" placeholder="https://"/>
	</div>
</div>
<div class="form-actions">
	<input type="button" class="btn btn-primary" id="installbutton_url"
		value="<?php echo JText::_('PLG_INSTALLER_URLINSTALLER_BUTTON'); ?>" onclick="Joomla.submitbuttonurl()" />
</div>
PK��#]�)�� installer/urlinstaller/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��$installer/packageinstaller/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]RdDD/installer/packageinstaller/packageinstaller.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin" group="installer">
	<name>plg_installer_packageinstaller</name>
	<author>Joomla! Project</author>
	<creationDate>May 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.6.0</version>
	<description>PLG_INSTALLER_PACKAGEINSTALLER_PLUGIN_XML_DESCRIPTION</description>

	<files>
		<filename plugin="packageinstaller">packageinstaller.php</filename>
	</files>

	<languages>
		<language tag="en-GB">en-GB.plg_installer_packageinstaller.ini</language>
		<language tag="en-GB">en-GB.plg_installer_packageinstaller.sys.ini</language>
	</languages>
</extension>
PK��#]u��	��/installer/packageinstaller/packageinstaller.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.packageInstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * PackageInstaller Plugin.
 *
 * @since  3.6.0
 */
class PlgInstallerPackageInstaller extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.6.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Textfield or Form of the Plugin.
	 *
	 * @return  array  Returns an array with the tab information
	 *
	 * @since   3.6.0
	 */
	public function onInstallerAddInstallationTab()
	{
		$tab            = array();
		$tab['name']    = 'package';
		$tab['label']   = JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_PACKAGE_FILE');

		// Render the input
		ob_start();
		include JPluginHelper::getLayoutPath('installer', 'packageinstaller');
		$tab['content'] = ob_get_clean();

		return $tab;
	}
}
PK��#]��q$q$+installer/packageinstaller/tmpl/default.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.packageinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');
JHtml::_('jquery.token');

JText::script('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_UNKNOWN');
JText::script('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_EMPTY');
JText::script('COM_INSTALLER_MSG_WARNINGS_UPLOADFILETOOBIG');

JFactory::getDocument()->addScriptDeclaration('
	Joomla.submitbuttonpackage = function()
	{
		var form = document.getElementById("adminForm");

		// do field validation 
		if (form.install_package.value == "")
		{
			alert("' . JText::_('PLG_INSTALLER_PACKAGEINSTALLER_NO_PACKAGE', true) . '");
		}
		else if (form.install_package.files[0].size > form.max_upload_size.value)
		{
			alert("' . JText::_('COM_INSTALLER_MSG_WARNINGS_UPLOADFILETOOBIG', true) . '");
		}
		else
		{
			JoomlaInstaller.showLoading();
			form.installtype.value = "upload"
			form.submit();
		}
	};
');

// Drag and Drop installation scripts
$token = JSession::getFormToken();
$return = JFactory::getApplication()->input->getBase64('return');

// Drag-drop installation
JFactory::getDocument()->addScriptDeclaration(
<<<JS
	jQuery(document).ready(function($) {
		if (typeof FormData === 'undefined') {
			$('#legacy-uploader').show();
			$('#uploader-wrapper').hide();
			return;
		}

		var uploading   = false;
		var dragZone    = $('#dragarea');
		var fileInput   = $('#install_package');
		var fileSizeMax = $('#max_upload_size').val();
		var button      = $('#select-file-button');
		var url         = 'index.php?option=com_installer&task=install.ajax_upload';
		var returnUrl   = $('#installer-return').val();
		var actions     = $('.upload-actions');
		var progress    = $('.upload-progress');
		var progressBar = progress.find('.bar');
		var percentage  = progress.find('.uploading-number');

		if (returnUrl) {
			url += '&return=' + returnUrl;
		}

		button.on('click', function(e) {
			fileInput.click();
		});

		fileInput.on('change', function (e) {
			if (uploading) {
				return;
			}

			Joomla.submitbuttonpackage();
		});

		dragZone.on('dragenter', function(e) {
			e.preventDefault();
			e.stopPropagation();

			dragZone.addClass('hover');

			return false;
		});

		// Notify user when file is over the drop area
		dragZone.on('dragover', function(e) {
			e.preventDefault();
			e.stopPropagation();

			dragZone.addClass('hover');

			return false;
		});

		dragZone.on('dragleave', function(e) {
			e.preventDefault();
			e.stopPropagation();
			dragZone.removeClass('hover');

			return false;
		});

		dragZone.on('drop', function(e) {
			e.preventDefault();
			e.stopPropagation();

			dragZone.removeClass('hover');

			if (uploading) {
				return;
			}

			var files = e.originalEvent.target.files || e.originalEvent.dataTransfer.files;

			if (!files.length) {
				return;
			}

			var file = files[0];

			var data = new FormData;

			if (file.size > fileSizeMax) {
				alert(Joomla.JText._('COM_INSTALLER_MSG_WARNINGS_UPLOADFILETOOBIG'), true);
				return;
			}

			data.append('install_package', file);
			data.append('installtype', 'upload');

			dragZone.attr('data-state', 'uploading');
			uploading = true;

			$.ajax({
				url: url,
				data: data,
				type: 'post',
				processData: false,
				cache: false,
				contentType: false,
				xhr: function () {
					var xhr = new window.XMLHttpRequest();

					progressBar.css('width', 0);
					progressBar.attr('aria-valuenow', 0);
					percentage.text(0);

					// Upload progress
					xhr.upload.addEventListener("progress", function (evt) {
						if (evt.lengthComputable) {
							var percentComplete = evt.loaded / evt.total;
							var number = Math.round(percentComplete * 100);
							progressBar.css('width', number + '%');
							progressBar.attr('aria-valuenow', number);
							percentage.text(number);

							if (number === 100) {
								dragZone.attr('data-state', 'installing');
							}
						}
					}, false);

					return xhr;
				}
			})
			.done(function (res) {
				// Handle extension fatal error
				if (!res || (!res.success && !res.data)) {
					showError(res);
					return;
				}

				// Always redirect that can show message queue from session 
				if (res.data.redirect) {
					location.href = res.data.redirect;
				} else {
					location.href = 'index.php?option=com_installer&view=install';
				}
			}).error(function (error) {
				uploading = false;

				if (error.status === 200) {
					var res = error.responseText || error.responseJSON;
					showError(res);
				} else {
					showError(error.statusText);
				}
			});

			function showError(res) {
				dragZone.attr('data-state', 'pending');

				var message = Joomla.JText._('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_UNKNOWN');

				if (res == null) {
					message = Joomla.JText._('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_EMPTY');
				} else if (typeof res === 'string') {
					// Let's remove unnecessary HTML
					message = res.replace(/(<([^>]+)>|\s+)/g, ' ');
				} else if (res.message) {
					message = res.message;
				}

				Joomla.renderMessages({error: [message]});
			}
		});
	});
JS
);

JFactory::getDocument()->addStyleDeclaration(
<<<CSS
	#dragarea {
		background-color: #fafbfc;
		border: 1px dashed #999;
		box-sizing: border-box;
		padding: 5% 0;
		transition: all 0.2s ease 0s;
		width: 100%;
	}

	#dragarea p.lead {
		color: #999;
	}

	#upload-icon {
		font-size: 48px;
		width: auto;
		height: auto;
		margin: 0;
		line-height: 175%;
		color: #999;
		transition: all .2s;
	}

	#dragarea.hover {
		border-color: #666;
		background-color: #eee;
	}

	#dragarea.hover #upload-icon,
	#dragarea p.lead {
		color: #666;
	}

	 .upload-progress, .install-progress {
		width: 50%;
		margin: 5px auto;
	 }

	/* Default transition (.3s) is too slow, progress will not run to 100% */
	.upload-progress .progress .bar {
		-webkit-transition: width .1s;
		-moz-transition: width .1s;
		-o-transition: width .1s;
		transition: width .1s;
	}

	#dragarea[data-state=pending] .upload-progress {
		display: none;
	}

	#dragarea[data-state=pending] .install-progress {
		display: none;
	}

	#dragarea[data-state=uploading] .install-progress {
		display: none;
	}

	#dragarea[data-state=uploading] .upload-actions {
		display: none;
	}

	#dragarea[data-state=installing] .upload-progress {
		display: none;
	}

	#dragarea[data-state=installing] .upload-actions {
		display: none;
	}
CSS
);

$maxSizeBytes = JFilesystemHelper::fileUploadMaxSize(false);
$maxSize = JHtml::_('number.bytes', $maxSizeBytes);
?>
<legend><?php echo JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_INSTALL_JOOMLA_EXTENSION'); ?></legend>

<div id="uploader-wrapper">
	<div id="dragarea" data-state="pending">
		<div id="dragarea-content" class="text-center">
			<p>
				<span id="upload-icon" class="icon-upload" aria-hidden="true"></span>
			</p>
			<div class="upload-progress">
				<div class="progress progress-striped active">
					<div class="bar bar-success"
						style="width: 0;"
						role="progressbar"
						aria-valuenow="0"
						aria-valuemin="0"
						aria-valuemax="100"
					></div>
				</div>
				<p class="lead">
					<span class="uploading-text">
						<?php echo JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOADING'); ?>
					</span>
					<span class="uploading-number">0</span><span class="uploading-symbol">%</span>
				</p>
			</div>
			<div class="install-progress">
				<div class="progress progress-striped active">
					<div class="bar" style="width: 100%;"></div>
				</div>
				<p class="lead">
					<span class="installing-text">
						<?php echo JText::_('PLG_INSTALLER_PACKAGEINSTALLER_INSTALLING'); ?>
					</span>
				</p>
			</div>
			<div class="upload-actions">
				<p class="lead">
					<?php echo JText::_('PLG_INSTALLER_PACKAGEINSTALLER_DRAG_FILE_HERE'); ?>
				</p>
				<p>
					<button id="select-file-button" type="button" class="btn btn-success">
						<span class="icon-copy" aria-hidden="true"></span>
						<?php echo JText::_('PLG_INSTALLER_PACKAGEINSTALLER_SELECT_FILE'); ?>
					</button>
				</p>
				<p>
					<?php echo JText::sprintf('JGLOBAL_MAXIMUM_UPLOAD_SIZE_LIMIT', $maxSize); ?>
				</p>
			</div>
		</div>
	</div>
</div>

<div id="legacy-uploader" style="display: none;">
	<div class="control-group">
		<label for="install_package" class="control-label"><?php echo JText::_('PLG_INSTALLER_PACKAGEINSTALLER_EXTENSION_PACKAGE_FILE'); ?></label>
		<div class="controls">
			<input class="input_box" id="install_package" name="install_package" type="file" size="57" />
			<input id="max_upload_size" name="max_upload_size" type="hidden" value="<?php echo $maxSizeBytes; ?>" /><br>
			<?php echo JText::sprintf('JGLOBAL_MAXIMUM_UPLOAD_SIZE_LIMIT', $maxSize); ?>
		</div>
	</div>
	<div class="form-actions">
		<button class="btn btn-primary" type="button" id="installbutton_package" onclick="Joomla.submitbuttonpackage()">
			<?php echo JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_AND_INSTALL'); ?>
		</button>
	</div>

	<input id="installer-return" name="return" type="hidden" value="<?php echo $return; ?>" />
	<input id="installer-token" name="return" type="hidden" value="<?php echo $token; ?>" />
</div>
PK��#]�)��sampledata/blog/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]wy�DDsampledata/blog/blog.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="sampledata" method="upgrade">
	<name>plg_sampledata_blog</name>
	<author>Joomla! Project</author>
	<creationDate>July 2017</creationDate>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.8.0</version>
	<description>PLG_SAMPLEDATA_BLOG_XML_DESCRIPTION</description>
	<files>
		<filename plugin="blog">blog.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_sampledata_blog.ini</language>
		<language tag="en-GB">en-GB.plg_sampledata_blog.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
		</fields>
	</config>
</extension>
PK��#]2�b||sampledata/blog/blog.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Sampledata.Blog
 *
 * @copyright   (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Session\Session;

/**
 * Sampledata - Blog Plugin
 *
 * @since  3.8.0
 */
class PlgSampledataBlog extends JPlugin
{
	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 *
	 * @since  3.8.0
	 */
	protected $db;

	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 *
	 * @since  3.8.0
	 */
	protected $app;

	/**
	 * Affects constructor behavior. If true, language files will be loaded automatically.
	 *
	 * @var    boolean
	 *
	 * @since  3.8.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Holds the menuitem model
	 *
	 * @var    MenusModelItem
	 *
	 * @since  3.8.0
	 */
	private $menuItemModel;

	/**
	 * Get an overview of the proposed sampledata.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since  3.8.0
	 */
	public function onSampledataGetOverview()
	{
		if (!Factory::getUser()->authorise('core.create', 'com_content'))
		{
			return;
		}

		$data              = new stdClass;
		$data->name        = $this->_name;
		$data->title       = JText::_('PLG_SAMPLEDATA_BLOG_OVERVIEW_TITLE');
		$data->description = JText::_('PLG_SAMPLEDATA_BLOG_OVERVIEW_DESC');
		$data->icon        = 'broadcast';
		$data->steps       = 3;

		return $data;
	}

	/**
	 * First step to enter the sampledata. Content.
	 *
	 * @return  array or void  Will be converted into the JSON response to the module.
	 *
	 * @since  3.8.0
	 */
	public function onAjaxSampledataApplyStep1()
	{
		if (!Session::checkToken('get') || $this->app->input->get('type') != $this->_name)
		{
			return;
		};

		if (!JComponentHelper::isEnabled('com_content') || !Factory::getUser()->authorise('core.create', 'com_content'))
		{
			$response            = array();
			$response['success'] = true;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 1, 'com_content');

			return $response;
		}

		// Get some metadata.
		$access = (int) $this->app->get('access', 1);
		$user   = JFactory::getUser();

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ? JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language . ')' : '';

		// Add Include Paths.
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_content/models/', 'ContentModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_content/tables/');
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_categories/models/', 'CategoriesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_categories/tables/');

		// Create "blog" category.
		$categoryModel = JModelLegacy::getInstance('Category', 'CategoriesModel');
		$catIds        = array();
		$categoryTitle = JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_CATEGORY_0_TITLE');
		$alias         = JApplicationHelper::stringURLSafe($categoryTitle);

		// Set unicodeslugs if alias is empty
		if (trim(str_replace('-', '', $alias) == ''))
		{
			$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
			$alias = JApplicationHelper::stringURLSafe($categoryTitle);
			JFactory::getConfig()->set('unicodeslugs', $unicode);
		}

		$category      = array(
			'title'           => $categoryTitle . $langSuffix,
			'parent_id'       => 1,
			'id'              => 0,
			'published'       => 1,
			'access'          => $access,
			'created_user_id' => $user->id,
			'extension'       => 'com_content',
			'level'           => 1,
			'alias'           => $alias . $langSuffix,
			'associations'    => array(),
			'description'     => '',
			'language'        => $language,
			'params'          => '',
		);

		try
		{
			if (!$categoryModel->save($category))
			{
				throw new Exception($categoryModel->getError());
			}
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $e->getMessage());

			return $response;
		}

		// Get ID from category we just added
		$catIds[] = $categoryModel->getItem()->id;

		// Create "help" category.
		$categoryTitle = JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_CATEGORY_1_TITLE');
		$alias         = JApplicationHelper::stringURLSafe($categoryTitle);

		// Set unicodeslugs if alias is empty
		if (trim(str_replace('-', '', $alias) == ''))
		{
			$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
			$alias = JApplicationHelper::stringURLSafe($categoryTitle);
			JFactory::getConfig()->set('unicodeslugs', $unicode);
		}

		$category      = array(
			'title'           => $categoryTitle . $langSuffix,
			'parent_id'       => 1,
			'id'              => 0,
			'published'       => 1,
			'access'          => $access,
			'created_user_id' => $user->id,
			'extension'       => 'com_content',
			'level'           => 1,
			'alias'           => $alias . $langSuffix,
			'associations'    => array(),
			'description'     => '',
			'language'        => $language,
			'params'          => '',
		);

		try
		{
			if (!$categoryModel->save($category))
			{
				throw new Exception($categoryModel->getError());
			}
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $e->getMessage());

			return $response;
		}

		// Get ID from category we just added
		$catIds[] = $categoryModel->getItem()->id;

		// Create Articles.
		$articleModel = JModelLegacy::getInstance('Article', 'ContentModel');
		$articles     = array(
			array(
				'catid'    => $catIds[1],
				'ordering' => 2,
			),
			array(
				'catid'    => $catIds[1],
				'ordering' => 1,
				'access'   => 3,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 2,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 1,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 0,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 0,
			),
		);

		foreach ($articles as $i => $article)
		{
			// Set values from language strings.
			$title                = JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i . '_TITLE');
			$alias                = JApplicationHelper::stringURLSafe($title);
			$article['title']     = $title . $langSuffix;
			$article['introtext'] = JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i . '_INTROTEXT');
			$article['fulltext']  = JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i . '_FULLTEXT');

			// Set values which are always the same.
			$article['id']              = 0;
			$article['created_user_id'] = $user->id;
			$article['alias']           = JApplicationHelper::stringURLSafe($article['title']);

			// Set unicodeslugs if alias is empty
			if (trim(str_replace('-', '', $alias) == ''))
			{
				$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
				$article['alias'] = JApplicationHelper::stringURLSafe($article['title']);
				JFactory::getConfig()->set('unicodeslugs', $unicode);
			}

			$article['language']        = $language;
			$article['associations']    = array();
			$article['state']           = 1;
			$article['featured']        = 0;
			$article['images']          = '';
			$article['metakey']         = '';
			$article['metadesc']        = '';
			$article['xreference']      = '';

			if (!isset($article['access']))
			{
				$article['access'] = $access;
			}

			if (!$articleModel->save($article))
			{
				JFactory::getLanguage()->load('com_content');
				$response            = array();
				$response['success'] = false;
				$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, JText::_($articleModel->getError()));

				return $response;
			}

			// Get ID from article we just added
			$ids[] = $articleModel->getItem()->id;
		}

		$this->app->setUserState('sampledata.blog.articles', $ids);
		$this->app->setUserState('sampledata.blog.articles.catids', $catIds);

		$response          = new stdClass;
		$response->success = true;
		$response->message = JText::_('PLG_SAMPLEDATA_BLOG_STEP1_SUCCESS');

		return $response;
	}

	/**
	 * Second step to enter the sampledata. Menus.
	 *
	 * @return  array or void  Will be converted into the JSON response to the module.
	 *
	 * @since  3.8.0
	 */
	public function onAjaxSampledataApplyStep2()
	{
		if (!Session::checkToken('get') || $this->app->input->get('type') != $this->_name)
		{
			return;
		}

		if (!JComponentHelper::isEnabled('com_menus') || !Factory::getUser()->authorise('core.create', 'com_menus'))
		{
			$response            = array();
			$response['success'] = true;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 2, 'com_menus');

			return $response;
		}

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ? JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language . ')' : '';

		// Create the menu types.
		$menuTable = JTable::getInstance('Type', 'JTableMenu');
		$menuTypes = array();

		for ($i = 0; $i <= 2; $i++)
		{
			$menu = array(
				'id'          => 0,
				'title'       => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_MENU_' . $i . '_TITLE') . $langSuffix,
				'description' => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_MENU_' . $i . '_DESCRIPTION'),
			);

			// Calculate menutype. The number of characters allowed is 24.
			$type = JHtml::_('string.truncate', $menu['title'], 23, true, false);

			$menu['menutype'] = $i . $type;

			try
			{
				$menuTable->load();
				$menuTable->bind($menu);

				if (!$menuTable->check())
				{
					throw new Exception($menuTable->getError());
				}

				$menuTable->store();
			}
			catch (Exception $e)
			{
				JFactory::getLanguage()->load('com_menus');
				$response            = array();
				$response['success'] = false;
				$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage());

				return $response;
			}

			$menuTypes[] = $menuTable->menutype;
		}

		// Storing IDs in UserState for later usage.
		$this->app->setUserState('sampledata.blog.menutypes', $menuTypes);

		// Get previously entered Data from UserStates.
		$articleIds = $this->app->getUserState('sampledata.blog.articles');

		// Get MenuItemModel.
		JLoader::register('MenusHelper', JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php');
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_menus/models/', 'MenusModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_menus/tables/');
		$this->menuItemModel = JModelLegacy::getInstance('Item', 'MenusModel');

		// Get previously entered categories ids
		$catids = $this->app->getUserState('sampledata.blog.articles.catids');

		// Insert menuitems level 1.
		$menuItems = array(
			array(
				'menutype'     => $menuTypes[0],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_0_TITLE'),
				'link'         => 'index.php?option=com_content&view=category&layout=blog&id=' . $catids[0],
				'component_id' => 22,
				'params'       => array(
					'layout_type'             => 'blog',
					'show_category_title'     => 0,
					'num_leading_articles'    => 4,
					'num_intro_articles'      => 0,
					'num_columns'             => 1,
					'num_links'               => 2,
					'multi_column_order'      => 1,
					'orderby_sec'             => 'rdate',
					'order_date'              => 'published',
					'show_pagination'         => 2,
					'show_pagination_results' => 1,
					'show_category'           => 0,
					'info_bloc_position'      => 0,
					'show_publish_date'       => 0,
					'show_hits'               => 0,
					'show_feed_link'          => 1,
					'menu_text'               => 1,
					'show_page_heading'       => 0,
					'secure'                  => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[0],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_1_TITLE'),
				'link'         => 'index.php?option=com_content&view=article&id=' . $articleIds[0],
				'component_id' => 22,
				'params'       => array(
					'info_block_position' => 0,
					'show_category'       => 0,
					'link_category'       => 0,
					'show_author'         => 0,
					'show_create_date'    => 0,
					'show_publish_date'   => 0,
					'show_hits'           => 0,
					'menu_text'           => 1,
					'show_page_heading'   => 0,
					'secure'              => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[0],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_2_TITLE'),
				'link'         => 'index.php?option=com_users&view=login',
				'component_id' => 25,
				'params'       => array(
					'logindescription_show'  => 1,
					'logoutdescription_show' => 1,
					'menu_text'              => 1,
					'show_page_heading'      => 0,
					'secure'                 => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_3_TITLE'),
				'link'         => 'index.php?option=com_content&view=form&layout=edit',
				'component_id' => 22,
				'access'       => 3,
				'params'       => array(
					'enable_category'   => 1,
					'catid'             => $catids[0],
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_4_TITLE'),
				'link'         => 'index.php?option=com_content&view=article&id=' . $articleIds[1],
				'component_id' => 22,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_5_TITLE'),
				'link'         => 'administrator',
				'type'         => 'url',
				'component_id' => 0,
				'browserNav'   => 1,
				'access'       => 3,
				'params'       => array(
					'menu_text' => 1,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_6_TITLE'),
				'link'         => 'index.php?option=com_users&view=profile&layout=edit',
				'component_id' => 25,
				'access'       => 2,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_7_TITLE'),
				'link'         => 'index.php?option=com_users&view=login',
				'component_id' => 25,
				'params'       => array(
					'logindescription_show'  => 1,
					'logoutdescription_show' => 1,
					'menu_text'              => 1,
					'show_page_heading'      => 0,
					'secure'                 => 0,
				),
			),
		);

		try
		{
			$menuIdsLevel1 = $this->addMenuItems($menuItems, 1);
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage());

			return $response;
		}

		// Insert another level 1.
		$menuItems = array(
			array(
				'menutype'     => $menuTypes[2],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_8_TITLE'),
				'link'         => 'index.php?option=com_users&view=login',
				'component_id' => 25,
				'params'       => array(
					'login_redirect_url'     => 'index.php?Itemid=' . $menuIdsLevel1[0],
					'logindescription_show'  => 1,
					'logoutdescription_show' => 1,
					'menu_text'              => 1,
					'show_page_heading'      => 0,
					'secure'                 => 0,
				),
			),
		);

		try
		{
			$menuIdsLevel1 = array_merge($menuIdsLevel1, $this->addMenuItems($menuItems, 1));
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage());

			return $response;
		}

		// Insert menuitems level 2.
		$menuItems = array(
			array(
				'menutype'     => $menuTypes[1],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_9_TITLE'),
				'link'         => 'index.php?option=com_config&view=config&controller=config.display.config',
				'parent_id'    => $menuIdsLevel1[4],
				'component_id' => 23,
				'access'       => 6,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_10_TITLE'),
				'link'         => 'index.php?option=com_config&view=templates&controller=config.display.templates',
				'parent_id'    => $menuIdsLevel1[4],
				'component_id' => 23,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
		);

		try
		{
			$this->addMenuItems($menuItems, 2);
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage());

			return $response;
		}

		$response            = array();
		$response['success'] = true;
		$response['message'] = JText::_('PLG_SAMPLEDATA_BLOG_STEP2_SUCCESS');

		return $response;
	}

	/**
	 * Third step to enter the sampledata. Modules.
	 *
	 * @return  array or void  Will be converted into the JSON response to the module.
	 *
	 * @since  3.8.0
	 */
	public function onAjaxSampledataApplyStep3()
	{
		if (!Session::checkToken('get') || $this->app->input->get('type') != $this->_name)
		{
			return;
		}

		if (!JComponentHelper::isEnabled('com_modules') || !Factory::getUser()->authorise('core.create', 'com_modules'))
		{
			$response            = array();
			$response['success'] = true;
			$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 3, 'com_modules');

			return $response;
		}

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ? JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language . ')' : '';

		// Add Include Paths.
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_modules/models/', 'ModulesModelModule');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_modules/tables/');
		$model  = JModelLegacy::getInstance('Module', 'ModulesModel');
		$access = (int) $this->app->get('access', 1);

		// Get previously entered Data from UserStates
		$menuTypes = $this->app->getUserState('sampledata.blog.menutypes');

		$catids = $this->app->getUserState('sampledata.blog.articles.catids');

		$modules = array(
			array(
				'title'     => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_0_TITLE'),
				'ordering'  => 1,
				'position'  => 'position-1',
				'module'    => 'mod_menu',
				'showtitle' => 0,
				'params'    => array(
					'menutype'        => $menuTypes[0],
					'startLevel'      => 1,
					'endLevel'        => 0,
					'showAllChildren' => 0,
					'class_sfx'       => ' nav-pills',
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'itemid',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'     => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_1_TITLE'),
				'ordering'  => 1,
				'position'  => 'position-1',
				'module'    => 'mod_menu',
				'access'    => 3,
				'showtitle' => 0,
				'params'    => array(
					'menutype'        => $menuTypes[1],
					'startLevel'      => 1,
					'endLevel'        => 0,
					'showAllChildren' => 1,
					'class_sfx'       => ' nav-pills',
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'itemid',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'     => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_2_TITLE'),
				'ordering'  => 6,
				'position'  => 'position-7',
				'module'    => 'mod_syndicate',
				'showtitle' => 0,
				'params'    => array(
					'display_text' => 1,
					'text'         => 'My Blog',
					'format'       => 'rss',
					'layout'       => '_:default',
					'cache'        => 0,
				),
			),
			array(
				'title'    => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_3_TITLE'),
				'ordering' => 4,
				'position' => 'position-7',
				'module'   => 'mod_articles_archive',
				'params'   => array(
					'count'      => 10,
					'layout'     => '_:default',
					'cache'      => 1,
					'cache_time' => 900,
					'cachemode'  => 'static',
				),
			),
			array(
				'title'    => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_4_TITLE'),
				'ordering' => 5,
				'position' => 'position-7',
				'module'   => 'mod_articles_popular',
				'params'   => array(
					'catid'      => $catids[0],
					'count'      => 5,
					'show_front' => 1,
					'layout'     => '_:default',
					'cache'      => 1,
					'cache_time' => 900,
					'cachemode'  => 'static',
				),
			),
			array(
				'title'    => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_5_TITLE'),
				'ordering' => 2,
				'position' => 'position-7',
				'module'   => 'mod_articles_category',
				'params'   => array(
					'mode'                         => 'normal',
					'show_on_article_page'         => 0,
					'show_front'                   => 'show',
					'count'                        => 6,
					'category_filtering_type'      => 1,
					'catid'                        => $catids[0],
					'show_child_category_articles' => 0,
					'levels'                       => 1,
					'author_filtering_type'        => 1,
					'author_alias_filtering_type'  => 1,
					'date_filtering'               => 'off',
					'date_field'                   => 'a.created',
					'relative_date'                => 30,
					'article_ordering'             => 'a.created',
					'article_ordering_direction'   => 'DESC',
					'article_grouping'             => 'none',
					'article_grouping_direction'   => 'krsort',
					'month_year_format'            => 'F Y',
					'item_heading'                 => 5,
					'link_titles'                  => 1,
					'show_date'                    => 0,
					'show_date_field'              => 'created',
					'show_date_format'             => JText::_('DATE_FORMAT_LC5'),
					'show_category'                => 0,
					'show_hits'                    => 0,
					'show_author'                  => 0,
					'show_introtext'               => 0,
					'introtext_limit'              => 100,
					'show_readmore'                => 0,
					'show_readmore_title'          => 1,
					'readmore_limit'               => 15,
					'layout'                       => '_:default',
					'owncache'                     => 1,
					'cache_time'                   => 900,
					'module_tag'                   => 'div',
					'bootstrap_size'               => 0,
					'header_tag'                   => 'h3',
					'style'                        => 0,
				),
			),
			array(
				'title'     => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_6_TITLE'),
				'ordering'  => 1,
				'position'  => 'footer',
				'module'    => 'mod_menu',
				'showtitle' => 0,
				'params'    => array(
					'menutype'        => $menuTypes[2],
					'startLevel'      => 1,
					'endLevel'        => 0,
					'showAllChildren' => 0,
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'itemid',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'    => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_7_TITLE'),
				'ordering' => 1,
				'position' => 'position-0',
				'module'   => 'mod_search',
				'params'   => array(
					'width'      => 20,
					'button_pos' => 'right',
					'opensearch' => 1,
					'layout'     => '_:default',
					'cache'      => 1,
					'cache_time' => 900,
					'cachemode'  => 'itemid',
				),
			),
			array(
				'title'     => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_8_TITLE'),
				'content'   => '<p><img src="images/headers/raindrops.jpg" alt="" /></p>',
				'ordering'  => 1,
				'position'  => 'position-3',
				'module'    => 'mod_custom',
				'showtitle' => 0,
				'params'    => array(
					'prepare_content' => 1,
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'static',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'    => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_9_TITLE'),
				'ordering' => 1,
				'position' => 'position-7',
				'module'   => 'mod_tags_popular',
				'params'   => array(
					'maximum'         => 8,
					'timeframe'       => 'alltime',
					'order_value'     => 'count',
					'order_direction' => 1,
					'display_count'   => 0,
					'no_results_text' => 0,
					'minsize'         => 1,
					'maxsize'         => 2,
					'layout'          => '_:default',
					'owncache'        => 1,
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'    => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_10_TITLE'),
				'ordering' => 0,
				'position' => '',
				'module'   => 'mod_tags_similar',
				'params'   => array(
					'maximum'        => 5,
					'matchtype'      => 'any',
					'layout'         => '_:default',
					'owncache'       => 1,
					'module_tag'     => 'div',
					'bootstrap_size' => 0,
					'header_tag'     => 'h3',
					'style'          => 0,
				),
			),
			array(
				'title'     => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_11_TITLE'),
				'ordering'  => 4,
				'position'  => 'cpanel',
				'module'    => 'mod_stats_admin',
				'access'    => 6,
				'client_id' => 1,
				'params'    => array(
					'serverinfo'     => 1,
					'siteinfo'       => 1,
					'counter'        => 0,
					'increase'       => 0,
					'layout'         => '_:default',
					'cache'          => 1,
					'cache_time'     => 900,
					'cachemode'      => 'static',
					'module_tag'     => 'div',
					'bootstrap_size' => 6,
					'header_tag'     => 'h3',
					'style'          => 0,
				),
			),
			array(
				'title'     => JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_12_TITLE'),
				'ordering'  => 1,
				'position'  => 'postinstall',
				'module'    => 'mod_feed',
				'client_id' => 1,
				'params'    => array(
					'rssurl'         => 'https://www.joomla.org/announcements/release-news.feed',
					'rssrtl'         => 0,
					'rsstitle'       => 1,
					'rssdesc'        => 1,
					'rssimage'       => 1,
					'rssitems'       => 3,
					'rssitemdesc'    => 1,
					'word_count'     => 0,
					'layout'         => '_:default',
					'cache'          => 1,
					'cache_time'     => 900,
					'module_tag'     => 'div',
					'bootstrap_size' => 0,
					'header_tag'     => 'h3',
					'style'          => 0,
				),
			),
		);

		foreach ($modules as $module)
		{
			// Append language suffix to title.
			$module['title'] .= $langSuffix;

			// Set values which are always the same.
			$module['id']         = 0;
			$module['asset_id']   = 0;
			$module['language']   = $language;
			$module['note']       = '';
			$module['published']  = 1;
			$module['assignment'] = 0;

			if (!isset($module['content']))
			{
				$module['content'] = '';
			}

			if (!isset($module['access']))
			{
				$module['access'] = $access;
			}

			if (!isset($module['showtitle']))
			{
				$module['showtitle'] = 1;
			}

			if (!isset($module['client_id']))
			{
				$module['client_id'] = 0;
			}

			if (!$model->save($module))
			{
				JFactory::getLanguage()->load('com_modules');
				$response            = array();
				$response['success'] = false;
				$response['message'] = JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 3, JText::_($model->getError()));

				return $response;
			}
		}

		$response            = array();
		$response['success'] = true;
		$response['message'] = JText::_('PLG_SAMPLEDATA_BLOG_STEP3_SUCCESS');

		return $response;
	}

	/**
	 * Adds menuitems.
	 *
	 * @param   array    $menuItems  Array holding the menuitems arrays.
	 * @param   integer  $level      Level in the category tree.
	 *
	 * @return  array  IDs of the inserted menuitems.
	 *
	 * @since  3.8.0
	 *
	 * @throws  Exception
	 */
	private function addMenuItems(array $menuItems, $level)
	{
		$itemIds = array();
		$access  = (int) $this->app->get('access', 1);
		$user    = JFactory::getUser();

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ? JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language . ')' : '';

		foreach ($menuItems as $menuItem)
		{
			// Reset item.id in model state.
			$this->menuItemModel->setState('item.id', 0);

			// Set values which are always the same.
			$menuItem['id']              = 0;
			$menuItem['created_user_id'] = $user->id;
			$menuItem['alias']           = JApplicationHelper::stringURLSafe($menuItem['title']);

			// Set unicodeslugs if alias is empty
			if (trim(str_replace('-', '', $menuItem['alias']) == ''))
			{
				$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
				$menuItem['alias'] = JApplicationHelper::stringURLSafe($menuItem['title']);
				JFactory::getConfig()->set('unicodeslugs', $unicode);
			}

			// Append language suffix to title.
			$menuItem['title'] .= $langSuffix;

			$menuItem['published']       = 1;
			$menuItem['language']        = $language;
			$menuItem['note']            = '';
			$menuItem['img']             = '';
			$menuItem['associations']    = array();
			$menuItem['client_id']       = 0;
			$menuItem['level']           = $level;
			$menuItem['home']            = 0;

			// Set browserNav to default if not set
			if (!isset($menuItem['browserNav']))
			{
				$menuItem['browserNav'] = 0;
			}

			// Set access to default if not set
			if (!isset($menuItem['access']))
			{
				$menuItem['access'] = $access;
			}

			// Set type to 'component' if not set
			if (!isset($menuItem['type']))
			{
				$menuItem['type'] = 'component';
			}

			// Set template_style_id to global if not set
			if (!isset($menuItem['template_style_id']))
			{
				$menuItem['template_style_id'] = 0;
			}

			// Set parent_id to root (1) if not set
			if (!isset($menuItem['parent_id']))
			{
				$menuItem['parent_id'] = 1;
			}

			if (!$this->menuItemModel->save($menuItem))
			{
				// Try two times with another alias (-1 and -2).
				$menuItem['alias'] .= '-1';

				if (!$this->menuItemModel->save($menuItem))
				{
					$menuItem['alias'] = substr_replace($menuItem['alias'], '2', -1);

					if (!$this->menuItemModel->save($menuItem))
					{
						throw new Exception($menuItem['title'] . ' => ' . $menuItem['alias'] . ' : ' . $this->menuItemModel->getError());
					}
				}
			}

			// Get ID from menuitem we just added
			$itemIds[] = $this->menuItemModel->getstate('item.id');
		}

		return $itemIds;
	}
}
PK��#]�)��sampledata/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��extension/joomla/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]tx%$extension/joomla/joomla.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="extension" method="upgrade">
	<name>plg_extension_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>May 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_EXTENSION_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_extension_joomla.ini</language>
		<language tag="en-GB">en-GB.plg_extension_joomla.sys.ini</language>
	</languages>
</extension>
PK��#]�5��wwextension/joomla/joomla.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Extension.Joomla
 *
 * @copyright   (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! master extension plugin.
 *
 * @since  1.6
 */
class PlgExtensionJoomla extends JPlugin
{
	/**
	 * @var    integer Extension Identifier
	 * @since  1.6
	 */
	private $eid = 0;

	/**
	 * @var    JInstaller Installer object
	 * @since  1.6
	 */
	private $installer = null;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Adds an update site to the table if it doesn't exist.
	 *
	 * @param   string   $name        The friendly name of the site
	 * @param   string   $type        The type of site (e.g. collection or extension)
	 * @param   string   $location    The URI for the site
	 * @param   boolean  $enabled     If this site is enabled
	 * @param   string   $extraQuery  Any additional request query to use when updating
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	private function addUpdateSite($name, $type, $location, $enabled, $extraQuery = '')
	{
		$db = JFactory::getDbo();

		// Look if the location is used already; doesn't matter what type you can't have two types at the same address, doesn't make sense
		$query = $db->getQuery(true)
			->select('update_site_id')
			->from('#__update_sites')
			->where('location = ' . $db->quote($location));
		$db->setQuery($query);
		$update_site_id = (int) $db->loadResult();

		// If it doesn't exist, add it!
		if (!$update_site_id)
		{
			$query->clear()
				->insert('#__update_sites')
				->columns(
					array(
						$db->quoteName('name'),
						$db->quoteName('type'),
						$db->quoteName('location'),
						$db->quoteName('enabled'),
						$db->quoteName('extra_query')
					)
				)
				->values(
					$db->quote($name) . ', '
					. $db->quote($type) . ', '
					// Trim to remove any whitespace from the XML file before saving the location to the db
					. $db->quote(trim($location)) . ', '
					. (int) $enabled . ', '
					. $db->quote($extraQuery)
				);
			$db->setQuery($query);

			if ($db->execute())
			{
				// Link up this extension to the update site
				$update_site_id = $db->insertid();
			}
		}

		// Check if it has an update site id (creation might have failed)
		if ($update_site_id)
		{
			// Look for an update site entry that exists
			$query->clear()
				->select('update_site_id')
				->from('#__update_sites_extensions')
				->where('update_site_id = ' . $update_site_id)
				->where('extension_id = ' . $this->eid);
			$db->setQuery($query);
			$tmpid = (int) $db->loadResult();

			if (!$tmpid)
			{
				// Link this extension to the relevant update site
				$query->clear()
					->insert('#__update_sites_extensions')
					->columns(array($db->quoteName('update_site_id'), $db->quoteName('extension_id')))
					->values($update_site_id . ', ' . $this->eid);
				$db->setQuery($query);
				$db->execute();
			}
		}
	}

	/**
	 * Handle post extension install update sites
	 *
	 * @param   JInstaller  $installer  Installer object
	 * @param   integer     $eid        Extension Identifier
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onExtensionAfterInstall($installer, $eid)
	{
		if ($eid)
		{
			$this->installer = $installer;
			$this->eid = $eid;

			// After an install we only need to do update sites
			$this->processUpdateSites();
		}
	}

	/**
	 * Handle extension uninstall
	 *
	 * @param   JInstaller  $installer  Installer instance
	 * @param   integer     $eid        Extension id
	 * @param   boolean     $result     Installation result
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onExtensionAfterUninstall($installer, $eid, $result)
	{
		// If we have a valid extension ID and the extension was successfully uninstalled wipe out any
		// update sites for it
		if ($eid && $result)
		{
			$db = JFactory::getDbo();
			$query = $db->getQuery(true)
				->delete('#__update_sites_extensions')
				->where('extension_id = ' . $eid);
			$db->setQuery($query);
			$db->execute();

			// Delete any unused update sites
			$query->clear()
				->select('update_site_id')
				->from('#__update_sites_extensions');
			$db->setQuery($query);
			$results = $db->loadColumn();

			if (is_array($results))
			{
				// So we need to delete the update sites and their associated updates
				$updatesite_delete = $db->getQuery(true);
				$updatesite_delete->delete('#__update_sites');
				$updatesite_query = $db->getQuery(true);
				$updatesite_query->select('update_site_id')
					->from('#__update_sites');

				// If we get results back then we can exclude them
				if (count($results))
				{
					$updatesite_query->where('update_site_id NOT IN (' . implode(',', $results) . ')');
					$updatesite_delete->where('update_site_id NOT IN (' . implode(',', $results) . ')');
				}

				// So let's find what update sites we're about to nuke and remove their associated extensions
				$db->setQuery($updatesite_query);
				$update_sites_pending_delete = $db->loadColumn();

				if (is_array($update_sites_pending_delete) && count($update_sites_pending_delete))
				{
					// Nuke any pending updates with this site before we delete it
					// TODO: investigate alternative of using a query after the delete below with a query and not in like above
					$query->clear()
						->delete('#__updates')
						->where('update_site_id IN (' . implode(',', $update_sites_pending_delete) . ')');
					$db->setQuery($query);
					$db->execute();
				}

				// Note: this might wipe out the entire table if there are no extensions linked
				$db->setQuery($updatesite_delete);
				$db->execute();
			}

			// Last but not least we wipe out any pending updates for the extension
			$query->clear()
				->delete('#__updates')
				->where('extension_id = ' . $eid);
			$db->setQuery($query);
			$db->execute();
		}
	}

	/**
	 * After update of an extension
	 *
	 * @param   JInstaller  $installer  Installer object
	 * @param   integer     $eid        Extension identifier
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onExtensionAfterUpdate($installer, $eid)
	{
		if ($eid)
		{
			$this->installer = $installer;
			$this->eid = $eid;

			// Handle any update sites
			$this->processUpdateSites();
		}
	}

	/**
	 * Processes the list of update sites for an extension.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	private function processUpdateSites()
	{
		$manifest      = $this->installer->getManifest();
		$updateservers = $manifest->updateservers;

		if ($updateservers)
		{
			$children = $updateservers->children();
		}
		else
		{
			$children = array();
		}

		if (count($children))
		{
			foreach ($children as $child)
			{
				$attrs = $child->attributes();
				$this->addUpdateSite($attrs['name'], $attrs['type'], trim($child), true, $this->installer->extraQuery);
			}
		}
		else
		{
			$data = trim((string) $updateservers);

			if ($data !== '')
			{
				// We have a single entry in the update server line, let us presume this is an extension line
				$this->addUpdateSite(JText::_('PLG_EXTENSION_JOOMLA_UNKNOWN_SITE'), 'extension', $data, true);
			}
		}
	}
}
PK��#]y(��extension/jce/jce.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin" group="extension" method="upgrade">
	<name>plg_extension_jce</name>
	<version>2.9.38</version>
  <creationDate>27-06-2023</creationDate>
  <author>Ryan Demmer</author>
  <authorEmail>info@joomlacontenteditor.net</authorEmail>
  <authorUrl>http://www.joomlacontenteditor.net</authorUrl>
  <copyright>Copyright (C) 2006 - 2023 Ryan Demmer. All rights reserved</copyright>
  <license>GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html</license>
	<description>PLG_EXTENSION_JCE_XML_DESCRIPTION</description>
	<files folder="plugins/extension/jce">
		<filename plugin="jce">jce.php</filename>
	</files>
	<languages folder="administrator/language/en-GB">
      <language tag="en-GB">en-GB.plg_extension_jce.ini</language>
      <language tag="en-GB">en-GB.plg_extension_jce.sys.ini</language>
  </languages>
</extension>
PK��#]B�GM��extension/jce/jce.phpnu�[���<?php
/**
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved
 * @copyright   Copyright (C) 2018 Ryan Demmer. All rights reserved
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;

/**
 * JCE extension plugin.
 *
 * @since  2.6
 */
class PlgExtensionJce extends JPlugin
{
    /**
     * Check the installer is for a valid plugin group.
     *
     * @param JInstaller $installer Installer object
     *
     * @return bool
     *
     * @since   2.6
     */
    private function isValidPlugin($installer)
    {
        if (empty($installer->manifest)) {
            return false;
        }

        foreach (array('type', 'group') as $var) {
            $$var = (string) $installer->manifest->attributes()->{$var};
        }

        return $type === 'plugin' && $group === 'jce';
    }

    public function onExtensionBeforeInstall($method, $type, $manifest, $extension = 0)
    {
        if ((string) $type === "file") {

            // get a reference to the current installer
            $manifestPath = JInstaller::getInstance()->getPath('manifest');

            if (empty($manifestPath)) {
                return true;
            }

            // get the filename of the manifest file, eg: pkg_jce_de-DE
            $element = basename($manifestPath, '.xml');

            // if this matches the current install...
            if (strpos($element, 'pkg_jce_') !== false) {
                // find an existing legacy language install, eg: jce-de-DE
                $element = str_replace('pkg_jce_', 'jce-', $element);

                $table = JTable::getInstance('extension');
                $id = $table->find(array('type' => 'file', 'element' => $element));

                if ($id) {
                    $installer = new JInstaller();

                    // try unisntall, if this fails, delete database entry
                    if (!$installer->uninstall('file', $id)) {
                        $table->delete($id);
                    }
                }
            }
        }
    }
    /**
     * Handle post extension install update sites.
     *
     * @param JInstaller $installer Installer object
     * @param int        $eid       Extension Identifier
     *
     * @since   2.6
     */
    public function onExtensionAfterInstall($installer, $eid)
    {
        if ($eid) {
            if (!$this->isValidPlugin($installer)) {
                return false;
            }

            $basename = basename($installer->getPath('extension_root'));

            if (strpos($basename, '-') === false) {
                return false;
            }

            require_once JPATH_ADMINISTRATOR . '/components/com_jce/helpers/plugins.php';

            // enable plugin
            $plugin = JTable::getInstance('extension');
            $plugin->load($eid);
            $plugin->publish();

            $parts = explode('-', $basename);
            $type = $parts[0];
            $name = $parts[1];

            $plugin = new StdClass();
            $plugin->name = $name;

            if ($type === 'editor') {
                $plugin->icon = (string) $installer->manifest->icon;
                $plugin->row = (int) (string) $installer->manifest->attributes()->row;
                $plugin->type = 'plugin';
            } else {
                $plugin->type = 'extension';
            }

            $plugin->path = $installer->getPath('extension_root');

            JcePluginsHelper::postInstall('install', $plugin, $installer);

            // clean up legacy extensions
            if ($plugin->type == 'extension') {
                jimport('joomla.filesystem.folder');
                jimport('joomla.filesystem.file');

                $path = JPATH_SITE . '/components/com_jce/editor/extensions/' . $type;

                // delete manifest
                if (is_file($path . '/' . $plugin->name . '.xml')) {
                    JFile::delete($path . '/' . $plugin->name . '.xml');
                }
                // delete file
                if (is_file($path . '/' . $plugin->name . '.php')) {
                    JFile::delete($path . '/' . $plugin->name . '.php');
                }
                // delete folder
                if (is_dir($path . '/' . $plugin->name)) {
                    JFolder::delete($path . '/' . $plugin->name);
                }
            }
        }
    }

    /**
     * Handle extension uninstall.
     *
     * @param JInstaller $installer Installer instance
     * @param int        $eid       Extension id
     * @param int        $result    Installation result
     *
     * @since   1.6
     */
    public function onExtensionAfterUninstall($installer, $eid, $result)
    {
        if ($eid) {
            if (!$this->isValidPlugin($installer)) {
                return false;
            }

            $basename = basename($installer->getPath('extension_root'));

            if (strpos($basename, '-') === false) {
                return false;
            }

            require_once JPATH_ADMINISTRATOR . '/components/com_jce/helpers/plugins.php';

            $parts = explode('-', $basename);
            $type = $parts[0];
            $name = $parts[1];

            $plugin = new StdClass();
            $plugin->name = $name;

            if ($type === 'editor') {
                $plugin->icon = (string) $installer->manifest->icon;
                $plugin->row = (int) (string) $installer->manifest->attributes()->row;
                $plugin->type = 'plugin';
            }

            $plugin->path = $installer->getPath('extension_root');

            JcePluginsHelper::postInstall('uninstall', $plugin, $installer);
        }
    }

    public function onExtensionAfterSave($context, $table, $result)
    {
        if ($context !== 'com_config.component') {
            return;
        }

        if ($table->element !== 'com_jce') {
            return;
        }

        $params = json_decode($table->params, true);

        if ($params && !empty($params['updates_key'])) {
            $updatesite = JTable::getInstance('Updatesite');

            // sanitize key
            $key = preg_replace("/[^a-zA-Z0-9]/", "", $params['updates_key']);

            $db = JFactory::getDBO();

            $query = $db->getQuery(true);
            $query->select($db->qn('update_site_id'))->from('#__update_sites_extensions')->where($db->qn('extension_id') . '=' . (int) $table->package_id);
            $db->setQuery($query);
            $update_site_id = $db->loadResult();

            if ($update_site_id) {
                if ($updatesite->load($update_site_id)) {
                    $updatesite->bind(array('extra_query' => 'key=' . $key));
                    $updatesite->check();
                    $updatesite->store();
                }
            }
        }
    }
}
PK��#]�)��extension/jce/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��extension/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��authentication/ldap/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]l��;��authentication/ldap/ldap.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="authentication" method="upgrade">
	<name>plg_authentication_ldap</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_LDAP_XML_DESCRIPTION</description>
	<files>
		<filename plugin="ldap">ldap.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_authentication_ldap.ini</language>
		<language tag="en-GB">en-GB.plg_authentication_ldap.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="host"
					type="text"
					label="PLG_LDAP_FIELD_HOST_LABEL"
					description="PLG_LDAP_FIELD_HOST_DESC"
					size="20"
				/>

				<field
					name="port"
					type="number"
					label="PLG_LDAP_FIELD_PORT_LABEL"
					description="PLG_LDAP_FIELD_PORT_DESC"
					min="1"
					max="65535"
					default="389"
					hint="389"
					validate="number"
					filter="integer"
					size="5"
				/>

				<field
					name="use_ldapV3"
					type="radio"
					label="PLG_LDAP_FIELD_V3_LABEL"
					description="PLG_LDAP_FIELD_V3_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="negotiate_tls"
					type="radio"
					label="PLG_LDAP_FIELD_NEGOCIATE_LABEL"
					description="PLG_LDAP_FIELD_NEGOCIATE_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="ignore_reqcert_tls"
					type="radio"
					label="PLG_LDAP_FIELD_IGNORE_REQCERT_TLS_LABEL"
					description="PLG_LDAP_FIELD_IGNORE_REQCERT_TLS_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="no_referrals"
					type="radio"
					label="PLG_LDAP_FIELD_REFERRALS_LABEL"
					description="PLG_LDAP_FIELD_REFERRALS_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="auth_method"
					type="list"
					label="PLG_LDAP_FIELD_AUTHMETHOD_LABEL"
					description="PLG_LDAP_FIELD_AUTHMETHOD_DESC"
					default="bind"
					>
					<option value="search">PLG_LDAP_FIELD_VALUE_BINDSEARCH</option>
					<option value="bind">PLG_LDAP_FIELD_VALUE_BINDUSER</option>
				</field>

				<field
					name="base_dn"
					type="text"
					label="PLG_LDAP_FIELD_BASEDN_LABEL"
					description="PLG_LDAP_FIELD_BASEDN_DESC"
					size="20"
				/>

				<field
					name="search_string"
					type="text"
					label="PLG_LDAP_FIELD_SEARCHSTRING_LABEL"
					description="PLG_LDAP_FIELD_SEARCHSTRING_DESC"
					size="20"
				/>

				<field
					name="users_dn"
					type="text"
					label="PLG_LDAP_FIELD_USERSDN_LABEL"
					description="PLG_LDAP_FIELD_USERSDN_DESC"
					size="20"
				/>

				<field
					name="username"
					type="text"
					label="PLG_LDAP_FIELD_USERNAME_LABEL"
					description="PLG_LDAP_FIELD_USERNAME_DESC"
					size="20"
				/>

				<field
					name="password"
					type="password"
					label="PLG_LDAP_FIELD_PASSWORD_LABEL"
					description="PLG_LDAP_FIELD_PASSWORD_DESC"
					size="20"
				/>

				<field
					name="ldap_fullname"
					type="text"
					label="PLG_LDAP_FIELD_FULLNAME_LABEL"
					description="PLG_LDAP_FIELD_FULLNAME_DESC"
					default="fullName"
					size="20"
				/>

				<field
					name="ldap_email"
					type="text"
					label="PLG_LDAP_FIELD_EMAIL_LABEL"
					description="PLG_LDAP_FIELD_EMAIL_DESC"
					default="mail"
					size="20"
				/>

				<field
					name="ldap_uid"
					type="text"
					label="PLG_LDAP_FIELD_UID_LABEL"
					description="PLG_LDAP_FIELD_UID_DESC"
					default="uid"
					size="20"
				/>
				<field
					name="ldap_debug"
					type="radio"
					label="PLG_LDAP_FIELD_LDAPDEBUG_LABEL"
					description="PLG_LDAP_FIELD_LDAPDEBUG_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]2� ��authentication/ldap/ldap.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.ldap
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Ldap\LdapClient;

/**
 * LDAP Authentication Plugin
 *
 * @since  1.5
 */
class PlgAuthenticationLdap extends JPlugin
{
	/**
	 * This method should handle any authentication and report back to the subject
	 *
	 * @param   array   $credentials  Array holding the user credentials
	 * @param   array   $options      Array of extra options
	 * @param   object  &$response    Authentication response object
	 *
	 * @return  boolean
	 *
	 * @since   1.5
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		$userdetails = null;
		$success = 0;
		$userdetails = array();

		// For JLog
		$response->type = 'LDAP';

		// Strip null bytes from the password
		$credentials['password'] = str_replace(chr(0), '', $credentials['password']);

		// LDAP does not like Blank passwords (tries to Anon Bind which is bad)
		if (empty($credentials['password']))
		{
			$response->status = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');

			return false;
		}

		// Load plugin params info
		$ldap_email    = $this->params->get('ldap_email');
		$ldap_fullname = $this->params->get('ldap_fullname');
		$ldap_uid      = $this->params->get('ldap_uid');
		$auth_method   = $this->params->get('auth_method');

		$ldap = new LdapClient($this->params);

		if (!$ldap->connect())
		{
			$response->status = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JGLOBAL_AUTH_NOT_CONNECT');

			return;
		}

		switch ($auth_method)
		{
			case 'search':
			{
				// Bind using Connect Username/password
				// Force anon bind to mitigate misconfiguration like [#7119]
				if ($this->params->get('username', '') !== '')
				{
					$bindtest = $ldap->bind();
				}
				else
				{
					$bindtest = $ldap->anonymous_bind();
				}

				if ($bindtest)
				{
					// Search for users DN
					$binddata = $this->searchByString(
						str_replace(
							'[search]',
							str_replace(';', '\3b', $ldap->escape($credentials['username'], null, LDAP_ESCAPE_FILTER)),
							$this->params->get('search_string')
						),
						$ldap
					);

					if (isset($binddata[0], $binddata[0]['dn']))
					{
						// Verify Users Credentials
						$success = $ldap->bind($binddata[0]['dn'], $credentials['password'], 1);

						// Get users details
						$userdetails = $binddata;
					}
					else
					{
						$response->status = JAuthentication::STATUS_FAILURE;
						$response->error_message = JText::_('JGLOBAL_AUTH_NO_USER');
					}
				}
				else
				{
					$response->status = JAuthentication::STATUS_FAILURE;
					$response->error_message = JText::_('JGLOBAL_AUTH_NOT_CONNECT');
				}
			}	break;

			case 'bind':
			{
				// We just accept the result here
				$success = $ldap->bind($ldap->escape($credentials['username'], null, LDAP_ESCAPE_DN), $credentials['password']);

				if ($success)
				{
					$userdetails = $this->searchByString(
						str_replace(
							'[search]',
							str_replace(';', '\3b', $ldap->escape($credentials['username'], null, LDAP_ESCAPE_FILTER)),
							$this->params->get('search_string')
						),
						$ldap
					);
				}
				else
				{
					$response->status = JAuthentication::STATUS_FAILURE;
					$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_PASS');
				}
			}	break;
		}

		if (!$success)
		{
			$response->status = JAuthentication::STATUS_FAILURE;

			if ($response->error_message === '')
			{
				$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_PASS');
			}
		}
		else
		{
			// Grab some details from LDAP and return them
			if (isset($userdetails[0][$ldap_uid][0]))
			{
				$response->username = $userdetails[0][$ldap_uid][0];
			}

			if (isset($userdetails[0][$ldap_email][0]))
			{
				$response->email = $userdetails[0][$ldap_email][0];
			}

			if (isset($userdetails[0][$ldap_fullname][0]))
			{
				$response->fullname = $userdetails[0][$ldap_fullname][0];
			}
			else
			{
				$response->fullname = $credentials['username'];
			}

			// Were good - So say so.
			$response->status        = JAuthentication::STATUS_SUCCESS;
			$response->error_message = '';
		}

		$ldap->close();
	}

	/**
	 * Shortcut method to build a LDAP search based on a semicolon separated string
	 *
	 * Note that this method requires that semicolons which should be part of the search term to be escaped
	 * to correctly split the search string into separate lookups
	 *
	 * @param   string      $search  search string of search values
	 * @param   LdapClient  $ldap    The LDAP client
	 *
	 * @return  array  Search results
	 *
	 * @since   3.8.2
	 */
	private static function searchByString($search, LdapClient $ldap)
	{
		$results = explode(';', $search);

		foreach ($results as $key => $result)
		{
			$results[$key] = '(' . str_replace('\3b', ';', $result) . ')';
		}

		return $ldap->search($results);
	}
}
PK��#]�)��authentication/joomla/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]cH��� authentication/joomla/joomla.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.joomla
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla Authentication plugin
 *
 * @since  1.5
 */
class PlgAuthenticationJoomla extends JPlugin
{
	/**
	 * This method should handle any authentication and report back to the subject
	 *
	 * @param   array   $credentials  Array holding the user credentials
	 * @param   array   $options      Array of extra options
	 * @param   object  &$response    Authentication response object
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		$response->type = 'Joomla';

		// Joomla does not like blank passwords
		if (empty($credentials['password']))
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');

			return;
		}

		// Get a database object
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('id, password')
			->from('#__users')
			->where('username=' . $db->quote($credentials['username']));

		$db->setQuery($query);
		$result = $db->loadObject();

		if ($result)
		{
			$match = JUserHelper::verifyPassword($credentials['password'], $result->password, $result->id);

			if ($match === true)
			{
				// Bring this in line with the rest of the system
				$user               = JUser::getInstance($result->id);
				$response->email    = $user->email;
				$response->fullname = $user->name;

				if (JFactory::getApplication()->isClient('administrator'))
				{
					$response->language = $user->getParam('admin_language');
				}
				else
				{
					$response->language = $user->getParam('language');
				}

				$response->status        = JAuthentication::STATUS_SUCCESS;
				$response->error_message = '';
			}
			else
			{
				// Invalid password
				$response->status        = JAuthentication::STATUS_FAILURE;
				$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_PASS');
			}
		}
		else
		{
			// Let's hash the entered password even if we don't have a matching user for some extra response time
			// By doing so, we mitigate side channel user enumeration attacks
			JUserHelper::hashPassword($credentials['password']);

			// Invalid user
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JGLOBAL_AUTH_NO_USER');
		}

		// Check the two factor authentication
		if ($response->status === JAuthentication::STATUS_SUCCESS)
		{
			$methods = JAuthenticationHelper::getTwoFactorMethods();

			if (count($methods) <= 1)
			{
				// No two factor authentication method is enabled
				return;
			}

			JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_users/models', 'UsersModel');

			/** @var UsersModelUser $model */
			$model = JModelLegacy::getInstance('User', 'UsersModel', array('ignore_request' => true));

			// Load the user's OTP (one time password, a.k.a. two factor auth) configuration
			if (!array_key_exists('otp_config', $options))
			{
				$otpConfig             = $model->getOtpConfig($result->id);
				$options['otp_config'] = $otpConfig;
			}
			else
			{
				$otpConfig = $options['otp_config'];
			}

			// Check if the user has enabled two factor authentication
			if (empty($otpConfig->method) || ($otpConfig->method === 'none'))
			{
				// Warn the user if they are using a secret code but they have not
				// enabled two factor auth in their account.
				if (!empty($credentials['secretkey']))
				{
					try
					{
						$app = JFactory::getApplication();

						$this->loadLanguage();

						$app->enqueueMessage(JText::_('PLG_AUTH_JOOMLA_ERR_SECRET_CODE_WITHOUT_TFA'), 'warning');
					}
					catch (Exception $exc)
					{
						// This happens when we are in CLI mode. In this case
						// no warning is issued
						return;
					}
				}

				return;
			}

			// Try to validate the OTP
			FOFPlatform::getInstance()->importPlugin('twofactorauth');

			$otpAuthReplies = FOFPlatform::getInstance()->runPlugins('onUserTwofactorAuthenticate', array($credentials, $options));

			$check = false;

			/*
			 * This looks like noob code but DO NOT TOUCH IT and do not convert
			 * to in_array(). During testing in_array() inexplicably returned
			 * null when the OTEP begins with a zero! o_O
			 */
			if (!empty($otpAuthReplies))
			{
				foreach ($otpAuthReplies as $authReply)
				{
					$check = $check || $authReply;
				}
			}

			// Fall back to one time emergency passwords
			if (!$check)
			{
				// Did the user use an OTEP instead?
				if (empty($otpConfig->otep))
				{
					if (empty($otpConfig->method) || ($otpConfig->method === 'none'))
					{
						// Two factor authentication is not enabled on this account.
						// Any string is assumed to be a valid OTEP.

						return;
					}
					else
					{
						/*
						 * Two factor authentication enabled and no OTEPs defined. The
						 * user has used them all up. Therefore anything they enter is
						 * an invalid OTEP.
						 */
						$response->status        = JAuthentication::STATUS_FAILURE;
						$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_SECRETKEY');

						return;
					}
				}

				// Clean up the OTEP (remove dashes, spaces and other funny stuff
				// our beloved users may have unwittingly stuffed in it)
				$otep  = $credentials['secretkey'];
				$otep  = filter_var($otep, FILTER_SANITIZE_NUMBER_INT);
				$otep  = str_replace('-', '', $otep);
				$check = false;

				// Did we find a valid OTEP?
				if (in_array($otep, $otpConfig->otep))
				{
					// Remove the OTEP from the array
					$otpConfig->otep = array_diff($otpConfig->otep, array($otep));

					$model->setOtpConfig($result->id, $otpConfig);

					// Return true; the OTEP was a valid one
					$check = true;
				}
			}

			if (!$check)
			{
				$response->status        = JAuthentication::STATUS_FAILURE;
				$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_SECRETKEY');
			}
		}
	}
}
PK��#]  �$$ authentication/joomla/joomla.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="authentication" method="upgrade">
	<name>plg_authentication_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_AUTH_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_authentication_joomla.ini</language>
		<language tag="en-GB">en-GB.plg_authentication_joomla.sys.ini</language>
	</languages>
</extension>
PK��#]G���� authentication/cookie/cookie.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin" group="authentication" method="upgrade">
	<name>plg_authentication_cookie</name>
	<author>Joomla! Project</author>
	<creationDate>July 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_AUTH_COOKIE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="cookie">cookie.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_authentication_cookie.ini</language>
		<language tag="en-GB">en-GB.plg_authentication_cookie.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="cookie_lifetime"
					type="number"
					label="PLG_AUTH_COOKIE_FIELD_COOKIE_LIFETIME_LABEL"
					description="PLG_AUTH_COOKIE_FIELD_COOKIE_LIFETIME_DESC"
					default="60"
					filter="integer"
					required="true"
				/>

				<field
					name="key_length"
					type="list"
					label="PLG_AUTH_COOKIE_FIELD_KEY_LENGTH_LABEL"
					description="PLG_AUTH_COOKIE_FIELD_KEY_LENGTH_DESC"
					default="16"
					filter="integer"
					required="true"
					>
					<option value="8">8</option>
					<option value="16">16</option>
					<option value="32">32</option>
					<option value="64">64</option>
				</field>

			</fieldset>
		</fields>
	</config>
</extension>
PK��#]��3��-�- authentication/cookie/cookie.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.cookie
 *
 * @copyright   (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla Authentication plugin
 *
 * @since  3.2
 * @note   Code based on http://jaspan.com/improved_persistent_login_cookie_best_practice
 *         and http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
 */
class PlgAuthenticationCookie extends JPlugin
{
	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.2
	 */
	protected $db;

	/**
	 * Reports the privacy related capabilities for this plugin to site administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_AUTHENTICATION_COOKIE') => array(
				JText::_('PLG_AUTH_COOKIE_PRIVACY_CAPABILITY_COOKIE'),
			)
		);
	}

	/**
	 * This method should handle any authentication and report back to the subject
	 *
	 * @param   array   $credentials  Array holding the user credentials
	 * @param   array   $options      Array of extra options
	 * @param   object  &$response    Authentication response object
	 *
	 * @return  boolean
	 *
	 * @since   3.2
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return false;
		}

		// Get cookie
		$cookieName  = 'joomla_remember_me_' . JUserHelper::getShortHashedUserAgent();
		$cookieValue = $this->app->input->cookie->get($cookieName);

		// Try with old cookieName (pre 3.6.0) if not found
		if (!$cookieValue)
		{
			$cookieName  = JUserHelper::getShortHashedUserAgent();
			$cookieValue = $this->app->input->cookie->get($cookieName);
		}

		if (!$cookieValue)
		{
			return false;
		}

		$cookieArray = explode('.', $cookieValue);

		// Check for valid cookie value
		if (count($cookieArray) !== 2)
		{
			// Destroy the cookie in the browser.
			$this->app->input->cookie->set($cookieName, '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));
			JLog::add('Invalid cookie detected.', JLog::WARNING, 'error');

			return false;
		}

		$response->type = 'Cookie';

		// Filter series since we're going to use it in the query
		$filter = new JFilterInput;
		$series = $filter->clean($cookieArray[1], 'ALNUM');

		// Remove expired tokens
		$query = $this->db->getQuery(true)
			->delete('#__user_keys')
			->where($this->db->quoteName('time') . ' < ' . $this->db->quote(time()));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// We aren't concerned with errors from this query, carry on
		}

		// Find the matching record if it exists.
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('user_id', 'token', 'series', 'time')))
			->from($this->db->quoteName('#__user_keys'))
			->where($this->db->quoteName('series') . ' = ' . $this->db->quote($series))
			->where($this->db->quoteName('uastring') . ' = ' . $this->db->quote($cookieName))
			->order($this->db->quoteName('time') . ' DESC');

		try
		{
			$results = $this->db->setQuery($query)->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		if (count($results) !== 1)
		{
			// Destroy the cookie in the browser.
			$this->app->input->cookie->set($cookieName, '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		// We have a user with one cookie with a valid series and a corresponding record in the database.
		if (!JUserHelper::verifyPassword($cookieArray[0], $results[0]->token))
		{
			/*
			 * This is a real attack!
			 * Either the series was guessed correctly or a cookie was stolen and used twice (once by attacker and once by victim).
			 * Delete all tokens for this user!
			 */
			$query = $this->db->getQuery(true)
				->delete('#__user_keys')
				->where($this->db->quoteName('user_id') . ' = ' . $this->db->quote($results[0]->user_id));

			try
			{
				$this->db->setQuery($query)->execute();
			}
			catch (RuntimeException $e)
			{
				// Log an alert for the site admin
				JLog::add(
					sprintf('Failed to delete cookie token for user %s with the following error: %s', $results[0]->user_id, $e->getMessage()),
					JLog::WARNING,
					'security'
				);
			}

			// Destroy the cookie in the browser.
			$this->app->input->cookie->set($cookieName, '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));

			// Issue warning by email to user and/or admin?
			JLog::add(JText::sprintf('PLG_AUTH_COOKIE_ERROR_LOG_LOGIN_FAILED', $results[0]->user_id), JLog::WARNING, 'security');
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		// Make sure there really is a user with this name and get the data for the session.
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('id', 'username', 'password')))
			->from($this->db->quoteName('#__users'))
			->where($this->db->quoteName('username') . ' = ' . $this->db->quote($results[0]->user_id))
			->where($this->db->quoteName('requireReset') . ' = 0');

		try
		{
			$result = $this->db->setQuery($query)->loadObject();
		}
		catch (RuntimeException $e)
		{
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		if ($result)
		{
			// Bring this in line with the rest of the system
			$user = JUser::getInstance($result->id);

			// Set response data.
			$response->username = $result->username;
			$response->email    = $user->email;
			$response->fullname = $user->name;
			$response->password = $result->password;
			$response->language = $user->getParam('language');

			// Set response status.
			$response->status        = JAuthentication::STATUS_SUCCESS;
			$response->error_message = '';
		}
		else
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JGLOBAL_AUTH_NO_USER');
		}
	}

	/**
	 * We set the authentication cookie only after login is successfully finished.
	 * We set a new cookie either for a user with no cookies or one
	 * where the user used a cookie to authenticate.
	 *
	 * @param   array  $options  Array holding options
	 *
	 * @return  boolean  True on success
	 *
	 * @since   3.2
	 */
	public function onUserAfterLogin($options)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return false;
		}

		if (isset($options['responseType']) && $options['responseType'] === 'Cookie')
		{
			// Logged in using a cookie
			$cookieName = 'joomla_remember_me_' . JUserHelper::getShortHashedUserAgent();

			// We need the old data to get the existing series
			$cookieValue = $this->app->input->cookie->get($cookieName);

			// Try with old cookieName (pre 3.6.0) if not found
			if (!$cookieValue)
			{
				$oldCookieName = JUserHelper::getShortHashedUserAgent();
				$cookieValue   = $this->app->input->cookie->get($oldCookieName);

				// Destroy the old cookie in the browser
				$this->app->input->cookie->set($oldCookieName, '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));
			}

			$cookieArray = explode('.', $cookieValue);

			// Filter series since we're going to use it in the query
			$filter = new JFilterInput;
			$series = $filter->clean($cookieArray[1], 'ALNUM');
		}
		elseif (!empty($options['remember']))
		{
			// Remember checkbox is set
			$cookieName = 'joomla_remember_me_' . JUserHelper::getShortHashedUserAgent();

			// Create a unique series which will be used over the lifespan of the cookie
			$unique     = false;
			$errorCount = 0;

			do
			{
				$series = JUserHelper::genRandomPassword(20);
				$query  = $this->db->getQuery(true)
					->select($this->db->quoteName('series'))
					->from($this->db->quoteName('#__user_keys'))
					->where($this->db->quoteName('series') . ' = ' . $this->db->quote($series));

				try
				{
					$results = $this->db->setQuery($query)->loadResult();

					if ($results === null)
					{
						$unique = true;
					}
				}
				catch (RuntimeException $e)
				{
					$errorCount++;

					// We'll let this query fail up to 5 times before giving up, there's probably a bigger issue at this point
					if ($errorCount === 5)
					{
						return false;
					}
				}
			}

			while ($unique === false);
		}
		else
		{
			return false;
		}

		// Get the parameter values
		$lifetime = $this->params->get('cookie_lifetime', 60) * 24 * 60 * 60;
		$length   = $this->params->get('key_length', 16);

		// Generate new cookie
		$token       = JUserHelper::genRandomPassword($length);
		$cookieValue = $token . '.' . $series;

		// Overwrite existing cookie with new value
		$this->app->input->cookie->set(
			$cookieName,
			$cookieValue,
			time() + $lifetime,
			$this->app->get('cookie_path', '/'),
			$this->app->get('cookie_domain', ''),
			$this->app->isHttpsForced(),
			true
		);

		$query = $this->db->getQuery(true);

		if (!empty($options['remember']))
		{
			// Create new record
			$query
				->insert($this->db->quoteName('#__user_keys'))
				->set($this->db->quoteName('user_id') . ' = ' . $this->db->quote($options['user']->username))
				->set($this->db->quoteName('series') . ' = ' . $this->db->quote($series))
				->set($this->db->quoteName('uastring') . ' = ' . $this->db->quote($cookieName))
				->set($this->db->quoteName('time') . ' = ' . (time() + $lifetime));
		}
		else
		{
			// Update existing record with new token
			$query
				->update($this->db->quoteName('#__user_keys'))
				->where($this->db->quoteName('user_id') . ' = ' . $this->db->quote($options['user']->username))
				->where($this->db->quoteName('series') . ' = ' . $this->db->quote($series))
				->where($this->db->quoteName('uastring') . ' = ' . $this->db->quote($cookieName));
		}

		$hashedToken = JUserHelper::hashPassword($token);

		$query->set($this->db->quoteName('token') . ' = ' . $this->db->quote($hashedToken));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * This is where we delete any authentication cookie when a user logs out
	 *
	 * @param   array  $options  Array holding options (length, timeToExpiration)
	 *
	 * @return  boolean  True on success
	 *
	 * @since   3.2
	 */
	public function onUserAfterLogout($options)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return false;
		}

		$cookieName  = 'joomla_remember_me_' . JUserHelper::getShortHashedUserAgent();
		$cookieValue = $this->app->input->cookie->get($cookieName);

		// There are no cookies to delete.
		if (!$cookieValue)
		{
			return true;
		}

		$cookieArray = explode('.', $cookieValue);

		// Filter series since we're going to use it in the query
		$filter = new JFilterInput;
		$series = $filter->clean($cookieArray[1], 'ALNUM');

		// Remove the record from the database
		$query = $this->db->getQuery(true)
			->delete('#__user_keys')
			->where($this->db->quoteName('series') . ' = ' . $this->db->quote($series));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// We aren't concerned with errors from this query, carry on
		}

		// Destroy the cookie
		$this->app->input->cookie->set($cookieName, '', 1, $this->app->get('cookie_path', '/'), $this->app->get('cookie_domain', ''));

		return true;
	}
}
PK��#]�)��authentication/cookie/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��authentication/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�f�]]authentication/gmail/gmail.phpnu�[���<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.gmail
 *
 * @copyright   (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Authentication\AuthenticationResponse;
use Joomla\Registry\Registry;

/**
 * GMail Authentication Plugin
 *
 * @since  1.5
 */
class PlgAuthenticationGMail extends JPlugin
{
	/**
	 * This method should handle any authentication and report back to the subject
	 *
	 * @param   array                   $credentials  Array holding the user credentials
	 * @param   array                   $options      Array of extra options
	 * @param   AuthenticationResponse  &$response    Authentication response object
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		// Load plugin language
		$this->loadLanguage();

		// No backend authentication
		if (JFactory::getApplication()->isClient('administrator') && !$this->params->get('backendLogin', 0))
		{
			return;
		}

		$success = false;

		$curlParams = array(
			'follow_location' => true,
			'transport.curl'  => array(
				CURLOPT_SSL_VERIFYPEER => $this->params->get('verifypeer', 1)
			),
		);

		$transportParams = new Registry($curlParams);

		try
		{
			$http = JHttpFactory::getHttp($transportParams, 'curl');
		}
		catch (RuntimeException $e)
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->type          = 'GMail';
			$response->error_message = JText::sprintf('JGLOBAL_AUTH_FAILED', JText::_('JGLOBAL_AUTH_CURL_NOT_INSTALLED'));

			return;
		}

		// Check if we have a username and password
		if ($credentials['username'] === '' || $credentials['password'] === '')
		{
			$response->type          = 'GMail';
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::sprintf('JGLOBAL_AUTH_FAILED', JText::_('JGLOBAL_AUTH_USER_BLACKLISTED'));

			return;
		}

		$blacklist = explode(',', $this->params->get('user_blacklist', ''));

		// Check if the username isn't blacklisted
		if (in_array($credentials['username'], $blacklist))
		{
			$response->type          = 'GMail';
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::sprintf('JGLOBAL_AUTH_FAILED', JText::_('JGLOBAL_AUTH_USER_BLACKLISTED'));

			return;
		}

		$suffix      = $this->params->get('suffix', '');
		$applysuffix = $this->params->get('applysuffix', 0);
		$offset      = strpos($credentials['username'], '@');

		// Check if we want to do suffix stuff, typically for Google Apps for Your Domain
		if ($suffix && $applysuffix)
		{
			if ($applysuffix == 1 && $offset === false)
			{
				// Apply suffix if missing
				$credentials['username'] .= '@' . $suffix;
			}
			elseif ($applysuffix == 2)
			{
				// Always use suffix
				if ($offset)
				{
					// If we already have an @, get rid of it and replace it
					$credentials['username'] = substr($credentials['username'], 0, $offset);
				}

				$credentials['username'] .= '@' . $suffix;
			}
		}

		$headers = array(
			'Authorization' => 'Basic ' . base64_encode($credentials['username'] . ':' . $credentials['password'])
		);

		try
		{
			$result = $http->get('https://mail.google.com/mail/feed/atom', $headers);
		}
		catch (Exception $e)
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->type          = 'GMail';
			$response->error_message = JText::sprintf('JGLOBAL_AUTH_FAILED', JText::_('JGLOBAL_AUTH_UNKNOWN_ACCESS_DENIED'));

			return;
		}

		$code = $result->code;

		switch ($code)
		{
			case 200 :
				$message = JText::_('JGLOBAL_AUTH_ACCESS_GRANTED');
				$success = true;
				break;

			case 401 :
				$message = JText::_('JGLOBAL_AUTH_ACCESS_DENIED');
				break;

			default :
				$message = JText::_('JGLOBAL_AUTH_UNKNOWN_ACCESS_DENIED');
				break;
		}

		$response->type = 'GMail';

		if (!$success)
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::sprintf('JGLOBAL_AUTH_FAILED', $message);

			return;
		}

		if (strpos($credentials['username'], '@') === false)
		{
			if ($suffix)
			{
				// If there is a suffix then we want to apply it
				$email = $credentials['username'] . '@' . $suffix;
			}
			else
			{
				// If there isn't a suffix just use the default gmail one
				$email = $credentials['username'] . '@gmail.com';
			}
		}
		else
		{
			// The username looks like an email address (probably is) so use that
			$email = $credentials['username'];
		}

		// Extra security checks with existing local accounts
		$db                  = JFactory::getDbo();
		$localUsernameChecks = array(strstr($email, '@', true), $email);

		$query = $db->getQuery(true)
			->select('id, activation, username, email, block')
			->from('#__users')
			->where('username IN(' . implode(',', array_map(array($db, 'quote'), $localUsernameChecks)) . ')'
				. ' OR email = ' . $db->quote($email)
			);

		$db->setQuery($query);

		if ($localUsers = $db->loadObjectList())
		{
			foreach ($localUsers as $localUser)
			{
				// Local user exists with same username but different email address
				if ($email !== $localUser->email)
				{
					$response->status        = JAuthentication::STATUS_FAILURE;
					$response->error_message = JText::sprintf('JGLOBAL_AUTH_FAILED', JText::_('PLG_GMAIL_ERROR_LOCAL_USERNAME_CONFLICT'));

					return;
				}
				else
				{
					// Existing user disabled locally
					if ($localUser->block || !empty($localUser->activation))
					{
						$response->status        = JAuthentication::STATUS_FAILURE;
						$response->error_message = JText::_('JGLOBAL_AUTH_ACCESS_DENIED');

						return;
					}

					// We will always keep the local username for existing accounts
					$credentials['username'] = $localUser->username;

					break;
				}
			}
		}
		elseif (JFactory::getApplication()->isClient('administrator'))
		{
			// We wont' allow backend access without local account
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JERROR_LOGIN_DENIED');

			return;
		}

		$response->status        = JAuthentication::STATUS_SUCCESS;
		$response->error_message = '';
		$response->email         = $email;

		// Reset the username to what we ended up using
		$response->username = $credentials['username'];
		$response->fullname = $credentials['username'];
	}
}
PK��#]��,	,	authentication/gmail/gmail.xmlnu�[���<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin" group="authentication" method="upgrade">
	<name>plg_authentication_gmail</name>
	<author>Joomla! Project</author>
	<creationDate>February 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_GMAIL_XML_DESCRIPTION</description>
	<files>
		<filename plugin="gmail">gmail.php</filename>
	</files>
	<languages>
		<language tag="en-GB">en-GB.plg_authentication_gmail.ini</language>
		<language tag="en-GB">en-GB.plg_authentication_gmail.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="applysuffix"
					type="list"
					label="PLG_GMAIL_FIELD_APPLYSUFFIX_LABEL"
					description="PLG_GMAIL_FIELD_APPLYSUFFIX_DESC"
					default="0"
					filter="integer"
					>
					<option value="0">PLG_GMAIL_FIELD_VALUE_NOAPPLYSUFFIX</option>
					<option value="1">PLG_GMAIL_FIELD_VALUE_APPLYSUFFIXMISSING</option>
					<option value="2">PLG_GMAIL_FIELD_VALUE_APPLYSUFFIXALWAYS</option>
				</field>

				<field
					name="suffix"
					type="text"
					label="PLG_GMAIL_FIELD_SUFFIX_LABEL"
					description="PLG_GMAIL_FIELD_SUFFIX_DESC"
					size="20"
					showon="applysuffix:1,2"
				/>

				<field
					name="verifypeer"
					type="radio"
					label="PLG_GMAIL_FIELD_VERIFYPEER_LABEL"
					description="PLG_GMAIL_FIELD_VERIFYPEER_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="user_blacklist"
					type="text"
					label="PLG_GMAIL_FIELD_USER_BLACKLIST_LABEL"
					description="PLG_GMAIL_FIELD_USER_BLACKLIST_DESC"
					size="20"
				/>

				<field
					name="backendLogin"
					type="radio"
					label="PLG_GMAIL_FIELD_BACKEND_LOGIN_LABEL"
					description="PLG_GMAIL_FIELD_BACKEND_LOGIN_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JENABLED</option>
					<option value="0">JDISABLED</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
PK��#]�)��authentication/gmail/.htaccessnu��6�$<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK��#]�)��actionlog/joomla/.htaccessnu��6�$PK��#]�>[>�s�s�actionlog/joomla/joomla.phpnu�[���PK��#]7K�Xuactionlog/joomla/joomla.xmlnu�[���PK��#]�)��ixactionlog/.htaccessnu��6�$PK��#]|��N!+yactionlog/akeebabackup/web.confignu�[���PK��#]�)�� �{actionlog/akeebabackup/.htaccessnu��6�$PK��#]NH���!`|actionlog/akeebabackup/script.phpnu�[���PK��#]�/���*�*'�~actionlog/akeebabackup/akeebabackup.phpnu�[���PK��#]���/��'ݩactionlog/akeebabackup/akeebabackup.xmlnu�[���PK��#]�)����console/.htaccessnu��6�$PK��#]�fɯ�finder/tags/tags.xmlnu�[���PK��#]���5%5%۲finder/tags/tags.phpnu�[���PK��#]�)��T�finder/tags/.htaccessnu��6�$PK��#]�)���finder/content/.htaccessnu��6�$PK��#]m�jk++��finder/content/content.phpnu�[���PK��#]n��!(()finder/content/content.xmlnu�[���PK��#]�)���finder/contacts/.htaccessnu��6�$PK��#]�m�7070c	finder/contacts/contacts.phpnu�[���PK��#]���..�9finder/contacts/contacts.xmlnu�[���PK��#]2���*�* `=finder/categories/categories.phpnu�[���PK��#]�y~:: 2hfinder/categories/categories.xmlnu�[���PK��#]�)���kfinder/categories/.htaccessnu��6�$PK��#]�)���lfinder/.htaccessnu��6�$PK��#]�
=��'�'Emfinder/newsfeeds/newsfeeds.phpnu�[���PK��#]���44A�finder/newsfeeds/newsfeeds.xmlnu�[���PK��#]�)��Øfinder/newsfeeds/.htaccessnu��6�$PK��#]�)����captcha/.htaccessnu��6�$PK��#]Æ��
�
3L�captcha/recaptcha_invisible/recaptcha_invisible.xmlnu�[���PK��#]��y��3��captcha/recaptcha_invisible/recaptcha_invisible.phpnu�[���PK��#]�)��%һcaptcha/recaptcha_invisible/.htaccessnu��6�$PK��#]�-4�)��captcha/recaptcha/postinstall/actions.phpnu�[���PK��#]�)���captcha/recaptcha/.htaccessnu��6�$PK��#]����captcha/recaptcha/recaptcha.xmlnu�[���PK��#]9t�V&V&A�captcha/recaptcha/recaptcha.phpnu�[���PK��#]�)���content/pagebreak/.htaccessnu��6�$PK��#]f ph����content/pagebreak/tmpl/toc.phpnu�[���PK��#]�54س�%�content/pagebreak/tmpl/navigation.phpnu�[���PK��#]��^�content/pagebreak/pagebreak.xmlnu�[���PK��#]}$*�%�%bcontent/pagebreak/pagebreak.phpnu�[���PK��#]�)���5content/contact/.htaccessnu��6�$PK��#]=�S���n6content/contact/contact.phpnu�[���PK��#]�=�bb�Ccontent/contact/contact.xmlnu�[���PK��#]�)��^Jcontent/loadmodule/.htaccessnu��6�$PK��#]�[z6��!)Kcontent/loadmodule/loadmodule.xmlnu�[���PK��#]Ձ�$��!Qcontent/loadmodule/loadmodule.phpnu�[���PK��#]�)��*lcontent/.htaccessnu��6�$PK��#]�F�3�lcontent/jce/jce.phpnu�[���PK��#]�Ȭ��5ocontent/jce/jce.xmlnu�[���PK��#]�)���rcontent/jce/.htaccessnu��6�$PK��#]�<���scontent/jce/css/media.cssnu&1i�PK��#]�#o,,�tcontent/jce/css/index.htmlnu&1i�PK��#]�)��=ucontent/readlesstext/.htaccessnu��6�$PK��#]q��e�]�]*
vcontent/readlesstext/readlesstextthumb.phpnu�[���PK��#]Jp!��m�m+�content/readlesstext/readlesstexthelper.phpnu�[���PK��#]Q�=�� � �Acontent/readlesstext/script.phpnu�[���PK��#]b%J�^�^�)%ccontent/readlesstext/readlesstextmain.phpnu�[���PK��#]D�c6ee*�Pcontent/readlesstext/readlesstextcache.phpnu�[���PK��#]Ō��%�%J�hcontent/readlesstext/language/en-GB/en-GB.plg_content_readlesstext.sys.ininu�[���PK��#]�h��a�a�F�content/readlesstext/language/en-GB/en-GB.plg_content_readlesstext.ininu�[���PK��#]��T���J�gcontent/readlesstext/language/nl-NL/nl-NL.plg_content_readlesstext.sys.ininu�[���PK��#]܍4<��F�pcontent/readlesstext/language/nl-NL/nl-NL.plg_content_readlesstext.ininu�[���PK��#])�O
�
�
%Ypcontent/readlesstext/readlesstext.phpnu�[���PK��#]��N�
`
`%V~content/readlesstext/readlesstext.xmlnu�[���PK��#]ʹ���+��content/readlesstext/readlesstextexpand.phpnu�[���PK��#]��`�jj��content/vote/vote.phpnu�[���PK��#]m*�~~{content/vote/vote.xmlnu�[���PK��#]^�y��>content/vote/tmpl/vote.phpnu�[���PK��#]'��ww7
content/vote/tmpl/rating.phpnu�[���PK��#]�)���content/vote/.htaccessnu��6�$PK��#]�)���content/emailcloak/.htaccessnu��6�$PK��#](q���!�content/emailcloak/emailcloak.xmlnu�[���PK��#]tKh��D�D!�content/emailcloak/emailcloak.phpnu�[���PK��#]�)���_content/finder/.htaccessnu��6�$PK��#]c|����`content/finder/finder.phpnu�[���PK��#]4M�FF�pcontent/finder/finder.xmlnu�[���PK��#]�)�� jtcontent/confirmconsent/.htaccessnu��6�$PK��#]�5�77)9ucontent/confirmconsent/confirmconsent.xmlnu�[���PK��#]�p�|��)�{content/confirmconsent/confirmconsent.phpnu�[���PK��#]P�Ltt,�content/confirmconsent/fields/consentbox.phpnu�[���PK��#]�)��؞content/rsform/.htaccessnu��6�$PK��#]�#o,,��content/rsform/index.htmlnu�[���PK��#]�5JJ�content/rsform/script.phpnu�[���PK��#]�S@##��content/rsform/rsform.xmlnu�[���PK��#]��}r

�content/rsform/rsform.phpnu�[���PK��#]'/�"�"d�content/joomla/joomla.phpnu�[���PK��#]�|f..��content/joomla/joomla.xmlnu�[���PK��#]�)���content/joomla/.htaccessnu��6�$PK��#]�)����content/fields/.htaccessnu��6�$PK��#]��ig``��content/fields/fields.phpnu�[���PK��#]���qqP�content/fields/fields.xmlnu�[���PK��#]�)�� 
�content/pagenavigation/.htaccessnu��6�$PK��#]@4'�content/pagenavigation/tmpl/default.phpnu�[���PK��#]f�;��)�content/pagenavigation/pagenavigation.xmlnu�[���PK��#]:k��)�content/pagenavigation/pagenavigation.phpnu�[���PK��#]1���MM(T)system/privacyconsent/privacyconsent.phpnu�[���PK��#]�UqGJ
J
(�vsystem/privacyconsent/privacyconsent.xmlnu�[���PK��#]��ɢ�
�
'T�system/privacyconsent/field/privacy.phpnu�[���PK��#]�)��>�system/privacyconsent/.htaccessnu��6�$PK��#]�h=::7�system/privacyconsent/privacyconsent/privacyconsent.xmlnu�[���PK��#]��&�V-V-0��system/updatenotification/updatenotification.phpnu�[���PK��#]�Z::0c�system/updatenotification/updatenotification.xmlnu�[���PK��#]�����9��system/updatenotification/postinstall/updatecachetime.phpnu�[���PK��#]�)��#��system/updatenotification/.htaccessnu��6�$PK��#]�)����system/redirect/.htaccessnu��6�$PK��#]1�r��!��system/redirect/form/excludes.xmlnu�[���PK��#]-LS�TT��system/redirect/redirect.xmlnu�[���PK��#]�6j�%&%&L�system/redirect/redirect.phpnu�[���PK��#]�)����system/logout/.htaccessnu��6�$PK��#][�G%�
�
��system/logout/logout.phpnu�[���PK��#]��C��
	system/logout/logout.xmlnu�[���PK��#]�)���
	system/p3p/.htaccessnu��6�$PK��#]�!$$�	system/p3p/p3p.xmlnu�[���PK��#]�g��	system/p3p/p3p.phpnu�[���PK��#]~��[{
{
!�	system/rsfprecaptchav2/script.phpnu�[���PK��#]�)�� �!	system/rsfprecaptchav2/.htaccessnu��6�$PK��#]
J���.f"	system/rsfprecaptchav2/forms/configuration.xmlnu�[���PK��#]�#o,,!�'	system/rsfprecaptchav2/index.htmlnu�[���PK��#]�#o,,+6(	system/rsfprecaptchav2/sql/mysql/index.htmlnu�[���PK��#]m�kk.�(	system/rsfprecaptchav2/sql/mysql/uninstall.sqlnu�[���PK��#]���dd,�*	system/rsfprecaptchav2/sql/mysql/install.sqlnu�[���PK��#]�#o,,%F0	system/rsfprecaptchav2/sql/index.htmlnu�[���PK��#]m�L��*�0	system/rsfprecaptchav2/rsfprecaptchav2.xmlnu�[���PK��#]eo���
�
*7	system/rsfprecaptchav2/rsfprecaptchav2.phpnu�[���PK��#]�)��.E	system/remember/.htaccessnu��6�$PK��#]q!����=�E	system/remember/plugin_googlemap2/plugin_googlemap2_proxy.phpnu�[���PK��#]|�wfK�K�)R	system/remember/plugin_googlemap2/gpl.txtnu�[���PK��#]�F�=h=h>��	system/remember/plugin_googlemap2/plugin_googlemap2_helper.phpnu�[���PK��#]r��88,PDsystem/remember/plugin_googlemap2/index.htmlnu�[���PK��#]�
�O.O.C�Dsystem/remember/plugin_googlemap2/plugin_googlemap2_twitter_kml.phpnu�[���PK��#]��d�5�57�ssystem/remember/plugin_googlemap2/plugin_googlemap2.phpnu�[���PK��#]�y5	5	7ͩsystem/remember/plugin_googlemap2/plugin_googlemap2.xmlnu�[���PK��#]���
�
i�
system/remember/remember.phpnu�[���PK��#]�-��<�
system/remember/remember.xmlnu�[���PK��#]�
��� ��
system/admintools/autoloader.phpnu&1i�PK��#]騸S��'��
system/admintools/feature/httpsizer.phpnu&1i�PK��#]dm+'�
system/admintools/feature/criticalfiles.phpnu&1i�PK��#]�gt���'��
system/admintools/feature/apache401.phpnu&1i�PK��#]V٘X��*�
system/admintools/feature/awayschedule.phpnu&1i�PK��#],.��&&*�system/admintools/feature/wafblacklist.phpnu&1i�PK��#]�0�OSS+'system/admintools/feature/linkmigration.phpnu&1i�PK��#]�W�

'�'system/admintools/feature/rfishield.phpnu&1i�PK��#]1�j��&K5system/admintools/feature/badwords.phpnu&1i�PK��#]b�4��/V<system/admintools/feature/blockemaildomains.phpnu&1i�PK��#]NQ��>>)gBsystem/admintools/feature/customblock.phpnu&1i�PK��#]6�N++-�Esystem/admintools/feature/autoipfiltering.phpnu&1i�PK��#]�$##'�Rsystem/admintools/feature/cleantemp.phpnu&1i�PK��#]�tH�ww%Ysystem/admintools/feature/utf8mb4.phpnu&1i�PK��#]��ν--,�]system/admintools/feature/superuserslist.phpnu&1i�PK��#]ZD�%""-+�system/admintools/feature/projecthoneypot.phpnu&1i�PK��#]^v�$$,��system/admintools/feature/templateswitch.phpnu&1i�PK��#]����
�
)*�system/admintools/feature/ipblacklist.phpnu&1i�PK��#]�#a/$�system/admintools/feature/customadminfolder.phpnu&1i�PK��#]��\f)��system/admintools/feature/nonewadmins.phpnu&1i�PK��#]zɃ%��+�system/admintools/feature/sessionshield.phpnu&1i�PK��#]�m&uR	R	.$�system/admintools/feature/saveusersignupip.phpnu&1i�PK��#]��>�11)��system/admintools/feature/nofesalogin.phpnu&1i�PK��#]\x��$$1^�system/admintools/feature/thirdpartyexception.phpnu&1i�PK��#]�o���)�system/admintools/feature/ipwhitelist.phpnu&1i�PK��#]��A��,%�system/admintools/feature/deleteinactive.phpnu&1i�PK��#]��[dII(system/admintools/feature/sqlishield.phpnu&1i�PK��#]�0�\��(�system/admintools/feature/csrfshield.phpnu&1i�PK��#]"���	�	'�!system/admintools/feature/phpshield.phpnu&1i�PK��#]�3����,�+system/admintools/feature/resetjoomlatfa.phpnu&1i�PK��#]D$.]AA*�0system/admintools/feature/cachecleaner.phpnu&1i�PK��#]��~���*@6system/admintools/feature/emailonlogin.phpnu&1i�PK��#]��G��*EHsystem/admintools/feature/removeoldlog.phpnu&1i�PK��#]|��%%&�Msystem/admintools/feature/abstract.phpnu&1i�PK��#]�����(�rsystem/admintools/feature/tmplswitch.phpnu&1i�PK��#]i\k,>xsystem/admintools/feature/sessioncleaner.phpnu&1i�PK��#]R^�4��(~system/admintools/feature/secretword.phpnu&1i�PK��#]0y���*b�system/admintools/feature/uploadshield.phpnu&1i�PK��#]x��UU+��system/admintools/feature/configmonitor.phpnu&1i�PK��#]o]�992U�system/admintools/feature/emailfailedadminlong.phpnu&1i�PK��#]��u		/��system/admintools/feature/trackfailedlogins.phpnu&1i�PK��#]���6RR'X�system/admintools/feature/dfishield.phpnu&1i�PK��#]cOO
O
'�system/admintools/feature/muashield.phpnu&1i�PK��#]�>���(�system/admintools/feature/quickstart.phpnu&1i�PK��#]tD����)�system/admintools/feature/selfprotect.phpnu&1i�PK��#]���ֈ�&�system/admintools/feature/urlredir.phpnu&1i�PK��#]�oQ�)�*system/admintools/feature/cacheexpire.phpnu&1i�PK��#]���iB
B
./system/admintools/feature/sessionoptimiser.phpnu&1i�PK��#]�r�4}}-�9system/admintools/feature/customgenerator.phpnu&1i�PK��#]5d��&�@system/admintools/feature/geoblock.phpnu&1i�PK��#]���cc,Isystem/admintools/util/exceptionshandler.phpnu&1i�PK��#]���Z!Z!!{�system/admintools/util/filter.phpnu&1i�PK��#]�5x::'&�system/admintools/admintools/index.htmlnu&1i�PK��#]B`��K�K%��system/admintools/admintools/main.phpnu&1i�PK��#]�Nwy^^ �system/admintools/admintools.phpnu&1i�PK��#]�)��M"system/admintools/.htaccessnu��6�$PK��#]h9?HH #system/admintools/admintools.xmlnu&1i�PK��#]�)���4system/logrotation/.htaccessnu��6�$PK��#]X�/9��"z5system/logrotation/logrotation.phpnu�[���PK��#]�g�##"NNsystem/logrotation/logrotation.xmlnu�[���PK��#]W�ާ��:�Tsystem/rsformdeletesubmissions/rsformdeletesubmissions.phpnu�[���PK��#]�/�zz:�asystem/rsformdeletesubmissions/rsformdeletesubmissions.xmlnu�[���PK��#]�)��(�fsystem/rsformdeletesubmissions/.htaccessnu��6�$PK��#]�#o,,)wgsystem/rsformdeletesubmissions/index.htmlnu�[���PK��#](���*�*0�gsystem/atoolsjupdatecheck/atoolsjupdatecheck.phpnu&1i�PK��#]��7��0+�system/atoolsjupdatecheck/atoolsjupdatecheck.xmlnu&1i�PK��#]�)��#)�system/atoolsjupdatecheck/.htaccessnu��6�$PK��#]~�����system/log/log.phpnu�[���PK��#]�$K��E�system/log/log.xmlnu�[���PK��#]�)��%�system/log/.htaccessnu��6�$PK��#]n*mf  �system/sef/sef.xmlnu�[���PK��#]?>� ��J�system/sef/sef.phpnu�[���PK��#]�)���system/sef/.htaccessnu��6�$PK��#]�)����system/.htaccessnu��6�$PK��#]�)����system/stats/.htaccessnu��6�$PK��#]�+Nbb[�system/stats/stats.xmlnu�[���PK��#]vc1��1�1�system/stats/stats.phpnu�[���PK��#]֙Q system/stats/layouts/message.phpnu�[���PK��#]_�mlffj	system/stats/layouts/stats.phpnu�[���PK��#]oT=		'
system/stats/layouts/field/uniqueid.phpnu�[���PK��#]�e����#|system/stats/layouts/field/data.phpnu�[���PK��#]G!E����system/stats/field/data.phpnu�[���PK��#]�V����$system/stats/field/base.phpnu�[���PK��#]EN8���'system/stats/field/uniqueid.phpnu�[���PK��#]a6��*system/cache/cache.xmlnu�[���PK��#]�~�cc�1system/cache/cache.phpnu�[���PK��#]�)��kHsystem/cache/.htaccessnu��6�$PK��#]r��88#0Isystem/plugin_googlemap2/index.htmlnu�[���PK��#]q!����4�Isystem/plugin_googlemap2/plugin_googlemap2_proxy.phpnu�[���PK��#]�F�=h=h5�Usystem/plugin_googlemap2/plugin_googlemap2_helper.phpnu�[���PK��#]�)��"_�system/plugin_googlemap2/.htaccessnu��6�$PK��#]��d�5�5.0�system/plugin_googlemap2/plugin_googlemap2.phpnu�[���PK��#]�y5	5	.N�system/plugin_googlemap2/plugin_googlemap2.xmlnu�[���PK��#]|�wfK�K� �system/plugin_googlemap2/gpl.txtnu�[���PK��#]�
�O.O.:|�system/plugin_googlemap2/plugin_googlemap2_twitter_kml.phpnu�[���PK��#]|��� 5�system/backuponupdate/script.phpnu�[���PK��#]�)��t�system/backuponupdate/.htaccessnu��6�$PK��#]��"�(�((B�system/backuponupdate/backuponupdate.phpnu�[���PK��#]#�,���(��system/backuponupdate/backuponupdate.xmlnu�[���PK��#]|��N ��system/backuponupdate/web.confignu�[���PK��#]sPw��,�system/sessiongc/sessiongc.xmlnu�[���PK��#]ҽ�F��Z�system/sessiongc/sessiongc.phpnu�[���PK��#]�)��q�system/sessiongc/.htaccessnu��6�$PK��#]�)��:�system/debug/.htaccessnu��6�$PK��#]�i�>>��system/debug/debug.xmlnu�[���PK��#]�+Gb�b��system/debug/debug.phpnu�[���PK��#]��W8�2�2+�system/fields/fields.phpnu�[���PK��#]W���psystem/fields/fields.xmlnu�[���PK��#]�)���system/fields/.htaccessnu��6�$PK��#]�)���system/akversioncheck/.htaccessnu��6�$PK��#]��Kf�� Rsystem/akversioncheck/script.phpnu�[���PK��#]@�؍FF(�system/akversioncheck/akversioncheck.xmlnu�[���PK��#]�Q�^p^p(/ system/akversioncheck/akversioncheck.phpnu�[���PK��#]{�͠�%�system/bfnetwork/bfnetwork/bfStep.phpnu�[���PK��#]%{ż"ڟsystem/bfnetwork/bfnetwork/VERSIONnu�[���PK��#]�i��41�system/bfnetwork/bfnetwork/bfApplicationMyjoomla.phpnu�[���PK��#]M���"��system/bfnetwork/bfnetwork/HOST_IDnu�[���PK��#]ƛ�%''&�system/bfnetwork/bfnetwork/openssl.cnfnu�[���PK��#]����&n�system/bfnetwork/bfnetwork/bfTimer.phpnu�[���PK��#]*Y&�Q�Q�)��system/bfnetwork/bfnetwork/bfSnapshot.phpnu�[���PK��#]|�wfK�K�"X|system/bfnetwork/bfnetwork/LICENSEnu�[���PK��#]�+�37374�system/bfnetwork/bfnetwork/lib/download/download.phpnu�[���PK��#]�i�;;9�=system/bfnetwork/bfnetwork/lib/download/adapter/fopen.phpnu�[���PK��#]�<�>>80Qsystem/bfnetwork/bfnetwork/lib/download/adapter/curl.phpnu�[���PK��#]�0����<�msystem/bfnetwork/bfnetwork/lib/download/adapter/abstract.phpnu�[���PK��#]�p
���5	�system/bfnetwork/bfnetwork/lib/download/interface.phpnu�[���PK��#]��@߲�.9�system/bfnetwork/bfnetwork/lib/timer/timer.phpnu�[���PK��#]5��8DD(I�system/bfnetwork/bfnetwork/lib/.htaccessnu�[���PK��#]��TA�4�4H�system/bfnetwork/bfnetwork/lib/update/provider/collection/collection.phpnu�[���PK��#]���r<M<M@6�system/bfnetwork/bfnetwork/lib/update/provider/joomla/joomla.phpnu�[���PK��#]�s�N� � O�3system/bfnetwork/bfnetwork/lib/AdminTools/Model/AdminPassword/AdminPassword.phpnu�[���PK��#]L�4]%%-:Usystem/bfnetwork/bfnetwork/lib/autoloader.phpnu�[���PK��#]�I���,�dsystem/bfnetwork/bfnetwork/bfWorkarounds.phpnu�[���PK��#]92�#nsystem/bfnetwork/bfnetwork/FIRSTRUNnu�[���PK��#]�%�Ύ�"�rsystem/bfnetwork/bfnetwork/MD5SUMSnu�[���PK��#]�lQ((!a�system/bfnetwork/bfnetwork/READMEnu�[���PK��#]kH�&**+ډsystem/bfnetwork/bfnetwork/bfInitJoomla.phpnu�[���PK��#]3+}DD,_�system/bfnetwork/bfnetwork/bfPreferences.phpnu�[���PK��#]5��8DD'��system/bfnetwork/bfnetwork/db/.htaccessnu�[���PK��#]����;�;�.��system/bfnetwork/bfnetwork/db/suspectfiles.txtnu�[���PK��#]��d
d
'3Zsystem/bfnetwork/bfnetwork/db/blank.sqlnu�[���PK��#],~��(�dsystem/bfnetwork/bfnetwork/bfVersion.phpnu�[���PK��#];
r ��+Jlsystem/bfnetwork/bfnetwork/Keys/private.keynu�[���PK��#]��;*%psystem/bfnetwork/bfnetwork/Keys/public.keynu�[���PK��#]5��8DD)�qsystem/bfnetwork/bfnetwork/Keys/.htaccessnu�[���PK��#]/��DXZXZ'.rsystem/bfnetwork/bfnetwork/bfPlugin.phpnu�[���PK��#]�#X%��system/bfnetwork/bfnetwork/bfPing.phpnu�[���PK��#]Aa��ff&I�system/bfnetwork/bfnetwork/bfTools.phpnu�[���PK��#]�fl��.�system/bfnetwork/bfnetwork/Math/BigInteger.phpnu�[���PK��#]5��8DD)o�!system/bfnetwork/bfnetwork/Math/.htaccessnu�[���PK��#]J��OJOJ(�!system/bfnetwork/bfnetwork/bfEncrypt.phpnu�[���PK��#]�RI�$�/"system/bfnetwork/bfnetwork/bfLog.phpnu�[���PK��#]$=�_��&I"system/bfnetwork/bfnetwork/bfAudit.phpnu�[���PK��#]�P��#�#'2Q"system/bfnetwork/bfnetwork/bfConfig.phpnu�[���PK��#]����&�&+�u"system/bfnetwork/bfnetwork/bfFilesystem.phpnu�[���PK��#]��O1[1[$��"system/bfnetwork/bfnetwork/bfZip.phpnu�[���PK��#](�F�gSgS+'�%system/bfnetwork/bfnetwork/bfExtensions.phpnu�[���PK��#]/c5�&�K&system/bfnetwork/bfnetwork/tmp/log.phpnu�[���PK��#]�A�D��(OL&system/bfnetwork/bfnetwork/tmp/index.phpnu�[���PK��#]}��u  2GQ&system/bfnetwork/bfnetwork/tmp/tmp.pattern.lastmd5nu�[���PK��#]g����(�Q&system/bfnetwork/bfnetwork/tmp/STATE.phpnu�[���PK��#]5��8DD(��)system/bfnetwork/bfnetwork/tmp/.htaccessnu�[���PK��#]�J_;@�@�*<�)system/bfnetwork/bfnetwork/tmp/tmp.patternnu�[���PK��#]�\���0�f*system/bfnetwork/bfnetwork/tmp/bfLocalConfig.phpnu�[���PK��#]�L(�QQ(�g*system/bfnetwork/bfnetwork/bfUpgrade.phpnu�[���PK��#]�����1E�*system/bfnetwork/bfnetwork/bfUpgradeConnector.phpnu�[���PK��#]m���O O ,��*system/bfnetwork/bfnetwork/bfActivitylog.phpnu�[���PK��#]!ȩn��5H�*system/bfnetwork/bfnetwork/bfPHPFiveThreePlusOnly.phpnu�[���PK��#]�A�%��*system/bfnetwork/bfnetwork/bfPref.phpnu�[���PK��#]�C��=
=
*+system/bfnetwork/bfnetwork/bfAutologin.phpnu�[���PK��#]T�;(�+system/bfnetwork/bfnetwork/bfUpdates.phpnu�[���PK��#]�ph��'	#+system/bfnetwork/bfnetwork/bfBackup.phpnu�[���PK��#]��imm(B+system/bfnetwork/bfnetwork/bfRestore.phpnu�[���PK��#]l>��+�+)�P/system/bfnetwork/bfnetwork/Crypt/Base.phpnu�[���PK��#]%��A�"�"(�|0system/bfnetwork/bfnetwork/Crypt/RC4.phpnu�[���PK��#]�IVB/n/n)�0system/bfnetwork/bfnetwork/Crypt/Hash.phpnu�[���PK��#]}���(v1system/bfnetwork/bfnetwork/Crypt/RSA.phpnu�[���PK��#]5��8DD*��2system/bfnetwork/bfnetwork/Crypt/.htaccessnu�[���PK��#]]ni){6{6+N�2system/bfnetwork/bfnetwork/Crypt/Random.phpnu�[���PK��#]:

&$�2system/bfnetwork/bfnetwork/bfError.phpnu�[���PK��#]�Џ�E�E�(��2system/bfnetwork/bfnetwork/bfAuditor.phpnu�[���PK��#]p��(6�4system/bfnetwork/bfnetwork/bfnetwork.phpnu�[���PK��#]8�lJ����4system/bfnetwork/bfnetwork.phpnu�[���PK��#]<�U\"\"&l�4system/bfnetwork/install.bfnetwork.phpnu�[���PK��#]7u�˹��4system/bfnetwork/bfnetwork.xmlnu�[���PK��#]�)��%5system/bfnetwork/.htaccessnu��6�$PK��#]�#o,,�5system/rsform/index.htmlnu�[���PK��#],:�b5system/rsform/rsform.xmlnu�[���PK��#]0МTUU�5system/rsform/rsform.phpnu�[���PK��#]�)��b5system/rsform/.htaccessnu��6�$PK��#]�x�.��$(5system/languagecode/languagecode.xmlnu�[���PK��#]�}`$m5system/languagecode/languagecode.phpnu�[���PK��#]�����D�+5system/languagecode/language/en-GB/en-GB.plg_system_languagecode.ininu�[���PK��#]o���H�/5system/languagecode/language/en-GB/en-GB.plg_system_languagecode.sys.ininu�[���PK��#]�)���15system/languagecode/.htaccessnu��6�$PK��#]���/�/ �25system/actionlogs/actionlogs.phpnu�[���PK��#]؞��� �b5system/actionlogs/actionlogs.xmlnu�[���PK��#]��<__&�g5system/actionlogs/forms/actionlogs.xmlnu�[���PK��#]�����'�k5system/actionlogs/forms/information.xmlnu�[���PK��#]�)���m5system/actionlogs/.htaccessnu��6�$PK��#]�)��Yn5system/languagefilter/.htaccessnu��6�$PK��#]�ա�b�b('o5system/languagefilter/languagefilter.phpnu�[���PK��#]aVOuss(�5system/languagefilter/languagefilter.xmlnu�[���PK��#]�R��((��5system/jce/js/media.jsnu�[���PK��#]��}�]],
6system/jce/jce.xmlnu�[���PK��#]mP��$($(�6system/jce/jce.phpnu�[���PK��#]#P]3LL 186system/jce/templates/astroid.phpnu�[���PK��#]t:+���<6system/jce/templates/wright.phpnu�[���PK��#]S��OO!�@6system/jce/templates/yootheme.phpnu�[���PK��#]��:���H6system/jce/templates/gantry.phpnu�[���PK��#]���A��!�U6system/jce/templates/joomlart.phpnu�[���PK��#]$�bb�Z6system/jce/templates/helix.phpnu�[���PK��#]���ˤ�b_6system/jce/templates/core.phpnu�[���PK��#]L���Se6system/jce/templates/sun.phpnu�[���PK��#]�)���j6system/jce/.htaccessnu��6�$PK��#]b��O* * Rk6system/jce/css/content.cssnu�[���PK��#]9�YY<	<	Ƌ6system/jce/css/media.cssnu�[���PK��#]����__"J�6system/jcemediabox/jcemediabox.phpnu&1i�PK��#]6���"��6system/jcemediabox/jcemediabox.xmlnu&1i�PK��#]�)���6system/jcemediabox/.htaccessnu��6�$PK��#]�#o,,!��6system/jcemediabox/css/index.htmlnu&1i�PK��#]�O]e""&b�6system/jcemediabox/css/jcemediabox.cssnu&1i�PK��#]��T�w`w`*��6system/jcemediabox/css/jcemediabox.min.cssnu�[���PK��#]���}��&�B7system/jcemediabox/img/broken-page.pngnu&1i�PK��#]#��#�U7system/jcemediabox/img/zoom-img.pngnu&1i�PK��#]�h�Lj�(�\7system/jcemediabox/img/loader-shadow.gifnu�[���PK��#]`&h�zz$�i7system/jcemediabox/img/zoom-link.gifnu&1i�PK��#]
�7��'�j7system/jcemediabox/img/broken-media.pngnu&1i�PK��#]�@��
�
'�s7system/jcemediabox/img/loader-light.gifnu�[���PK��#]"C�+JJ'�~7system/jcemediabox/img/broken-image.pngnu&1i�PK��#]J��r(i�7system/jcemediabox/img/loader-circle.gifnu�[���PK��#]t�M++ Ǜ7system/jcemediabox/img/blank.gifnu&1i�PK��#]�#o,,!B�7system/jcemediabox/img/index.htmlnu&1i�PK��#]i��}
}
(��7system/jcemediabox/fields/components.phpnu�[���PK��#]T%r����(��7system/jcemediabox/js/jcemediabox.min.jsnu�[���PK��#]�{�/�O�O(�8system/jcemediabox/js/jcemediabox-src.jsnu&1i�PK��#]�#o,, ��:system/jcemediabox/js/index.htmlnu&1i�PK��#])S�R����$
�:system/jcemediabox/js/jcemediabox.jsnu&1i�PK��#]�)��T�;system/highlight/.htaccessnu��6�$PK��#]#�K<<�;system/highlight/highlight.phpnu�[���PK��#];��f44��;system/highlight/highlight.xmlnu�[���PK��#]�)��)�;user/joomla/.htaccessnu��6�$PK��#]m�_�))�;user/joomla/joomla.phpnu�[���PK��#]���B�;user/joomla/joomla.xmlnu�[���PK��#]�)����;user/profile/.htaccessnu��6�$PK��#]��i�;4;4\�;user/profile/profile.phpnu�[���PK��#]̨h)x'x'�'<user/profile/profile.xmlnu�[���PK��#]!�*����O<user/profile/field/dob.phpnu�[���PK��#]*��U<user/profile/field/tos.phpnu�[���PK��#]�uH!d<user/profile/profiles/profile.xmlnu�[���PK��#]�)��xo<user/contactcreator/.htaccessnu��6�$PK��#]6�^�kk&Dp<user/contactcreator/contactcreator.xmlnu�[���PK��#]]��c��&w<user/contactcreator/contactcreator.phpnu�[���PK��#]&����<user/terms/terms/terms.xmlnu�[���PK��#]�r
���<user/terms/field/terms.phpnu�[���PK��#]�*����7�<user/terms/terms.xmlnu�[���PK��#]�+''b�<user/terms/terms.phpnu�[���PK��#]�)��ͯ<user/terms/.htaccessnu��6�$PK��#]�)����<user/.htaccessnu��6�$PK��#]�)��M�<qmap/.htaccessnu��6�$PK��#]�)��
�<qmap/content/.htaccessnu��6�$PK��#]���Ȗ�ϲ<qmap/content/content.phpnu�[���PK��#]]�qc��<qmap/content/content.xmlnu�[���PK��#]3V��;;��<qmap/menu/menu.phpnu�[���PK��#]�l��r�<qmap/menu/menu.xmlnu�[���PK��#]�)����<qmap/menu/.htaccessnu��6�$PK��#]�		m�<qmap/categories/categories.xmlnu�[���PK��#]�
d{{��<qmap/categories/categories.phpnu�[���PK��#]�)����<qmap/categories/.htaccessnu��6�$PK��#]�w�R�	�	'U�<fields/repeatable/params/repeatable.xmlnu�[���PK��#]N���� t�<fields/repeatable/repeatable.phpnu�[���PK��#]q.�)nn ��<fields/repeatable/repeatable.xmlnu�[���PK��#]���??%]�<fields/repeatable/tmpl/repeatable.phpnu�[���PK��#]�)����<fields/repeatable/.htaccessnu��6�$PK��#]{Rx  ��<fields/list/list.phpnu�[���PK��#]�e��<fields/list/list.xmlnu�[���PK��#]oƔ�##y�<fields/list/params/list.xmlnu�[���PK��#]�)���<fields/list/.htaccessnu��6�$PK��#]�ӃZXX��<fields/list/tmpl/list.phpnu�[���PK��#]�)��L�<fields/radio/.htaccessnu��6�$PK��#]�%_iTT�<fields/radio/tmpl/radio.phpnu�[���PK��#]~щ�		�=fields/radio/radio.xmlnu�[���PK��#]/P�#���=fields/radio/radio.phpnu�[���PK��#]�ʗ���
=fields/radio/params/radio.xmlnu�[���PK��#]�E!���T=fields/color/tmpl/color.phpnu�[���PK��#]1�?2=fields/color/color.xmlnu�[���PK��#]Y�		�=fields/color/color.phpnu�[���PK��#]�)���=fields/color/.htaccessnu��6�$PK��#]!��D!�=fields/integer/params/integer.xmlnu�[���PK��#]�)���=fields/integer/.htaccessnu��6�$PK��#]t�޽��=fields/integer/tmpl/integer.phpnu�[���PK��#],q����=fields/integer/integer.phpnu�[���PK��#](�-tt�!=fields/integer/integer.xmlnu�[���PK��#]�)���)=fields/.htaccessnu��6�$PK��#]�ٸYvv%X*=fields/checkboxes/tmpl/checkboxes.phpnu�[���PK��#]��b��'#-=fields/checkboxes/params/checkboxes.xmlnu�[���PK��#]��I�;; u0=fields/checkboxes/checkboxes.xmlnu�[���PK��#]���� 7=fields/checkboxes/checkboxes.phpnu�[���PK��#]�)��"9=fields/checkboxes/.htaccessnu��6�$PK��#]�:W���9=fields/sql/sql.xmlnu�[���PK��#]�>��NN�?=fields/sql/sql.phpnu�[���PK��#]$צ?��aG=fields/sql/params/sql.xmlnu�[���PK��#]�)��=J=fields/sql/.htaccessnu��6�$PK��#]���
��K=fields/sql/tmpl/sql.phpnu�[���PK��#]�)��3O=fields/imagelist/.htaccessnu��6�$PK��#]�o�l��#�O=fields/imagelist/tmpl/imagelist.phpnu�[���PK��#]�5�T=fields/imagelist/imagelist.xmlnu�[���PK��#]%m�auu�[=fields/imagelist/imagelist.phpnu�[���PK��#]�hE�		%G`=fields/imagelist/params/imagelist.xmlnu�[���PK��#]!p��!�d=fields/mediajce/tmpl/mediajce.phpnu�[���PK��#]v!ie
e
�y=fields/mediajce/mediajce.phpnu�[���PK��#]wN�uxx~�=fields/mediajce/mediajce.xmlnu�[���PK��#]�)��B�=fields/mediajce/.htaccessnu��6�$PK��#]&�Ao		#
�=fields/mediajce/params/mediajce.xmlnu�[���PK��#]����#v�=fields/mediajce/fields/mediajce.xmlnu�[���PK��#]뭘�!�!#K�=fields/mediajce/fields/mediajce.phpnu�[���PK��#]���� �=fields/mediajce/fields/media.xmlnu�[���PK��#]�&��$$(��=fields/mediajce/fields/extendedmedia.phpnu�[���PK��#]�)��l�=fields/usergrouplist/.htaccessnu��6�$PK��#]Mp^/��-9�=fields/usergrouplist/params/usergrouplist.xmlnu�[���PK��#]�����+s�=fields/usergrouplist/tmpl/usergrouplist.phpnu�[���PK��#]�	/^  &s�=fields/usergrouplist/usergrouplist.xmlnu�[���PK��#]�H���&��=fields/usergrouplist/usergrouplist.phpnu�[���PK��#]-�gW���=fields/user/params/user.xmlnu�[���PK��#]ӸR���=fields/user/user.phpnu�[���PK��#]�;p%�=fields/user/user.xmlnu�[���PK��#]�)��{�=fields/user/.htaccessnu��6�$PK��#]��NH��?�=fields/user/tmpl/user.phpnu�[���PK��#]N�"�hh! �=fields/textarea/tmpl/textarea.phpnu�[���PK��#]�����#��=fields/textarea/params/textarea.xmlnu�[���PK��#]�)���=fields/textarea/.htaccessnu��6�$PK��#]_��;		��=fields/textarea/textarea.xmlnu�[���PK��#]��5��>fields/textarea/textarea.phpnu�[���PK��#]�8���>fields/media/media.xmlnu�[���PK��#]��oD��J
>fields/media/tmpl/media.phpnu�[���PK��#]@���->fields/media/media.phpnu�[���PK��#]�)��>fields/media/.htaccessnu��6�$PK��#]kb9���D>fields/media/params/media.xmlnu�[���PK��#]v��--a>fields/text/params/text.xmlnu�[���PK��#]�)���>fields/text/.htaccessnu��6�$PK��#]�$`;;�>fields/text/text.xmlnu�[���PK��#]�Cr��&>fields/text/text.phpnu�[���PK��#]ϫ���(>fields/text/tmpl/text.phpnu�[���PK��#]3\���)>fields/editor/params/editor.xmlnu�[���PK��#]����ff(0>fields/editor/tmpl/editor.phpnu�[���PK��#]���
A	A	�1>fields/editor/editor.xmlnu�[���PK��#]Ƌ�O��d;>fields/editor/editor.phpnu�[���PK��#]�)��e@>fields/editor/.htaccessnu��6�$PK��#]��ZEDD+A>fields/calendar/calendar.xmlnu�[���PK��#]��m���D>fields/calendar/calendar.phpnu�[���PK��#]����#�I>fields/calendar/params/calendar.xmlnu�[���PK��#]�ӫ�$$!L>fields/calendar/tmpl/calendar.phpnu�[���PK��#]�)���N>fields/calendar/.htaccessnu��6�$PK��#]�)��XO>fields/url/.htaccessnu��6�$PK��#]�6��P>fields/url/url.xmlnu�[���PK��#]D��dd�V>fields/url/url.phpnu�[���PK��#]`�o�pp�[>fields/url/params/url.xmlnu�[���PK��#]z��""A_>fields/url/tmpl/url.phpnu�[���PK��#]�)��	�a>.htaccessnu��6�$PK��#]�)��bb>editors-xtd/module/.htaccessnu��6�$PK��#]����-c>editors-xtd/module/module.xmlnu�[���PK��#]�C����f>editors-xtd/module/module.phpnu�[���PK��#]�)���l>editors-xtd/article/.htaccessnu��6�$PK��#]�k\�gm>editors-xtd/article/article.xmlnu�[���PK��#]�"EOO�p>editors-xtd/article/article.phpnu�[���PK��#]|�/4}}lx>editors-xtd/image/image.phpnu�[���PK��#]�)��4�>editors-xtd/image/.htaccessnu��6�$PK��#]�6���>editors-xtd/image/image.xmlnu�[���PK��#]�RL$$T�>editors-xtd/contact/contact.xmlnu�[���PK��#]�)��Lj>editors-xtd/contact/.htaccessnu��6�$PK��#]K������>editors-xtd/contact/contact.phpnu�[���PK��#]�)��t�>editors-xtd/readmore/.htaccessnu��6�$PK��#]���GG!A�>editors-xtd/readmore/readmore.phpnu�[���PK��#]��bi!ٕ>editors-xtd/readmore/readmore.xmlnu�[���PK��#]<^�I..#F�>editors-xtd/pagebreak/pagebreak.xmlnu�[���PK��#]Rk����#ǜ>editors-xtd/pagebreak/pagebreak.phpnu�[���PK��#]�)����>editors-xtd/pagebreak/.htaccessnu��6�$PK��#]�)����>editors-xtd/menu/.htaccessnu��6�$PK��#]��=K�>editors-xtd/menu/menu.xmlnu�[���PK��#]�䮉XX��>editors-xtd/menu/menu.phpnu�[���PK��#]�)��F�>editors-xtd/fields/.htaccessnu��6�$PK��#]�����>editors-xtd/fields/fields.phpnu�[���PK��#]�4yl-�>editors-xtd/fields/fields.xmlnu�[���PK��#]�)����>editors-xtd/.htaccessnu��6�$PK��#]�8���]�>search/tags/tags.phpnu�[���PK��#]�$?B����>search/tags/tags.xmlnu�[���PK��#]�)��_�>search/tags/.htaccessnu��6�$PK��#]6\}��� #�>search/categories/categories.xmlnu�[���PK��#]�i��� S�>search/categories/categories.phpnu�[���PK��#]�)��'�>search/categories/.htaccessnu��6�$PK��#]	�~�44��>search/content/content.phpnu�[���PK��#]��ֆ���)?search/content/content.xmlnu�[���PK��#]�)��1?search/content/.htaccessnu��6�$PK��#]�)���1?search/newsfeeds/.htaccessnu��6�$PK��#]T���2?search/newsfeeds/newsfeeds.xmlnu�[���PK��#]*o��9?search/newsfeeds/newsfeeds.phpnu�[���PK��#]�)��N?search/.htaccessnu��6�$PK��#]�)���N?search/contacts/.htaccessnu��6�$PK��#]f �����O?search/contacts/contacts.xmlnu�[���PK��#]�"(�77�V?search/contacts/contacts.phpnu�[���PK��#]�)��Ak?privacy/actionlogs/.htaccessnu��6�$PK��#]�����!l?privacy/actionlogs/actionlogs.phpnu�[���PK��#]�N��!9s?privacy/actionlogs/actionlogs.xmlnu�[���PK��#]�)���v?privacy/message/.htaccessnu��6�$PK��#]��E�%%qw?privacy/message/message.phpnu�[���PK��#]����

�}?privacy/message/message.xmlnu�[���PK��#]�)��9�?privacy/user/.htaccessnu��6�$PK��#]r9GG��?privacy/user/user.phpnu�[���PK��#]H׾����?privacy/user/user.xmlnu�[���PK��#]�Ü�

ɜ?privacy/content/content.xmlnu�[���PK��#]��.H��!�?privacy/content/content.phpnu�[���PK��#]�)���?privacy/content/.htaccessnu��6�$PK��#]�)����?privacy/consents/.htaccessnu��6�$PK��#]����?privacy/consents/consents.xmlnu�[���PK��#]G������?privacy/consents/consents.phpnu�[���PK��#]�)��#�?privacy/.htaccessnu��6�$PK��#]�)���?privacy/contact/.htaccessnu��6�$PK��#]�(�r//��?privacy/contact/contact.phpnu�[���PK��#]�L�0

%�?privacy/contact/contact.xmlnu�[���PK��#]�)��}�?editors/.htaccessnu��6�$PK��#]6����#=�?editors/tinymce/form/setoptions.xmlnu�[���PK��#]X�ʬ��1�?editors/tinymce/field/skins.phpnu�[���PK��#]w��--(`�?editors/tinymce/field/tinymcebuilder.phpnu�[���PK��#]���h	h	$�?editors/tinymce/field/uploaddirs.phpnu�[���PK��#]��G~�~��@editors/tinymce/tinymce.phpnu�[���PK��#]�)��j�@editors/tinymce/.htaccessnu��6�$PK��#]�o�c��2�@editors/tinymce/tinymce.xmlnu�[���PK��#]� 8y;);)!4�@editors/codemirror/codemirror.phpnu�[���PK��#]�W"�)�)!�Aeditors/codemirror/codemirror.xmlnu�[���PK��#]���--�CAeditors/codemirror/fonts.jsonnu�[���PK��#]�1nB	B	8GPAeditors/codemirror/layouts/editors/codemirror/styles.phpnu�[���PK��#]GL:**9�YAeditors/codemirror/layouts/editors/codemirror/element.phpnu�[���PK��#]��'d��6�^Aeditors/codemirror/layouts/editors/codemirror/init.phpnu�[���PK��#]�)���mAeditors/codemirror/.htaccessnu��6�$PK��#]>MDDXnAeditors/codemirror/fonts.phpnu�[���PK��#]{,t���'�rAeditors/jce/layouts/editor/textarea.phpnu�[���PK��#]�)���uAeditors/jce/.htaccessnu��6�$PK��#]�yq�//�vAeditors/jce/jce.xmlnu�[���PK��#]@���%�%{Aeditors/jce/jce.phpnu�[���PK��#]B�C_uu)�Aeditors/none/none.phpnu�[���PK��#]�)���Aeditors/none/.htaccessnu��6�$PK��#]3�8b����Aeditors/none/none.xmlnu�[���PK��#]00cFJ!J!!�Atwofactorauth/yubikey/yubikey.phpnu�[���PK��#]�Q�ee#��Atwofactorauth/yubikey/tmpl/form.phpnu�[���PK��#]�Stt!8�Atwofactorauth/yubikey/yubikey.xmlnu�[���PK��#]�)����Atwofactorauth/yubikey/.htaccessnu��6�$PK��#]�)����Atwofactorauth/totp/.htaccessnu��6�$PK��#]���!!��Atwofactorauth/totp/totp.phpnu�[���PK��#]�^*UU*Btwofactorauth/totp/postinstall/actions.phpnu�[���PK��#]�E�\oo�Btwofactorauth/totp/totp.xmlnu�[���PK��#]�/�d�� kBtwofactorauth/totp/tmpl/form.phpnu�[���PK��#]�)���Btwofactorauth/.htaccessnu��6�$PK��#]�)��#oBquickicon/extensionupdate/.htaccessnu��6�$PK��#]J�Ƶuu-ABquickicon/extensionupdate/extensionupdate.xmlnu�[���PK��#]��Mq
q
-!Bquickicon/extensionupdate/extensionupdate.phpnu�[���PK��#]�;��!�+Bquickicon/akeebabackup/script.phpnu�[���PK��#]L�J���!".Bquickicon/akeebabackup/index.htmlnu�[���PK��#]|��N!]/Bquickicon/akeebabackup/web.confignu�[���PK��#]�)�� �1Bquickicon/akeebabackup/.htaccessnu��6�$PK��#]Q6Q��'�2Bquickicon/akeebabackup/akeebabackup.xmlnu�[���PK��#]b�d�3�3'o>Bquickicon/akeebabackup/akeebabackup.phpnu�[���PK��#]�)��zrBquickicon/.htaccessnu��6�$PK��#]�)��<sBquickicon/jce/.htaccessnu��6�$PK��#]'�n
��tBquickicon/jce/jce.xmlnu�[���PK��#]+E����wBquickicon/jce/jce.phpnu�[���PK��#]�)��#�~Bquickicon/phpversioncheck/.htaccessnu��6�$PK��#]���mII-�Bquickicon/phpversioncheck/phpversioncheck.xmlnu�[���PK��#]�����-7�Bquickicon/phpversioncheck/phpversioncheck.phpnu�[���PK��#]�.U9��[�Bquickicon/eos310/eos310.xmlnu�[���PK��#]-&\�**^�Bquickicon/eos310/eos310.phpnu�[���PK��#]�)����Bquickicon/eos310/.htaccessnu��6�$PK��#]�)�� ��Bquickicon/privacycheck/.htaccessnu��6�$PK��#]��f55'_�Bquickicon/privacycheck/privacycheck.xmlnu�[���PK��#]�w	ڔ	�	'��Bquickicon/privacycheck/privacycheck.phpnu�[���PK��#]�)�� ��Bquickicon/joomlaupdate/.htaccessnu��6�$PK��#]"[؋\\'��Bquickicon/joomlaupdate/joomlaupdate.xmlnu�[���PK��#]���NN'X�Bquickicon/joomlaupdate/joomlaupdate.phpnu�[���PK��#]�V�
��Bindex.htmlnu�[���PK��#]�)��#V�Binstaller/folderinstaller/.htaccessnu��6�$PK��#]�a���*(�Binstaller/folderinstaller/tmpl/default.phpnu�[���PK��#]�?>>-7�Binstaller/folderinstaller/folderinstaller.xmlnu�[���PK��#]�#���-�Binstaller/folderinstaller/folderinstaller.phpnu�[���PK��#]�)���Binstaller/.htaccessnu��6�$PK��#]���Binstaller/rsform/rsform.phpnu�[���PK��#]?��$Cinstaller/rsform/rsform.xmlnu�[���PK��#]�)���Cinstaller/rsform/.htaccessnu��6�$PK��#]��ĸ88PCinstaller/rsform/index.htmlnu�[���PK��#]i���yy'�Cinstaller/webinstaller/tmpl/default.phpnu�[���PK��#])�H]��&�Cinstaller/webinstaller/tmpl/hathor.phpnu�[���PK��#]�)�� �Cinstaller/webinstaller/.htaccessnu��6�$PK��#]O�,,.�Cinstaller/webinstaller/webinstaller.script.phpnu�[���PK��#]�a�'+Cinstaller/webinstaller/webinstaller.xmlnu�[���PK��#]u�d��'y/Cinstaller/webinstaller/webinstaller.phpnu�[���PK��#]�)���ICinstaller/jce/.htaccessnu��6�$PK��#]X	�`���JCinstaller/jce/jce.xmlnu�[���PK��#]�dd�T
T
eNCinstaller/jce/jce.phpnu�[���PK��#],�/���'�XCinstaller/urlinstaller/urlinstaller.phpnu�[���PK��#]d�,,'+]Cinstaller/urlinstaller/urlinstaller.xmlnu�[���PK��#]�)haa'�`Cinstaller/urlinstaller/tmpl/default.phpnu�[���PK��#]�)�� feCinstaller/urlinstaller/.htaccessnu��6�$PK��#]�)��$5fCinstaller/packageinstaller/.htaccessnu��6�$PK��#]RdDD/gCinstaller/packageinstaller/packageinstaller.xmlnu�[���PK��#]u��	��/�jCinstaller/packageinstaller/packageinstaller.phpnu�[���PK��#]��q$q$+oCinstaller/packageinstaller/tmpl/default.phpnu�[���PK��#]�)��ΓCsampledata/blog/.htaccessnu��6�$PK��#]wy�DD��Csampledata/blog/blog.xmlnu�[���PK��#]2�b||"�Csampledata/blog/blog.phpnu�[���PK��#]�)��mDsampledata/.htaccessnu��6�$PK��#]�)��0Dextension/joomla/.htaccessnu��6�$PK��#]tx%$�Dextension/joomla/joomla.xmlnu�[���PK��#]�5��wwTDextension/joomla/joomla.phpnu�[���PK��#]y(��6Dextension/jce/jce.xmlnu�[���PK��#]B�GM���9Dextension/jce/jce.phpnu�[���PK��#]�)��UDextension/jce/.htaccessnu��6�$PK��#]�)���UDextension/.htaccessnu��6�$PK��#]�)���VDauthentication/ldap/.htaccessnu��6�$PK��#]l��;��YWDauthentication/ldap/ldap.xmlnu�[���PK��#]2� ���iDauthentication/ldap/ldap.phpnu�[���PK��#]�)���}Dauthentication/joomla/.htaccessnu��6�$PK��#]cH��� �~Dauthentication/joomla/joomla.phpnu�[���PK��#]  �$$ �Dauthentication/joomla/joomla.xmlnu�[���PK��#]G���� ^�Dauthentication/cookie/cookie.xmlnu�[���PK��#]��3��-�- ��Dauthentication/cookie/cookie.phpnu�[���PK��#]�)����Dauthentication/cookie/.htaccessnu��6�$PK��#]�)����Dauthentication/.htaccessnu��6�$PK��#]�f�]]p�Dauthentication/gmail/gmail.phpnu�[���PK��#]��,	,	�Dauthentication/gmail/gmail.xmlnu�[���PK��#]�)����Dauthentication/gmail/.htaccessnu��6�$PK��)�b�D